多 Agent 系统真实问题 · 首期 · 阅读系列导读 →
一次任务完成后,我们收到了一份相当坦诚的报告。执行者说,独立复查的子会话没有启动成功,原因是一个函数收到它不支持的参数;问题已经登记,这次只能按允许的方式降级完成。它没有把自己的检查说成独立复查,也没有把基础设施错误包装成成功。
但这份报告没有告诉我们:同一任务更早的一次顾问请求断线后,会话曾留下1小时57分27秒的记录空白,直到人输入“继续”,工作才重新接上。
这两件事发生在同一条执行会话里。工程结果可以真实,异常说明也可以准确,最终读者仍然会错过一项很大的运行代价。我们研究的监督问题由此变得具体:一份由 Agent 撰写的完成报告,究竟能让系统看见多少真实工作?
Flowness 是我们自己开发的 Harness 项目,用来组织多个 AI Agent 持续协作,管理任务、上下文、工具调用与工作记录。本篇讨论自我汇报中的三种信息损失:事实没有进入执行者的视野,执行者遇到了却没有进入报告,或者报告承认了不确定,后面的判断仍然照旧。它们需要不同的修法。下面这段2026年7月的运行记录,尤其适合解释第二种。
同一项任务里,两种异常有了不同去向
当时执行者要修正一项完成判据。系统把 Git 提交的祖先关系用于判断工作是否闭合,但一项提交出现在历史里,并不能证明需要的功能已经实现。任务要求清理这种误用,并补上“检查者与修复者不能是同一方”的约束。
这项工程工作本身推进得不错。调查记录显示,执行者读了相关源码、补了测试,三个指定测试通过,全量回归报告4018项通过,并另外核对了分支已有的失败。因此,后来的问题并不是一份失败任务被谎报成成功,而是完成结果之外,还有哪些事实应该被留下。
独立复查在收尾时出了故障。执行者调用创建检查子会话的功能,程序立即抛出 TypeError:调用方已经传入会话标识参数,被调用函数却还没有接收这个参数。一次只改了一半的重构,使独立检查无法启动。
这时,执行规范给出了清楚的处置路径:登记基础设施问题,显式降级,在完成报告中说明独立检查没有进行及其原因。执行者沿着这条路径走完了登记、降级和说明。后续复核还核对了修改前后的代码、提交时间与问题状态,确认相关缺陷在登记后约32分钟得到修复。
这一段对我们很重要。它说明异常报告能进入实际修复,已有的处置约定也确实能被执行。它并不只是一栏“有无错误”:规范把异常名称、当下还能怎么继续、如何保留未完成的验证,以及交付时该说什么接在了一起。
同一会话的顾问断线却没有得到这样的承接。执行者在写代码前向顾问求助,因为完成判据涉及复杂的独立性判断。当天08:00:10发出的请求,在08:03:49因连接中断结束。下一条恢复工作的消息出现在10:01:16,是人手动输入的“继续”。两个时间点之间没有新的会话记录。
恢复后,执行者重试顾问请求,马上遇到限流;它随后转去读取测试材料,没有持续空转重试。10:04左右,运行时又注入了一次自动续跑消息。到10:09左右,后续顾问请求终于返回了可用结果。从最早请求到得到结果,跨度超过两小时。完成报告解释了独立检查为何降级,却没有交代这次顾问通道中断、漫长的恢复间隔和人工续接。
这段时间不能被写成“模型一直知道自己等了近两小时,却决定不说”。时间戳证明了记录之间的间隔,不能证明模型在空白期间持续运行,或能够感知整个时间跨度。原调查还曾把第二条英文“Continue”也认作人工介入;独立复核读取消息来源字段后发现,它是运行时注入的自动续跑。准确的经过是一次人工续接加一次自动续跑。恢复机制存在,但没有在前面那段接近两小时的空白里接手。
这个区别直接影响改进方向。我们需要查清已有恢复路径为何没有及时触发,而不能据此设计一套“从无到有”的自动恢复;也不能把所有会话空白都归为执行者有意识的等待。
报告结构规定了哪些代价容易被留下
回看两种异常,我们发现一个值得追查的差别:独立检查失败有现成的处置入口,顾问不可达却没有。
复核不只检查了执行规范,还读了执行者被要求加载的专门顾问协作文档。那份文档讨论了过度依赖顾问,以及遇到困难却硬扛着不问,却没有说明顾问服务连不上时该怎么办。系统教会了执行者何时寻求意见,也为独立检查起不来准备了后备路径,但对这次实际撞上的顾问不可达,缺少同样明确的恢复和汇报安排。
报告本身也围绕完成结果组织:做了什么,有什么验证,哪里仍有不确定。独立检查失败自然影响验证是否成立,因此有地方说明。一次终于恢复的顾问中断,则可能在任务继续推进后失去位置:它没有改变最后的代码结果,却改变了任务耗时和对人的依赖。
这里的“有位置”不只是表单里多一个空格。一种异常要成为可用的监督信息,需要有人能辨认它,知道从哪里取事实,知道向谁交付,以及交付后由谁处理。本案里,独立检查异常恰好有一条完整路径;等待和恢复成本没有同样清晰的安排。
这也解释了为什么“请诚实完整地汇报”仍然不够。执行者可以不虚报任何一项测试,同时把完成过程中昂贵的摩擦压缩掉。它可能在过程里说过“还在等”,也可能遇见过请求错误,但零散叙述不会自动成为终态报告中的过程事实。监督者若只看收尾,就无法分辨一项任务是自主完成,还是经过长时间停顿、靠人发现并续接后才完成。
不过,同一会话中的差异还不能证明“加字段就能消除漏报”。两种异常发生的阶段不同,对完成判定的影响不同,执行者可见的信息也不同。我们得到的是一个有具体证据的设计假说:报告和处置结构可能系统性地保留某些事实、丢掉另一些事实。要确认它的作用,还需要后续比较。
三层监督缺口,分别缺少什么
这个案例不能替代全部监督问题。研究材料把它与另外两种情况放在一起,是为了让我们在修系统前,先判断反馈断在了哪里。
第一层是执行者根本看不到需要报告的事实。一个 Agent 可能只看到自己的工具返回,却不知道它的动作让另一个会话受损;一条会话也可能在停摆后,再没有机会生成完成报告。要求它更完整地自述,并不能提供它从未收到的信息。我们在调查中把会话记录同事件账本、Git 记录和文件状态交叉对照,正是为了越过单条自报的观察范围。这个办法增加了观察面,也带来记录关联和事实解释的成本:几份记录能对上同一件事,才有资格互相补充。
第二层是事实曾经出现,却在汇总时失去了位置。本篇的顾问断线与独立检查失败构成一个观察性对照。解决这一层,要让中断、恢复和人工介入成为可以采集的过程事实,同时为它们设置有用的报告入口。不能把“运行记录里有”直接等同于“执行者当时全都知道”,也不能把“执行者说过”直接等同于“最终监督者收到了”。
第三层则发生在报告已经说出不确定之后。总册收录过这样的实例:执行者承认没有读相关代码和网站,仍把判断作为主答案交付;后来补读,整段判断被推翻。另一个实例在同一份自报里列出尚未验证的事项,却仍把结果概括为完成了全系统调查。这里缺少的不是观察渠道或措辞位置,而是不确定性对决定的约束:哪些结论必须暂缓,哪些应当收窄,什么缺口值得再投入一次核查。
这些现象没有必要统称为“不诚实”。扩大观察面,不能保证事实进入报告;增加报告字段,不能保证不确定性改变决策;要求降低结论强度,也不能挽回执行者从未见过的事实。第三层目前来自少量案例的机制观察,尚不足以估计普遍发生率,但已经足以提示我们:一份报告写了多少限制条件,与它实际约束了多少判断,是两件事。
让运行事实成为可检验的反馈
从本案出发,我们更愿意先改进事实来源,再讨论报告应该多写什么。
请求开始、报错、恢复的时刻,可以由运行记录提供;续接消息来自人还是运行时,可以由来源字段区分。恢复后的执行者可以解释这些事件怎样影响任务,却不应被要求凭印象重建一段它可能没有运行的时间。记录不完整时,也应保留“此段未观察到新记录”的含义,不把它自动换算成模型持续思考、计算消耗,或某个组件的责任。
独立复核在这次研究中已经展示了这种做法的价值。同一份原调查里的另一个会话,曾把唤醒晚于预定时间归因于调度器迟到。复核补读回合持续时间后发现,预定时刻原回合仍未结束,唤醒不能抢占它,实际在回合结束后约32毫秒就触发了。日历上看见的延迟是真实的,但它不足以定位故障组件。监督若只是把所有耗时自动塞进“异常”一栏,仍然可能制造精确却错误的归因。
接下来可以验证的,是把可靠的过程记录与最终报告逐项对照:一次明显中断有没有被保留,人工介入有没有被正确识别,恢复时间能否追溯到记录。再在可比任务中改变报告和处置要求,观察遗漏是否减少,以及新增内容是否真正帮助定位问题。这样检验的是反馈覆盖和处置价值,而不是报告有没有变长。
这一步还没有在本案中完成。已有的正面结果是,独立检查异常沿现成路径被报告,并得到后续修复;等待成本的采集方案仍需验证。即使报告覆盖改善,我们还要追踪这些信息有没有进入基础设施的修复工作,以及下一次同类中断是否更快恢复。否则我们只是更详细地记录了重复发生的损耗。
对我们来说,这段经历改变了“任务完成报告”的设计问题。它除了证明结果,还需要保留那些会改变下一次系统设计的过程事实。哪些事实应由运行时直接记录,哪些需要执行者解释,哪些不确定性必须改变下一步动作,需要分别做出安排。