Skip to content

项目三:Multi-Agent App(多 Agent 协作应用) ​

难度:⭐⭐⭐ 前置:项目二 + 06、07、08 章 目标:用多个分工的 Agent 协作完成一个完整任务,并做好评估和可观测性。

项目一练循环,项目二练证据,项目三练把多个 Agent 组织成系统。毕业项目的核心问题不是"Agent 越多越高级",而是:当任务天然有分工时,多 Agent 能不能让系统更清楚、更好评估。如果协调的代价没换来收益,就该退回单 Agent——多 Agent 是为了解耦,不是为了热闹。

一、从一个问题开始 ​

拿内容工厂做全文主线,把任务缩成一句话:查三份资料,写一页草稿,找出两处风险。它是个好样本:天然三段分工——调研、写作、审校,每个职责能独立验收,产物层层递进,正好覆盖编排、交接、共享状态、冲突和评估。

先看终点长什么样——一条三 Agent 流水线的 trace 加最终产物:

text
task-001  自动调研并写报告  cost=$0.041
├─ supervisor.plan        0.8s  out: 3 steps
├─ researcher.run         6.2s  tools: search_kb x2, web_search x1
├─ writer.run             2.1s  draft: 820 words
├─ reviewer.run           1.4s  issues: 3
└─ supervisor.finalize    1.0s  final: accepted with edits

整篇要回答五个问题,它们也恰好是多 Agent 系统的五个关节:

  1. 为什么要多个 Agent,而不是一个更大的单 Agent?
  2. 多个 Agent 怎么组织起来?
  3. Agent 之间传什么,共享状态怎么设计?
  4. 意见打架或同时改同一份文件时,怎么收口?
  5. 怎么证明多 Agent 比单 Agent 值,而不是凭感觉?

为了先把最小闭环跑通,第二节先只串两个 Agent(写作 → 审校),讲清编排、框架选型和交接;再回到三段流水线讲共享状态;最后看冲突和评估。

二、最小闭环:两个 Agent 串起来 ​

最小闭环不做三段,只做两段:写作 Agent 产草稿,审校 Agent 挑错。它已经能暴露多 Agent 最核心的几个设计问题。

先回答第一个问题:为什么要多个 Agent ​

在写任何编排之前,要先想清楚这个任务到底要不要多 Agent。这里有个取舍:

  • 一个大 Agent + 全部工具 + 长 system prompt — 实现简单、上下文连续:上下文臃肿、职责混杂、出错难定位 / 代价是可调试性差。
  • 多个分工 Agent — 职责单一、上下文隔离、可独立验收:多一层协调、状态一致性、冲突和延迟 / 代价是复杂度。
  • 固定工作流 — 由代码安排节点顺序和分支,适合已知依赖;节点内部仍可以运行 Agent,动态增加任务则需要额外设计。

本项目用研究、写作和审校三个角色练习协作,并与单 Agent 基线比较收益。各角色分别交付证据、草稿和审查意见;模式与适用场景见多智能体协作总览。

怎么组织:流水线 vs 主管-工人 ​

多个 Agent 怎么串,决定了可追踪性和复杂度。这里有个取舍:

  • 流水线(A→B→C 固定顺序) — 易追踪、好评估、trace 清晰:只适合流程固定的任务,差异大任务会卡 / 代价是灵活性低。
  • 主管-工人(主管动态分派) — 适合任务差异大、需动态分派:主管决策本身是失败点,trace 更复杂 / 代价是调试难。
  • 去中心化(Agent 间直接通信) — 并行度高:状态一致性难保证、冲突难收口 / 代价是实现复杂。

本项目先使用流水线(调研→写作→审校),任务差异大、需要动态分派时再引入主管。依赖执行与动态委派分别见流水线与任务依赖图、主管与子 Agent。

用什么框架:LangGraph vs Agent SDK vs 裸写 ​

