DeerFlow 源码解析:一个产品经理读完之后,终于搞懂了 AI Agent 是怎么「自主工作」的
开篇:为什么要读懂这个
字节跳动 2025 年开源了 DeerFlow,在 GitHub 上发布后直接冲到了 Trending 第一。然后大多数人看了一眼 README,觉得「哇好厉害」,然后关掉了。
这篇文章想做一件不一样的事:把 DeerFlow 怎么实现 DeepResearch 的,逐模块拆给你看。
不是给工程师看的代码解析,是给产品经理看的「这个系统背后的逻辑和判断」。因为理解了这些,你才知道这类产品的能力边界在哪、设计决策应该怎么做、改造一个 DeepResearch 要动哪些地方。
系好安全带,开始了。
先建立一个整体认知
DeerFlow 的架构本质上就干了一件事:
把一个复杂问题,变成一个有状态的任务执行图,然后让专门的 Agent 在图里走一遍。
用流程图表示是这样:
用户输入
│
▼
Coordinator(接待员)── 普通聊天 ──▶ 直接回答,结束
│
│ 判定为"需要研究"
▼
Background Investigator(预研员)← 可选
│
▼
Planner(规划师)── 生成计划 ──▶ 等用户确认(可跳过)
│
▼
┌──────────────────────────────┐
│ 调度循环 │
│ ┌──────────────────────┐ │
│ │ 还有未执行的步骤? │ │
│ └────────┬─────────────┘ │
│ │ 是 │
│ ┌──────┴──────┐ │
│ │ step_type? │ │
│ └──┬──────┬───┘ │
│ research processing │
│ │ │ │
│ Researcher Coder │
│ │ │ │
│ 写回结果,继续循环 │
└──────────────────────────────┘
│ 所有步骤完成
▼
Reporter(报告员)
│
▼
最终报告,输出给用户
整个系统用的是 LangGraph,一个「有状态的流程图引擎」。每个方块是一个节点,箭头是跳转规则,所有节点共享一个叫 State 的全局记事本。
理解这个结构,后面的所有细节都是在填充「每个节点里到底发生了什么」。
第一块:State——整个系统的记忆本
先说 State,因为它是一切的基础。
所有 Agent 共享同一个 State 对象,每个 Agent 读它、往里写,然后下一个 Agent 继续用。你可以把它理解成一个实时同步的项目文档,每个人都能看,每个人都能写。
它大概包含这些字段:
messages → 完整对话历史(自动累积)
current_plan → 当前的执行计划(Plan 对象)
observations → 每步执行的结果摘要
auto_accepted_plan → 是否跳过人工确认
final_report → 最终报告内容
其中最重要的是 <code>current_plan</code>,它是一个 Plan 对象,里面有 <code>steps</code> 列表,每个 Step 长这样:
title → "搜索特斯拉 Q4 交付数据"
description → "从官网和新闻找到最新季度数字"
step_type → research 或 processing
execution_res → (执行前为空,执行后写入结果)
整个系统的工作本质,就是把这个 steps 列表从头到尾执行一遍,然后把所有 execution_res 汇总成报告。
第二块:Coordinator——那个判断「你是来聊天还是要干活」的人
Coordinator 是第一个接触用户消息的节点,职责非常单一:判断用户意图,决定往哪走。
它调用一次 LLM,系统提示词大意是:「判断这条消息是普通对话还是需要深度研究的任务,如果是研究任务,返回 goto: planner」。
LLM 返回之后,根据返回值路由:
if goto == "planner":
return Command(goto="planner")
elif goto == "background_investigator":
return Command(goto="background_investigator")
else:
# 普通对话,直接回复
return Command(goto="__end__", update={"messages": [response]})
<code>Command</code> 是 LangGraph 的路由对象,含义是「我做完了,下一步去 XXX,顺便把这个数据写入 State」。
作为 PM 要注意的设计点:这里的意图判断是靠 LLM 的,这意味着边界情况的处理完全依赖提示词质量。比如「帮我简单搜一下 XXX」到底算聊天还是研究?这种模糊地带就需要在提示词里明确定义。
第三块:Background Investigator——计划之前的「情报预热」
这是一个可选节点,可以通过配置开关控制。
它存在的原因很朴素:有些问题太专业了,LLM 直接规划可能跑偏。
比如你问「分析量子计算对密码学的影响」,如果 LLM 对这个领域不熟,生成的计划可能抓不住重点。先做一次快速搜索,把背景资料写入 State 的 messages,Planner 在有上下文的情况下制定计划会准确得多。
这一步通常只做一到两次搜索,快速收集背景,不追求完整性,追求的是「给 Planner 打底」。
第四块:Planner——整个系统最重要的节点
如果你只能深入理解一个节点,选 Planner。
它的输出质量,决定了整个研究的质量上限。
Planner 调用 LLM,开启 Structured Output(结构化输出),要求 LLM 返回一个严格格式的 JSON:
{
"title": "特斯拉竞品分析报告",
"steps": [
{
"title": "获取特斯拉 2024 Q4 官方交付数据",
"description": "从特斯拉官网和 IR 页面找到最新数据",
"step_type": "research"
},
{
"title": "获取比亚迪同期数据",
"description": "搜索比亚迪 2024 Q4 销量公告",
"step_type": "research"
},
{
"title": "计算同比增长率并画对比图",
"description": "用 Python 处理数据,生成可视化",
"step_type": "processing"
}
]
}
步骤数量通常控制在 3~8 个,太少研究不深,太多执行太慢。<code>step_type</code> 只有两个值:<code>research</code>(交给 Researcher)和 <code>processing</code>(交给 Coder)。
生成计划后,根据 <code>auto_accepted_plan</code> 决定下一步:
- <code>True</code> → 直接开始执行
- <code>False</code> → 跳转到 <code>human_feedback</code> 节点,等用户确认
第五块:Human-in-the-Loop——优雅的「暂停按钮」
这是 LangGraph 提供的 interrupt 机制,DeerFlow 在两个地方用到了它:
- 计划生成后,展示给用户确认
- 工具调用前(可选),让用户决定是否允许执行某个操作
工作方式是:工作流跑到这个节点时,整个图暂停,当前 State 被序列化保存。前端拿到计划内容,渲染给用户。用户操作后,通过 API 恢复工作流,并把用户的反馈注入 State。
这个设计很聪明,它把「全自动」和「人工监督」做成了同一套系统,通过配置控制介入程度。
作为 PM 要想的问题是:在什么场景下用户愿意等 + 看 + 确认? 对于高价值、高风险的研究任务(比如出竞品报告给老板),用户愿意花 30 秒确认计划。对于轻量查询,直接跑就好。这个阈值需要通过用户研究来定。
第六块:Researcher——那个在互联网上反复搜索的人
Researcher 是执行 <code>research</code> 类型步骤的 Agent,它的工作模式是 ReAct 循环:
推理(Reasoning)→ 行动(Acting)→ 观察(Observing)→ 推理 → ...
具体来说:
- 读取当前步骤的 description
- 决定用什么关键词搜索
- 调用 <code>web_search</code> 工具,拿到摘要列表
- 看结果,判断:「够了吗?还需要深入哪条链接?」
- 如果需要深入,调用 <code>crawl_tool</code> 抓取网页全文
- 继续推理,决定是否需要再搜一次
- 觉得信息足够,输出 observation(本步的研究小结)
可用工具:
| 工具 | 作用 | 底层实现 |
|---|---|---|
| <code>web_search</code> | 搜索引擎检索 | Tavily / Brave Search API |
| <code>crawl_tool</code> | 抓取网页正文 | Jina Reader API |
| MCP 服务 | 自定义数据源 | 通过 MCP 协议接入 |
循环次数有上限配置,防止无限追查。结果写入 <code>step.execution_res</code>,然后系统回到调度节点取下一步。
第七块:Coder——那个帮你写代码跑数据的同事
Coder 执行 <code>processing</code> 类型步骤,工具只有一个:Python REPL(交互式 Python 解释器)。
工作流程:
- 读取步骤描述,LLM 生成 Python 代码
- 代码扔进沙箱执行
- 拿回 stdout / stderr
- 如果报错,LLM 看报错信息修改代码,重试
- 执行成功,把输出写入 <code>step.execution_res</code>
能做什么:
- 数据处理(pandas 处理 CSV、计算增长率)
- 可视化(matplotlib 生成图表)
- 文件操作(读写研究中间文件)
- 调 API(有网络权限的话)
沙箱是安全保障。代码在 Docker 容器里运行,有独立的文件系统 <code>/mnt/user-data/</code>(分 uploads / workspace / outputs 三个目录),出了容器什么都带不走,执行恶意代码也不会影响宿主机。
这里有个产品设计的有趣点:Coder 能「读」Researcher 写的文件,因为它们共享同一个 State 和沙箱文件系统。前面搜到的数据,后面直接拿来算,这就是多步研究「能形成合力」的关键。
第八块:Reporter——那个最终整合输出的人
Reporter 是整个流程里最「佛系」的节点——它不调工具、不循环,就是一次 LLM 调用。
它拿到什么:
- 用户的原始问题
- Planner 生成的计划大纲
- 每个步骤的 <code>execution_res</code>(Researcher 和 Coder 的产出)
- 所有引用来源
它做什么:把这些塞进提示词,让 LLM 生成一篇结构清晰、有引用的 Markdown 报告。
提示词大概是:
"根据以下研究计划和每步的执行结果,生成一份专业的研究报告。要求:结构清晰,有核心结论,关键数据要有引用来源,适当使用表格对比。"
输出写入 <code>State.final_report</code>,流式返回给前端,工作流结束。
第九块:Memory——越用越懂你的长期记忆
这是 DeerFlow 2.0 的亮点功能,用来解决一个实际问题:每次对话都要重新介绍自己太烦了。
Memory 不是对话历史(那是 State.messages),而是跨会话持久化的用户画像,结构分三层:
User Context → 你是谁(职业、背景、偏好语言)
History → 你做过什么研究、关注什么领域
Facts → 离散知识点,每条附置信度分数(0~1)和时间戳
举个例子:如果你上周问过「中国新能源汽车补贴政策」,Memory 里可能记下「用户对新能源政策感兴趣,偏好政策解读类内容」,下次你问「最新汽车政策」,Coordinator 注入这条记忆,Planner 制定的计划会更贴你的口味。
技术实现上,Memory 是异步更新的(debounced queue,延迟队列),不阻塞主对话流程。注入时有 token 上限控制(<code>max_injection_tokens</code>),避免把 prompt 撑爆。
第十块:Skills——Markdown 写的「可插拔能力包」
这是 DeerFlow 最有创意的设计之一。
Skills 是 Markdown 文件。每个 Skill 描述一类任务的最佳做法、工具选择、输出格式,附带 YAML frontmatter 声明元信息:
---
name: competitive-analysis
version: 1.0
tools: [web_search, crawl]
---
# 竞品分析技能
当用户需要竞品分析时,遵循以下步骤:
1. 先确定分析框架(功能对比 / 商业模式 / 用户画像)
2. 重点关注官网、App Store 评价、融资信息、招聘 JD...
(后面是详细的 prompt 指令)
关键是按需加载:系统判断当前任务需要哪个 Skill,只把那个 Skill 的内容注入 prompt,其余的不加载。这让 Skills 数量可以很多,但实际消耗的 token 很少。
想扩展能力?写一个 <code>.skill</code> 压缩包上传到 Gateway,立刻生效,不用改一行代码。这对于面向不同垂直领域的 DeepResearch 产品来说,意味着可以做成「插件市场」。
第十一块:MCP 集成——对外接私有数据源的标准插口
MCP(Model Context Protocol)是 Anthropic 提出的标准协议,用来让 AI Agent 调用外部工具服务。DeerFlow 原生支持,配置非常简单:
{
"mcp_servers": [
{
"name": "company-knowledge-base",
"transport": "http",
"url": "http://internal-server:8080/mcp",
"auth": { "type": "client_credentials" }
}
]
}
加上这条配置,Researcher 和 Coder 就能调用你的内部知识库了,就像用 <code>web_search</code> 一样自然。
支持的传输协议:<code>stdio</code>(本地进程)、<code>SSE</code>(流式 HTTP)、<code>HTTP</code>,后两种支持 OAuth 认证。
这是 DeepResearch 能做「垂直领域私有化部署」的核心技术支撑。通用 DeepResearch 搜公开网络,接了私有数据源之后,它就能搜你的内部文档、数据库、CRM,变成真正懂你业务的研究员。
把这些串起来,讲一个完整的故事
你在 DeerFlow 里问:「帮我分析一下 2025 年国内 AIGC 工具的竞争格局。」
发生了什么:
- Coordinator 判断:这是研究任务,转 Background Investigator
- Background Investigator 快速搜几条「AIGC 工具 2025」背景资料,存入 State
- Planner 读背景资料 + 你的问题,生成计划:
- Step 1(research):搜索主要 AIGC 工具及市场份额
- Step 2(research):搜索各玩家融资和商业模式
- Step 3(research):搜索用户评价和差评集中点
- Step 4(processing):用 Python 整理成对比表格
- 计划展示给你确认,你觉得没问题,点确认
- 调度节点分发 Step 1 给 Researcher
- Researcher:搜索 → 觉得不够 → 抓取几个分析网页 → 写结果
- Step 2、Step 3 重复上面过程
- Step 4 交给 Coder,写 Python 生成 Markdown 表格
- 全部完成,Reporter 拿到四步结果,生成完整 Markdown 报告
- 报告流式输出到你的界面
整个过程可能调用了 20+ 次工具,花了 8 分钟,但你只点了一次确认。
作为 PM,你应该记住什么
产品设计层面:
- 进度透明是体验核心——用户等 8 分钟的心理承受力取决于他知不知道在干什么
- 人工确认节点的设计要慎重——插哪里、显示什么、怎么交互,直接影响信任感
- 计划质量 = 报告质量的上限,提示词调优是最高性价比的优化点
技术实现层面:
- LangGraph 做 Agent 编排比自研状态机省 80% 的工作量
- Skills 的按需加载机制值得借鉴,避免 prompt 膨胀
- MCP 接私有数据源是从 Demo 到生产的关键一步
机会判断层面:
- 通用 DeepResearch 已经卷了,垂直场景(投研、法律、医疗、营销)还有大量空间
- 工作流的可配置化(深度、广度、步骤数、工具选择)是差异化点
- 报告的下游消费(直接导出 PPT、推送到飞书、触发下游 Action)是护城河
最后说一句
读完 DeerFlow 的架构,我最深的感受是:这不是什么魔法,就是精心设计的流水线。
每个节点做一件明确的事,共享同一个 State,通过结构化输出和工具调用把信息一层层叠加,最后汇总成报告。
这也意味着:如果你懂这套逻辑,你可以在这个基础上搭出符合自己场景的 DeepResearch 产品——换掉 LLM、换掉搜索工具、加上私有数据源、定制输出格式——核心框架是稳的,改造成本是可控的。
工具已经给你了,接下来是你的事了。