拆解 Deer-Flow 的 Prompt 设计:它如何把"会聊天的模型"约束成"能执行的 Agent"


Deer-Flow(Deep Exploration and Efficient Research Flow)是字节跳动开源的深度工作 Agent,官方把 2.0 版本定位为一套 super agent harness:编排子 Agent、管理长期记忆、提供沙箱、挂载可扩展的技能工具箱。它和常见的大模型聊天产品有明显差异——不只是”回答问题”,而更像一个被严格约束、能分解任务并调用工具的执行系统。

我真正关心的是它背后的 Prompt 设计:它是怎么把”会聊天的模型”约束成”能执行的 Agent”的?本文是拆解 Deer-Flow 的第一篇,重点不放在 UI,而放在主 Agent 的系统提示词上。换句话说,要回答的是:Deer-Flow 的 Prompt,到底和我们平时在网页端直接聊天有什么不同。

分析方法

为了把这个问题看清楚,拆解按两步走。

第一步:改代码,把真实下发的 Prompt 落盘

在运行链路里增加日志,把 LLM 对话过程中真正下发的 Prompt 保存下来。这样拿到的不是文档里的示例,而是线上实际生效的完整文本。

第二步:回看代码,分析 Prompt 设计

与大模型对话的 Prompt 模板定义在 backend/packages/harness/deerflow/agents/lead_agent/prompt.py。其中 SYSTEM_PROMPT_TEMPLATE 接近 200 行,已经不是简单的几段角色设定,而是一份完整的 Agent 行为规约。

lead_agent/prompt.py 本质上是 Deer-Flow 主 Agent 的 system prompt assembler。它把身份、长期记忆、技能系统、工具发现、目录约束、citation 规范、clarification 策略、subagent 编排策略统一组装成一份最终 system prompt,再交给 create_agent() 使用。这份 prompt 既定义”你是谁”,也定义”你怎么工作”,还定义”你能访问什么、必须遵守什么规则”。

SYSTEM_PROMPT_TEMPLATE 的整体结构

从功能分层看,系统提示词大致是六层:

┌──────────────────────────────────────────────────────┐
│ 1. 角色层    Role / Soul / MemoryContext             │
│ 2. 思考层    Thinking Style                          │
│ 3. 流程层    Clarification System(控制流引擎)       │
│ 4. 能力层    Skills / 工具发现                        │
│ 5. 环境层    Working Directory + Tools                │
│ 6. 输出层    Response Style + Citation                │
│                                                      │
│ 兜底层      Critical Reminders + Current Date         │
└──────────────────────────────────────────────────────┘

对应到模板标签,大致由以下内容按序拼装:

  1. <role>
  2. {soul}(可选)
  3. {memory_context}(可选)
  4. <thinking_style>
  5. <clarification_system>
  6. {skills_section}
  7. {deferred_tools_section}
  8. {subagent_section}
  9. <working_directory>
  10. <response_style>
  11. <citations>
  12. <critical_reminders>
  13. 末尾额外追加 <current_date>

其中 {soul}、{memory_context}、{skills_section}、{subagent_section} 等都是条件注入的,是否出现取决于配置和运行时的开关状态。

重点分析的几个核心模块

下面重点看 memory_context、thinking_style、clarification_system、response_style、citations、critical_reminders 这几块提示词的构造方式。

memory_context:不是塞原始 JSON,而是二次整理的摘要

memory 注入函数是 _get_memory_context(),它会依次:

  1. 读取 memory 配置
  2. 检查 memory.enabled 与 memory.injection_enabled
  3. 加载 memory 数据
  4. 格式化为文本
  5. 包成 <memory> ... </memory>

涉及的具体依赖:

职责位置
读取 memory 配置config/memory_config.py 的 get_memory_config()
加载 memory 数据agents/memory/updater.py 的 get_memory_data()
格式化为注入文本agents/memory/prompt.py 的 format_memory_for_injection()

format_memory_for_injection() 会把 memory 压缩成三大块:

  1. User Context
  2. History
  3. Facts

并受 max_injection_tokens 限制。

