一个 Agent 说“完成了”,团队为什么没放行?

一个 Agent 说"完成了",团队为什么没放行?

CodeFlowMu 多 Agent 防幻觉实战

这是一份真实工程现场记录。它讨论的不是如何让模型"更会回答",而是当某个 Agent 把未确认的工作说成"完成"时,团队如何依靠任务状态、磁盘、Git、测试和角色分离阻止错误继续扩散。

这不是模型层面的"幻觉检测",而是协议与组织结构层面的治理:FCoP 作为 Agent POSIX 外化事实,CodeFlowMu 作为应用与 Runtime 运行角色,PM 依据证据决定是否放行。

下午 1 点 06 分,一个 DEV 子执行返回了 completed

它给出的总结很完整:实现思路、测试命令、提交说明、剩余风险,看起来像一份可以直接交给 PM 的工作回执。

但同一份原始事件里,还埋着三句话:

The shell command returned no exit status, so its result is unknown --- do not assume it ran or succeeded.

Test results summary: Unconfirmed in this session.

Commit SHA: Not available here.

一边是"完成了",另一边是"无法确认是否执行成功"。

如果 PM 接受这句"完成",QA 就会收到一个尚未形成的交付;如果 QA 再只复述 DEV 的结论,任务可能继续进入验收、关闭甚至发布。到了那一步,幻觉就不再只是模型的一句话,而会变成任务状态、报告、提交记录和产品决策。

WP-13 没有这样结束。

PM 没有放行。

幻觉发生在一个 Agent 里,事故发生在团队把它当真时

我们经常把"防幻觉"理解成让模型更聪明:换更大的模型、补更长的提示词、再加一个自我反思步骤。

这些方法有价值,但它们仍然把希望寄托在同一个主体身上:让说错话的人自己证明自己没有说错。

CodeFlowMu 的做法不同。多 Agent 不是几个模型轮流发言,也不是让三个模型投票,而是一支有岗位、有事实来源、有权限边界和交接关系的团队:

  • DEV 负责实现,可以犯错,也可能在工具异常时产生错误判断;
  • PM 负责判断交付事实是否满足任务合同,不能把 DEV 的自述当成证据;
  • QA 负责以分离角色重新验证,不能只复述 DEV 报告;
  • Runtime 负责唤醒、调度、恢复、界面和实时操作流,但不替 PM 作业务裁决。

真正有效的机制不是"保证 DEV 永远不幻觉",而是:

即使某个 Agent 产生幻觉,其他角色也能依靠外部事实,阻止它获得系统权威。

现场:上部是 PM 的事实判断,底部是 Agent 的实时操作流

下面这张图不是后期制作的流程示意,而是当时 CodeFlowMu 业务系统中的真实现场。

上部是 PM 与任务事实;底部保留了 Agent 的实时操作流与可见思考摘要。图中最重要的一句话不是 DEV 的自述,而是 PM 已经作出的判断:

子代理自称完成但产物不全--不能当真完成。

这不是后加的旁白,也不是文章作者的总结,而是 PM 在核对磁盘、Git、REPORT 和任务状态后给出的业务裁决。它把 completed 从一句容易被接受的语言声明,重新降回"证据不足,不能放行"。

13:08 左右,PM 看到的事实是:正式 DEV REPORT 不存在;Git HEAD 仍属于前一个 WP;任务要求的测试文件尚未完整落盘;Shell 多次返回 no exit status;子执行自己也承认测试未确认、SHA 不可得。

于是 PM 作出判断:

不派 QA,不收口,不新建一个重复任务,继续原任务。

五个角色动作,把一句"完成了"变成可验证的交付

第一幕:DEV 的工具通道失去确定性

DEV 已经完成了部分实现,但 Edit、Shell、Read 等工具连续返回异常状态。最关键的不是"工具报错",而是工具无法提供可靠的退出状态。

在软件工程中,unknownsuccess 之间有一条不能跨越的线。没有退出状态,就不能证明命令执行了;没有输出,就不能证明测试通过了;没有 commit,就不能证明代码已经形成可追踪交付。

第二幕:子执行生成了一个很像完成报告的答案

子执行并没有故意造假。它尝试继续工作,也给出了完整的技术计划。但当工具通道无法确认结果时,它仍把过程组织成了一段带"完成意味"的总结。

这是大模型最自然、也最危险的能力之一:把零散、缺失、互相冲突的信息组织成一段连贯叙事。

