01-多Agent系统为什么总是过早宣布完成

多 Agent 系统为什么总是"过早宣布完成"?

你有没有遇到过这种情况:让 Agent 帮你写一个完整的功能模块,它信心满满地说"已完成",结果你一跑------缺了三个文件、两个函数没实现、测试用例一个都没写。

这不是模型能力不够,而是多 Agent 系统的结构性缺陷。今天我从架构设计的角度,拆解这个行业的顽疾,以及我设计 Symbio 框架时的解决方案。


一、一个真实的崩溃瞬间

上周五晚上 11 点,我让一个多 Agent 编码系统帮我实现一个完整的 REST API 模块,包含用户注册、登录、JWT 鉴权、RBAC 权限控制。

Agent 信心满满地回复:

✅ 任务完成!已创建以下文件:

  • models/user.py
  • routes/auth.py
  • middleware/jwt.py
  • tests/test_auth.py

我满怀期待地打开项目目录,结果:

  • models/user.py --- 只有 class 定义,字段全是 pass
  • routes/auth.py --- 注册接口写了一半,登录接口直接 # TODO
  • middleware/jwt.py --- 文件是空的
  • tests/test_auth.py --- 只有一个 def test_placeholder(): pass

四个文件,没有一个能跑。

这不是个例。用过 Cursor、Claude Code、Devin 等 AI 编程工具的同学,大概率都踩过类似的坑。问题的根源不在于模型"不会写代码",而在于多 Agent 系统缺少一套工程化的"完成判定机制"


二、"过早完成"的三个根源

2.1 根源一:EOS Token 的训练偏差

大语言模型在训练时被优化为"尽快结束对话"。当模型输出 EOS(End of Sequence)token 时,生成就停止了。问题是:

复制代码
训练目标:最大化 P(EOS | 当前上下文)
    ↓
模型倾向:只要上下文看起来"差不多完成了",就尽快输出 EOS
    ↓
实际效果:Agent 在完成 60% 的工作后,就认为自己"已经完成"

这不是模型"偷懒",而是训练目标和实际需求之间的结构性矛盾。模型被训练成一个"对话者",而不是一个"工程师"。对话者追求的是"让对话自然结束",工程师追求的是"所有需求都验收通过"。

2.2 根源二:缺乏外部参照

Agent 只能看到自己的对话历史,没有全局视角。它不知道:

  • 其他 Agent 在做什么
  • 整体任务的完成进度
  • 上下游依赖是否就绪
  • 测试用例是否通过

这就像一个程序员只看自己写的代码,从不跑测试、从不 review、从不集成------他当然觉得自己写完了。

2.3 根源三:多 Agent 通信的"传话游戏"效应

在传统的多 Agent 系统中,Agent 之间通过"对话"传递信息:

复制代码
Agent A: "我需要一个用户模型"
Agent B: "好的,我创建了一个 User 类"  ← 实际上只写了 class 定义
Agent A: "收到,继续下一步"  ← 信任了 B 的口头汇报
Agent B: "登录接口已完成"  ← 实际上只写了一半
Agent A: "任务完成!"  ← 没有验证,直接宣布

这就是"传话游戏"效应:

  1. 信息在传递中丢失 --- B 说"已完成",A 不知道实际完成度
  2. Token 爆炸 --- 每次传递都携带大量冗余历史对话
  3. 钻牛角尖 --- Agent 陷入自己的对话上下文无法自拔


三、为什么多 Agent 比单 Agent 更严重?

你可能会问:单 Agent 不也会过早完成吗?

会,但程度完全不同。多 Agent 系统的"过早完成"是一个系统性放大的问题:

复制代码
单 Agent 的失败模式:
    任务 → Agent 执行 → 过早完成 → 人类发现 → 人工修正

多 Agent 的失败模式:
    任务 → Agent A 执行 → 过早完成
         → Agent B 基于 A 的"完成"结果继续执行 → 过早完成
         → Agent C 基于 B 的"完成"结果继续执行 → 过早完成
         → ... → 级联失败

关键区别在于错误传播链

维度 单 Agent 多 Agent
错误发现时机 人类直接检查 需要跨 Agent 验证
错误传播范围 局部 级联放大
修正成本 低(回退一步) 高(回退多步)
Token 浪费 可控 指数级增长

这就是为什么多 Agent 系统需要一套工程化的防过早完成机制,而不是靠模型"自觉"。


四、Symbio 的解决方案:三层防御体系

在设计 Symbio 框架时,我从工程角度构建了三层防御体系,从根源上解决"过早完成"问题。

4.1 第一层:强制 Tool Calling 结束

核心思想 :不允许 Agent 通过自然语言输出 EOS 来结束任务,必须调用一个显式的 submit_task 工具。

复制代码
# ❌ 传统方式:Agent 自己判断是否完成
class Agent:
    def run(self, task):
        result = self.llm.generate(task)
        return result  # Agent 说完就结束,不管做没做完