所以这里的 memory 不是原样塞一整份 memory.json,而是二次整理后的紧凑摘要。这一点很关键:长期记忆如果没有预算约束和结构压缩,很快就会把上下文窗口吃掉,反而降低模型表现。

<thinking_style>:把”先想后做”写进系统层

这是 Agent 的内部推理行为约束层,核心要求包括:

  • 先思考再行动
  • 先检查是否缺信息或有歧义
  • 如果需要澄清,必须优先澄清
  • thinking 不等于 final answer
  • 必须输出对用户可见的实际响应

当 subagent_enabled=true 时,这里还会额外插入 {subagent_thinking},由 apply_prompt_template() 动态生成。这部分会要求模型先数清楚 sub-task 数量,并严格控制每轮最多多少个 task 调用。

关键原文与含义对照:

原文含义
Think concisely and strategically about the user's request BEFORE taking action采取行动之前,先对请求做简洁且有策略的思考
Break down the task: What is clear? What is ambiguous? What is missing?先拆解任务:哪些清楚、哪些有歧义、哪些缺失
If anything is unclear ... you MUST ask for clarification FIRST只要有不清楚、缺失、可多种解释的地方,必须先澄清,不能直接干
Never write down your full final answer or report in thinking process, but only outlinethinking 阶段只做提纲式规划,不把最终报告写进”思考”
After thinking, you MUST provide your actual response to the user思考结束后必须给出用户可见的正式回答

这部分的设计含义有三层:

  1. 在系统 prompt 层把”先想后做”固定下来,避免模型一上来就盲目调用工具。
  2. 把”需求诊断”显式化,让模型在任何任务开始前都先判断信息完备性。
  3. 要求 thinking 与 final answer 分离,避免把内部规划直接泄漏成最终交付物。

<clarification_system>:整套 Prompt 里最强的约束

这是 prompt 中最强约束之一。它把工作流显式写成 CLARIFY → PLAN → ACT,并列出了 5 类必须先澄清的场景,还给出了 ask_clarification(...) 的工具调用格式示例。

也就是说,Deer-Flow 的设计不是”需要时可以澄清”,而是在系统 prompt 层硬编码了澄清优先级。

关键原文与含义对照:

原文含义
WORKFLOW PRIORITY: CLARIFY → PLAN → ACT工作流优先级固定为:先澄清,再计划,最后执行
Clarification ALWAYS comes BEFORE action澄清必须先于行动,不能边做边问
MANDATORY Clarification Scenarios以下场景下澄清不是建议,而是强制要求
DO NOT start working and then ask for clarification mid-execution不允许先开工再中途补问
DO NOT make assumptions when information is missing信息缺失时禁止自行脑补
If you identify the need for clarification in your thinking, you MUST call the tool IMMEDIATELY只要内部判断需要澄清,就必须立刻调用 ask_clarification

五类强制澄清场景:

场景含义
missing_info缺少完成任务所必须的信息
ambiguous_requirement需求本身可被多种方式理解
approach_choice存在多种合理技术路线,需要用户拍板
risk_confirmation操作具有破坏性、不可逆性或高风险
suggestion模型有建议方案,但想先获得用户许可

这块的真正作用,不只是让回答更谨慎,而是把 Agent 的执行策略改造成:默认不做猜测、默认不抢跑、默认把需求确认看得比执行速度更重要。也正因为这块写得很重,Deer-Flow 对”先澄清后执行”的偏好会明显强于很多普通聊天型 assistant。

代价也很直接:简单任务上会多一轮交互。这是设计上的主动取舍,不是缺陷。

<response_style>:输出层的收束

这是最终回答风格约束,三个要点:

原文含义
Clear and Concise: Avoid over-formatting unless requested表达清楚简洁,除非用户要求,否则不要过度排版
Natural Tone: Use paragraphs and prose, not bullet points by default语气自然,默认优先用段落和自然语言,而不是满屏项目符号
Action-Oriented: Focus on delivering results, not explaining processes重点是交付结果,而不是长篇解释自己做事的过程

这层不是执行规则,而是输出风格收束,体现的是对”工程型回答”的偏好:

  1. 默认不追求花哨格式,而追求信息密度。
  2. 默认不把回复写成官样清单,而尽量像自然交流。
  3. 默认把”结果导向”放在首位,减少无价值的过程汇报。