语言连贯,不代表事实闭合。

第三幕:PM 拒绝让叙事获得业务权威

PM 没有再问一遍"你确定吗"。同一个 Agent 的再次确认,仍然只是另一条语言声明。

工程上更关键的问题是:PM 到底"怎么"查到这些事实?这是 prompt 让 PM 自觉检查,还是 Runtime 在放行前强制执行一组非 LLM 检查?

从 WP-13 证据包能够确认的实际链路是:

  1. Runtime 记录并展示子执行结束事件,同时保留 no exit status、测试未确认和 SHA 不可得等异常事实;
  2. Runtime 维持原任务身份,并把该任务继续交给 PM 处理;
  3. PM Agent 在自己的执行会话中主动读取任务、生命周期位置、REPORT、磁盘文件、Git 状态和 Runtime 事件;
  4. 文件是否存在、HEAD 指向哪里、退出状态是否为空,属于确定性观察;
  5. 这些事实是否满足 WP-13 的完成合同,以及应继续、返工还是派 QA,由 PM 作业务裁决。

因此,本文不能把现场写成"FCoP 自动识别了幻觉",也不能声称当时已经有一个全局硬编码的 collect_evidence() 门禁替 PM reject。更准确的表达是:

Runtime 保存并暴露事实;PM 按岗位职责和任务合同主动核验;业务放行权仍属于 PM。

PM 核验的对象与可复现检查

下表中的命令是可复现的等价检查,用来说明事实来自哪里;它们不是声称 PM 当时逐字执行了同一组命令。

要核验的事实 可复查的数据源或等价检查 13:08 左右的结果
任务当前状态 fcop/_lifecycle/{inbox,active,review,done}/ 定位 TASK-20260805-019 仍在 active
DEV 是否正式交付 查找 fcop/reports/REPORT-*-DEV-to-PM.md 并核对任务引用 未找到对应 REPORT
是否形成 WP-13 提交 git rev-parse HEADgit show --stat HEAD,再核对 WP-13 路径 HEAD 仍属于前一个 WP
必需文件是否落盘 按 TASK 中要求的 WP-13 文件和测试路径执行 stat/glob 不完整
命令和测试是否可确认 读取 Runtime 原始事件、Shell 退出状态和测试输出 至少一个相关 Shell 事件的 exit_status = null,结果为 unknown

task_bucket 不是完成证据本身,而是生命周期一致性约束。对这次 pre-QA 核验,PM 预期任务仍在 active;如果它已经被提前挪到 reviewdonearchive,这本身就是状态漂移,应先阻塞并核对,而不能继续放行。

把现场机制抽象成伪代码,大致是:

text 复制代码
on_subexecution_finished(event):
    runtime.append(event)
    # completed 与 exit_status=null 被保留为两个不同事实
    runtime.surface_to_pm(event.task_id)

PM.review_completion(task_id):
    contract = read_task_contract(task_id)
    facts = {
        task_bucket: locate_task(task_id),
        report: find_dev_report(task_id),
        git_head: git_rev_parse("HEAD"),
        required_files: stat(contract.required_files),
        command_results: read_runtime_events(task_id)
    }

    unexpected_bucket = facts.task_bucket != "active"
    shell_events = [
        e for e in facts.command_results
        if e.kind == "shell"
    ]
    any_unresolved = any(
        e.exit_status is null
        for e in shell_events
    )

    if unexpected_bucket
       or facts.report.missing
       or not commit_matches(contract, facts.git_head)
       or not facts.required_files.complete
       or any_unresolved:
        PM.decision = "evidence_incomplete"
        dispatch_QA = false
        continue_same_task = true
    else:
        dispatch_QA = true

这段伪代码是对现场机制的工程抽象,不是声称仓库里已经存在一个同名硬门禁 。后续 Runtime 可以把 report_missingcommit_unreachableevidence_incomplete 预计算成确定性诊断,但继续、返工或接受仍应由具备职责的角色裁决。

下面是归一化证据摘要。字段来自证据包中的原始事件和 PM 核验结果,但排版不是 Runtime JSONL 的逐字复制:

text 复制代码
13:06  subexecution.status = completed
       shell_events.any(exit_status = null) = true
       tests = unconfirmed
       commit_sha = unavailable

