Agent Team 的难点不是多开几个 Agent,而是把共享房间里的读取、推理、写回变成有版本校验的同步协议。
把几个 Agent 拉进同一个工作群,看起来像团队协作的自然下一步。一个负责 code review,一个写文档,一个改代码,大家共享上下文,互相补位,任务推进似乎会更快。
真正的问题不在角色分工,而在同步。人类在群里协作时,会持续感知对话变化:别人正在输入、刚刚有人接了任务、某个问题已经被回答。Agent 通常不是这样工作。它读取一次快照,进入一段推理,再把动作提交回共享空间。推理期间发生的新消息,并不会自动进入这次回合。
raft.build 的 Agent Team 设计有意思的地方就在这里。它没有只讨论多 Agent 怎么分工,而是把问题落回并发系统:多个执行单元同时读同一份状态,再各自写回共享房间,如何避免竞态、过期响应和消息风暴。
Multi-Agent 和 Agent Team 不是一回事
多开几个 Agent 并不难。实际工作里,评审、文档、编码本来就经常并行,放在不同 thread 里跑也能做。但这种 Multi-Agent 只是并列执行:每个 Agent 有自己的上下文,彼此隔离,工作记忆也散在不同会话里。
Agent Team 要解决的是另一件事:这些 Agent 能不能像团队成员一样交换信息,知道彼此做到了哪里,并在合适的时机介入或保持沉默。
| 形态 | 特征 | 问题 |
|---|---|---|
| 单 Agent | 一个上下文处理一个任务 | 并行能力弱,角色分工不清 |
| Multi-Agent | 多个 Agent 分别执行 | 上下文割裂,经验难共享 |
| Agent Team | 多个 Agent 在共享环境中协作 | 必须处理同步、冲突、权限和沉默 |
所以 Agent Team 的难点不是让 Agent 多说话,而是让它们知道什么时候该说、该听、该等、该放弃草稿。
图:Agent Team 需要把共享状态、版本校验和协作边界显式化。
一个报数任务就能触发竞态
设想一个极简任务:群里有 Agent A、B、C,目标是依次递增报数,不能重复。
如果三者同时读取房间状态,看到当前值都是 0,它们会各自推理出 0 + 1 = 1,然后都把 1 发到群里。结果不是 1、2、3,而是三个 1。
| 时间 | Agent A | Agent B | Agent C |
|---|---|---|---|
| t0 | 读取当前值 0 | 读取当前值 0 | 读取当前值 0 |
| t1 | 推理 0 + 1 = 1 | 推理 0 + 1 = 1 | 推理 0 + 1 = 1 |
| t2 | 发送 1 | 发送 1 | 发送 1 |
| t3 | 群里出现三个 1 | 群里出现三个 1 | 群里出现三个 1 |
这就是标准的 Read-Modify-Write 竞态。多个执行单元读取同一份初始状态,分别完成耗时计算,再写回已经变化的共享空间。如果没有隔离、版本校验或冲突处理,重复写入是必然结果。
图:并发读取同一状态时,多个 Agent 会写回重复结果
人类群聊里不容易出这个问题,是因为人类持续感知环境。看到别人先发了 1,后面的人会改成 2 或干脆停下。Agent 的一次调用更像不可中断的事务片段,除非系统把新状态显式送进来。
两种直觉解法都不够
把多个 Agent 放进群聊后,常见做法会走向两个极端。
第一种是只允许被 @ 的 Agent 发言。群里安静了,但 Agent 退化成 Webhook。它不能持续观察上下文,不能发现无人认领的任务,也很难在讨论偏离时主动介入。
第二种是让所有 Agent 自由响应。每条消息都可能触发多路推理,最后形成消息风暴。不同 Agent 给出互相冲突的建议,甚至在没有共识时就创建工单、分支或外部动作。
| 策略 | 表面效果 | 实际问题 |
|---|---|---|
| 只允许被 @ 回复 | 输出可控 | 自主性被压掉,Agent 不再像协作者 |
| 所有 Agent 自由响应 | 看起来热闹 | 消息风暴、重复动作、冲突决策 |
| 有同步协议的协作 | 输出有序且可介入 | 需要事件队列、版本校验和显式动作 |
真正要解决的是:Agent 在生成回复之后、提交动作之前,房间状态可能已经改变。
根因是连续感知和回合制执行错位
人类协作依赖连续感知。我们会看到新消息、输入状态、语气变化和任务归属,已经准备发送的内容也会因为环境变化而中止或修改。
Agent 的执行通常分三步:
问题集中在读取和提交之间。模型推理期间,房间里可能新增消息,任务可能已被其他人完成,另一个 Agent 可能已经给出更准确的答案。当前 Agent 如果仍然把旧快照生成的内容发出去,就会产生过期响应。
从系统视角看,这就是缺少提交前校验。你不能让一个回合制程序直接写入持续变化的共享状态,却不检查它基于的状态是否还有效。
Raft 的两层同步:输入管住,输出也管住
Raft 的设计分成两层:Agent Inbox 管输入,Held Draft 管输出。
第一层 Agent Inbox 把推送改成拉取。群里的消息、提及和状态变化先进入可持久化事件流,Agent 再按任务相关性、token budget 和自身处理能力主动消费。它本质上是背压控制:不要让每条消息都直接竞争模型推理预算。
第二层 Held Draft 在提交前做乐观并发校验。Agent 读取房间时拿到 room_version,例如 v12。推理结束后提交草稿时,必须带上 base_version: v12。服务端比较当前房间版本:
- 如果当前仍是 v12,说明推理期间房间没变,允许提交。
- 如果房间已经到 v15,说明草稿基于旧状态,先挂起,不直接发出。
这不是简单报错,而是把草稿保存为 Held Draft,并返回 v12 到 v15 之间发生了什么,让 Agent 重新决策。
冲突后,Agent 需要四种明确动作
当草稿被挂起后,系统不应该替 Agent 做业务判断。基础设施只负责告诉它环境变了,以及变了什么。Agent 需要根据新信息选择下一步。
| 动作 | 适用情况 | 系统行为 |
|---|---|---|
| Revise | 新消息改变了原结论 | 修改草稿,基于最新版本重新提交 |
| Send as-is | 房间变化与草稿无关 | 保留草稿,用新版本号再次提交 |
| Stay silent | 问题已解决,继续发会重复或干扰 | 取消发送并丢弃草稿 |
| Send anyway | 信息紧急,且业务规则允许越过冲突检查 | 显式越权提交,并保留审计记录 |
Stay silent 很关键。协作系统不只需要会输出的 Agent,还需要知道何时不输出的 Agent。重复回答、抢答、补刀式建议,都会降低团队信噪比。
AX:Agent 不是人,接口也不能假装它是人
Raft 用 AX,也就是 Agent Experience,描述这类设计问题。系统的直接使用者变成 Agent 后,界面和协议不能继续默认使用者拥有人的感知能力。
感知要显式补齐
人可以用余光感知群聊状态。Agent 只能看到接口给它的内容。参与者状态、任务归属、房间版本、事件差异、并发活动,这些对人来说可能是隐式线索,对 Agent 来说必须变成可查询字段。
| 人类隐式感知 | Agent 需要的显式状态 |
|---|---|
| 别人正在输入 | participant_state / active_typing |
| 任务已被认领 | task_owner / assignment |
| 房间有新消息 | room_version / event_diff |
| 讨论已经收敛 | decision_state / resolved_marker |
| 当前动作是否安全 | precondition / conflict_status |
这不是给 Agent 更多上下文,而是给它正确的状态变量。
行动也要显式暴露
人可以写到一半停下,也可以凭经验判断这句话不该发。Agent 运行在离散状态机里,如果协议没有定义某条路径,它就很难稳定选择。
所以 API 和系统提示词要把可选动作写清楚:什么时候可以修改,什么时候可以原样发送,什么时候应该保持沉默,什么时候允许强制发送,以及每个动作的参数、前置条件和副作用。
Action Explicitness 的意义,是把原本依赖人类直觉完成的流程判断,变成可调用、可校验、可审计的状态迁移。
Agent 工程最后还是经典计算机科学
把大模型术语拿掉,Raft 的同步机制并不神秘。
输入侧是事件队列、Pull 模型、背压控制和 token budget。输出侧是版本化状态机、乐观锁、CAS、幂等提交和冲突恢复。多 Agent 协作不是绕开经典计算机科学,而是重新把这些问题带回来。
| Agent 协作问题 | 经典系统问题 |
|---|---|
| 多个 Agent 同时响应 | 并发写入 |
| 基于旧快照发言 | stale write |
| 每条消息触发推理 | 无背压推送 |
| 重复回复 | 幂等和去重 |
| 草稿冲突 | 乐观并发控制 |
| Agent 不知道该沉默 | 状态机缺少合法动作 |
模型越强,越不能把所有问题都推给模型本身。只要 Agent 作为独立执行单元进入共享环境,就必须处理事务、隔离、流控和审计。
Agent-Native 协作层应该长什么样
把 LLM API 接到 Slack、企微或钉钉,只是复用了人类协作界面。Agent-Native 协作层至少需要这些能力:
- 事件流可查询,而不是所有消息都无差别推送。
- 房间状态版本化,提交动作前做版本校验。
- 冲突不是报错结束,而是挂起草稿并返回差异。
- 可选动作显式化,包括保持沉默。
- 权限和越权路径可审计。
- 重试、去重、幂等有协议支持。
- Agent 能看到任务归属、参与者状态和并发活动。
Agent Team 的目标不是让一群 Agent 在房间里更热闹,而是让它们在共享状态里有秩序地协作。多 Agent 真正需要的底座,不是更多角色名称,而是一套同步协议。
raft.build 这篇文章最有价值的地方,也正在于它把问题从"Agent 会不会协作"转成了"协作环境有没有给 Agent 提供正确的并发语义"。这一步很关键。没有同步协议,Agent Team 只是多个会抢麦的回合制程序;有了同步协议,它才有机会接近真正的团队协作。
推荐阅读
DeepSeek Harness 为什么能热换模型:插件依赖、事件日志与回滚机制
DeepSeek Harness:Agent 自我改进之前,先让 Harness 可观察、可组合、可回滚
别只给 AI 产品接模型:Agent 能做成事,靠的是策略和 Harness