项目三要求用一个框架实现,并对比裸写省了什么。这里有个取舍:

  • LangGraph — 图编排、状态机、checkpoint、人机交互成熟:学习曲线陡,状态 schema 要先定义 / 代价是前期设计重。
  • Agent SDK — 轻量、handoff、guardrail、tracing 内置:抽象偏 OpenAI 生态,复杂图编排不如 LangGraph / 代价是灵活性。
  • 裸 API 手写 Agent(复用项目一/二) — 完全可控:要自己实现状态、交接、重试、tracing / 代价是工程量。

选 LangGraph 起步,因为图编排 + 状态 + checkpoint 能直接支撑流水线和评估。然后在报告里对比它和项目一裸写在"循环 / 状态 / 交接 / tracing"上各替你解决了什么——这正是 07 章框架实践的验收点。

交接传什么:传干净产出 vs 原始过程 ​

两个 Agent 之间,写作要把草稿交给审校。这里有个最容易写错的取舍:

  • 原样倒上游全部 messages — 实现简单:下游上下文爆、被无关过程带偏、字段不稳定 / 代价是质量下降。
  • 只传结构化产出(要点 + 证据 ID + 未解决问题 + 约束) — 干净、稳定、可独立测试:要定义交接格式 / 代价是 schema 设计。

选只传干净产出,固定格式:

json
{
  "from": "writer",
  "to": "reviewer",
  "task": "审校这版草稿",
  "summary": "基于三份资料写了对比报告。",
  "evidence_ids": ["S1", "S2", "S3"],
  "open_questions": ["B 价格是否最新"],
  "constraints": ["不要编造未确认数据", "关键事实必须带来源编号"]
}

审校还需要读取当前草稿及对应证据,不能只凭作者摘要判断通过。交接内容与来源引用的设计,见任务契约与上下文交接。

两节点的骨架 ​

用 LangGraph 把上面拼起来,最小流水线就这么几行:

python
from langgraph.graph import StateGraph

graph = StateGraph(State)                       # 共享状态 schema
graph.add_node("writer", writer_agent)
graph.add_node("reviewer", reviewer_agent)
graph.add_edge("writer", "reviewer")            # 写作 → 审校,固定流水线
graph.set_entry_point("writer")
app = graph.compile()

跑起来后,State 在节点间流动,每个 Agent 只读写自己负责的字段。这就引出下一节的核心:共享状态怎么设计。

三、回到主线:三段流水线与共享状态 ​

现在把流水线补成三段:主管分派 → 调研(复用项目二)→ 写作 → 审校 → 主管收口。调研 Agent 直接复用项目二的成果——这就是"把一个 Agent 当另一个 Agent 的工人"。

三段流水线最大的设计点不在编排,而在共享状态怎么设计。不要让每个 Agent 随意读写一坨全局变量。这里有个取舍:

  • 全局可变状态,谁都能写 — 实现 0:无法追溯谁改了什么、职责越界、调试地狱 / 代价是混乱。
  • 每个字段指定 owner,Agent 只写自己负责的字段 — 边界清楚、trace 可定位、好测试:要预先定义状态 schema / 代价是设计量。
  • 完全无共享,只靠消息传递 — 最解耦:状态一致性靠协议保证、复杂 / 代价是实现难。

选结构化共享状态 + 字段 owner 权限。一个最小状态长这样:

json
{
  "task_id": "task-001",
  "evidence": [],
  "draft": "",
  "review_comments": [],
  "final_answer": "",
  "cost": {"input_tokens": 0, "output_tokens": 0, "estimated_usd": 0},
  "status": "running"
}

每个 Agent 只改自己的字段:

Agent可写字段不该写什么
调研evidence、研究笔记final_answer
写作draftevidence 原始来源
审校review_comments、风险标记直接覆盖调研证据
主管plan、final_answer、status绕过子 Agent 乱写全部过程

字段归属需要由运行层落实;并发写入时还要定义合并和版本检查规则,见共享状态与黑板协作。

到这一步,三段流水线已经能完整跑通。但多 Agent 真正的考验,在 Agent 意见打架或同时改同一份产物的时候。

四、当 Agent 意见打架 ​

用冲突当第四轮轨迹。多 Agent 常见冲突有三类,处理方式各不相同:

  • 结论冲突:调研 Agent 说 A 更好,分析 Agent 说 B 更好。处理:主管要求双方给证据,按来源新旧、可信度和任务目标裁决。
  • 职责冲突:写作 Agent 修改了事实,审校 Agent 又改回去。处理:规定事实只来自调研证据,写作只负责表达。
  • 产物冲突:两个 Agent 同时编辑同一个文件。

