主要技术:LangChain、LangGraph、FastAPI、python-docx
项目目录
项目简介
DeerFlow 是把资料研究、代码执行和文件制作组织在一起的开源 Agent 工作台。用户给出任务并上传材料,主 Agent 调用工具或分派子任务,生成报告、图表、网页等产物;当前 2.x 版本基于 Python、LangGraph 和可扩展技能组织执行。
官方案例中,用户上传 Titanic CSV 数据并要求分析生存因素,Agent 读取数据、编写并运行分析脚本,交付文字总结和多张统计图。网页支持查看任务过程与输出文件;研究、写作和演示材料制作等任务还可按需读取对应技能及资源。

项目亮点
- 技能按需加载: 先提供技能名称和简介,需要执行时再读取
SKILL.md及引用资料,把工具调用方法与制作要求按任务补入上下文。 - 有额度的多任务委派: 普通
task默认使用独立上下文,需要承接前文时可携带派发时的父会话快照;中间件同时约束单轮委派数量和本次运行总量,裁去超额调用。 - 共享文件与执行租约: 主、子 Agent 可共用线程工作区,通过虚拟路径访问上传资料和产物。执行租约保留尚在使用的环境,在释放请求发出且最后一个持有者退出后,才调用 Provider 释放。
- 产物检查独立于任务状态: 委派可附带
acceptance_criteria,在子任务完成后检查文件、JSON语法、CSV表头或已记录的测试证据,分别返回成立、不成立和未验证结果。
技术架构
Next.js 前端通过 FastAPI Gateway 上传材料、发起运行并接收流式事件,Agent 运行时内嵌于 Gateway。基于 LangGraph 的主 Agent 组合模型、技能、中间件和工具;普通子任务由执行器异步运行,将结果及文件引用交回主任务。
文件按用户、线程划分为 uploads、workspace 和 outputs,由 Sandbox Provider 解析统一虚拟路径。本地文件 Provider 和容器 Provider 分别承接不同执行方式;产物通过 present_files 登记当前线程输出路径,再交由文件接口供前端查看和下载。
| 代码位置 | 主要职责 |
|---|---|
frontend/、backend/app/gateway/ |
任务界面、上传与产物接口、内嵌运行和事件传输 |
backend/packages/harness/deerflow/agents/lead_agent/、skills/ |
组织主 Agent,发现和按需加载技能 |
backend/packages/harness/deerflow/tools/builtins/task_tool.py、backend/packages/harness/deerflow/subagents/executor.py |
传递委派上下文,执行子任务并返回结果 |
backend/packages/harness/deerflow/sandbox/、backend/packages/harness/deerflow/config/paths.py |
管理执行后端、线程目录、虚拟路径与共享租约 |
backend/packages/harness/deerflow/subagents/acceptance_checks.py、backend/packages/harness/deerflow/tools/builtins/present_file_tool.py |
检查具体交付条件,登记可呈现的输出路径 |
如何写进简历
投标工作台 · 工业装备投标协作助手 | 工业装备场景示例
项目描述:面向工业装备投标团队的资料协作助手,将招标条款、设备手册和资质材料组织为响应矩阵,生成带依据的响应草稿及缺件清单,供投标人员复核。
技术栈:Python、LangChain、LangGraph、FastAPI、python-docx
主要工作:
- Skill 渐进加载与条款证据组织:编写投标资料
Skill,把条款、证明材料及响应位置组织为任务模板;先加载技能元信息,执行时再读取SKILL.md与引用文件,按需组织设备手册和资质证据,减少整套材料常驻模型上下文。 - 子任务委派与预算控制:通过
task按条款范围分派商务、技术及资质整理,以文档版本和输出契约汇总响应;结合独立上下文、可选父会话snapshot及单轮/运行总量限制,控制重复拆分和背景传递规模。 - Sandbox 文件生成与共享执行租约:通过
Sandbox Provider的文件与命令接口生成DOCX响应稿和缺件清单,主、子任务共用线程资料;以执行租约协调共享环境的释放,避免子任务仍在生成文件时提前关闭客户端。 - 产物三态检查与响应复核:为子任务附加
acceptance_criteria,完成后检查响应文件与缺件清单的CSV表头,以checked/holds区分成立、不成立和未验证;再按条款矩阵核对缺件与引用,衔接结构检查和业务复核。
稿易达 · 专题内容制作助手 | 传媒出版场景示例
项目描述:面向专题采编团队的内容制作助手,将采访笔记与公开资料组织为可追溯素材,围绕统一事实表生成专题稿、图表及演示材料,并按编辑意见更新相关产物。
技术栈:Python、LangChain、LangGraph、FastAPI、Matplotlib、python-pptx
主要工作:
- Skill 渐进加载与采编工作流:编写专题采编
Skill,将素材索引、写作及配套制作组织为可复用流程;按任务读取SKILL.md和参考文件,分别保留原话、编辑概括及来源位置,避免整套制作说明一次性占满上下文。 - 独立子任务与编辑背景快照:默认以独立上下文分派资料整理和内容制作,需要承接选题、受众或多轮修改意见时显式传入父会话
snapshot;按任务固定素材版本和输出范围,使子任务获得必要背景并保持各自执行上下文。 - Sandbox 多产物生成与路径约束:通过
Sandbox Provider在工作区处理素材,由同一事实表驱动Matplotlib图表和python-pptx演示稿;最终文件写入outputs,通过present_files登记当前线程产物,减少跨文件数字及交付路径错配。 - 依赖修订与确定性产物检查:为段落、图表和幻灯片维护事实依赖及版本,按编辑修改单定位重制范围;通过
acceptance_criteria检查文件非空和事实表JSON语法,再由交付清单关联来源与待核项,保留可复查的修订结果。
面试题与回答
3 题子 Agent 是否使用父 Agent 的全部上下文?
展开收起
这一版
DeerFlow的普通task委派提供两种context_mode:默认isolated,只用当前委派任务作为对话输入;显式选择snapshot时,再附带父会话的保留历史和摘要。子 Agent 仍使用自己的角色、工具配置和执行链路。快照复制什么,何时复制
task校验委派类型与允许范围后,在子 Agent 初始化前调用ParentContextSnapshot.from_state(...)。快照读取派发当时的summary_text与仍保留的对话消息,过滤父系统消息和框架注入等内容,再序列化为独立数据。因此,父会话若已经压缩,子 Agent 得到的是当前保留内容与摘要,不会恢复所有被压缩掉的原始消息。快照也不会因为父状态后来发生变化而自动更新;重新构建子消息时使用独立容器,不与父消息或兄弟任务共用可变历史。
历史作为背景,当前任务单独传入
子 Agent 初始输入的顺序是:自己的
SystemMessage、名为parent_context_snapshot的背景HumanMessage,然后是当前任务的HumanMessage。背景里保留用户要求、已知决定和观察,但不提升为子 Agent 的系统指令。父 Agent 已完成的工具调用会与保留结果匹配后,以“历史工具调用”的文本进入背景;尚未取得对应结果的调用不作为可重放操作传入。这样既能解释过去查到了什么,又避免子 Agent 把父方调用、回执或历史动作误认为自己本次已经执行的结果。
怎样使用两种模式
任务目标和资料位置已经明确时,选
isolated,减少重复携带父会话。接续复杂排障、需要理解多轮更正或失败尝试时,选snapshot,同时在任务中指出当前要解决的部分。为避免多轮规划不断追加子任务,
SubagentLimitMiddleware在模型返回后统计本条消息的task调用,并结合委派账本中当前run_id的已用次数,只保留单次上限与本次运行剩余额度共同允许的调用。超出部分被裁去,不会转成等待队列;总量耗尽则附加限额说明,要求主 Agent 基于已有结果收敛。委派限额与是否传入父会话快照是独立控制。委派限额实现。两种模式都不等于复制父 Agent 的全部运行状态。工具所需的工作区、线程或上传文件信息可由宿主另外传入,这与复制聊天历史是两条路径。父方后来出现新要求时,需要明确补充或重新派发;子任务完成后,再将报告与产物交回父 Agent 汇总。
Agent 沙箱工作区如何设计和实现?
展开收起
核心回答
DeerFlow把沙箱工作区拆成线程文件目录、沙箱 Provider 和统一文件工具:按用户与线程定位上传文件、过程文件和最终产物,工具通过 Provider 读写对应环境。目录解决文件归属,Provider 决定实际在哪执行;本地文件模式与容器模式的隔离能力不同。例如整理上传资料并生成报告时,输入放
uploads,中间笔记放workspace,报告放outputs。普通子 Agent 委派会带入父任务的线程和文件上下文,因此可以读取已有材料、交回文件产物;这不等于每个子 Agent 都获得一台独立虚拟机。线程路径怎样变成工具可用的工作区?
Paths在用户作用域下,将线程文件组织到{base_dir}/users/{user_id}/threads/{thread_id}/user-data/,下分workspace、uploads、outputs;不带用户的旧路径另有兼容逻辑。ThreadDataMiddleware根据运行上下文中的用户与线程,生成三个实际路径,放入thread_data。模型侧使用固定虚拟路径/mnt/user-data/...,不需要知道部署机器的真实目录。路径定义、线程路径注入。默认可以延迟到首次文件或命令工具调用时再初始化沙箱。
ensure_sandbox_initialized()在复用或申请环境前检查沙箱执行授权,并结合当前用户、线程校验缓存的沙箱身份;不能只拿历史状态中的sandbox_id就认定环境仍适用。初始化与复用。本地文件模式和容器后端有什么区别?
LocalSandboxProvider在宿主进程侧操作文件。 它按用户、线程缓存LocalSandbox,把虚拟路径映射到对应实际目录。文件工具先校验允许路径,再解析真实路径并检查是否仍在当前线程目录内;自定义挂载还要遵守只读标记。当前示例配置默认使用此 Provider,并设置allow_host_bash: false。开启宿主命令后,命令可以使用宿主真实路径,所以这些映射不能替代进程隔离。本地 Provider、路径边界检查。AioSandboxProvider的本机后端才负责创建独立容器。 无provisioner_url时选择LocalContainerBackend,由它管理Docker或Apple Container;配置 provisioner 时改用远端后端。这里的“本机容器后端”和上面的“宿主文件 Provider”是两种实现。后端选择、容器运行时。本机容器通过挂载把当前线程三个目录暴露为相同的虚拟路径,因此后端写入上传文件后,容器可以直接读取。远端环境若不共享存储,则需要文件同步,不能只把同一个路径字符串传过去。线程目录挂载、远端同步配置。
文件怎样从生成走到交付?
以
/mnt/user-data/outputs/report.md为例,write_file先取得沙箱并确保线程目录存在;本地模式完成路径映射和越界检查后调用sandbox.write_file(),容器模式由对应 Provider 的文件接口处理。读取也走同一沙箱抽象。主 Agent 和普通子 Agent 可以共享线程文件,因此并行工作宜分配不同产物路径,最后再汇总,不能把共享工作区当成自动冲突合并机制。文件读写入口、写入处理、委派携带文件上下文。文件准备好后,
present_files将路径规范到当前线程的outputs范围,并把虚拟路径加入状态中的artifacts,供客户端展示。它负责登记交付引用,不负责生成文件或判断报告结论是否正确。产物呈现。环境释放与文件保留怎样配合?
并发的主、子 Agent 执行分别持有沙箱租约,最后一个使用者释放后才进行相应环境回收,避免主任务先结束就关闭仍被子任务使用的环境。AIO 的健康环境可以进入预热池复用;本地 Provider 的
release()则不删除线程文件。线程文件与执行环境分开管理,才便于后续读取产物和继续任务。租约生命周期、AIO 释放、本地释放。这种设计的取舍是:本地模式启动和调试简单;容器或远端 Provider 提供更独立的执行环境,但增加镜像、挂载、同步和回收成本。应按代码可信程度与部署方式选后端,目录隔离、工具授权和进程隔离分别落实。
参考资料
- 国内:DeerFlow:Sandbox 配置:依据本地模式、宿主命令开关和 AIO 容器模式的区别说明后端选择,并采用远端是否共享目录决定同步方式的约定。
- 国内:JavaGuide:Harness Engineering:采用文件系统保存产物、执行环境承接工具动作的分工,解释线程文件与运行资源为何分开管理。
- 国内:zero2Agent:Agent 文件系统访问边界与工作目录隔离:采用路径校验与运行隔离各有职责的解释,说明本地路径映射不能视为宿主进程的安全边界。
- 国内:WeThinkIn:Workspace 与抽象文件系统:采用统一文件接口与底层存储语义的区分,说明虚拟路径统一后,远端同步和并发文件归属仍需处理。
- 国外:Docker Engine security:依据命名空间、资源限制与挂载配置的职责,说明使用容器后的隔离仍取决于实际权限和挂载范围。
- 国外:Introduction to gVisor security:依据用户态应用内核及系统调用处理机制,解释通用答案中普通容器和更强隔离选项的区别。
如何校验 Agent 产生的确定性结果?
展开收起
核心回答
DeerFlow可以把确定性检查随子任务传递:主 Agent 在task中提供acceptance_criteria,子任务执行结束后,程序读取实际文件或已记录的命令结果,逐项返回检查结果。模型的完成说明、子任务的completed状态和检查条件是否成立分别记录,不能互相替代。这条检查链适合确认文件存在、格式可解析和特定执行记录。研究结论是否有依据、数据口径是否正确,仍要依据需求另作核对;主 Agent 再根据具体未满足项安排修正或补证。
把检查条件随子任务传递
例如委派整理企业资料,要求交付结构化数据和摘要文件,可以附上两项条件:
file:/mnt/user-data/outputs/companies.json json-valid file:/mnt/user-data/outputs/summary.md non-empty这是检查项示例。第一项检查文件能否按
UTF-8 JSON解析;第二项检查摘要文件非空。即使两项都成立,数据也可能缺少企业名称、来源或日期,摘要也可能遗漏关键反证,因此不能把这两项扩成“研究结果正确”。必填字段可以再用JSON Schema校验,结论则需要对照原始来源;这些是业务侧应增加的判据。程序实际检查了什么
普通
task在子任务进入COMPLETED,且委派携带检查条件时,才调用确定性检查器。检查器通过当前线程的工作区读取文件,归一化虚拟路径并核对可访问范围;支持的条件包括:- 文件存在、非空,以及
file_written对应文件的读取确认。 json-valid检查JSON语法,csv-columns检查必需表头;它们不检查每行数据与业务含义。tests_passed:<command>对照已记录的bash执行,核对命令归属、状态与测试摘要;它不会在父任务里重新执行测试。
检查有读取与证据边界。比如
JSON文件超出该版50,000字节检查上限、测试命令或输出无法可靠归因、产生记录的 Shell 来源未知或为持久会话时,对应条件会保留为未验证。只看到退出码为零、构建成功或“没有测试”,都不应直接视为测试通过。检查器实现。失败、未知和执行结束怎样区分
每项结果使用
checked和holds记录,返回给主 Agent 的清单区分:holds:这项执行条件已有证据支持。does not hold:已检查,条件不成立,可以针对具体原因修正。UNVERIFIED:现有检查或证据不足,需要补充验证。
该版普通
task的返回路径仍将子任务标为completed,同时附上检查结果;条件不成立不会自动改成failed,检查器异常时还可能没有清单。应用不能只读任务状态就宣布验收成功。检查调用与结果回传。主 Agent 的提示要求针对不成立的条件修补、对未知项补证,并复用已经确认的产物。这是后续决策要求,不是程序已经自动完成修复。若业务要求全部检查通过才能交付,应在应用交付层读取检查结果,并为字段、口径和来源等业务条件增加独立校验。主 Agent 的处置规则。
- 文件存在、非空,以及