多 Agent 协同编排:最后还是回到了显式状态机
让几个 Agent 在群里自由讨论,demo 很漂亮,交付很要命。最后把流程改成了能重放的任务图。
最开始的版本挺有意思:一个统筹角色、几个干活的角色,大家在一个共享会话里轮流发言,谁觉得信息不够就追问,谁做完了就 @ 下一个。演示的时候看着确实像一支小团队,能自己把任务拆开、互相纠错。跑了两天真实任务之后,我把这套全删了。
三个绕不过去的问题
- 上下文互相污染。 A 的检索结果、B 的中间推理全堆在同一段对话里,越到后面,每个角色看到的内容越不干净,结论开始漂移。
- 失败不可重放。 某一步错了,没法只重跑那一步;从头上跑一遍,前面的随机性又变了,两次输出对不上,连「到底哪里坏了」都说不清。
- 责任边界模糊。 出问题时日志里是一段对话,不是一次调用。想回答「这个结论是哪一步、哪一版提示词产出的」,基本靠猜。
第三点在 ToB 场景里是硬伤。业务方不关心你的 Agent 有多聪明,他们要的是出了问题能定位到环节、能复现、能解释。一段自由对话给不了这个。
改成显式任务图
现在的做法很朴素:把流程预先拆成有限的步骤,每一步有明确输入、输出和状态,产物落盘;调度器只读状态,不让模型自己决定「下一步找谁」。
{
"run_id": "r-20261103-01",
"steps": [
{"id": "s1", "role": "extract", "state": "done", "artifact": "s1.json"},
{"id": "s2", "role": "verify", "state": "done", "artifact": "s2.json"},
{"id": "s3", "role": "draft", "state": "running", "depends_on": ["s1","s2"]},
{"id": "s4", "role": "review", "state": "pending", "depends_on": ["s3"]}
]
}
几个具体约束:
- 每个 worker 只拿到自己那一步的上下文,加上上游产物的结构化字段,不拿整段历史。
- 步骤之间只传 JSON,不传自然语言结论,避免「翻译损耗」层层累积。
- 重试必须幂等:用
run_id + step_id + attempt做键,重复执行覆盖同一份产物,不追加。 - 调度器不调用模型。它只做状态迁移、超时和重试,逻辑可以单测。
改完之后最直观的变化是,出错时我能直接打开 s2.json 看上游给了什么,而不是翻两万字的聊天记录。代价是灵活性下降:流程之外的分支得先改图,不能指望模型临场发挥。
一个反直觉的取舍
原本以为「让模型自己决定下一步」是能力,实际跑下来它更像不确定性来源。把决策权收回到代码里以后,整体耗时反而降了,因为少了大量互相确认、复述、纠偏的往返 token。
自由对话适合探索期——你还不知道流程长什么样的时候。要交付、要审计、要能重放,就得有骨架。
还没解决的
一是人类中途介入:跑到一半业务方改了口径,目前只能整单作废重跑,代价太大。二是长任务的成本控制,步骤一多,中间产物的存储和重复校验本身就成了开销。这两块还在试,等有结论再单独写一篇。