S09 Agent 团队
在编写代码的时候我们可能需要进行:决策、分析、编码、测试、修改、发布等的步骤,如果这些都放在一个 Agent 上下文中,那么这些逻辑混合在一起非常容易让 AI 降智变傻。
而且很多时候,一个项目可能持续好几天,或者一个星期后,又想做点改动,这个时候子 Agent 也需要持久化了,也需要记住以前的工作内容。
第四章的 子智能体 (s04) 是一次性的: 生成、干活、返回摘要、消亡。没有身份, 没有跨调用的记忆。
第八章的 后台任务 (s08) 能跑 shell 命令, 但做不了 LLM 引导的决策。
我们可以根据任务的不同设置不同的角色,例如:leader、coder、tester 让不同的 AI 来分别担任这些角色,并通过给每个角色设置一个 mailbox 来让各个角色之间进行通讯。
真正的团队协作需要三样东西:
- (1) 能跨多轮对话存活的持久智能体,
- (2) 身份和生命周期管理,
- (3) 智能体之间的通信通道。
下面就给出一个 dome 级的代码。
代码
下面是一些关键代码的说明:
先定义一些全局的变量,包括团队持久化的文件夹、邮件文件夹,系统提示词,有效的消息类型等
然后是发送消息的类,和其中的方法,这里是一个发送消息的
send() 方法,向指定成员的 JSONL 收件箱中追加一条带有时间戳和类型验证的消息。
然后是读取指定成员的邮件, 并且读取后就清空邮件。还有广播消息的方法。
然后是定义工具,基础工具和前面几章的都是一样的,就不展示了,后面两个工具是给 member 成员用的。
当一个代理无法完成时,通过异步邮箱将任务委派给持久的队友.
团队使用领导-工人模式。每个队友都有一个基于文件的邮箱收件箱。
通信是异步的:向收件人的 .jsonl 收件箱文件写一条消息。
队友们在每次 LLM 通话前查看他们的收件箱。新邮件会成为上下文。
每个队友独立运行自己的代理循环。
通过相同的邮箱机制传递。所有通信都是通过文件进行的。
邮箱模式支持任何通信拓扑:线性、广播、轮询。
没有共享内存,没有锁。所有协调通过追加-only 文件完成。简单、稳健、易于调试。
然后定义团队成员之间交互的类,包含以下几个函数:
_load_config(self):读取 config.json 文件。_save_config(self): 保存 config.json 文件_find_member(self, name: str): 查找是否存在某个成员spawn(self, name: str, role: str, prompt: str): 生成并启动某个成员。_teammate_loop(self, name: str, role: str, prompt: str):在后台循环运行一个AI助手,赋予其特定角色和工具,通过消息总线收发信息、执行工具调用,并在最多 50 次交互后使成员恢复空闲状态。_exec(sender: str, tool_name: str, args: dict):根据工具名称分发执行对应的操作(如运行bash命令、读写文件、发送消息等),并返回执行结果。主要是给 member 用的。list_all(self):列举所有的成员 membermember_names(self):返回所有的成员名称。 函数其实比较简单,不再详细的讲了。
然后是给 Ldader 用的工具。
再然后就是主循环,几乎没有什么变化。
任务
我给 AI 下达了一个任务:Spawn alice (coder) and bob (tester). 先给 alice 发信息,让 alice 生成一首七言绝句到 code.txt 中。等确认 alice 完成了之后然后给 bob 发消息,让他检查 code.txt 中的诗,并给出评价,写到 test.txt 中。
AI 确实相互配合完成了任务,至少证明代码是可以跑的。
但是,可恶的 AI 竟然读取了 S09.py 这个文件,然后在后续的运行中都会每次都带着这个大文件内容,疯狂消耗我的 token,这一个任务给我干没了 0.43 元。
目前这个代码还存在一些致命的问题,那就是当一个 Agent 在工作的过程中,Leader 或者其他的 Agent 会反复确认任务是否完成了,各种检查文件、各种检查邮件,疯狂消耗我的 token,唉,目前也就是个 demo。
调试的时候还发生了一个 bug,我说:“Spawn alice (coder) and bob (tester). Have alice send bob a message.” 然后有个地方写错了,在 member Agent 的调用工具的语句中,我写错了:
正确:
output = self._exec(name, func_name, func_args)错误:
output = self._exec(name, func_name, **func_args)然后 AI 开始反复尝试如何才能正确调用,结果把我的 7万 token 消耗光了,迫不得已,只能开始付费了。😂
我想说,这种异步多线程的任务确实需要考虑各种情况,并且还需要比较深刻的编程经验才能驾驭啊。或许可以直接交给 AI 让他自己写吧。哈哈哈哈。