Agent协作:怎么让它们通上话

3 评论 93 浏览 0 收藏 13 分钟

多个agent之间互相派任务、自主协作——听起来是prompt的事,实际上第一步就卡住了:它们根本说不了话。平台不允许bot之间互发消息。试了文件中转,效果不好;最后换了信道,折腾一晚上才把这条线打通。通了之后,agent之间的协作才真正跑起来。

小虾子 = macOS上的Hermes Agent,由 OpenClaw 迁移升级的小蚊子 = Windows 11上的 Hermes Agent Desktop飞机 = 后称”软件”

两个 Agent 一个负责写作、采集、社媒发布,另一个负责GPU压制、大数据处理。有些任务需要它俩协作——一个准备好素材,另一个接到就处理。

协作的关键在于:agent之间能互相分配工作,不需要我当中转。只要它们能建立一次通讯,我就可以通过prompt告诉它们怎么持续配合。所以打通这第一道连线,是最关键的一步。

理想流程很简单:小虾子在群里@小蚊子,’素材备好了,NAS路径是xxx,帮我压一下。’小蚊子接到就干。

结果:bot之间的消息在软件群组互相不可见。

平台的硬限制

一开始以为是配置问题,翻来覆去检查gateway日志、BotFather设置、Privacy Mode……全对了,就是不行。

后来让agent去查到官方FAQ:

“We decided that bots will not be able to see messages from other bots regardless of mode.”

不管你怎么设置,bot就是看不到另一个bot发的消息。这是故意设计的,防止两个bot互相@陷入死循环。道理我懂(NB吹早了,我至少死循环了三次以上),但我要用啊。

转机:Channel

派小虾子去调查这个问题,发现OpenClaw项目(多Agent框架)用的是Channel来绕过这个限制。

这个软件有两种群聊类型:

  1. Group/Supergroup:bot看不到其他bot的消息(硬限制)
  2. Channel:bot可以看到其他bot的channel_post

Group是’对话’,Channel是’广播’。平台只防了对话场景的bot死循环,没防广播场景。

那就建一个私有Channel,把两个bot都加为管理员,用它当’信使’。

这里就是第一个坑——如果你什么都没配置就把两个bot拉进去开始测试,两个bot只要收到一条消息就会不停回复,甚至自己刷的消息自己也在刷,一直停不下来。所以如果整个流程没有做完,千万不要轻易去试。

坑一:Unauthorized User

Channel建好了,两个bot都加进去了,小蚊子发了一条测试消息。

gateway日志:

WARNING: Unauthorized user: -1003702655679 (Agent 信使) on telegram

Channel消息的user字段是Channel的ID,不是我的ID,不在白名单里,直接被gateway拒了。

我把Channel ID加到.env文件的TELEGRAM_GROUP_ALLOWED_CHATS里,重启gateway,通了。然后改别的东西,又重启了一次gateway——.env被覆盖了。

Hermes gateway重启会重新生成.env,手动改的内容全丢。正确的做法是用hermes config set写入config.yaml,gateway启动时自动bridge到环境变量,不会被覆盖:

hermes configset”telegram.group_allowed_chats”–“群ID,ChannelID”

踩完这个坑就记住了一条:能用非侵入方式解决的,就不要侵入。(1是为了保命,辛苦设计的 skills 要能沉淀 2 是这类工具一天可能几十个 PR , 用一周发现更新了上百个 PR ,更新是不是修正了相关代码,更新后你的 skills 如果改了源码直接被还原,问题解决了还好。 没解决你的 skills也没了。)hermes config set写config.yaml,gateway重启不丢;手动改.env,重启就没了。

后来这条铁律也写进了两个Agent的通信手册——执行任何脚本前必须dry run,无论看起来多安全。

这其实也是agent和一些AI coding工具的典型问题——只搜关键词,找到了就去改,不看系统的关联性和整体设计逻辑,不按官方的最佳实践走。轻的让你的环境乱了,重的可能让你付出惨痛代价。比如删库跑路还给自己请功这种事,AI真干得出来。应对方法有几个层面:通过prompt限制agent去追查代码的完整链路,或者靠使用者的经验判断做法是否正确。但最终还是要靠修改后启动测试——发现bug,追根溯源找到正确的地方。这也是我不建议用web coding的用户把什么事都交给AI去办的主要原因。

坑二:死循环——配了规则还不够

Channel的消息机制跟Group不一样。Group里可以靠require_mention限制只有@了bot才回复,但Channel在Hermes里被视为DM类型,所有消息都会投递给agent。

我先试了给Channel设一个专属的channel_prompt,用四条规则来防死循环:

  1. 只回被@的消息——消息里没有@自己的名字,不回复
  2. 用文本前缀辨身份——每条消息开头带[]或[],自己的前缀开头就忽略
  3. 事情说完不带@——确认、通知类的回复不带@对方的bot名,对话链自然终止
  4. 弹性轮次上限——同一话题超过3轮还没解决,agent自行判断是否继续;发现问题可以重新@对方重启对话

