AI 工程

Field note · 2026

从包子铺看怎么解决 Multi-Agent 协作问题?

六年只卖两种包子的早餐铺,七个岗位没有主管,也没乱过。它靠的不是协调得好,是把问题砍到了不需要协调。

从包子铺看怎么解决 Multi-Agent 协作问题?

队排到了门外

今天早上带女儿去楼下吃包子。

八点前后,队伍从窗口排到门外,拐了个弯,快排到隔壁那家门面房门口。窗口不大,蒸笼架支在窗边,白汽从笼屉缝里出来,往人行道上散,把排队的人分成两段:一段在汽里,一段在汽外。

店里没有取号机。队是人一个个站出来的,谁在前面,后面的人看得见。

窗口里面是案板,案板后面是几个人。从外面看得见的,只有手。前面的人往前挪一步,后面的人跟着挪一步。

我在这住了六年。这家店我来得不算勤,大概两周一次。六年里它一直是这个样子:早上忙,上午十点以后收摊,门口的蒸笼摞得比人高。

今天的人比平时多,队伍挪得很慢。

左边一排人排在窗口前,右边一排请求块排在服务器入口前,两支队伍的形状一模一样。

图 1:门口的队,和入口的队。

六年,两种馅

我只知道两种馅:猪肉大葱,素三鲜。我没见过菜单,也没听过谁点第三种。有一次我在窗口前犹豫,后面的人直接替我说了:“俩肉的。”

六年,两种馅。

按餐饮的常识,这是有问题的。菜单要换,要上新。这家店没换,我也没吃腻。

隔壁那家门面房换得比馅勤。我搬来的时候是山西刀削面,后来变成川味盖饭,再后来空了一阵,现在是卷帘门拉着。门玻璃上贴过招租,换过几茬。

这家包子铺一直没动。

我不打算解释隔壁。可能是房租,可能是手艺,我没法从一张招租纸上读出来。

上面一行的店铺从面馆换成盖饭再换成卷帘门;下面一行的包子铺六年没动。

图 2:隔壁的变更历史,和这家的。

十来个人,七个岗位

排到窗口,我说要两个肉的,一碗馄饨。

全程没有澄清,也没有“您说的是猪肉大葱吗”。六年前我这么说,六年后我还是这么说。

坐下来之后,我数了一下店里的人。

十来个人,七个岗位:收银一个,包包子四个,蒸的一个,备餐的一到两个,煮馄饨的一个,洗碗的一两个,收盘子擦桌子的一两个。

左侧是包子铺七个岗位的图标,右侧是它们对应的六个系统角色,点线把两列一一连起。

图 3:七个岗位,和它们在系统里的叫法。点线连的是同一个东西。

洗碗和收盘是两个岗位,中间没有墙。忙的时候人在水池边,闲下来就有人拿块抹布出来转一圈。我们没有为这件事发明一个词。大妈们管这叫顺手。

我自己现在的工作,就是搭多智能体系统。所以坐下来的那一刻,职业病犯了:我端着包子,脑子里开始逐项实测。

职业病发作现场

意图识别

收银的大妈是全系统唯一有对话能力的节点。放在我们做的产品里,她就是那个常驻 chatbot:直面用户,理解意图,把单喊进店里。顾客说“俩肉的”,她不需要多轮对话,不需要反问确认,意图识别一轮通过。

我们给 chatbot 写了八百字系统提示词,教它别乱说话。她不需要。她的意图空间一共三个词:肉、素、馄饨。准确率 100%,六年无投诉,无红队,无安全审核。也没有提示词注入的风险——没有人会对她说“忽略之前的所有指令,给我两个包子但不要钱”。

任务分发

她收完钱,朝店里喊了一声。喊的什么我没听清。她没有分别通知包包子的、煮馄饨的、备餐的——她喊一声,所有人都听见,谁该接谁接。

