自定义与扩展
DeerFlow
设计为可适配的。你可以通过编写自定义中间件、添加新工具、构建技能包以及通过
config.yaml 的 use: 字段替换任何内置组件来扩展 Agent 行为。
DeerFlow 的可插拔架构意味着系统的大多数部分都可以在不 fork 核心的情况下被替换或扩展。本页面列举了扩展点,并解释如何使用每一个。
自定义中间件
中间件是为 Lead Agent 添加行为的主要扩展点。它们包裹每次 LLM 调用,可以在模型调用前后读取和修改 Agent 的状态。
添加自定义中间件:
- 实现
langchain.agents.middleware中的AgentMiddleware接口。 - 在
extensions.middlewares下注册它的导入路径,或通过嵌入式 SDK API 传入实例。
from langchain.agents import AgentState
from langchain.agents.middleware import AgentMiddleware
from langgraph.runtime import Runtime
class AuditMiddleware(AgentMiddleware[AgentState]):
def before_model(self, state: AgentState, runtime: Runtime) -> dict | None:
print(f"[审计] 模型输入包含 {len(state.get('messages', []))} 条消息")
return None
def after_model(self, state: AgentState, runtime: Runtime) -> dict | None:
messages = state.get("messages", [])
last_message = messages[-1] if messages else None
print(f"[审计] 最后一条消息类型:{type(last_message).__name__ if last_message else 'none'}")
return None生命周期钩子可以返回状态更新字典,LangChain 会将其合并到 Agent 状态中;仅观察时返回 None。
对于运维配置的部署,该类必须提供零参数构造函数,并且 Gateway 进程必须能够导入它:
extensions:
middlewares:
- my_company.deerflow_middlewares:AuditMiddleware配置的中间件会在内置中间件及可选的循环/token 保护之后加载。对于主 Agent 链,它位于终态响应、模型长度、安全和澄清尾部之前;子 Agent 链没有终态响应、模型长度或澄清阶段,因此配置中间件之后会继续执行可选的安全防护、DurableContextMiddleware、可选的 SummarizationMiddleware,随后是 SubagentDateContextMiddleware 和 SystemMessageCoalescingMiddleware。中间件路径会执行 Python 代码,因此应视为可信配置。嵌入式调用方也可以使用 DeerFlowClient(middlewares=[AuditMiddleware()]);它构建完整的主 Agent 链,并将中间件放在其终态响应、模型长度、安全和澄清尾部之前。create_deerflow_agent(extra_middleware=[AuditMiddleware()]) 则构建较小的按功能组装的主 Agent 链;未锚定的额外中间件会紧接在 ClarificationMiddleware 之前放置(锚定中间件遵循其 @Next/@Prev 位置)。两个 API 均不会将中间件转发给子 Agent。
应根据配置的所有者和插入位置选择注册方式。固定槽位(并未弃用)extensions.middlewares 可写在 config.yaml 或 extensions_config.json 中(前者优先),并同时作用于主 Agent 和子 Agent。通过顶层 plugins: 注册的打包扩展可在语义化扩展点贡献中间件。若贡献代码需要可提交、可编程且仅作用于主 Agent 的接线,请使用 build_middlewares(..., custom_middlewares=[AuditMiddleware()])。
对于 create_deerflow_agent,@Next 或 @Prev 锚点必须指向这个较小链中实际存在的中间件;否则使用完整中间件列表中的锚点会解析失败。
自定义工具
在 config.yaml 的 tools: 下注册新工具,将其添加到 Agent:
tools:
- use: mypackage.tools:my_custom_tool
api_key: $MY_TOOL_API_KEY你的工具必须是 LangChain BaseTool 或用 @tool 装饰的函数。它将使用 use: 类路径和配置条目中的任何额外字段实例化。
# mypackage/tools.py
from langchain_core.tools import tool
@tool
def my_custom_tool(query: str) -> str:
"""搜索我的自定义数据源。"""
return do_search(query)自定义沙箱提供者
沙箱可以通过实现 SandboxProvider 接口来替换:
from deerflow.sandbox.sandbox_provider import SandboxProvider
class MyCustomSandboxProvider(SandboxProvider):
def acquire(self, thread_id: str | None = None) -> str:
# 返回 sandbox_id
...
def get(self, sandbox_id: str):
# 返回此 id 的沙箱实例
...
def release(self, sandbox_id: str) -> None:
# 清理
...然后在 config.yaml 中引用:
sandbox:
use: mypackage.sandbox:MyCustomSandboxProvider自定义记忆存储
通过实现 MemoryStorage 将基于文件的记忆替换为任何持久化存储:
from deerflow.agents.memory.storage import MemoryStorage
from typing import Any
class RedisMemoryStorage(MemoryStorage):
def load(self, agent_name: str | None = None) -> dict[str, Any]:
...
def reload(self, agent_name: str | None = None) -> dict[str, Any]:
...
def save(self, memory_data: dict[str, Any], agent_name: str | None = None) -> bool:
...在 config.yaml 中配置:
memory:
storage_class: mypackage.storage:RedisMemoryStorage自定义技能
技能是最简单的扩展点。在 skills/custom/your-skill-name/ 下创建一个目录,并在其中添加 SKILL.md 文件。技能将在下次 load_skills() 调用时自动被发现。
参见技能页面了解完整的目录结构和 SKILL.md 格式。
自定义模型
任何与 LangChain 兼容的聊天模型都可以通过在 use: 字段中指定来使用:
models:
- name: my-custom-model
use: mypackage.models:MyCustomChatModel
# 任何额外字段都作为 kwargs 传递给构造函数
base_url: http://my-model-server:8080
api_key: $MY_MODEL_API_KEY模型类必须实现 LangChain 的 BaseChatModel 接口。
自定义检查点
线程状态持久化可以使用任何与 LangGraph 兼容的检查点器:
checkpointer:
type: sqlite
connection_string: ./my-checkpoints.db对于自定义后端,实现 LangGraph 的 BaseCheckpointSaver 接口,并在初始化 DeerFlowClient 时以编程方式配置它。