Skip to content

Lead Agent 与 Agent 工厂

本章目标:

  1. 讲清 make_lead_agent 应用级入口与 create_deerflow_agent 纯参数 SDK 工厂这两层工厂为何分层、各自边界在哪里。
  2. 拆解一次 make_lead_agent(config) 调用如何把 model / tools / middleware / system_prompt 解析装配进 langchain.agents.create_agent
  3. 给出用 create_deerflow_agent + RuntimeFeatures 构建自定义 agent 的最小模板与从源码校验逻辑读出的约束清单。

TL;DR

DeerFlow 的 agent 装配分两层:make_lead_agentlanggraph.json 注册的图工厂,从 RunnableConfig 解析运行时配置并查全局 AppConfig,产出生产用 lead agent;create_deerflow_agent 是无 YAML、无全局单例的纯参数 SDK 工厂,通过 RuntimeFeatures 声明式开关装配中间件链。两者最终都调用同一个 langchain.agents.create_agent 原语,装配的四要素是 model、tools、middleware、system_prompt,外加 state_schema=ThreadStatemake_lead_agent 的中间件链由 build_lead_runtime_middlewares(共享基座)+ _build_middlewares(lead 专属)两段顺序追加而成。featuresmiddleware 互斥,后者是「完全接管」。

Overview

为什么需要两层工厂?核心矛盾是「生产入口要懂配置」与「SDK 入口要可测、可嵌入」。

make_lead_agent(config: RunnableConfig) 是 LangGraph Server 注册的图,签名必须兼容 LangGraph Server agent.py:343-347。它从 config.configurable / config.context 合并运行时上下文,读全局 AppConfig,解析模型名、加载 agent 配置与技能、注入 LangSmith trace 元数据 agent.py:350-409。它「重」——耦合 YAML 配置、全局单例、技能存储、子代理注册表。

create_deerflow_agent 则刻意「轻」:它接受纯 Python 参数,工厂装配本身不读任何配置文件 factory.py:1-11,用 RuntimeFeatures 数据类声明要开哪些中间件 features.py:14-34。它定位于「create_agent 原语」与「make_lead_agent 应用工厂」之间的 SDK 层,便于单测、嵌入式客户端复用和构造定制 agent。

两层共享同一终点 langchain.agents.create_agent,装配骨架一致,差别只在「谁来决定 model/tools/mw/prompt」。

Architecture

Source 文件清单:

角色文件关键符号 (Source)
应用级图工厂backend/packages/harness/deerflow/agents/lead_agent/agent.pymake_lead_agent L343-347_make_lead_agent L350-446_build_middlewares L240-318
纯参数 SDK 工厂backend/packages/harness/deerflow/agents/factory.pycreate_deerflow_agent L61-147_assemble_from_features L155-298
特性声明数据类backend/packages/harness/deerflow/agents/features.pyRuntimeFeatures L14-34Next/Prev L42-63
系统提示词组装backend/packages/harness/deerflow/agents/lead_agent/prompt.pyapply_prompt_template L768-823
共享中间件基座backend/packages/harness/deerflow/agents/middlewares/tool_error_handling_middleware.pybuild_lead_runtime_middlewares L129-136
公共导出backend/packages/harness/deerflow/agents/__init__.pycreate_deerflow_agent / make_lead_agent 导出 L1-20
图注册backend/langgraph.jsongraphs.lead_agent L8-10

langgraph.json 把图名 lead_agent 指向 deerflow.agents:make_lead_agent langgraph.json:8-10,而 deerflow.agents.__init__ 在导入时即调用 prime_enabled_skills_cache() 预热技能缓存 init.py:6-10

Components / Subsystems

make_lead_agent — 应用级图入口

职责:作为 langgraph.json 注册的图工厂,从 LangGraph 传入的 RunnableConfig 出发,产出完整生产 lead agent。

关键函数:

  • make_lead_agent(config) agent.py:343-347:薄包装,取 runtime_config["app_config"],否则 get_app_config(),转入 _make_lead_agent
  • _get_runtime_config(config) agent.py:29-35:把 configurable 与 LangGraph context 合并成一个 dict。
  • _make_lead_agent(config, *, app_config) agent.py:350-446:核心装配体。
  • _resolve_model_name(...) agent.py:38-50:模型名安全解析,无效时回退默认模型。

