第 3 章 · 协调的契约:Plan
一句话结论:多 agent 协调的第一性原理是——让 agent 之间通过「一份共享的、结构化的中间产物」来对表,而不是通过来回的自然语言聊天。在 DeerFlow 1.x 里,这份中间产物就是 Plan(一份树形的、类型化的研究计划)。
1. 先看「最直觉但最糟」的协调方式
假设研究员 A 搜完资料,要把结果交给报告员 B。最直觉的做法:A 把搜到的东西原封不动丢给 B。
# 糟:原始信息直接流转
for r in researchers:
raw = r.run(step) # raw = 一大堆网页原文
report_writer.send(raw) # 直接把原文塞给报告员问题立刻出现:
- 上下文滚雪球:每个研究员的原始输出都塞进报告员的窗口,报告员的窗口又爆了——等于把单 agent 的上下文溢出问题,平移到了「汇总端」。
- 没有「契约」:A 的输出格式是随意的,B 拿到后得自己猜「哪些是结论、哪些是来源、哪些是废料」。猜错一次,整份报告就歪了。
- 无法并行、无法中断、无法追溯:谁先干完谁后干完,B 拿到什么算什么,整个流程不可控。
2. 思考的分叉:agent 之间到底靠什么「对表」?
方向 A:靠自然语言对话来回聊(A 说一堆,B 回一堆,像微信群)。
- 优点:灵活,模型天然会聊天。
- 致命伤:聊天没有结构,也没有收敛条件。A 说「我查到了 X」,B 问「那 Y 呢」,A 再去查……什么时候算聊完?没人知道。而且每轮聊天都在消耗 token、都占上下文。
方向 B:靠一份显式的、结构化的「计划」(先产出 Plan,大家照着 Plan 各干各的,往 Plan 里填结果)。
- 优点:Plan 是契约——它规定了「要做什么、谁来做、结果往哪填」,所有人照章办事,天然可并行、可追溯、可收敛。
- 代价:多了一步「先把计划定下来」的工程成本,且计划本身可能出错。
为什么 DeerFlow 选 B:
- 因为「协调」最怕的不是「某个人干错了」,而是「没有共同的时间表和边界」。一份显式 Plan,等于给所有 agent 立了一根共同的坐标轴——每个人都知道自己在哪一格、别人在哪一格、做完往哪交。结构化的代价,换来的是「可收敛、可并行、可追溯」这三样多 agent 系统最稀缺的东西。
类比:一群人装修房子。方案 A 是大家在群里聊天「你去买漆」「我觉得还缺个灯」,聊到哪算哪;方案 B 是先出一张施工图(Plan),每个人照图干活、在图上打勾。方案 A 看起来灵活,但工期和结果完全不可控;方案 B 前期多花点时间,但每一步都可预期。多 agent 系统要的是「可预期」,不是「灵活」。
3. 伪代码:Plan 到底长什么样
DeerFlow 1.x 的 Plan 不是一段自由文本,而是一个类型化的树结构(每个步骤可以有子步骤),并且用 Pydantic 模型做了校验:
class PlanStep(BaseModel):
title: str # 这一步的标题
description: str # 这一步具体要研究什么
steps: list["PlanStep"] = [] # 子步骤,形成一棵树
# 注意:树形,不是扁平列表——某些步骤天然需要先拆解
class Plan(BaseModel):
title: str
steps: list[PlanStep] # 顶层步骤列表
# Planner 的职责:把一句研究问题,变成这样一份树形 Plan
def planner_run(question) -> Plan:
# 用 LLM 生成结构化计划,并强制通过 Pydantic 校验
plan = llm_structured(question, output_schema=Plan)
return plan关键设计点,一个一个拆:
- 类型化(Pydantic 校验):Plan 不是「让模型随便写一段文字」,而是强制模型输出一个能被解析成数据结构的东西。这是「协调契约」的根基——如果 Plan 本身是自由文本,下游 agent 就没法稳定地解析它,契约就形同虚设。
- 树形而非扁平:一个研究问题往往要先拆成几个大方向,每个大方向再拆成具体步骤。树形结构保留了这种层级依赖,为后面的「并行/串行调度」提供了依据(同一父节点下的兄弟节点通常可并行)。
- Plan 是「共享产物」,不是「私人物品」:它一旦产出,就被所有角色共同持有、共同填写。研究员在步骤里填「我查到了什么」,报告员从步骤里读「这些结论是什么」。协调,本质上就是对这份共享产物的一致读写。
4. 为什么「计划先行」能解决上一章埋的钩子
第 2 章末尾留了个问题:为什么 Planner 出完计划,中间要插一个 Research Team?
现在能回答了:因为 Plan 只是「约定要做什么」,执行时每一步都会产出大量不确定的中间结果。 这些中间结果必须被结构化地写回 Plan(或与 Plan 关联的状态),而不是自由扩散。
所以完整的心智模型是:
Planner 产出 Plan(契约)
↓
Research Team 照着 Plan 的每一步去执行,把结果填回对应步骤
↓
Reporter 读「填满的 Plan」,收敛成最终报告
Plan 是贯穿全程的那根轴——上游产出它,中游执行它、填充它,下游消费它。这就是「协调的契约」最直白的含义。
思考题
Q:既然 Plan 这么重要,那 Planner 把计划定错了怎么办?比如它把「本应并行调查的两个方向」错拆成了「一个套一个的串行步骤」,或者干脆漏掉了一个关键方向。
参考答案:
这触及了 Plan 契约的边界——契约能约束「怎么执行」,但约束不了「计划本身的质量」。应对办法是分层防御:
- 结构层兜底:Pydantic 校验保证 Plan 在格式上合法(是棵树、每步有标题描述),但管不了内容对不对。
- 人兜底:在 Planner 之后插一个「人工确认」环节(human-in-the-loop),让用户看计划、改计划——这是第 8 章的内容,DeerFlow 正是这么干的。
- 执行中兜底:允许执行到一半发现「上下文不够」时重新规划(re-plan),并限制重规划次数防止死循环——这是第 9 章的内容。
先记住结论:Plan 契约解决的是「协调的可控性」,它不解决、也不该试图解决「计划本身的智慧」——后者交给「人 + 重规划」来兜。 一个框架如果把「计划必须一次对」的赌注全押在模型上,必然脆弱。