# ✅ Symbio 方式:强制 Tool Calling 结束
class Agent:
    def run(self, task):
        while True:
            result = self.llm.generate_with_tools(task, tools=self.tools)
            
            if result.tool_call == "submit_task":
                # 必须提交:修改了哪些文件、测试结果如何
                return self.verify_submission(result)
            elif result.tool_call:
                # 继续执行其他工具调用
                task = self.execute_tool(result.tool_call)
            else:
                # 没有工具调用 = 还没完成,继续
                task = self.remind_incomplete(result)

为什么有效?

传统方式中,Agent 说"我完成了"就结束了。但在 Symbio 中,Agent 必须调用 submit_task(task_id, files_changed) 才能结束。这个工具调用会触发一系列验证:

  1. 检查所有文件是否真实存在
  2. 检查文件内容是否非空
  3. 检查是否所有 checklist 项都已标记完成
  4. 如果有测试用例,自动运行测试

从工程上绕过 EOS 提前停机问题。

4.2 第二层:显式未完成清单(Checklist)

核心思想:在任务开始时,由 Initializer Agent 生成一个 JSON 格式的 Checklist,将"完成"标准以代码形式固化。

复制代码
{
  "task_id": "auth-module-001",
  "status": "in_progress",
  "checklist": [
    {
      "id": "user-model",
      "description": "创建 User 数据模型,包含字段定义和验证",
      "status": "done",
      "files": ["models/user.py"],
      "test": "tests/test_user_model.py"
    },
    {
      "id": "auth-routes",
      "description": "实现注册和登录接口",
      "status": "in_progress",
      "files": ["routes/auth.py"],
      "test": "tests/test_auth_routes.py"
    },
    {
      "id": "jwt-middleware",
      "description": "实现 JWT 鉴权中间件",
      "status": "pending",
      "files": ["middleware/jwt.py"],
      "test": "tests/test_jwt.py"
    },
    {
      "id": "rbac",
      "description": "实现 RBAC 权限控制",
      "status": "pending",
      "files": ["middleware/rbac.py"],
      "test": "tests/test_rbac.py"
    }
  ],
  "completion_criteria": {
    "all_items_done": true,
    "all_tests_pass": true,
    "no_todo_comments": true
  }
}

关键设计

  • Checklist 在任务开始时生成,不是过程中动态创建
  • 每个条目有明确的 files(产出文件)和 test(验证用例)
  • completion_criteria 定义了"完成"的硬性标准
  • Agent 每完成一个条目,必须更新 Checklist 状态
  • 最终提交时,系统检查 completion_criteria 是否全部满足

4.3 第三层:测试验证闭环

核心思想:不靠模型主观判断"是否完成",而是用工程化的测试结果作为最终判定。

复制代码
传统方式:
    Agent 说"我完成了" → 人类相信 → 结果是假的

Symbio 方式:
    Agent 说"我完成了"
        → Testing Agent 执行 pytest / npm test
        → 捕获 stderr/stdout
        → 如果有失败 → 回退到 Coder Agent 重新修复
        → 循环直到所有测试通过

class TestDrivenVerifier:
    def verify(self, task_id, checklist):
        results = []
        for item in checklist:
            if item["test"]:
                # 在沙箱中执行测试
                test_result = self.run_test_in_sandbox(item["test"])
                results.append({
                    "item_id": item["id"],
                    "test_file": item["test"],
                    "passed": test_result.returncode == 0,
                    "stdout": test_result.stdout,
                    "stderr": test_result.stderr
                })
        
        all_passed = all(r["passed"] for r in results)
        
        if not all_passed:
            # 将失败信息反馈给 Coder Agent
            failures = [r for r in results if not r["passed"]]
            return VerificationResult(
                passed=False,
                feedback=self.format_failures(failures),
                action="retry"
            )
        
        return VerificationResult(passed=True, action="complete")

三层防御的协同效果

复制代码
任务进入
    ↓
第一层:强制 Tool Calling → Agent 不能"说完就走"
    ↓
第二层:Checklist 验证 → 检查所有产出文件和功能点
    ↓
第三层:测试验证 → 用 pytest/npm test 真实验证
    ↓
全部通过 → 任务完成
任一失败 → 回退重试

五、进阶:状态驱动 vs 对话驱动

三层防御解决了"单个 Agent 过早完成"的问题,但多 Agent 协作还需要解决另一个关键问题:Agent 间通信

5.1 传统方案:对话驱动

复制代码
Agent A → 消息 → Agent B → 消息 → Agent C → 消息 → Agent A

Agent 之间通过"对话"传递信息,就像人类开会一样。问题在于:

  • 传话游戏效应:信息在传递中丢失和变形
  • Token 爆炸:每次传递都携带完整对话历史
  • 钻牛角尖:Agent 陷入自己的对话上下文

5.2 Symbio 方案:状态驱动

复制代码
┌─────────────────────────────────────┐
│     全局状态对象 (JSON Checklist)      │
│     Single Source of Truth           │
└──────────────┬──────────────────────┘
               │
    ┌──────────┼──────────┐
    ▼          ▼          ▼
Initializer  Coder      Tester
Agent        Agent      Agent
    │          │          │
    └──────────┴──────────┘
         状态读写,非对话传递