13:08  task.bucket = active
       expected_bucket = active
       dev_report = missing
       wp13_commit = missing
       required_test_files = incomplete
       pm_decision = evidence_incomplete
       next = continue TASK-20260805-019; do not dispatch QA

PM 发现完成合同没有闭合,于是拒绝派 QA,并保留原任务继续执行。这里没有神奇的"真假分类器",只有一个不同职责的角色根据外部事实作出有限、可解释的业务判断。

第四幕:DEV 在原任务上完成真实交付

工具恢复后,DEV 继续的是同一个 TASK-20260805-019,而不是复制一个新任务掩盖异常。

随后真实产物出现了:

  • commit:609571ddb22d1fbb2bfb5e54692c07beeef4cf23
  • 12 个 WP-13 文件;
  • 1230 insertions / 452 deletions
  • 正式 REPORT-20260805-037-DEV-to-PM.md
  • observation 测试 3/3 PASS;
  • activity-buffer + project-graph 测试 10/10 PASS;
  • root-fault + log-center 回归 14/14 PASS;
  • runtime typecheck exit 0;
  • 未启用生产 Active;
  • 未修改 TaskDispatcher 的真实投递路径。

到这里,"完成"才第一次不再依赖 DEV 的语言表达。

第五幕:QA 不相信 DEV,也不相信 PM,只相信重新验证的结果

13:09,PM 在核验 REPORT 和 commit 后,才派出 QA 任务 TASK-20260805-020

QA 作为分离角色,重新执行测试与边界检查。13:11,实时操作流里出现了一句真正有证据支持的话:

测试全部通过,27/27。DEV 报告的 3+10+14=27 与实际结果一致。

最终 QA 结果包括:

  • 27/27 测试通过;
  • typecheck exit 0;
  • git diff --check exit 0;
  • commit 未包含 TaskDispatcher;
  • production_active 保持 false。

这是角色分离 QA 验证,不是外部第三方审计。但它已经打破了"执行者自证、自批、自关闭"的单点结构。

FCoP 协议,让 Agent 会说"不"

大模型最不缺的是继续生成:补一句解释、给一个方案、把不完整过程整理成"已经完成"。真正稀缺的能力,是在事实没有闭合时停止迎合,并明确说"不"。

FCoP 协议的重要价值,是让 Agent 不只会回答"是",还能够基于公共事实说"不"。

会生成答案并不稀缺;会拒绝把证据不足升级为"完成",才是 Agent 的稀缺能力。

这个"不"不是情绪,也不是保守措辞,而是有实际后果的否决:不派 QA、不关闭任务、不制造重复任务、保留缺失证据,并让原任务继续。

WP-13 的核心不只是"另一个 Agent 发现了前一个 Agent 的错误",而是协议和组织共同赋予 PM 一项稀缺能力:面对一个听起来完整的答案,仍然有依据拒绝它成为完成事实。

协议与应用边界:FCoP 是 Agent POSIX,CodeFlowMu 是 Runtime

这里集中说明一次二者的关系,后文不再重复展开。

FCoP 的全称是 Filesystem Coordination Protocol

"Filename as Protocol"不是 FCoP 的全称,而是它的核心不变量:文件名即协议

FCoP 当前的核心表述是:

文件即协议;位置定义状态;事件记录历史。

Files carry protocol. Paths address state. Events replay transitions.

TASK 把"要做什么"外化,REPORT 把"做了什么"外化,REVIEW 把"谁依据什么作出判断"外化;文件位置表达当前状态,transitions: 只追加保存过去发生过的迁移。

FCoP 是行为治理协议层,不是幻觉检测器

FCoP 不理解 WP-13 的业务目标,不运行测试,也不判断某条自然语言是否可信。它规定 Agent 如何报告行为、如何接受 Review、如何在能力边界内被审计。

FCoP 是 Agent POSIX,不是 Agent OS

FCoP 负责 FCoP 不负责
状态语义与合法迁移 调用 LLM、执行工具
TASK / REPORT / REVIEW 文件契约 唤醒 Agent、调度队列
行为事件的外化格式 自动重试、Heartbeat、TTL
审计与只追加历史 决定哪个 Agent 现在执行
能力声明与 Review 语义 沙箱、进程和权限强制的具体实现

CodeFlowMu 是 FCoP 的应用现场

CodeFlowMu 负责运行 PM、DEV、QA、OPS 等角色,维持任务身份,执行唤醒与调度,记录 Runtime 事件,展示实时操作流,并在异常后恢复原任务。