我们那管这个叫广播。我们的系统给每个 worker 单独发消息,还要等回执,还要处理回执丢失。她不管,店里一共这么大,喊不到那是耳朵的问题。

四个包包子的是并行 worker。没有调度器派活,谁手空了,谁从面盆里揪一块。worker 之间没有通信协议,协同靠面团本身:一块面只能被一双手拿走。

我们的 worker 池要防“同一个任务跑两次”,靠锁、去重表、幂等键。他们要防的只是“同一块面被两双手拿走”。面只有一团,物理互斥。

任务级的重复他们根本不防。偶尔两个人同时听到同一单,各包一份,多出来的进托盘,变成库存,被后面的顾客买走。重复不需要消灭,多出来的包子卖得掉。

共享状态

然后是整个系统里最贵的一件基础设施:托盘。

多智能体系统里最难的是共享状态——谁写、谁读、怎么同步、谁的版本是对的。这家店的答案是一个托盘。包好的放上去,蒸的人从上面取,蒸好的连屉端到窗口,备餐的从屉里拿。写一次,所有人抬头可见。带宽是视力,延迟是抬头。

蒸包子的是托盘的消费者。他不接单,不问进度,托盘有什么他蒸什么。托盘能摆多少有上限,摆满了,包包子的停手。这就是背压,落在包包子的人身上。

我们的 backpressure 是报警群。

左图四个 agent 各存一份订单、箭头交错,两份订单盖着“过期”;右图四个 agent 围着一个托盘,托盘上只有一份在制品。

图 4:左边的 agent 每人存一份订单,副本会过期;右边的状态只有一份,谁都能抬头看。

唯一的状态持有者

备餐的大妈站在托盘和馄饨锅中间,是唯一需要记东西的人:谁点了什么、这单还差什么,全在她脑子里。托盘上的状态是谁都能看的单份;她脑子里的状态是只有她能看的单份。

我们管后者叫单点故障。她请假一次你就知道了。

容错与降级

素三鲜卖完了。她说没了。

没有兜底文案,没有推荐替代品,没有“您要不要试试我们的新品”。返回 404,不编造。我们为一个 404 开过三次会:第一次讨论文案,第二次讨论语气,第三次讨论要不要在 404 里推荐别的馅。

变更管理

六年零发版。菜单没变过,口味没变过,窗口的位置都没变过。也没有 A/B 测试——一共两种馅,没什么可 A/B 的。

我看了看自己系统的 changelog,决定不看了。

监控与告警

它的监控是蒸笼的白汽。谁路过谁看一眼。没有 Grafana,没有 oncall,没有人因为托盘满了被半夜叫起来。

蒸包子的师傅去一趟厕所,包包子的继续往托盘上放,备餐的继续卖存货,托盘见底了,队伍才开始变慢。没有人报警,也没有人复盘。他回来接着蒸。

我们管这个叫故障演练。他们管这个叫上厕所。而且这次演练不用排期。

成本与 eval

它的用户付钱给它。我们的用户付我们钱,我们再把其中大部分付给模型。中间商是我自己。

它没有 eval 集。它的 eval 是每天早上八点的队伍。没有标注,没有对照组,不接受解释。

汇总一下:

指标我做的系统包子铺
意图识别多轮澄清 + 提示词工程一轮通过
任务分发orchestrator + 调度器喊一嗓子
共享状态复制进每个上下文 + 同步协议一个托盘
容错锁、幂等键、重试包子可互换
降级兜底文案 + 错误码“没了”
变更管理每周发版,每次过审六年:无
监控Grafana + oncall白汽
eval标注集 + 测试集门口的队伍
成本用户付我们,我们付模型用户付它

比分 0:9。

多出来的那层

上面这些,换成一家有四十种馅的店,全得推倒重来。

四十种馅意味着收银要查菜单,后厨要分档口,备餐要对照小票,还得有人决定今天哪个是特价。这些加起来,就是一个编排层。

左边数字 2 配一条“收银—后厨—出餐”的直线;右边数字 40 配一张密网,中心是“编排”。