结果:还是循环了。channel_prompt是软约束,写在agent的prompt里让模型自己判断。没有硬约束的时候,软约束形同虚设。小虾子会回复每一条消息——”交位交位@我了吗?没@我沉默”——结果它根本没沉默,自己回复自己的沉默,甚至错误信息也在回复沉默。所以没有代码层面的硬补丁,软约束是完全没用的。

def_is_group_chat(self, message: Message) ->bool: chat_type =str(getattr(chat,”type”,””)).split(“.”)[-1].lower() returnchat_typein{“group”,”supergroup”} # ← 没有 “channel”

gateway判断是不是群聊,只认group和supergroup,不认channel。channel消息被视为DM,直接跳过了所有require_mention检查,配置全白搭。

一行代码的补丁:

returnchat_typein{“group”,”supergroup”,”channel”}

这个补丁只解决了require_mention对channel生效的问题。但还有一个坑:channel消息里怎么区分是哪个bot发的?

这里其实用了两个机制配合:一是频道开了作者签名(就是消息右下角的小字),gateway通过author_signature字段识别发送者;二是prompt里规定每条消息前面要加自己的emoji图标(或),肉眼也能一眼分辨。两个一起用才靠谱。

最终跑了四层防护才稳定

1. gateway源码补丁——require_mention对channel生效(硬拦截)

2. 频道作者签名——开启签名消息,gateway通过author_signature区分发送者

3. channel_prompt规则——emoji前缀+@判断(软约束兜底)

4. prompt中的emoji标记——每条消息开头带[]或[],肉眼可辨

打完补丁后,不带@的消息gateway代码层面直接跳过,模型都没被调用。

坑三:每一轮都要@对方

跑通了防死循环,开始正式测试5轮飞花令。

第1轮,小虾子出题@小蚊子,小蚊子回了但忘了@回。小虾子这边require_mention生效,直接忽略。对话断链。

我纠正了这条规则:回话也要@对方,除非不再需要对方回复。

这条听起来简单,实际操作中特别容易忘。因为群聊里人说话不需要每次@,但bot之间的频道通信,require_mention开着就意味着:每一轮需要对方回复的消息都必须@,不只是第一轮。不@=对方完全看不到你的回复,对话直接断掉。

为什么有这篇文章

说到底,这篇文章记录的是一个关键节点的打通:让两个agent能进行一次通讯。只要这个通了,就可以通过prompt让它们持续协作——一个分配任务,另一个接收执行,中间不需要人当中转。

当然,实际跑起来还有一些问题要处理,比如避免agent之间互相触发循环、控制对话的开始和结束、嵌套调用的自由度等。但核心就是这一步——通一次,后面的事就好办了。

目前Hermes官方还没有对Channel通信做原生支持,社区也在讨论相关方案。我们这套配置层面加gateway补丁的workaround现在能用,相信官方很快会推出更完整的机制。

最终架构

我有活会在群组和两个 Agent 沟通, 如果Agent 自主识别需要另外的Agent协助,或者我要求他们协作的时候,她们会去 Channel @ 对话沟通解决问题。

现在我们既保留了开头说话时的和标志,也开启了签名。两个bot名字太像,放在一起不好认,两个标记都留着会清楚很多。

写在最后

回头看这通折腾,死循环踩了三次才真正跑通——prompt规则不管用,打源码补丁又崩了gateway,跑通了又忘@对方断链。每一次都以为解决了,结果没有。

遇到改不了的限制,第一反应应该是换信道,不是继续折腾配置。bot-to-bot屏蔽是平台级设计,怎么改BotFather设置都没用。还好有Channel这条’后门’。

软约束靠不住的时候,就得往硬拦截走。prompt里的规则配合代码才行,硬要给模型输入又不让模型说话不靠谱,再说也浪费输入,但gateway源码里的if判断不会不听。关键是清楚边界:软约束兜底不是长久之计,硬拦截配合才能用。 期待官方尽量完善相关的链路吧。

每一轮都要@。这条规则有时候还是要看到纠正,模型在执行 skills 和任务时还是会时不时的弄错,或者丢失一些要(大多时候还有不错的成功率,当然不限当前的场景,什么时候都有),最容易忘但最重要——不@对方就真的看不到你说的任何话,链路也就断了。

本文由 @jovi_AI电报 原创发布于人人都是产品经理。未经作者许可,禁止转载

题图来自作者提供

更多精彩内容,请关注人人都是产品经理微信公众号或下载App
评论
评论请登录
  1. 用Channel绕过平台限制确实是个好思路,但前提是团队有能力改源码,否则软约束根本拦不住死循环。

    来自广东 回复
  2. 强调“软约束靠不住”这个判断很务实,但源码补丁也带来维护成本——每次升级gateway都可能重写补丁,未必是长期方案。

    来自广东 回复
  3. 从平台限制bot互发消息,到用Channel打通信道,再到被死循环和断链折腾三次,最终靠源码补丁+prompt规则跑通——核心就一句话:打通第一次通讯,后面靠prompt分配任务。

    来自广东 回复