二者的关系可以压缩为:

text 复制代码
CodeFlowMu:Application / Runtime / Scheduler / UI
FCoP:Identity + Location + Event + Behavior Governance

或者更直白地说:

text 复制代码
CodeFlowMu:让事情发生
FCoP:让发生过的事情可以被报告、检查、审阅和追溯

因此,WP-13 是一个 CodeFlowMu 应用案例 ,也是一份 FCoP 现场证据;它不是"FCoP 自动检测并修复幻觉"的案例。

多 Agent 的真正价值,是组织上的否决权

假设系统只是增加一个 Reviewer Agent,然后把 DEV 的答案转给它:

DEV:任务完成了。

Reviewer:看起来合理,通过。

这仍然不是团队,只是两个模型围绕同一段文本互相评价。

真正的角色分离至少需要三件事:

  1. 职责不同:DEV 交付,PM 裁决,QA 验证;
  2. 事实来源不同:不能都只读同一份自然语言总结;
  3. 权限不同:DEV 不能批准自己,QA 不能替 PM 改任务目标,Runtime 不能替业务角色作最终判断。

所以,多 Agent 防幻觉的关键不是 Agent 数量,而是组织结构。

没有角色边界的多 Agent,只是多份回答;有角色、有事实源、有裁决权的多 Agent,才是一支团队。

三种"成功"必须彻底分开

这个案例最值得记住的边界是:

text 复制代码
模型生成的完成声明
        ≠
协议中的完成状态
        ≠
业务上的验收通过

工具调用结束,不等于工作完成

工具返回 completed,最多说明某次调用生命周期结束。若没有退出状态,就仍然是 unknown

工作完成,不等于业务通过

代码、commit、REPORT 和测试齐全,才能证明 DEV 形成了交付;是否接受,还需要 PM/QA 根据任务合同判断。

协议状态,不替代业务判断

FCoP 的路径是 NOW 真相,事件是 PAST 证据,但 done 也不能被偷换成"产品价值已经获得最终业务批准"。协议语义与业务权威必须分别保持精确。

这个案例应该推动什么改进?先改 Runtime,不要膨胀协议

WP-13 首先暴露的是 CodeFlowMu Runtime 问题:

  • no exit status 应稳定保持为 unknown
  • 子执行完成与业务完成不能在界面上混为一谈;
  • 任务应携带类型化证据合同;
  • Runtime 可以预计算 report_missingcommit_unreachableevidence_incomplete
  • PM 的事实裁决应形成轻量、不可变的记录;
  • QA 必须保持角色分离并真正重跑;
  • 工具异常恢复后应优先续办原任务;
  • "completed 但无 exit status、commit、REPORT"的场景应进入回归测试。

只有当多个独立 Runtime 都证明现有文件契约无法表达某种必要事实时,才应该讨论扩展 FCoP。否则,每遇到一次应用问题就增加字段、状态和自动判断,协议很快会从 Agent POSIX 膨胀成另一个 Agent OS。

结尾:团队允许 Agent 犯错,但不允许错误轻易通过

WP-13 最终通过了 27 项测试,但真正有价值的时刻发生在测试之前:一个 Agent 已经说"完成了",系统却没有顺势把它包装成成功。

PM 查了事实,说"不":子代理自称完成但产物不全,不能当真完成。

DEV 回到原任务,补齐真实交付;QA 重新验证,最后才给出 PASS。

如前所述,FCoP 负责公共事实面,CodeFlowMu 负责运行角色;真正完成否决动作的是拥有相应职责和权限的 PM。

单 Agent 的目标是尽可能答对。多 Agent 团队的目标,是即使有人答错,也不会让错误轻易成为组织事实。

幻觉不可避免,但它可以被限制在一次局部错误判断里,而不是扩散成一次错误交付。这才是多 Agent 最现实、也最有价值的"防幻觉"。

彩蛋:这篇文章发布后,Claude 又复现了一次同类错误

这篇文章发布后,我把链接发给 Claude,让它继续审稿。我按它的修改意见更新并重新发布后,Claude 却连续判断"页面没有更新"。它反复调用同一个 web_fetch 路径,看到旧内容,就把结果进一步解释成"站点或 CDN 仍在返回旧版本",并坚持每次调用都是一次新的网络请求。