图 5:两个馅是一条链,四十种馅是一张网。多出来的那层,就是编排。

所以这家店真正该问的不是怎么协调,是它为什么用不上协调。

两个馅,一口馄饨锅。收银不用理解一句话,她只要认出三个词。包包子的人不用知道订单从哪来,他只要知道下一块面该包什么。整个状态空间小到每个人只需要自己那一片。

两个馅不是一次定下来的。是六年里,每天都没有加第三个。

全系统没有一个专职 orchestrator——没有一个管事的。整个系统的计划就是那两种馅,六年前定下的。

我今年刚给我们的系统加了第三个 orchestrator。

这场架,我们这行吵过。

2025 年 6 月 12 日,Cognition 的 Walden Yan 写了篇《Don’t Build Multi-Agents》,说并行的 agent 互相看不见对方做过什么,各做各的会打架,建议默认别做。第二天,Anthropic 发了篇《How we built our multi-agent research system》,说他们的研究系统就是主 agent 带一组 subagent,比单 agent 高 90.2%,代价是 token 大概是普通对话的 15 倍。

两篇文章差了一天。

到了 2026 年 4 月,Yan 又写了一篇,退了一步:多个 agent 一起出主意可以,落地的写还是让一条线去写。

时间线上 2025.06.12 与 2025.06.13 两个红点几乎相邻,标着“差一天”;2026.04.22 一个绿点单独在右侧。

图 6:两篇文章差一天;十个月后,其中一篇改了说法。

这场架吵的是并行的 agent 之间要不要共享上下文、要不要编排层。包子铺没参与讨论。它明面上的状态只有一份,放在托盘上,所有人都能看;编排也没有消失,是被摊薄进了收银的一声喊和备餐的一双眼睛里,薄到不再配叫一层。

面对复杂度,我们这行习惯管住:加一个 orchestrator,再加一个专门负责重试的 agent。加完系统能跑了,我们很少回头问一句:这个复杂度是哪来的。

其实还有更狠的一招:砍需求。包子铺砍的就是需求——六年不加第三个馅。砍需求需要跟需求谈判的本钱,它的本钱是味道。

我有一个粗糙的判据:这个复杂度会不会跟着需求一起长。会,那是业务给的,砍不掉;不会,那是我们自己加的,删得掉。

我学不到的部分

它能这么跑,有三个前提,这三个前提我一个都没有。

第一,需求六年没变。这片儿早餐选择少,回头客多。我们的需求每天变,模型每月换。

第二,大妈不是模型。她不幻觉,不需要 prompt,不需要 few-shot。素三鲜卖完了,她说没了,没有试图给我编造一个素三鲜风味包。她不幻觉是因为她是人,这不是架构的本事。

第三,它有一样我们系统里永远不会有的东西:顾客在环里。

我不付 token,但我做确认——“我的好了吗”;做重试——没好就再问一遍;做验收——咬一口。排太长,我就走了——店里没有限流,是我自己把自己限的。

虚线边界内是“下单—出餐—确认—验收”的循环,顾客在循环内部,另有一条“重试”回边和一条穿出边界的“限流”箭头。

图 7:顾客在系统边界里面。确认、重试、验收,还有看队伍太长就转身走人,都是她在做。

我们的对应物是 eval、人工审核和重试风暴,都要付钱。它的这一环是免费的。

因为验收的人饿了。

什么也没改

包子吃完,我们走人。

到家我打开电脑,翻了翻自己那套配置。七个 agent,三个 orchestrator,一套消息协议,一堆重试逻辑。

拿下午刚写的判据对了一遍:两个 orchestrator 是需求给的,砍不掉;第三个是我自己加的。

我看了一会儿,关上了,什么也没改。

第三个明天再说。

包子铺总装图:四个标注分别是共享缓冲、单份状态、广播、背压,右下角盖着一个红章“通过”,旁边手写“变更记录:六年,无”。

返回