核心规则

  1. 每个 Agent 启动时只接收:当前状态 JSON + 代码 Diff + 单一任务指令
  2. Agent 结束后只输出:状态更新 + 测试结果
  3. 清空会话历史 --- 每轮任务完成后重置,防止上下文污染
  4. Token 成本降低 80%+ --- 消除冗余对话传递

为什么状态驱动更好?

维度 对话驱动 状态驱动
信息传递方式 对话历史 JSON 状态对象
信息完整性 会丢失(传话游戏) 完整(单一事实来源)
Token 消耗 高(携带历史) 低(只传当前状态)
可审计性 低(对话难以追溯) 高(状态变更有记录)
并发安全性 低(对话冲突) 高(状态原子更新)


六、实战效果:一个对比实验

为了验证这套方案的效果,我做了一个对比实验:

任务:实现一个完整的博客系统 API,包含用户管理、文章 CRUD、评论系统、标签系统。

对比对象

  • 方案 A:传统多 Agent(对话驱动,无防过早完成机制)
  • 方案 B:Symbio(状态驱动 + 三层防御)
指标 方案 A 方案 B 提升
首次完成率 23% 91% +296%
平均重试次数 4.7 次 0.9 次 -81%
总 Token 消耗 187K 62K -67%
端到端耗时 23 分钟 8 分钟 -65%
最终代码可运行率 67% 98% +46%

关键发现

  1. 首次完成率从 23% 提升到 91% --- Agent 不再"说完就走",而是真正完成所有任务
  2. Token 消耗降低 67% --- 状态驱动消除了冗余对话传递
  3. 可运行率从 67% 提升到 98% --- 测试验证闭环确保代码质量

七、你可以立即应用的三个原则

即使你不用 Symbio 框架,以下三个原则也可以立即应用到你的 Agent 系统中:

原则一:永远不要让 Agent 自己判断"是否完成"

Agent 说"完成了"不算数,要有外部验证机制。最简单的方式:

复制代码
# 在 prompt 中强制要求
system_prompt = """
你必须完成以下所有步骤才能结束任务:
1. 创建所有必要的文件
2. 实现所有函数(不能有 pass 或 TODO)
3. 编写测试用例
4. 运行测试并确保通过

只有调用 submit_task 工具才能结束任务。
不要用自然语言说"任务完成"。
"""

原则二:用 Checklist 固化"完成"标准

在任务开始时,让 Agent 生成一个明确的 Checklist:

复制代码
{
  "tasks": [
    {"id": 1, "description": "创建 User 模型", "done": false},
    {"id": 2, "description": "实现注册接口", "done": false},
    {"id": 3, "description": "编写测试用例", "done": false}
  ]
}

每完成一项,Agent 必须更新 Checklist。最终提交时检查是否所有项都 done: true

原则三:用真实测试替代主观判断

Agent 写完代码后,自动运行测试:

复制代码
# 自动检测项目类型并运行测试
if [ -f "pytest.ini" ] || [ -f "pyproject.toml" ]; then
    pytest --tb=short 2>&1
elif [ -f "package.json" ]; then
    npm test 2>&1
fi

将测试结果(通过/失败 + 错误信息)反馈给 Agent,让它修复失败的测试。


八、写在最后

"过早完成"不是模型能力的问题,而是系统设计的问题。

模型被训练成"对话者",而不是"工程师"。对话者追求"自然结束",工程师追求"验收通过"。我们要做的,是在系统层面弥补这个鸿沟。

Symbio 的三层防御体系------强制 Tool Calling、显式 Checklist、测试验证闭环------从工程角度系统性地解决了这个问题。但这不是唯一的方式,核心思想是:

不要信任 Agent 的自我判断,用工程化的机制来验证。

如果你也在做多 Agent 系统的开发,希望这篇文章能帮你少走一些弯路。


关于作者 :Agent Infra 架构手记,专注 Agent 架构、AI Infra、多模态数据系统实战。Symbio 框架作者,GitHub: 854875058/Symbio

下一篇预告:《Agent 间通信的致命陷阱:为什么你不该让 Agent 互相聊天》

相关推荐
LienJack2 小时前
《Re0 Build Harness》第三章 系统边界:ChatBot、Workflow、Agent、Harness 的区别
agent
feiwuw3 小时前
Agent和传统大模型的区别以及目前的困境和解决
人工智能·agent·智能体
大强同学3 小时前
我用 Claude Code,把 NotebookLM 变成了 Obsidian 插件
人工智能·agent·claude·skill·notebooklm
L3S4 小时前
Claude Code 配置 Skills 的三种姿势:从手动拖放、skills.sh 一键安装到官方 Plugin
agent
guyoung4 小时前
BoxAgnts介绍(6)——Agent多轮对话及Tool、Skill调用
agent·ai编程
人工智能培训5 小时前
数字孪生赋能建筑行业 解锁工程全周期智慧管理
大数据·人工智能·机器学习·prompt·agent
AirGo.5 小时前
Eino Skill 机制架构分析
agent·skill·eino
吾AI科技6 小时前
Agent的诞生(二):让模型开始调用工具
ai·agent·智能体·deepseek