所以即便前面的 prompt 有很多严格约束,最后输出层仍被要求看起来像”一个直接、自然、能干活的工程助手”。

<citations>:把引用规范硬编码进 System Prompt

这是 Web 研究任务的重要结构块,强制要求:

  • 使用 web_search / web_fetch 后必须给 citation
  • 行内引用格式是 [citation:TITLE](URL)
  • 报告末尾要有 Sources 段
  • Sources 段必须是可点击的 markdown link

关键原文与含义对照:

原文含义
CRITICAL: Always include citations when using web search results只要用了 web search 或外部信息源,就必须带引用
Format: [citation:TITLE](URL) immediately after the claim行内引用格式固定,且要紧跟在对应结论后面
Also collect all citations in a "Sources" section at the end报告末尾必须集中列出 Sources 来源区
DO NOT write research content without citations不允许写没有出处支撑的研究性内容

这块要解决两个问题:

  1. 防止模型在 research / report 类任务里写出”像研究、但没出处”的内容。
  2. 把”可追溯性”从可选项变成硬约束。

它很像一套嵌入在 system prompt 里的轻量引用规范:行内引用解决”这一句从哪来”,Sources 段解决”本次整体用了哪些资料”。因此研究类输出在理想情况下不该只是”总结”,而应该是带来源链路的总结。

<critical_reminders>:最后的收口层

这是收口层提醒,集中重复最关键的执行原则:

条目含义
Clarification First永远先确认不清楚的点,再执行
Skill First复杂任务优先加载 skill,不要裸奔执行
Progressive Loading资源按需逐步加载,不要一次性灌入所有上下文
Output Files最终交付文件必须放在 /mnt/user-data/outputs
Language Consistency保持和用户一致的语言
Always Respondthinking 是内部的,最终必须给用户一个可见回答

当 subagent_enabled=True 时,这里还会注入 {subagent_reminder},再次强调 orchestrator 模式和并发上限。

这块的作用像”最后一道总开关”:它并不引入新能力,而是把最关键的原则再压一遍,防止模型在长 prompt 的后半程遗忘前面的约束。几个值得注意的点:

  1. Skill First 说明 skill 被定位为复杂任务的默认入口,而不是偶尔使用的插件。
  2. Progressive Loading 与前面的 skill 系统配套,系统不鼓励一次性把所有参考资料都塞给模型。
  3. Language Consistency 是很实用的 UX 约束,避免中英文混乱切换。
  4. Always Respond 是防呆条款,防止模型停留在内部 reasoning 或只做工具动作却不回话。

总结

如果把整个 Prompt 看成一个多层控制系统,那么 critical_reminders 就是最后的”收口层”和”兜底层”。把前面几个模块连起来看,Deer-Flow 的设计思路就很清楚了:它并不是单纯给模型补充更多背景信息,而是在系统提示词里同时规定角色、流程、工具边界、输出风格和引用要求。

这才是 Deer-Flow 的 Prompt 最值得关注的地方。它真正想解决的不是”让模型回答得更聪明”,而是”让模型在复杂任务里更像一个可靠的执行系统”。从这个角度看,Prompt 在 Agent 体系里已经不只是提示词,更接近一份运行时行为规范。

几个可以迁移到自建 Agent 的经验:

  • 先澄清后执行要写在系统层并给出强制场景,只在工具描述里提一句几乎不会生效。
  • 记忆注入必须做预算与压缩,原始全量注入会反噬效果。
  • thinking 与 final answer 必须显式分离,否则内部规划容易变成泄漏的交付物。
  • 长 prompt 需要收口层,把最关键的原则在末尾重复一遍,抵消注意力衰减。
  • 输出风格也是提示词的一部分,默认段落而非清单、默认结果而非过程,会显著改变体感。

后续如果继续拆 Deer-Flow,我会再看它的 skill system、subagent orchestration 和 memory 更新机制。这几部分和本文分析的系统 Prompt 结合起来,才更接近一个完整的 Agent 执行框架。

参考

← 返回博客