要点:

  • runtime config 读取的关键键:thinking_enabled(默认 True)、reasoning_effortmodel_name/modelis_plan_modesubagent_enabledmax_concurrent_subagents(默认 3)、is_bootstrapagent_name agent.py:358-365
  • 模型名解析优先级:请求 → agent 配置 → 全局默认 agent.py:370-373。模型不支持 thinking 时自动降级 agent.py:379-381
  • 两条产出分支:is_bootstrap=True 走最小提示词 + setup_agent 工具 agent.py:413-427;否则默认/自定义 agent 分支,自定义 agent 额外注入 update_agent 工具 agent.py:429-446
  • 两分支最终都调用 create_agent(model=..., tools=..., middleware=..., system_prompt=..., state_schema=ThreadState)

create_deerflow_agent — 纯参数 SDK 工厂

职责:在 create_agent 原语与 make_lead_agent 应用工厂之间提供无 YAML、无全局单例的 SDK 入口。

关键函数:

  • create_deerflow_agent(model, tools, *, system_prompt, middleware, features, extra_middleware, plan_mode, state_schema, checkpointer, name) factory.py:61-147
  • _assemble_from_features(feat, ...) factory.py:155-298:按 RuntimeFeatures 顺序构建 14 个中间件 + 注入的 extra_tools。
  • _insert_extra(chain, extras) factory.py:306-379:用 @Next/@Prev 锚点把额外中间件插入链中。

要点:

  • middleware 是「完全接管」:一旦提供,该列表原样使用,且不能与 featuresextra_middleware 共存 factory.py:110-117
  • 走 features 分支时,feature 注入的 extra_tools 按名去重追加,用户提供的工具优先 factory.py:132-137
  • state_schema 默认 ThreadState factory.py:120

RuntimeFeatures — 声明式特性开关

职责:用纯数据类声明 create_deerflow_agent 要开启哪些中间件,无 I/O、无副作用 features.py:1-4

要点:

  • 多数特性接受三态:True(用内置默认中间件)、False(禁用)、AgentMiddleware 实例(自定义替换)features.py:18-25
  • summarizationguardrail 无内置默认,只接受 False 或自定义实例;在 _assemble_from_features 中传 Trueraise ValueError factory.py:209-223
  • 默认值:sandbox=Trueloop_detection=True,其余特性默认 False features.py:27-34
  • @Next(anchor) / @Prev(anchor) 装饰器给中间件类打 _next_anchor / _prev_anchor 标记,供 _insert_extra 定位 features.py:42-63

prompt 组装 — apply_prompt_template

职责:把角色、SOUL、技能、延迟工具、子代理指令拼成完全静态的系统提示词。

关键函数:apply_prompt_template(subagent_enabled, max_concurrent_subagents, *, agent_name, available_skills, app_config) prompt.py:768-823

要点:

  • SYSTEM_PROMPT_TEMPLATE.format(...) 填入 agent_namesoulself_update_sectionskills_sectiondeferred_tools_sectionsubagent_sectionsubagent_reminder/subagent_thinkingacp_section prompt.py:813-823
  • 仅当 subagent_enabled=True 时才拼接子代理编排段(含并发上限 n)prompt.py:776-796
  • 提示词刻意保持「完全静态」:当前日期与 memory 由 DynamicContextMiddleware<system-reminder> 注入首个 HumanMessage,以最大化前缀缓存复用 prompt.py:809-812,与 _build_middlewares 中追加 DynamicContextMiddleware 对应 agent.py:262-265

Data Flow

Implementation Details

create_deerflow_agent 入口的三段互斥校验,是理解「middleware 完全接管」语义的关键 factory.py:110-131:

python
if middleware is not None and features is not None:
    raise ValueError("Cannot specify both 'middleware' and 'features'...")
if middleware is not None and extra_middleware:
    raise ValueError("Cannot use 'extra_middleware' with 'middleware' (full takeover).")
if extra_middleware:
    for mw in extra_middleware:
        if not isinstance(mw, AgentMiddleware):
            raise TypeError(...)

if middleware is not None:
    effective_middleware = list(middleware)          # 完全接管,原样使用
else:
    feat = features or RuntimeFeatures()             # 默认特性集
    effective_middleware, extra_tools = _assemble_from_features(feat, ...)

解读:middlewarefeatures/extra_middleware 三者两两互斥。给定 middleware 时跳过一切自动装配;否则用 features(缺省退化为默认 RuntimeFeatures())逐项构建。

_assemble_from_features 内对每个特性的三态处理统一遵循「AgentMiddleware 实例直接用 / 否则建内置默认」的模式,而 summarizationguardrail 因缺内置默认会显式报错 factory.py:218-223:

python
if feat.summarization is not False:
    if isinstance(feat.summarization, AgentMiddleware):
        chain.append(feat.summarization)
    else:
        raise ValueError("summarization=True requires a custom AgentMiddleware instance ...")

链尾不变量:ClarificationMiddleware 必须在最后。_insert_extra@Next 可能把它顶离链尾,因此插入后会强制把它挪回末位 factory.py:289-298make_lead_agent 侧同样把 ClarificationMiddleware() 作为最后一个 append agent.py:316-318

make_lead_agent 的中间件链分两段:build_lead_runtime_middlewares 提供共享基座(ThreadData → Sandbox → Uploads → DanglingToolCall → LLMError → Guardrail → SandboxAudit → ToolError)tool_error_handling_middleware.py:82-136,_build_middlewares 在其后顺序追加 lead 专属中间件并以 ClarificationMiddleware 收尾 agent.py:258-318。中间件清单细节见第 12 章。

扩展指南

create_deerflow_agent + RuntimeFeatures 构建自定义 agent 的最小模板:

python
from deerflow.agents import create_deerflow_agent, RuntimeFeatures
from deerflow.models import create_chat_model

model = create_chat_model(name="my-model", thinking_enabled=False)

agent = create_deerflow_agent(
    model=model,
    tools=[my_tool],                       # 用户工具,feature 注入工具会去重追加
    system_prompt="You are a helper.",     # None 则用最小默认
    features=RuntimeFeatures(
        sandbox=True,                      # 默认 True
        memory=True,                       # True=用内置 MemoryMiddleware
        loop_detection=True,               # 默认 True
        vision=False,
        subagent=False,
    ),
    plan_mode=False,                       # True 则插入 TodoMiddleware
    name="my-agent",
)

约束清单(从 create_deerflow_agent / _assemble_from_features 校验逻辑读出):

  1. middlewarefeatures 互斥;同时传 → ValueError factory.py:110-111
  2. middlewareextra_middleware 互斥(middleware 即完全接管)→ ValueError factory.py:112-113
  3. extra_middleware 每项必须是 AgentMiddleware 实例,否则 TypeError factory.py:114-117
  4. features.summarization=True / features.guardrail=True 不被支持,必须传自定义 AgentMiddleware 实例或保持 FalseValueError factory.py:209-223
  5. 同一中间件不能同时带 @Next@Prev;两个 extra 锚到同一 anchor(同向或反向)会冲突报错 factory.py:322-342
  6. 锚点无法解析或 extra 之间循环依赖 → ValueError factory.py:371-378
  7. vision 开启且 sandbox 不为 False 时,会自动追加 view_image_tool;subagent 开启会追加 task_tool;ClarificationMiddleware 总会追加 ask_clarification_tool factory.py:249-287

Common Pitfalls / Tips

  • 不要在 create_deerflow_agent 里既传 middleware 又传 features:middleware 是完全接管语义,会直接报错而非合并。需要在自动链上加东西时用 extra_middleware + @Next/@Prev
  • summarization/guardrail 没有内置默认:在 SDK 工厂里要这两个能力必须自己构造中间件实例传入;make_lead_agent 侧的 summarization 由 _create_summarization_middleware 从配置创建 agent.py:53-112,guardrail 由 _build_runtime_middlewaresapp_config.guardrails 创建 tool_error_handling_middleware.py:99-120
  • thinking_enabled 默认 True 但会被模型能力降级:若 model_config.supports_thinking 为假,_make_lead_agent 会打 warning 并把 thinking_enabledFalse agent.py:379-381
  • make_lead_agent 签名固定:它是 LangGraph Server 注册的图工厂,改签名会破坏 langgraph.json 注册 agent.py:343-344
  • 系统提示词要保持静态:别把 per-turn 变化的内容塞进 apply_prompt_template,会破坏前缀缓存;动态内容走 DynamicContextMiddleware prompt.py:809-812

References

页面关系
09-Harness与App分层边界.md上游:解释 harness/app 分层,本章工厂位于 harness 一侧
11-ThreadState与状态管理.md下游:两层工厂均以 state_schema=ThreadStatecreate_agent,状态结构详见此页
12-中间件链机制.md下游:本章只讲装配骨架,18 个中间件清单与顺序细节见此页
05-模型配置与Model工厂.md关联:_resolve_model_name + create_chat_model 的模型解析与构造细节
20-工具系统与内置工具.md关联:get_available_tools 如何聚合 sandbox/built-in/MCP/subagent 工具

公司内部参考 · 由 claude-wiki-gen 基于源码自动生成的二次分析