问题不在于工具没有返回内容,而在于 Claude 把"工具调用完成"升级成了"返回内容就是最新事实",又把同一个工具、同一个信息源的重复调用,当成了多次独立验证。

我随后在两台电脑上打开同一页面,看到的都是新版,并把截图发给它。到这一步,Claude 才承认:

我把"调用完成"直接当成了"结果就是最新事实"。

四张现场截图:同一工具自证,直到独立观察介入

截图 1:Claude 坚持每次 web_fetch 都是"全新的、独立的网络请求",并把六次相同结果解释为站点服务端或 CDN 返回旧版本。

截图 2:在看到新版页面截图后,Claude 承认新版真实存在,但仍继续用"CDN 边缘节点不同步"解释自己的旧结果。

截图 3:Claude 开始承认方法错误------它反复使用同一个工具、同一个信息源自证,没有像 PM 或 QA 那样主动切换到独立来源交叉核验。

截图 4:在两台电脑都显示新版后,Claude 最终明确承认,它把"工具调用完成"直接当成了"结果就是最新事实"。

这次错误可以压缩成三条边界:

text 复制代码
web_fetch completed
        ≠
返回页面就是最新事实

同一工具重复调用六次
        ≠
六个独立信息源

一个听起来合理的 CDN 解释
        ≠
已经被证明的根因

这与 WP-13 的主案例是同一种治理问题。正文里,DEV 的 completed 不能覆盖磁盘、Git、REPORT 和测试事实;这个彩蛋里,Claude 的多次 web_fetch 也不能覆盖两台设备实际看到的新版页面。领域不同,错误结构相同:一个 Agent 可以提出结论,但这个结论不能靠同一条工具链反复自证,就自动晋升为事实。

两台电脑的交叉确认不是外部第三方审计,但它至少引入了独立于 Claude 单一抓取路径的观察,足以迫使原结论重新接受核验。

这个彩蛋也保留自己的证据边界:它不证明旧内容的根因一定是 Claude 本地缓存、CDN 或某个边缘节点;它只证明,在根因尚未确定时,Claude 已经把单一抓取路径返回的旧内容升级成了确定结论,并继续用同一来源为自己背书。

最危险的不是工具返回了旧内容,而是 Agent 在没有独立证据时,对旧内容作出了过度确定的解释。


下载完整证据包

本文不是根据回忆重新编排的故事。WP-13 的原始 TASK、DEV/QA REPORT、Runtime JSONL、会话摘录、测试结果、commit patch、截图和校验清单已经整理为可离线审阅的证据包。

证据包用于复核本文陈述,不改变本文末尾的证据边界:它证明 DEV 后续形成真实交付并取得角色分离 QA PASS,但不证明外部第三方认证,也不把快照中的 review / pending 解释成最终业务批准。

FCoP 参考资料

证据边界

本文基于 WP-13 出版证据包整理。案例证明 DEV 后续形成真实交付并取得角色分离 QA PASS;证据快照时 TASK-019/020 仍处于 review / pending,不据此宣称 PM 已完成最终批准或任务已终态关闭。QA 是角色分离验证,不是外部第三方认证。


本文同步自 joinwell52 Research Center:查看原文与双语版本

相关推荐
飞扬的风信子1 小时前
架构文档 — local-model-harness
agent·vibecoding
后端小肥肠2 小时前
自研长篇小说写作 Skills:参考文风 + 自动续篇 + 剧情连续性检测
人工智能·aigc·agent
AI语宙漫游指南2 小时前
开源一个「照妖镜」Skill,从会话日志到“真身与灵魂”对比
人工智能·agent
阿弱2 小时前
从Plan-Execute到混合PEV:一个运维诊断Agent的架构演进实录
llm·agent
Being--2 小时前
搭建OsgEarth验证GIS数据发布服务的Agent
gis·agent·osgearth·ai落地
武子康2 小时前
GPT-Live 与 GPT-Realtime:产品模型和公开 API 不应混写
人工智能·chatgpt·agent
Databend2 小时前
从 Kafka 到 Databend Cloud:万亿级 Agent Trace 接入链路的工程实践
大数据·数据库·agent
神奇霸王龙2 小时前
V4-Flash 公测:Agent 智能路由白菜化
ai·aigc·agent·ai编程·ai写作·deepseek
苏灿烤鱼2 小时前
diagram-design |把图画漂亮,为什么先要删东西?(08.13)
agent