deerflow学习
从一次请求如何执行开始,理解代理背后的运行机制。
再亲手完成安装、研究任务与源码阅读。
目录 · 选择阅读章节
认识 DeerFlow
当你要求一个系统“阅读资料、比较方案,再交付报告”时,真正困难的部分并不止于生成文字。它还要找到资料、执行工具、维护文件、处理失败,并在许多轮操作之后记得最初的目标。DeerFlow 把这些工作组织为一套可以运行长任务的代理系统。
官方将 2.0 定位为 Super Agent Harness。这里的 harness 可以理解为围绕模型构建的运行框架:模型参与决策,框架负责连接工具、状态与执行环境。2.0 是一次重写,与早期以 Deep Research 为重点的 1.x 存在明显架构差异。
模型负责根据上下文产生输出;代理把模型输出与工具操作连接起来;运行框架负责让这些操作在会话、文件、资源与生命周期中有序发生。
本篇以当前 2.0 主线为范围。你需要具备基础命令行知识;如果要读源码,了解 Python 函数、异步调用与字典即可开始。先读第 8、9 章可以跑通使用,再回到前面的章节解释你观察到的行为。
版本定位:官方仓库 README。下文的类比、练习与排查顺序是教学设计。
系统架构与请求路径
把系统分成三个入口职责会更容易理解:浏览器展示交互,反向代理统一访问地址,Gateway 处理接口并承载代理运行时。当前官方默认拓扑中,运行时嵌入 FastAPI Gateway;看到 LangGraph 兼容接口,并不意味着必须单独启动一个 LangGraph 服务。
一次任务可以沿着“浏览器 → Nginx → Gateway → 代理 → 工具 → 代理 → 浏览器”追踪。普通页面请求进入前端;API 请求进入 Gateway。公开的 /api/langgraph/* 路径会被转为 Gateway 对应的接口,流式事件通过 SSE 返回界面。
由此可以建立一个排查习惯:页面能打开,只说明页面这一段可达;模型能回应,也不说明文件工具和沙箱已经可用。分别检查每一层,比把所有故障归为“模型不行”更有效。
架构依据:Backend Architecture。
代理循环与中间件
一次回答可能包含多轮模型调用
可以把代理循环想成一个反复更新的工作台:模型读取当前上下文,提出工具调用;运行时执行工具,把观察结果放回上下文;模型再决定继续操作、提出澄清,还是结束任务。工具调用是一项结构化请求,真正执行读写或命令的是程序。
state = prepare_thread(user_request)
while task_is_running:
context = prepare_context(state)
response = model(context, available_tools)
if response.needs_clarification:
pause_for_user()
elif response.has_tool_calls:
results = execute_tools(response.tool_calls)
state = append_observations(state, results)
else:
finish(response)
break中间件负责运行过程中的共同事务
主代理工厂把模型、提示词、工具和中间件装配在一起。中间件可以处理上传材料、上下文压缩、任务跟踪、工具错误等事项。这样,资料目录初始化或错误处理就不需要在每一项具体业务工具里重复实现。
阅读 make_lead_agent 时,应关注“什么条件下加入某项能力”,而不仅是记住类名。不同配置会改变可用工具和装配结果。当前源码已包含比部分文档示意图更丰富的中间件,因此不宜把某张图中的数量与顺序当作永久约定。
让系统读取一份你上传的短文并列出三条事实。观察是否出现文件读取操作,再比较工具返回内容与最终回答。目标是区分“模型说它读过”和“工具记录显示它读过”。
装配入口:lead_agent/agent.py。
工具、Skills 与 MCP
这三者都能扩展能力,但它们解决的问题不同。理解区别后,才能判断一项需求需要增加说明、编写工具,还是连接外部服务。
| 机制 | 承担的作用 | 学习时的例子 |
|---|---|---|
| 工具 Tool | 以明确输入执行操作并返回结果 | 读文件、搜索网页、列出目录 |
| Skill | 描述某类任务的做法,可附带脚本与资源 | 规定研究报告需要问题、证据、比较和结论 |
| MCP | 通过协议连接外部服务提供的工具 | 让代理访问一个已配置的数据服务 |
在 DeerFlow 中,工具来自内置实现、配置和 MCP 集成,技能则以 SKILL.md 等资源组织。可以把工具看作动作,把技能看作使用动作的说明。说明写得再完整,如果对应工具未配置或调用失败,任务依然无法完成。
先验证最小动作,再组合工作流
例如你要做“资料对比报告”,先单独验证搜索是否返回结果、网页读取是否取得正文、文件写入是否生成实际文件。三项各自工作后,再引入报告结构。这样可以明确失败来自信息获取、任务组织还是输出环节。
一个技能说明应写清适用任务、输入、步骤、输出与检查标准。“尽可能专业”很难执行,而“每个结论提供一个支持它的来源,不足时标注待确认”就容易检查。技能不是保证执行顺序的硬编码程序;关键格式仍应在应用侧验证。
能力分类:Backend README。
子代理如何协作
子代理让主代理把一个有边界的子问题交给独立执行单元。主代理可以提供任务描述,收取结果,再完成总体汇总。DeerFlow 的子代理执行器维护任务执行与状态;主代理的装配代码也会根据配置处理可用子代理和运行限制。
适合分工的是问题,不是字数
假设目标是比较三种技术方案,可以分别调查各方案的一手资料,再由主代理统一比较维度。如果直接把“写一份报告”分成三个代理各写一份完整报告,往往只会产生重复内容,而没有减少核心工作。
- 明确输入
给子任务限定对象、资料范围和要回答的问题,避免依赖未提供的背景。
- 约定输出
要求返回事实、来源、限制与未解决的问题。只返回结论会让汇总阶段难以核验。
- 主代理整合
统一术语、删除重复内容、处理来源冲突,再给出最终答案。
并发不是越多越好。它可能缩短部分等待,但也会增加模型调用、协调与结果合并的成本。有前后依赖的任务必须先取得上一步结果。具体并发、超时和总量限制应查看你所使用版本的配置与代码,不要沿用旧教程里的默认数字。
实现入口:subagents/executor.py;策略装配见 主代理工厂。
沙箱与文件系统
代理生成代码之后,需要一个实际执行环境。DeerFlow 通过沙箱接口组织命令与文件操作,并为会话建立工作目录。模型看到的虚拟路径可以映射到实际存储位置,因此阅读日志时要分清“代理内部路径”和“宿主机路径”。
/mnt/user-data/
├── uploads/ # 输入材料
├── workspace/ # 中间文件与工作区
└── outputs/ # 准备交付的结果
/mnt/skills/ # 技能资源本地文件系统提供者与基于容器的提供者具有不同执行边界。目录按会话划分有助于组织数据,但目录隔离本身不等于操作系统级隔离。学习执行代码的任务时,要确认使用了哪种沙箱、工具实际具有哪些权限,以及结果保存在哪里。
用真实文件判断交付是否完成
当系统说“已生成报告”,检查三个层面:工具是否成功写入;文件是否出现在输出位置;界面中的文件能否打开并包含预期内容。仅出现文件名或下载链接文字,不能替代这三项检查。
要求生成包含三行测试数据的 CSV,随后让系统重新读取这个文件并报告行数。比较写入与读回的内容,可以验证文件工具形成了完整闭环。
路径与提供者说明:Sandbox System。
上下文、状态与记忆
“系统记得什么”其实包含不同层面。区分它们有助于解释长任务为什么会遗失细节,以及为什么开启持久化并不等于把所有资料都塞进模型。
| 层面 | 需要回答的问题 | 不要混淆为 |
|---|---|---|
| 模型上下文 | 这次调用实际看到了哪些消息与资料? | 全部历史始终可见 |
| 线程状态 / 检查点 | 一次会话执行到了什么位置? | 任意外部操作都能撤销或重放 |
| 长期记忆 | 哪些稳定信息值得在后续会话中使用? | 完整聊天记录或原始资料库 |
| 文件产物 | 哪些材料已保存,可按需重新读取? | 保存后就会自动进入每次调用 |
压缩是取舍,不是无损存储
DeerFlow 的摘要中间件把较早上下文压缩,并保留近期消息。当前实现还区分摘要生成失败与有效摘要,避免把空内容作为成功结果替换历史。这个机制缓解上下文增长,但摘要依然可能省略细节。
因此,长任务应把关键数字、来源与中间结论保存到文件中,让后续步骤能够重新读取原始依据。可以在每个阶段留下“完成了什么、证据在哪里、下一步是什么”,而不是只留下笼统进度。
长期记忆应服务于稳定信息
后端文档描述了跨会话的事实与偏好提取机制。使用时要区分稳定偏好和一次性任务要求:例如“习惯中文回答”与“这份报告只比较两种方案”具有不同作用域。不要依靠长期记忆替代每次任务的明确输入。
上下文实现:摘要中间件;记忆概述:Memory System。
安装与首次运行
以下是查阅时官方主线的 Docker 开发启动路径。它用于学习和本地验证。命令会下载仓库、镜像与依赖;模型调用通常还需要你自己的服务凭据与配额。本文仅提供操作教程,没有在当前环境中实际部署 DeerFlow。
1. 准备环境并取得代码
准备 Git、Make 和 Docker;官方当前要求 Docker Compose v2.24 或更高。确保 Docker 服务能够启动,再取得仓库。
git clone https://github.com/bytedance/deer-flow.git
cd deer-flow
docker compose version
git rev-parse HEAD保存最后一条命令输出的提交标识。主分支持续变化,这个标识可以帮助你在排查时确认教程、配置与代码是否处于同一个版本。
2. 用向导生成配置
make setup
make doctor向导用于选择模型服务、可选搜索与执行设置,生成 config.yaml 并把密钥写入 .env。先配置一个可用模型即可。需要执行联网研究时,再确认搜索服务可用;需要运行代码时,确认所选沙箱和命令工具设置。
3. 初始化并启动
make docker-init
make docker-start
# 查看运行日志
make docker-logs默认访问 http://localhost:2026。首次运行可能需要较长时间构建镜像。启动日志出现错误时先定位具体服务,不要一遍遍重新执行全部步骤。
4. 做三次递进验证
- 发一个不需要工具的短问题,确认模型连接。
- 上传一份短文本并要求提取其中三条事实,确认资料读取。
- 要求生成一个小文件并打开下载结果,确认输出链路。
模型标识、服务地址和能力开关必须与你实际使用的供应商对应。不要将示例里的名字当作保证可用的模型,也不要将 API 密钥写进网页。若命令与当前版本不符,先阅读该提交的 README 与配置模板。
启动命令与环境要求:官方 Quick Start;配置细节:Configuration Guide。
完成一次研究任务
第一次练习不必追求很长的报告。选一个你能亲自核验的问题,例如“比较关键词检索与向量检索在个人笔记搜索中的适用场景”。目标是观察系统怎样把问题变成材料、结论和文件。
请比较关键词检索与向量检索在个人笔记搜索中的适用场景。
读者:了解基础 Python,但没有搭建过搜索系统。
资料:优先使用官方文档、原始论文或作者的技术说明。
范围:比较精确术语、自然语言提问、更新维护三个维度。
请先列出简短计划,再查阅资料并完成报告。
每个关键事实附来源链接,区分资料结论与自己的推断。
资料不足时明确说明,不虚构实验结果。
将最终内容保存为 Markdown 文件,包含:
1. 问题与范围
2. 比较表
3. 三个具体查询例子
4. 实施建议及适用条件
5. 来源与仍需验证的问题
完成后重新读取文件,检查章节是否齐全。执行时看什么
观察它是否先澄清范围,是否访问实际资料,是否把搜索摘要误当作完整正文,以及最终结论是否对应引用。若发生子代理委派,检查子任务之间是否真的可以独立完成。没有子代理也不代表任务不完整,简单任务通常不需要强行拆分。
交付后怎么验收
从报告挑出三条关键结论,打开来源逐条核对。检查“论文在特定数据上得到的结果”有没有被扩大为“所有场景都成立”。再打开输出文件,确认它不是空文件,并且包含全部要求的章节。
把材料范围限制为你上传的两份文档,重新执行同一任务。比较两轮答案的来源、遗漏与不确定性。记录差异来自资料变化、提示词变化还是模型波动,不要只比较文字长度。
从哪里开始读源码
不要按目录顺序逐个打开文件。带着一个请求沿调用链走,效率通常更高。下面的路线以官方当前目录结构为基础;路径变动时,用函数或类名重新搜索。
| 阅读对象 | 入口 | 带着什么问题读 |
|---|---|---|
| 整体架构 | backend/docs/ARCHITECTURE.md | 哪些请求进入哪个服务? |
| 主代理装配 | backend/packages/harness/deerflow/agents/lead_agent/agent.py | 模型、工具与中间件如何组合? |
| 子任务执行 | backend/packages/harness/deerflow/subagents/executor.py | 子任务何时启动,结果如何收集? |
| 上下文压缩 | backend/packages/harness/deerflow/agents/middlewares/summarization_middleware.py | 压缩什么,保留什么,失败时怎么办? |
# 找主代理创建入口
rg -n 'def make_lead_agent|def _make_lead_agent' backend
# 找子任务工具与执行器的关联
rg -n 'SubagentExecutor|def task\(' backend
# 找摘要中间件在哪里被创建
rg -n 'create_summarization_middleware' backend把源码阅读变成一张小记录
每读一个模块,记录它接收的输入、修改的状态、调用的外部能力与失败路径。尤其注意配置默认值是否会被运行时覆盖。文档中的一张示意图能帮你建立方向,最终生效逻辑仍要回到实际执行路径核对。
一个很好的入门问题是:“为什么模型已经能回答,却不能写文件?”沿可用工具过滤、沙箱配置、工具执行和产物展示依次追踪,就能把多个模块连接起来。
以上入口链接集中列于下一节的参考资料中,均指向可变的 main 分支。
排查问题与评估
排查时先保留一个最小可复现任务:短输入、单个文件、少量工具。复杂任务同时涉及很多环节,失败时很难判断第一处问题在哪里。
| 现象 | 优先检查 | 最小验证 |
|---|---|---|
| 页面无法打开 | 启动日志、端口、前端与入口服务 | 确认服务仍在运行且访问了正确地址 |
| 能打开,但模型报错 | 凭据、模型名、地址、配额与能力配置 | 只发一个不需要工具的问题 |
| 没有检索到资料 | 搜索工具是否配置,返回错误还是空结果 | 用一个明确术语进行单次搜索 |
| 工具执行失败 | 沙箱状态、工具权限、文件路径 | 列出工作目录,再读取一个已知文件 |
| 长任务反复绕圈 | 是否重复同一操作,目标是否缺少验收标准 | 缩成一个可交付子任务并检查观察结果 |
| 有回答却没有文件 | 实际写入结果、输出路径、产物展示 | 创建小文件并重新读取 |
用一组固定任务衡量改进
准备五个任务:纯文本总结、上传资料问答、联网研究、小型数据处理、文件交付。每项写明通过条件,记录版本、模型配置、耗时、工具错误和人工核验结果。修改配置之后跑同一组任务,避免用一次顺利演示判断全部能力。
结果质量、过程成本与执行稳定性需要分开记录。更长的答案不一定更好,更多工具调用也不一定更认真。真正值得追踪的是:关键结论是否有依据,要求的产物是否可用,同类任务是否能够稳定完成。
提交标识 / 模型配置 / 输入材料 / 任务提示 / 预期结果 / 实际结果 / 失败位置。分享排查信息时移除凭据与不相关的私人内容。
参考资料与下一步
以下资料均来自官方仓库。主线会持续更新,重现实验时应优先保存提交标识,再阅读对应版本的文档。本文所列步骤未经过本地部署实测,安装细节以实际检出的版本为准。
- 项目仓库与 Quick Start ↗了解 2.0 定位、启动方式和主线变化。
- Backend Architecture ↗理解服务拓扑、接口路由与组件关系。
- Backend README ↗查阅工具、沙箱、记忆与后端结构概述。
- Configuration Guide ↗核对模型与运行环境的配置字段。
- 主代理工厂源码 ↗从装配逻辑理解实际启用的能力。
- 子代理执行器源码 ↗追踪委派任务的执行过程。
- 摘要中间件源码 ↗理解长任务中的上下文取舍与失败处理。
下一步:为一个真实问题保留完整记录
选一个与你学习或工作相关的小任务,保存输入、配置、工具记录和最终产物。之后只改变一个因素,例如材料范围或报告结构,再比较结果。这样得到的经验比收集更多安装截图更容易迁移到下一个项目。