第 1 章 · 为什么需要多 Agent
一句话结论:多 agent 不是为了炫技,也不是「人多力量大」,而是因为单个 agent 的上下文窗口是一个有硬上限的物理资源。把一个大任务塞进一个 agent 的上下文里,等于让一个人同时记住一本百科全书的每一页再去答题——不是能力问题,是「工作记忆」装不下。
1. 先看一个失败的「单 agent」方案
假设你要 agent 做一份深度研报:《2026 年 AI 视频生成赛道竞争格局》。
最 naive 的写法,是给一个大 agent 一个循环,让它自己一步步干:
def single_agent_run(question):
ctx = [system_prompt, user(question)] # 上下文从一句话开始
for step in range(MAX_STEPS):
action = llm(ctx) # 让模型自己决定下一步
if action.type == "search":
result = web_search(action.query) # 搜索
ctx.append(result) # 把结果塞回上下文
elif action.type == "browse":
result = crawl(action.url)
ctx.append(result)
elif action.type == "write":
return compose_report(ctx) # 最终成稿这个循环在 demo 里跑得不错。但任务一复杂,你会立刻撞上三堵墙:
- 上下文溢出:研报要搜 20 个公司、读 50 篇网页、跑 3 段数据分析。每个
ctx.append(result)都在往同一个窗口里塞东西。塞到 100k token,模型开始「忘掉」开头——第 1 步搜到的东西,写到第 30 步已经模糊了。这是物理上限,不是 prompt 调优能解决的。 - 注意力稀释:一个窗口里既有「我下一步该搜什么」的规划,又有「搜回来的 30 段原文」,还有「报告的格式要求」。模型的分辨率被摊薄到所有内容上,反而容易在关键处犯低级错误。
- 耦合到死:搜索逻辑、代码执行、最终成稿全挤在一个 agent 里。想换一个搜索工具,得动整个 prompt;想让代码执行更稳,也没法单独加固。
2. 思考的分叉:面对这个问题,有三条路
方向 A:换更大的上下文窗口的模型,硬扛。
- 代价:窗口再大也有上限,且 token 越长越贵、越慢、注意力越稀释。这是在「买更大的桶」,不是在解决「为什么要一次性倒进去」。
方向 B:不做 agent 了,写死一个 pipeline(搜索→总结→成稿)。
- 代价:省心,但丢掉了 agent 最核心的价值——面对未知任务的自适应能力。pipeline 每一步写死了,遇到「需要先算个数才能决定搜什么」这种分支就抓瞎。
方向 C:把任务拆成多个 agent,每个 agent 只扛一个小上下文,靠协调拼出整体。
- 代价:要解决一个新问题——这些 agent 之间怎么协调。这正是本教程要讲的全部内容。
为什么 DeerFlow(以及几乎所有成熟框架)走 C:
- 拆开后,每个 agent 的上下文短、专注、可替换。研究员的窗口里只有「搜什么、搜回来的内容」,报告员的窗口里只有「一堆半成品结论、怎么写」。
- 「协调」虽然难,但它是一次性投入、长期复用的工程问题;而「上下文溢出」是每次运行都会踩、且无法靠单点优化根除的物理问题。用可控的工程复杂度,换掉不可控的物理瓶颈,这笔账划算。
一个生活化类比:你一个人写 5 万字论文,写到一半会忘了开头写过什么;但你把「查资料」「跑数据」「动笔」分给三个人,每人只盯自己的那份材料,最后靠一个「提纲」对齐,三个人反而都能记得住自己那摊子事。拆分的本质,是让每个人都只装「他那一份」上下文。
3. 伪代码:把「单 agent」重构成「多 agent」的骨架
第一步,先把任务从「一个大循环」变成「若干角色 + 一份共享计划」:
class AgentRole:
"""一个角色:有自己的一套工具,只干一件事"""
def __init__(self, name, tools, system_prompt):
self.name = name
self.tools = tools
self.system_prompt = system_prompt
def run(self, task, ctx):
# 每个角色在自己的上下文里跑,ctx 是「别人交给我的那一小份」
return llm(self.system_prompt + task, tools=self.tools)关键变化不在代码,在心智模型:
- 单 agent:
一个大循环,全装一个 ctx - 多 agent:
多个角色,各装各的 ctx,靠显式传递对齐
但这里立刻冒出一个新问题——角色之间靠什么「对表」?如果只是让 agent A 把原始输出丢给 agent B,那和单 agent 的 ctx.append 没有本质区别,上下文还是会在传递中越滚越大。
这个问题,就是第 3 章「协调的契约」要解决的。而在这之前,第 2 章得先回答一个更基础的问题:到底该拆成哪几个角色?
思考题
Q:既然上下文窗口是硬上限,那为什么不干脆「拆到极致」——一个 agent 只搜一次网页、另一个 agent 只写一句话,让每个 agent 的上下文小到可以忽略?
参考答案:
拆到极致是另一个极端,会掉进「协调成本 > 单 agent 上下文压力」的坑。核心矛盾是:协调本身也要花钱、也占上下文、也会出错。
- 每多一个 agent,就多一次「任务分派 + 结果汇总」的往返。这个往返本身要消耗 token、引入延迟、增加出错面(A 没听懂 B 的任务怎么办)。
- 当一个 agent 干的活小到「搜一次网页」时,它那点上下文压力,远不如「为了让它干这点活所付出的协调成本」大。
所以合理的拆法不是「越细越好」,而是按「职责的自然边界」拆——每个角色是一类内聚的工作(规划 / 检索 / 计算 / 成稿),而不是一个机械的步骤。这正是第 2 章「角色的诞生」要讲的分寸感。