deer-flow/backend/README_zh.md
luo jiyin 3820515155
fix(test): exclude blocking I/O suite from make test (#5105)
* fix(test): exclude blocking I/O suite from make test

Keep make test-blocking-io as the dedicated suite owner.

Add regression coverage for the Makefile contract.

Refs #5088

* test: pin blocking I/O workflow ownership

Document both targets required for full offline validation.

Keep the dedicated workflow and Makefile target under contract coverage.

Refs #5088

* docs(test): align blocking-I/O test guidance
2026-08-30 22:05:24 +08:00

24 KiB
Raw Permalink Blame History

DeerFlow 后端

语言: English | 简体中文

DeerFlow 是一个基于 LangGraph 的 AI 超级智能体,具备沙箱执行、持久记忆和可扩展工具集成能力。后端使 AI 智能体能够执行代码、浏览网页、管理文件、将任务委派给子智能体,并在多轮对话之间保留上下文——所有操作都在按线程隔离的环境中进行。


架构

                        ┌──────────────────────────────────────┐
                        │          Nginx端口 2026          │
                        │             统一反向代理             │
                        └───────┬──────────────────┬───────────┘
                                │
            /api/langgraph/*    │    /api/*(其他)
              重写为 /api/*     │
                                ▼
               ┌────────────────────────────────────────┐
               │          Gateway API8001           │
               │      FastAPI REST + 智能体运行时       │
               │                                        │
               │ 模型、MCP、技能、记忆、上传、          │
               │ 产物、线程、运行、流式传输             │
               │                                        │
               │ ┌────────────────────────────────────┐ │
               │ │ 主智能体                           │ │
               │ │ 中间件链、工具、子智能体           │ │
               │ └────────────────────────────────────┘ │
               └────────────────────────────────────────┘

请求路由(通过 Nginx

  • /api/langgraph/* → 与 LangGraph 兼容的 Gateway API——智能体交互、线程和流式传输
  • /api/*(其他)→ Gateway API——模型、MCP、技能、记忆、产物、上传和线程本地数据清理
  • /(非 API→ 前端——Next.js Web 界面

核心组件

主智能体

唯一的 LangGraph 智能体(lead_agent)是运行时入口,通过 make_lead_agent(config) 创建。它组合了:

  • 支持思考和视觉能力的动态模型选择
  • 处理横切关注点的中间件链9 个中间件)
  • 包含沙箱、MCP、社区工具和内置工具的工具系统
  • 用于并行执行任务的子智能体委派
  • 注入技能、记忆上下文和工作目录指导的系统提示词

中间件链

中间件按照严格顺序执行,每个中间件负责一个特定关注点:

# 中间件 用途
1 ThreadDataMiddleware 为每个线程创建独立目录(工作区、上传、输出)
2 UploadsMiddleware 将新上传的文件注入对话上下文
3 SandboxMiddleware 获取用于代码执行的沙箱环境
4 SummarizationMiddleware 接近 Token 限制时压缩上下文(可选)
5 TodoListMiddleware 在计划模式中跟踪多步骤任务(可选)
6 TitleMiddleware 在第一次交互后自动生成对话标题
7 MemoryMiddleware 将对话加入异步记忆提取队列
8 ViewImageMiddleware 为支持视觉的模型注入图像数据(有条件启用)
9 ClarificationMiddleware 拦截澄清请求并中断执行(必须放在最后)

沙箱系统

按线程隔离执行,并提供虚拟路径转换:

  • 抽象接口execute_commandread_filewrite_filelist_dir
  • 提供程序LocalSandboxProvider(文件系统)和 AioSandboxProviderDocker位于 community/)。异步运行时路径使用异步沙箱生命周期钩子,使启动、就绪轮询和释放操作不会阻塞事件循环。AioSandboxProvider 会在获取或复用期间验证活跃缓存和预热池中的容器,移除已确定失效的条目,使线程能够在容器意外退出后创建新沙箱,同时让 get() 保持为内存查询。后端健康检查失败会被视为状态未知,而不是容器已失效;在发现过程中无法验证的容器不会被采用,获取流程会继续创建容器,而不是直接失败。
  • 虚拟路径/mnt/user-data/{workspace,uploads,outputs} → 线程专属的物理目录
  • 技能路径/mnt/skillsdeer-flow/skills/ 目录
  • 技能加载:递归发现 skills/{public,custom} 下嵌套的 SKILL.md 文件,并保留其嵌套容器路径
  • SkillScan:安装技能或由智能体写入技能时,原生离线确定性扫描会先于 LLM 技能扫描器执行;CRITICAL 级别的问题会阻止操作,警告则会成为 LLM 上下文
  • 文件写入安全str_replace 按照 (sandbox.id, path) 对“读取—修改—写入”操作进行串行化,因此即使虚拟路径相同,彼此隔离的沙箱仍能保持并发
  • 工具bashlsread_filewrite_filestr_replacewrite_file 默认覆盖文件,并提供 append 以在文件末尾追加内容;使用 LocalSandboxProvider 时,bash 默认禁用;如需隔离的 Shell 访问,请使用 AioSandboxProvider

子智能体系统

支持并发执行的异步任务委派:

  • 内置智能体general-purpose(完整工具集)和 bash(命令专家,仅在 Shell 访问可用时提供)
  • 并发限制:每轮最多 3 个子智能体,超时时间为 15 分钟
  • 执行方式:后台线程池,并提供状态跟踪和 SSE 事件
  • 流程:智能体调用 task() 工具 → 执行器在后台运行子智能体 → 轮询完成状态 → 返回结果

记忆系统

由 LLM 驱动、可跨对话保留上下文的持久记忆:

  • 自动提取:分析对话中的用户上下文、事实和偏好
  • 作用域安全写入:中间件提取过程只存储持久且具有描述性的用户级事实;全局摘要同样需要描述权限。当缺少作用域元数据,或者内容仅限于某个任务或项目时,矛盾移除和事实合并将采用失败关闭策略
  • 原子替换:与替换项关联的矛盾移除,只有在替换项通过作用域和置信度门控、去重及事实数量裁剪后才会执行
  • 结构化存储:用户上下文(工作、个人、当前关注事项)、历史记录以及带置信度评分的事实
  • 防抖更新:批量处理更新以减少 LLM 调用次数(等待时间可配置)
  • 系统提示词注入:将最重要的事实和上下文注入智能体提示词
  • 运行级记忆标识GET /api/threads/{thread_id}/runs/{run_id}/events?event_types=context:memory 返回实际隐藏记忆块的 SHA-256 标识,而不会把记忆文本复制进事件存储
  • 存储方式JSON 文件,并基于 mtime 实现缓存失效

工具生态系统

类别 工具
沙箱 bashlsread_filewrite_filestr_replace
内置 present_filesask_clarificationview_imagetask(子智能体)
社区 Tavily网页搜索、Jina AI网页获取、Crawl4AI网页获取、Firecrawl网页抓取、fastCRW网页抓取、DuckDuckGo图片搜索
MCP 任意 Model Context Protocol 服务器stdio、SSE、HTTP 传输)
技能 通过系统提示词注入的领域专用工作流

Gateway API

FastAPI 应用程序,为前端集成提供 REST 接口:

路由 用途
GET /api/models 列出可用的 LLM 模型
GET/PUT /api/mcp/config 管理 MCP 服务器配置
POST /api/mcp/cache/reset 重置缓存的 MCP 工具,使其在下次使用时重新加载
GET/PUT /api/skills 列出并管理技能
POST /api/skills/install .skill 归档文件安装技能
GET /api/memory 获取记忆数据
POST /api/memory/reload 强制重新加载记忆
GET /api/memory/config 获取记忆配置
GET /api/memory/status 获取组合后的配置和数据状态
GET /api/threads/{id}/runs/{run_id}/events 获取某次运行的调试或审计事件;可使用 event_types=context:memory 筛选实际记忆标识
POST /api/threads/{id}/uploads 上传文件(自动将 PDF、PPT、Excel、Word 转换为 Markdown拒绝目录路径自动重命名单次请求中的重复文件名
GET /api/threads/{id}/uploads/list 列出已上传的文件
DELETE /api/threads/{id} 删除 LangGraph 线程后,清除由 DeerFlow 管理的本地线程数据;意外错误会记录在服务端,并返回通用的 500 错误信息
GET /api/threads/{id}/artifacts/{path} 提供生成产物的访问

即时通信渠道

即时通信桥接支持飞书、Slack 和 Telegram。Slack 和 Telegram 仍然使用最终的 runs.wait() 响应路径;飞书现在通过 runs.stream(["messages-tuple", "values"]) 进行流式传输,在渠道管理器内部对同一线程中快速连续到达的请求进行串行化,并针对每条源消息原地更新线程内的同一张卡片。

对于飞书卡片更新DeerFlow 会按每条入站消息保存运行中卡片的 message_id,并持续更新同一张卡片直到运行结束,同时保留现有的 OK / DONE 表情回应流程。当现有飞书话题中的上一轮仍在运行时收到后续消息,新消息会在映射的 DeerFlow thread_id 上等待,在对应的源消息上显示排队中或运行中的卡片,并在后续更新中保留简洁的源消息引用块,使快速连续提出的问题仍然容易区分。


快速开始

前置条件

  • Python 3.12+
  • uv 包管理器
  • 所选 LLM 提供商的 API 密钥

安装

cd deer-flow

# 复制配置文件
cp config.example.yaml config.yaml

# 安装后端依赖
cd backend
make install

配置

编辑项目根目录中的 config.yaml

models:
  - name: gpt-4o
    display_name: GPT-4o
    use: langchain_openai:ChatOpenAI
    model: gpt-4o
    api_key: $OPENAI_API_KEY
    supports_thinking: false
    supports_vision: true

  - name: gpt-5-responses
    display_name: GPT-5 (Responses API)
    use: langchain_openai:ChatOpenAI
    model: gpt-5
    api_key: $OPENAI_API_KEY
    use_responses_api: true
    output_version: responses/v1
    supports_vision: true

设置 API 密钥:

export OPENAI_API_KEY="your-api-key-here"

运行

完整应用程序(从项目根目录运行):

make dev  # 启动 Gateway、Frontend 和 Nginx

访问地址:http://localhost:2026

仅运行后端(从 backend 目录运行):

# Gateway API + 嵌入式智能体运行时
make dev

直接访问Gateway 位于 http://localhost:8001

终端工作台TUI——基于嵌入式 Harness 的终端原生界面, 无需运行任何服务:

uv pip install 'deerflow-harness[tui]'   # 可选的 textual 依赖
deerflow                                 # 启动 TUI
deerflow --print "summarize this repo"   # 无界面的单次运行
deerflow --recursion-limit 250 --print "run a longer task"

在 TUI 中打开的会话会出现在 Web UI 侧边栏中(它会在本地默认用户下写入共享的 threads_meta 存储)。详见 docs/TUI.md


项目结构

backend/
├── packages/harness/           # deerflow-harness 包导入路径deerflow.*
│   └── deerflow/
│       ├── agents/             # 智能体系统
│       │   ├── lead_agent/     # 主智能体(工厂、提示词)
│       │   ├── middlewares/    # 中间件组件
│       │   ├── memory/         # 记忆提取与存储
│       │   └── thread_state.py # ThreadState 数据结构
│       ├── sandbox/            # 沙箱执行
│       │   ├── local/          # 本地文件系统提供程序
│       │   ├── sandbox.py      # 抽象接口
│       │   ├── tools.py        # bash、ls、read/write/str_replace
│       │   └── middleware.py   # 沙箱生命周期
│       ├── subagents/          # 子智能体委派
│       │   ├── builtins/       # general-purpose、bash 智能体
│       │   ├── executor.py     # 后台执行引擎
│       │   └── registry.py     # 智能体注册表
│       ├── tools/builtins/     # 内置工具
│       ├── mcp/                # MCP 协议集成
│       ├── models/             # 模型工厂
│       ├── skills/             # 技能发现与加载
│       ├── config/             # 配置系统
│       ├── runtime/            # 嵌入式运行执行RunManager、StreamBridge
│       ├── persistence/        # Checkpointer/Store 引擎和数据库结构迁移
│       ├── guardrails/         # 工具调用前的授权提供程序
│       ├── tracing/            # Tracer 工厂和追踪元数据
│       ├── uploads/            # 上传管理器
│       ├── tui/                # 终端 UI`deerflow` 控制台脚本)
│       ├── community/          # 社区工具和提供程序
│       ├── reflection/         # 动态模块加载
│       └── utils/              # 工具函数
├── app/                        # FastAPI Gateway + 即时通信渠道导入路径app.*
│   ├── gateway/                # Gateway API
│   │   ├── app.py              # 应用程序配置
│   │   └── routers/            # 路由模块
│   └── channels/               # 即时通信渠道集成
├── docs/                       # 文档
├── tests/                      # 测试套件
├── langgraph.json              # 用于工具和 Studio 兼容性的 LangGraph 图注册表
├── pyproject.toml              # Python 依赖
├── Makefile                    # 开发命令
└── Dockerfile                  # 容器构建文件

langgraph.json 并不是默认的服务入口。脚本和 Docker 部署使用 Gateway 嵌入式运行时;保留该文件是为了兼容 LangGraph 工具、Studio 或直接运行 LangGraph Server。


配置

主配置(config.yaml

将其放置在项目根目录。以 $ 开头的配置值会被解析为环境变量。

主要配置节:

  • models——包含类路径、API 密钥、思考和视觉标志的 LLM 配置
  • tools——包含模块路径和分组的工具定义
  • tool_groups——工具的逻辑分组
  • sandbox——执行环境提供程序
  • skills——技能目录路径
  • title——自动生成标题的设置
  • summarization——上下文摘要设置
  • subagents——子智能体系统(启用或禁用)
  • memory——记忆系统设置(启用状态、存储方式、防抖和事实数量限制)

提供商说明:

  • models[*].use 通过模块路径引用提供商类,例如 langchain_openai:ChatOpenAI
  • 如果缺少某个提供商模块DeerFlow 会返回包含安装指导的可操作错误信息,例如 uv add langchain-google-genai

扩展配置(extensions_config.json

在同一个文件中配置 MCP 服务器和技能状态:

{
  "mcpServers": {
    "github": {
      "enabled": true,
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {"GITHUB_TOKEN": "$GITHUB_TOKEN"}
    },
    "secure-http": {
      "enabled": true,
      "type": "http",
      "url": "https://api.example.com/mcp",
      "oauth": {
        "enabled": true,
        "token_url": "https://auth.example.com/oauth/token",
        "grant_type": "client_credentials",
        "client_id": "$MCP_OAUTH_CLIENT_ID",
        "client_secret": "$MCP_OAUTH_CLIENT_SECRET"
      }
    },
    "postgres": {
      "enabled": false,
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres", "postgresql://localhost/mydb"],
      "description": "PostgreSQL database access",
      "routing": {
        "mode": "prefer",
        "priority": 50,
        "keywords": ["orders", "users", "SQL", "database", "table"]
      },
      "tools": {
        "query": {
          "routing": {
            "priority": 100,
            "keywords": ["query database", "orders table", "metrics"]
          }
        }
      }
    }
  },
  "skills": {
    "pdf-processing": {"enabled": true}
  }
}

routing 会向智能体提示词添加柔性的 MCP 偏好提示。它能帮助模型在处理匹配的请求时优先选择配置的 MCP 工具,同时不会禁止其他工具。当 tool_search.enabled=true 延迟加载 MCP Schema 时,匹配的路由元数据可以在模型调用前自动提升最多 tool_search.auto_promote_top_k 个延迟 Schema。

环境变量

  • DEER_FLOW_CONFIG_PATH——覆盖 config.yaml 的位置
  • DEER_FLOW_EXTENSIONS_CONFIG_PATH——覆盖 extensions_config.json 的位置
  • 模型 API 密钥:OPENAI_API_KEYANTHROPIC_API_KEYDEEPSEEK_API_KEY
  • 工具 API 密钥:TAVILY_API_KEYGITHUB_TOKEN

LangSmith 追踪

DeerFlow 内置了 LangSmith 可观测性集成。启用后,所有 LLM 调用、智能体运行、工具执行和中间件处理过程都会被追踪,并可在 LangSmith 控制台中查看。

配置步骤:

  1. smith.langchain.com 注册并创建一个项目。
  2. 将以下内容添加到项目根目录的 .env 文件:
LANGSMITH_TRACING=true
LANGSMITH_ENDPOINT=https://api.smith.langchain.com
LANGSMITH_API_KEY=lsv2_pt_xxxxxxxxxxxxxxxx
LANGSMITH_PROJECT=xxx

**旧版变量:**为了向后兼容,仍然支持 LANGCHAIN_TRACING_V2LANGCHAIN_API_KEYLANGCHAIN_PROJECTLANGCHAIN_ENDPOINT。当两组变量同时设置时,优先使用 LANGSMITH_* 变量。

Langfuse 追踪

DeerFlow 同样支持使用 Langfuse 观察与 LangChain 兼容的运行过程。

将以下内容添加到 .env 文件:

LANGFUSE_TRACING=true
LANGFUSE_PUBLIC_KEY=pk-lf-xxxxxxxxxxxxxxxx
LANGFUSE_SECRET_KEY=sk-lf-xxxxxxxxxxxxxxxx
LANGFUSE_BASE_URL=https://cloud.langfuse.com

如果使用自托管的 Langfuse 部署,请将 LANGFUSE_BASE_URL 设置为你的 Langfuse 主机地址。

同时使用两个提供商时的行为

如果同时启用了 LangSmith 和 LangfuseDeerFlow 会初始化并附加两者的回调,使相同的运行数据同时上报给两个系统。

如果明确启用了某个提供商但缺少必要凭据或者无法初始化该提供商的回调DeerFlow 会在模型创建期间初始化追踪时抛出错误,而不是静默禁用追踪。

**Docker**在 docker-compose.yaml 中,追踪默认处于禁用状态(LANGSMITH_TRACING=false)。如需在容器化部署中启用追踪,请在 .env 中设置 LANGSMITH_TRACING=true 和/或 LANGFUSE_TRACING=true,并同时提供所需凭据。


开发

命令

make install    # 安装依赖
make dev        # 运行 Gateway API 和嵌入式智能体运行时(端口 8001
make gateway    # 运行不带热重载的 Gateway API端口 8001
make lint       # 运行代码检查器ruff
make format     # 格式化代码ruff
make detect-blocking-io  # 统计可能阻塞后端事件循环的阻塞式 IO
make migrate-rev MSG="..."  # 根据当前 ORM 模型自动生成新的 Alembic 修订

数据库结构迁移

DeerFlow 的应用程序表(runsthreads_metafeedbackusersrun_eventschannel_* 表)由 Alembic 管理。Gateway 启动时会通过 bootstrap_schema(engine, backend=...) 自动运行 alembic upgrade head,因此运维人员不需要在生产环境中手动运行 alembic。初始化过程支持并发安全(跨进程使用 PostgreSQL advisory lock单个 SQLite 进程内按引擎使用 asyncio.Lock),并能针对已有数据库结构(空数据库、旧版数据库或已带版本的数据库)保持幂等。

添加或修改 ORM 模型时,请在 packages/harness/deerflow/persistence/migrations/versions/ 下提交新的迁移版本:

make migrate-rev MSG="add foo column to runs"

该目标会调用 scripts/_autogen_revision.py。脚本先在一个新的临时 SQLite 数据库上迁移到 head,然后将当前模型与其进行比较,因此全新检出的代码不需要预先存在的 ./data/deerflow.db。提交前请检查生成的文件,并将原始的 op.add_column / op.drop_column 调用替换为 migrations/_helpers.py 中的幂等辅助函数。项目有意不提供 make migrate / make migrate-stamp 目标——Gateway 启动是唯一的迁移执行路径,从而避免运维误操作。完整设计请参阅 backend/CLAUDE.md 中的“Schema Migrations”部分。

代码风格

  • 代码检查器/格式化工具ruff
  • 行长度240 个字符
  • Python3.12+,使用类型提示
  • 引号:双引号
  • 缩进4 个空格

测试

# 默认离线后端测试套件(排除调用外部真实 API 和阻塞式 I/O 的测试)
make test

# 严格的阻塞式 I/O 测试套件
make test-blocking-io

# 显式运行使用真实 API 的 DeerFlowClient 集成测试套件
make test-live

实时测试套件需要有效的根目录 config.yaml 和 API 凭据。它可能产生 API 费用,或创建本地沙箱、产物和文件,因此不属于默认测试流程或 CI。直接通过 pytest 运行 tests/test_client_live.py 时,也需要设置 DEER_FLOW_RUN_LIVE_TESTS=1

make detect-blocking-io 会静态扫描后端业务代码,寻找可能在后端事件循环上运行且不受测试覆盖范围限制的阻塞式 IO。它会输出便于人工审查的简明摘要并把完整的 JSON 结果写入仓库根目录的 .deer-flow/blocking-io-findings.json,无论该目标是在仓库根目录还是 backend/ 目录中调用。JSON 结果同时包含宽泛的 IO 分类和面向审查的字段,例如 prioritylocationblocking_callevent_loop_exposurereasoncodepriority 只是根据操作类型生成的确定性审查顺序,并不能证明存在缺陷。对于同一文件中通过裸名称调用的函数,扫描器按函数名解析,因此当一个文件中存在同名辅助函数时,可能会保守地高估异步可达性。


技术栈

  • LangGraph1.0.6+)——智能体框架和多智能体编排
  • LangChain1.2.3+——LLM 抽象和工具系统
  • FastAPI0.115.0+——Gateway REST API
  • langchain-mcp-adapters——Model Context Protocol 支持
  • agent-sandbox——沙箱化代码执行
  • markitdown——多格式文档转换
  • tavily-python / firecrawl-py——网页搜索和抓取

文档


许可证

请参阅项目根目录中的 LICENSE 文件。

参与贡献

贡献指南请参阅 CONTRIBUTING.md