DeerFlow
bytedance/deer-flow项目目录
项目简介
DeerFlow 是面向复杂任务的 Agent 框架,由主助手调用工具、按需委派子任务,结合 Skill、线程工作区和文件产物处理资料研究、分析与内容生成。
如何写进简历
标策 · 企业投标材料协作平台 | 场景化示例
项目描述:基于 DeerFlow,面向投标团队分工整理招标文件、产品资料与资质材料,生成条款响应草稿和缺件清单,供投标人员复核。
技术栈:Python、LangChain、LangGraph、FastAPI
主要工作:
- 子任务并发与上下文交接:基于
DeerFlow的task并发委派商务条款、技术要求和产品资料任务,限定并发与委派总量;默认使用独立上下文,多轮澄清时按需附加父会话快照。 - 线程工作区与沙箱生命周期:基于
Sandbox Provider将虚拟路径映射到用户、线程工作区,利用租约管理主、子 Agent 的共享环境;待最后一个使用者释放后再回收,避免主任务先结束导致子任务环境提前关闭。 - 可执行验收与三态反馈:将
acceptance_criteria随子任务传入,由检查器读取实际产物和已记录执行结果;通过checked/holds区分成立、不成立与未验证,为响应材料的定点修正和补证提供依据。
面试题与回答
子 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 的处置规则。
- 文件存在、非空,以及