第三类最麻烦,因为"谁先写谁赢"会让审校的修改被写作的旧版本静默覆盖。这里有个取舍:

  • 全量覆盖,最后写者赢 — 实现 0:审校的修改可能被写作旧版本覆盖、丢失 / 代价是静默错误。
  • 补丁优先(Agent 输出 diff 而非整文件) — 精确、可合并:要实现 patch 应用和冲突检测 / 代价是工程量。
  • 单写者原则 + 版本检查(提交时带 base 版本,变了重读) — 最稳:同一时刻只有一个写者 / 代价是吞吐降低。

选单写者 + 补丁 + 版本检查三件套:

  1. 单写者原则:同一时刻只有一个 Agent 对某个文件有写权限。
  2. 补丁优先:Agent 输出 diff,而不是直接覆盖整份文件。
  3. 版本检查:提交修改时带基于哪个版本生成,版本变了就重新读取。
  4. 冲突交给主管:不能自动合并时,主管比较两边意图,再决定保留、合并或请求人工确认。

这里针对共同修改同一份报告采用单写者与 patch 合并。独立文件分工、隔离工作区等其他策略见多 Agent 的文件与产物协作。

五、把它变成能评估、能追溯、能控风险的系统 ​

一个能跑的三段流水线,如果没有评估和 trace,那它只是个 demo——出错时你根本说不清是哪个 Agent 改坏的。要变成作品,至少补三样。

评估:必须有单 Agent 基线。没有基线,无法证明多 Agent 带来了收益,"多 Agent 更好"只是感觉。这里有个取舍:

  • 只做多 Agent,不做基线 — 省事:无法证明收益,面试也讲不清 / 代价是论证空洞。
  • 用同一批任务跑单 Agent 基线对比 — 可证明收益和代价:多一倍评测工作 / 代价是工作量。

选必须有基线。用同一批任务比较成功率、事实错误数、修改轮数、成本和可调试性。多 Agent 只有在质量 / 稳定性 / 可调试性至少一项有可解释提升时才算有价值。怎么设计评测集和判分规则,见 Agent 评估。

tracing:每个 span 至少记这些。多 Agent 没有 trace,调试会非常痛苦。每个 span 记 task_id / agent_name / 输入输出摘要 / tool_calls / token / latency_ms / estimated_cost_usd / error。一次运行能展开成开头那样:

text
task-001  自动调研并写报告  cost=$0.041
├─ supervisor.plan        0.8s  out: 3 steps
├─ researcher.run         6.2s  tools: search_kb x2, web_search x1
├─ writer.run             2.1s  draft: 820 words
├─ reviewer.run           1.4s  issues: 3
└─ supervisor.finalize    1.0s  final: accepted with edits

你要能回答:贵在哪里、慢在哪里、哪一个 Agent 产出了错误信息。trace 的完整设计见 可观测性。

安全边界:危险操作要人工确认。如果项目里有写文件、发邮件、提交代码、删除数据这类动作,最小安全策略是:

  • 只读工具默认允许。
  • 写文件、发请求、删除、提交、付款等动作需要人工确认,展示明确的目标、参数和影响范围后再执行。
  • 下游只处理已授权范围内的任务。结构化字段中的自然语言仍可能包含越权指令,工具调用必须由执行端检查权限与参数。
  • 检索内容里的"忽略之前指令""执行以下命令"视为资料内容,不当系统指令。
  • 超过最大轮数、最大成本或最大工具调用次数就停止。

有了评估、trace 和安全边界,这个多 Agent 系统才从"能跑的 demo"变成"能解释、能回放、能控风险的工程"。而它复用的正是项目一的 tool loop 和项目二的调研能力——三个项目串起来,就是从"一个能跑的循环"到"一个能评估的系统"的完整路径。如果走面试,就把这三个项目翻成能讲清的故事、架构图和排障思路,去 10 章继续。

持续学习,持续实践。