826 lines
26 KiB
Markdown
826 lines
26 KiB
Markdown
# DeerFlow 后端开发文档
|
||
|
||
> 本文档面向开发人员,梳理后端项目结构、核心模块、API 接口、配置系统和常用开发命令,方便快速上手和维护。
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
1. [项目概述](#1-项目概述)
|
||
2. [技术栈](#2-技术栈)
|
||
3. [目录结构](#3-目录结构)
|
||
4. [架构分层](#4-架构分层)
|
||
5. [快速启动](#5-快速启动)
|
||
6. [配置系统](#6-配置系统)
|
||
7. [核心模块详解](#7-核心模块详解)
|
||
8. [API 接口汇总](#8-api-接口汇总)
|
||
9. [Agent 系统](#9-agent-系统)
|
||
10. [中间件链](#10-中间件链)
|
||
11. [沙箱执行系统](#11-沙箱执行系统)
|
||
12. [内存系统](#12-内存系统)
|
||
13. [工具系统](#13-工具系统)
|
||
14. [IM 频道集成](#14-im-频道集成)
|
||
15. [数据持久化](#15-数据持久化)
|
||
16. [测试](#16-测试)
|
||
17. [常见问题与排错](#17-常见问题与排错)
|
||
|
||
---
|
||
|
||
## 1. 项目概述
|
||
|
||
DeerFlow 是一个基于 **LangGraph** 的 AI 超级 Agent 系统。后端提供:
|
||
|
||
- **Lead Agent**:具备沙箱执行、持久内存、子 Agent 委托和可扩展工具集成的主 Agent
|
||
- **Gateway API**:FastAPI REST API(端口 8001),同时内嵌 LangGraph 兼容的 Agent 运行时
|
||
- **IM 频道集成**:飞书、Slack、Telegram、钉钉、Discord、微信、企业微信
|
||
- **每线程隔离**:沙箱和工作目录按 `用户 / 线程` 两级隔离
|
||
|
||
整体入口(通过 Nginx,端口 2026):
|
||
- `/api/langgraph/*` → 内嵌 LangGraph 运行时(转发到 Gateway `/api/*`)
|
||
- `/api/*` → Gateway REST API(8001)
|
||
- `/` → 前端(3000)
|
||
|
||
---
|
||
|
||
## 2. 技术栈
|
||
|
||
| 层次 | 技术 |
|
||
|------|------|
|
||
| Web 框架 | FastAPI + Uvicorn |
|
||
| Agent 框架 | LangGraph(状态图 + 检查点) |
|
||
| LLM 调用 | LangChain(多模型适配) |
|
||
| 数据库 | SQLite(默认)/ PostgreSQL |
|
||
| ORM | SQLAlchemy + Alembic(迁移) |
|
||
| 包管理 | uv(workspace 模式) |
|
||
| 测试 | pytest |
|
||
| 代码规范 | ruff(检查 + 格式化) |
|
||
| Python 版本 | 3.12+ |
|
||
|
||
---
|
||
|
||
## 3. 目录结构
|
||
|
||
```
|
||
backend/
|
||
├── Makefile # 开发命令入口
|
||
├── pyproject.toml # 项目配置和依赖
|
||
├── config.yaml # 主配置文件(模型、沙箱、工具等)
|
||
├── langgraph.json # LangGraph Studio 图配置
|
||
├── ruff.toml # 代码风格配置(行长 240)
|
||
│
|
||
├── app/ # 应用层(FastAPI + IM 集成)
|
||
│ ├── gateway/ # FastAPI 网关 API
|
||
│ │ ├── app.py # 应用主入口,创建 FastAPI 实例,挂载所有路由
|
||
│ │ ├── auth/ # JWT 身份认证模块
|
||
│ │ ├── routers/ # 16 个 API 路由模块
|
||
│ │ ├── auth_middleware.py # 认证中间件
|
||
│ │ ├── csrf_middleware.py # CSRF 保护中间件
|
||
│ │ └── deps.py # FastAPI 依赖注入
|
||
│ └── channels/ # IM 平台集成
|
||
│ ├── manager.py # 频道管理器(核心调度)
|
||
│ ├── message_bus.py # 消息总线(pub/sub)
|
||
│ ├── store.py # 线程持久化(chat → thread_id 映射)
|
||
│ ├── feishu.py # 飞书集成
|
||
│ ├── slack.py # Slack 集成
|
||
│ ├── telegram.py # Telegram 集成
|
||
│ ├── dingtalk.py # 钉钉集成
|
||
│ ├── discord.py # Discord 集成
|
||
│ ├── wechat.py # 微信集成
|
||
│ └── wecom.py # 企业微信集成
|
||
│
|
||
├── packages/harness/ # deerflow-harness 核心包(可独立发布)
|
||
│ └── deerflow/ # 导入前缀:deerflow.*
|
||
│ ├── agents/ # Agent 系统
|
||
│ │ ├── lead_agent/ # 主 Agent(工厂 + 提示词)
|
||
│ │ ├── middlewares/ # 18 个中间件
|
||
│ │ ├── memory/ # 内存提取、队列、存储
|
||
│ │ └── thread_state.py # ThreadState 数据模型
|
||
│ ├── config/ # 配置系统(25 个模块)
|
||
│ ├── sandbox/ # 沙箱执行(本地 + Docker)
|
||
│ ├── tools/ # 工具工厂 + 内置工具
|
||
│ ├── subagents/ # 子 Agent 委托系统
|
||
│ ├── mcp/ # Model Context Protocol 集成
|
||
│ ├── models/ # LLM 模型工厂
|
||
│ ├── skills/ # 技能发现和加载
|
||
│ ├── runtime/ # 运行时管理(检查点、流、调度)
|
||
│ ├── persistence/ # 数据库 ORM 和迁移
|
||
│ ├── community/ # 社区工具(Tavily、Jina、Firecrawl 等)
|
||
│ ├── guardrails/ # 护栏系统(工具调用授权)
|
||
│ ├── reflection/ # 动态模块加载
|
||
│ ├── uploads/ # 文件上传和文档转换
|
||
│ ├── utils/ # 网络、可读性等工具函数
|
||
│ └── client.py # 嵌入式 Python 客户端(无需 HTTP)
|
||
│
|
||
├── tests/ # 测试套件
|
||
├── scripts/ # 辅助脚本
|
||
├── docs/ # 文档目录
|
||
└── skills/ # 技能目录
|
||
├── public/ # 公开技能(提交到 git)
|
||
└── custom/ # 自定义技能(git 忽略)
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 架构分层
|
||
|
||
### Harness / App 分层原则
|
||
|
||
后端严格分为两层,依赖方向单向:
|
||
|
||
```
|
||
app.* →(允许导入)→ deerflow.*
|
||
deerflow.* ×(禁止导入)× app.*
|
||
```
|
||
|
||
- **Harness**(`packages/harness/deerflow/`):可发布的 Agent 框架包,包含 Agent 编排、工具、沙箱、模型、MCP、技能、配置——一切构建和运行 Agent 所需的内容。
|
||
- **App**(`app/`):不对外发布的应用代码,包含 FastAPI Gateway API 和 IM 频道集成。
|
||
|
||
此边界通过 `tests/test_harness_boundary.py` 在 CI 中强制检查。
|
||
|
||
### 运行时数据流
|
||
|
||
```
|
||
前端 / IM 平台
|
||
↓
|
||
Nginx(2026)
|
||
↓
|
||
Gateway API(8001)— FastAPI
|
||
↓
|
||
RunManager + run_agent() + StreamBridge
|
||
↓
|
||
Lead Agent(LangGraph 状态图)
|
||
↓
|
||
[中间件链] → [LLM] → [工具调用] → [沙箱执行]
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 快速启动
|
||
|
||
### 环境要求
|
||
|
||
- Python 3.12+
|
||
- [uv](https://github.com/astral-sh/uv)(包管理器)
|
||
- 可选:Docker(用于容器化沙箱)
|
||
|
||
### 安装依赖
|
||
|
||
```bash
|
||
# 在 backend/ 目录下
|
||
make install
|
||
# 等价于:uv sync
|
||
```
|
||
|
||
### 启动开发服务器
|
||
|
||
```bash
|
||
# 方式一:仅启动后端 Gateway(带热重载,端口 8001)
|
||
make dev
|
||
|
||
# 方式二:启动完整应用(含前端和 Nginx)
|
||
# 在项目根目录执行
|
||
make dev
|
||
```
|
||
|
||
启动后访问:
|
||
- API 文档:`http://localhost:8001/docs`
|
||
- 健康检查:`http://localhost:8001/health`
|
||
|
||
### 停止服务
|
||
|
||
```bash
|
||
# 项目根目录
|
||
make stop
|
||
```
|
||
|
||
### 开发常用命令
|
||
|
||
```bash
|
||
make lint # ruff 代码检查
|
||
make format # ruff 自动格式化
|
||
make test # 运行全部测试
|
||
make gateway # 启动 Gateway(不带热重载)
|
||
|
||
# 运行特定测试文件
|
||
PYTHONPATH=. uv run pytest tests/test_memory_updater.py -v
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 配置系统
|
||
|
||
### 主配置文件 `config.yaml`
|
||
|
||
**查找顺序**(优先级从高到低):
|
||
1. 显式 `config_path` 参数
|
||
2. 环境变量 `DEER_FLOW_CONFIG_PATH`
|
||
3. `backend/config.yaml`
|
||
4. 项目根目录 `config.yaml`(**推荐放置位置**)
|
||
|
||
**关键配置段**:
|
||
|
||
```yaml
|
||
config_version: 1 # 配置版本,升级时自动提示
|
||
|
||
log_level: info
|
||
|
||
database:
|
||
backend: sqlite # 数据库后端(sqlite / postgres)
|
||
sqlite_dir: .deer-flow/data
|
||
|
||
sandbox:
|
||
use: deerflow.sandbox.local:LocalSandboxProvider # 沙箱提供者类路径
|
||
allow_host_bash: false
|
||
|
||
models: # LLM 模型配置列表
|
||
- name: my-model # 模型标识名
|
||
display_name: 我的模型
|
||
use: langchain_openai:ChatOpenAI # 提供者类(通过反射加载)
|
||
model: gpt-4o
|
||
api_key: $OPENAI_API_KEY # 以 $ 开头代表读取环境变量
|
||
base_url: https://api.openai.com/v1
|
||
supports_vision: true
|
||
supports_thinking: false
|
||
|
||
tools: # 工具配置
|
||
- use: deerflow.community.tavily:tavily_search
|
||
group: search
|
||
|
||
memory:
|
||
enabled: true
|
||
injection_enabled: true
|
||
debounce_seconds: 30
|
||
max_facts: 100
|
||
fact_confidence_threshold: 0.7
|
||
max_injection_tokens: 2000
|
||
|
||
subagents:
|
||
enabled: true # 是否启用子 Agent 委托
|
||
|
||
title:
|
||
enabled: true # 是否自动生成对话标题
|
||
```
|
||
|
||
### 扩展配置 `extensions_config.json`
|
||
|
||
MCP 服务器和技能的启用状态存放在此文件:
|
||
|
||
```json
|
||
{
|
||
"mcpServers": {
|
||
"my-mcp-server": {
|
||
"enabled": true,
|
||
"type": "stdio",
|
||
"command": "npx",
|
||
"args": ["-y", "@my/mcp-server"]
|
||
}
|
||
},
|
||
"skills": {
|
||
"my-skill": { "enabled": true }
|
||
}
|
||
}
|
||
```
|
||
|
||
**查找顺序**同 `config.yaml`,环境变量为 `DEER_FLOW_EXTENSIONS_CONFIG_PATH`。
|
||
|
||
### 环境变量
|
||
|
||
| 变量名 | 说明 |
|
||
|--------|------|
|
||
| `DEER_FLOW_CONFIG_PATH` | 指定 config.yaml 路径 |
|
||
| `DEER_FLOW_EXTENSIONS_CONFIG_PATH` | 指定 extensions_config.json 路径 |
|
||
| `GATEWAY_CORS_ORIGINS` | 允许的跨域来源(逗号分隔) |
|
||
| `GATEWAY_CORS_ALLOW_ALL` | 允许所有跨域(1/true) |
|
||
| `GATEWAY_ENABLE_DOCS` | 是否启用 `/docs` 页面(默认开启) |
|
||
| `AUTH_JWT_SECRET` | JWT 签名密钥 |
|
||
| `DEER_FLOW_AUTH_DISABLED` | 禁用认证(开发用) |
|
||
|
||
---
|
||
|
||
## 7. 核心模块详解
|
||
|
||
### 7.1 应用主入口 `app/gateway/app.py`
|
||
|
||
FastAPI 应用工厂,负责:
|
||
- 创建 FastAPI 实例,配置 CORS、认证、CSRF 中间件
|
||
- 挂载全部 16 个路由模块
|
||
- 通过 `lifespan` 管理启动/关闭钩子:初始化数据库、运行 Alembic 迁移、启动 IM 频道服务
|
||
- 首次启动时创建管理员用户
|
||
|
||
### 7.2 模型工厂 `deerflow/models/factory.py`
|
||
|
||
```python
|
||
from deerflow.models import create_chat_model
|
||
|
||
model = create_chat_model(name="my-model", thinking_enabled=False)
|
||
```
|
||
|
||
- 通过反射(`resolve_variable`)按 `config.yaml` 中的 `use` 字段实例化 LangChain 模型
|
||
- 支持 `thinking_enabled` 标志和按模型的 `when_thinking_enabled` 覆盖
|
||
- 支持 vLLM Qwen 推理模型的 `enable_thinking` 参数
|
||
- 配置值以 `$` 开头时自动解析为环境变量
|
||
- 缺少提供者模块时给出可操作的安装提示
|
||
|
||
### 7.3 嵌入式客户端 `deerflow/client.py`
|
||
|
||
无需启动 HTTP 服务即可直接调用所有 DeerFlow 能力:
|
||
|
||
```python
|
||
from deerflow.client import DeerFlowClient
|
||
|
||
client = DeerFlowClient()
|
||
|
||
# 同步对话
|
||
text = client.chat("你好", thread_id="thread-1")
|
||
|
||
# 流式对话
|
||
for event in client.stream("分析这份文档", thread_id="thread-1"):
|
||
print(event)
|
||
|
||
# 其他 API
|
||
client.list_models()
|
||
client.upload_files(thread_id, [Path("doc.pdf")])
|
||
client.get_memory()
|
||
```
|
||
|
||
返回格式与 Gateway REST API 一致,方便在两种模式下复用代码。
|
||
|
||
---
|
||
|
||
## 8. API 接口汇总
|
||
|
||
所有接口基础路径:`http://localhost:8001`(或通过 Nginx `http://localhost:2026`)
|
||
|
||
### 8.1 核心接口
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| GET | `/health` | 健康检查 |
|
||
| GET | `/docs` | Swagger API 文档 |
|
||
|
||
### 8.2 线程运行(主要对话接口)
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| POST | `/api/threads/{id}/runs/stream` | 创建运行并 SSE 流式返回 |
|
||
| POST | `/api/threads/{id}/runs/wait` | 创建运行并阻塞等待结果 |
|
||
| POST | `/api/threads/{id}/runs` | 创建后台运行 |
|
||
| GET | `/api/threads/{id}/runs` | 列出线程的所有运行 |
|
||
| GET | `/api/threads/{id}/runs/{rid}` | 获取运行详情 |
|
||
| POST | `/api/threads/{id}/runs/{rid}/cancel` | 取消运行 |
|
||
| GET | `/api/threads/{id}/runs/{rid}/join` | 加入 SSE 流 |
|
||
| GET | `/api/threads/{id}/runs/{rid}/messages` | 分页获取消息 |
|
||
| GET | `/api/threads/{id}/messages` | 线程所有消息(含反馈) |
|
||
|
||
### 8.3 无状态运行
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| POST | `/api/runs/stream` | 无状态运行 + SSE 流 |
|
||
| POST | `/api/runs/wait` | 无状态运行 + 阻塞 |
|
||
|
||
### 8.4 文件上传
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| POST | `/api/threads/{id}/uploads` | 上传文件(自动转换 PDF/PPT/Excel/Word) |
|
||
| GET | `/api/threads/{id}/uploads/list` | 列出已上传文件 |
|
||
| DELETE | `/api/threads/{id}/uploads/{filename}` | 删除文件 |
|
||
|
||
### 8.5 其他接口
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| GET | `/api/models` | 列出所有可用 LLM 模型 |
|
||
| GET | `/api/models/{name}` | 模型详情 |
|
||
| GET | `/api/mcp/config` | 获取 MCP 配置 |
|
||
| PUT | `/api/mcp/config` | 更新 MCP 配置 |
|
||
| GET | `/api/skills` | 列出技能 |
|
||
| PUT | `/api/skills/{name}` | 启用/禁用技能 |
|
||
| POST | `/api/skills/install` | 安装 .skill 包 |
|
||
| GET | `/api/memory` | 获取个人内存数据 |
|
||
| POST | `/api/memory/reload` | 强制重新加载内存 |
|
||
| GET/POST/PUT/DELETE | `/api/agents` | 自定义 Agent CRUD |
|
||
| GET | `/api/threads/{id}/artifacts/{path}` | 下载工件文件 |
|
||
| POST | `/api/threads/{id}/suggestions` | 生成后续问题建议 |
|
||
| DELETE | `/api/threads/{id}` | 清理线程本地数据 |
|
||
| PUT | `/api/threads/{id}/runs/{rid}/feedback` | 提交运行反馈 |
|
||
| POST/GET | `/api/scheduled-tasks` | 定时任务管理 |
|
||
| POST | `/api/v1/auth/login` | 用户登录 |
|
||
| POST | `/api/v1/auth/register` | 用户注册 |
|
||
|
||
---
|
||
|
||
## 9. Agent 系统
|
||
|
||
### Lead Agent
|
||
|
||
**入口**:`deerflow.agents.lead_agent.agent:make_lead_agent`,注册在 `langgraph.json`。
|
||
|
||
```python
|
||
from deerflow.agents import make_lead_agent
|
||
from langgraph.types import RunnableConfig
|
||
|
||
config = RunnableConfig(configurable={
|
||
"thinking_enabled": False, # 是否启用扩展思考
|
||
"model_name": "my-model", # 指定 LLM 模型
|
||
"is_plan_mode": False, # 是否启用计划模式(TodoList)
|
||
"subagent_enabled": True, # 是否启用子 Agent 委托
|
||
})
|
||
agent = make_lead_agent(config)
|
||
```
|
||
|
||
### ThreadState 数据模型
|
||
|
||
`deerflow/agents/thread_state.py`:
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `messages` | list | LangGraph 消息列表 |
|
||
| `sandbox` | SandboxInfo | 当前线程沙箱 |
|
||
| `thread_data` | dict | 线程本地数据(路径等) |
|
||
| `title` | str | 自动生成的对话标题 |
|
||
| `artifacts` | list | 生成的工件文件 |
|
||
| `todos` | list | 计划模式下的待办事项 |
|
||
| `uploaded_files` | list | 已上传的文件 |
|
||
| `viewed_images` | list | 已查看的图像(base64) |
|
||
|
||
### 子 Agent 系统
|
||
|
||
- **内置子 Agent**:`general-purpose`(所有工具,除 `task`)、`bash`(命令专家)
|
||
- **最大并发**:3 个(`SubagentLimitMiddleware` 强制限制)
|
||
- **超时时间**:15 分钟
|
||
- **触发方式**:调用 `task` 工具委托任务
|
||
- **执行流程**:`task()` → `SubagentExecutor` → 后台线程 → 每 5 秒轮询 → SSE 事件
|
||
|
||
```python
|
||
# 委托子 Agent 执行任务(在 Agent 提示词中由 LLM 自动调用)
|
||
task(
|
||
description="...",
|
||
prompt="分析这份数据并生成报告",
|
||
subagent_type="general-purpose",
|
||
max_turns=10
|
||
)
|
||
```
|
||
|
||
---
|
||
|
||
## 10. 中间件链
|
||
|
||
Lead Agent 中间件按固定顺序组装,每个中间件负责一个横切关注点:
|
||
|
||
| 顺序 | 中间件 | 作用 |
|
||
|------|--------|------|
|
||
| 1 | `ThreadDataMiddleware` | 创建每线程隔离目录(workspace/uploads/outputs) |
|
||
| 2 | `UploadsMiddleware` | 注入新上传的文件到对话 |
|
||
| 3 | `SandboxMiddleware` | 获取沙箱实例,存储 sandbox_id |
|
||
| 4 | `DanglingToolCallMiddleware` | 为中断的工具调用注入占位 ToolMessage |
|
||
| 5 | `LLMErrorHandlingMiddleware` | 将 LLM 调用失败归一化为可恢复错误 |
|
||
| 6 | `GuardrailMiddleware` | 工具调用前授权检查(可选) |
|
||
| 7 | `SandboxAuditMiddleware` | 沙箱操作安全审计日志 |
|
||
| 8 | `ToolErrorHandlingMiddleware` | 将工具异常转为错误 ToolMessage,避免中止 |
|
||
| 9 | `SummarizationMiddleware` | 接近 Token 上限时压缩上下文(可选) |
|
||
| 10 | `TodoListMiddleware` | 计划模式下的任务追踪(可选) |
|
||
| 11 | `TokenUsageMiddleware` | 记录 Token 用量指标(可选) |
|
||
| 12 | `TitleMiddleware` | 首次完整交互后自动生成标题 |
|
||
| 13 | `MemoryMiddleware` | 将对话加入内存更新队列 |
|
||
| 14 | `ViewImageMiddleware` | 调用 LLM 前注入 base64 图像(视觉模型) |
|
||
| 15 | `DeferredToolFilterMiddleware` | 隐藏延迟工具 Schema(可选) |
|
||
| 16 | `SubagentLimitMiddleware` | 限制最大并发子 Agent 数(可选) |
|
||
| 17 | `LoopDetectionMiddleware` | 检测工具调用循环并强制终止 |
|
||
| 18 | `ClarificationMiddleware` | 拦截澄清请求,中断到 END(必须最后) |
|
||
|
||
---
|
||
|
||
## 11. 沙箱执行系统
|
||
|
||
### 概述
|
||
|
||
每个线程拥有独立的沙箱环境,Agent 通过沙箱执行命令和读写文件。
|
||
|
||
### 虚拟路径映射
|
||
|
||
Agent 看到的虚拟路径 → 物理路径:
|
||
|
||
| 虚拟路径 | 物理路径 |
|
||
|----------|----------|
|
||
| `/mnt/user-data/workspace/` | `backend/.deer-flow/users/{user_id}/threads/{thread_id}/user-data/workspace/` |
|
||
| `/mnt/user-data/uploads/` | `backend/.deer-flow/users/{user_id}/threads/{thread_id}/user-data/uploads/` |
|
||
| `/mnt/user-data/outputs/` | `backend/.deer-flow/users/{user_id}/threads/{thread_id}/user-data/outputs/` |
|
||
| `/mnt/skills/` | `deer-flow/skills/` |
|
||
|
||
### 沙箱工具
|
||
|
||
| 工具 | 说明 |
|
||
|------|------|
|
||
| `bash` | 执行 Shell 命令(含路径转换) |
|
||
| `ls` | 目录列表(树形格式,最多 2 层) |
|
||
| `read_file` | 读取文件内容(支持行范围) |
|
||
| `write_file` | 写入/追加文件(自动创建目录) |
|
||
| `str_replace` | 字符串替换(单次或全部) |
|
||
|
||
### 沙箱提供者
|
||
|
||
- **LocalSandboxProvider**:单例本地文件系统执行(默认)
|
||
- **AioSandboxProvider**:基于 Docker 的隔离执行(需要 Docker)
|
||
|
||
在 `config.yaml` 中切换:
|
||
```yaml
|
||
sandbox:
|
||
use: deerflow.sandbox.local:LocalSandboxProvider
|
||
# 或 Docker 沙箱:
|
||
# use: deerflow.community.aio_sandbox:AioSandboxProvider
|
||
```
|
||
|
||
---
|
||
|
||
## 12. 内存系统
|
||
|
||
### 功能
|
||
|
||
- 自动从对话中提取用户偏好、知识和上下文,存储为结构化事实
|
||
- 下次对话时自动注入内存上下文到系统提示词
|
||
- 每用户独立存储,按 Agent 进一步隔离
|
||
|
||
### 存储路径
|
||
|
||
```
|
||
backend/.deer-flow/users/{user_id}/memory.json # 默认 Agent 内存
|
||
backend/.deer-flow/users/{user_id}/agents/{agent_name}/memory.json # 自定义 Agent 内存
|
||
```
|
||
|
||
### 数据结构
|
||
|
||
```json
|
||
{
|
||
"workContext": "用户是一名 Python 开发者...",
|
||
"personalContext": "...",
|
||
"topOfMind": "...",
|
||
"recentMonths": "...",
|
||
"facts": [
|
||
{
|
||
"id": "fact-001",
|
||
"content": "用户偏好使用 TypeScript",
|
||
"category": "preference",
|
||
"confidence": 0.9,
|
||
"createdAt": "2025-01-01T00:00:00Z"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 工作流程
|
||
|
||
1. `MemoryMiddleware` 过滤消息(用户输入 + 最终 AI 回复),捕获 `user_id`,加入更新队列
|
||
2. 队列去抖(默认 30 秒),按线程去重
|
||
3. 后台线程调用 LLM 提取上下文更新和事实
|
||
4. 原子写入(临时文件 + rename),跳过重复事实
|
||
5. 下次交互注入前 15 条事实 + 上下文到 `<memory>` 标签
|
||
|
||
### 配置
|
||
|
||
```yaml
|
||
memory:
|
||
enabled: true
|
||
injection_enabled: true
|
||
debounce_seconds: 30 # 去抖等待时间
|
||
model_name: null # null 表示使用默认模型
|
||
max_facts: 100 # 最大存储事实数
|
||
fact_confidence_threshold: 0.7 # 事实置信度阈值
|
||
max_injection_tokens: 2000 # 注入 Token 上限
|
||
```
|
||
|
||
---
|
||
|
||
## 13. 工具系统
|
||
|
||
### 工具组装
|
||
|
||
`get_available_tools(groups, include_mcp, model_name, subagent_enabled)` 按顺序组装:
|
||
|
||
1. **config.yaml 定义的工具**:通过 `resolve_variable()` 反射加载
|
||
2. **MCP 工具**:来自已启用的 MCP 服务器(懒加载,带 mtime 失效)
|
||
3. **内置工具**:
|
||
- `present_files` — 将输出文件呈现给用户(仅 `/mnt/user-data/outputs`)
|
||
- `ask_clarification` — 请求澄清(由 `ClarificationMiddleware` 拦截,中断对话)
|
||
- `view_image` — 读取图像为 base64(仅视觉模型)
|
||
4. **子 Agent 工具**(启用时):`task` — 委托子 Agent
|
||
|
||
### 社区工具
|
||
|
||
| 工具 | 模块 | 说明 |
|
||
|------|------|------|
|
||
| Tavily 搜索 | `deerflow.community.tavily` | Web 搜索(默认 5 条结果) |
|
||
| Tavily 获取 | `deerflow.community.tavily` | Web 页面获取(4KB 限制) |
|
||
| Jina AI | `deerflow.community.jina_ai` | 通过 Jina reader API 获取页面 |
|
||
| Firecrawl | `deerflow.community.firecrawl` | 网页爬取 |
|
||
| 图像搜索 | `deerflow.community.image_search` | DuckDuckGo 图像搜索 |
|
||
|
||
### MCP 集成
|
||
|
||
- 使用 `langchain-mcp-adapters` 的 `MultiServerMCPClient`
|
||
- 懒加载:首次使用时初始化
|
||
- 配置变更自动失效(mtime 检测)
|
||
- 支持 stdio、SSE、HTTP 传输
|
||
- 支持 OAuth 令牌刷新(HTTP/SSE)
|
||
|
||
---
|
||
|
||
## 14. IM 频道集成
|
||
|
||
### 消息流程
|
||
|
||
```
|
||
外部平台消息
|
||
↓
|
||
频道实现(feishu.py / slack.py 等)
|
||
↓
|
||
MessageBus.publish_inbound()
|
||
↓
|
||
ChannelManager._dispatch_loop()
|
||
↓
|
||
查找/创建线程(通过 Gateway API)
|
||
↓
|
||
执行 Agent 运行(stream 或 wait)
|
||
↓
|
||
OutboundMessage → 平台回复
|
||
```
|
||
|
||
### 各平台特性
|
||
|
||
| 平台 | 特性 |
|
||
|------|------|
|
||
| 飞书 | 增量更新,修改同一消息卡片(`update_multi=true`) |
|
||
| Slack | 阻塞等待最终结果 |
|
||
| Telegram | 阻塞等待最终结果 |
|
||
| 钉钉 | 支持 AI 卡片流式更新(需配置 `card_template_id`) |
|
||
|
||
### 配置(`config.yaml` → `channels`)
|
||
|
||
```yaml
|
||
channels:
|
||
langgraph_url: http://localhost:8001/api # LangGraph 兼容 API 基础 URL
|
||
gateway_url: http://localhost:8001 # Gateway API URL
|
||
feishu:
|
||
app_id: $FEISHU_APP_ID
|
||
app_secret: $FEISHU_APP_SECRET
|
||
slack:
|
||
bot_token: $SLACK_BOT_TOKEN
|
||
app_token: $SLACK_APP_TOKEN
|
||
telegram:
|
||
bot_token: $TELEGRAM_BOT_TOKEN
|
||
dingtalk:
|
||
client_id: $DINGTALK_CLIENT_ID
|
||
client_secret: $DINGTALK_CLIENT_SECRET
|
||
card_template_id: "" # 可选,启用 AI 卡片流式
|
||
```
|
||
|
||
> **Docker 部署注意**:IM 频道运行在 `gateway` 容器内,应将 `localhost` 改为服务名,例如 `langgraph_url: http://gateway:8001/api`。
|
||
|
||
---
|
||
|
||
## 15. 数据持久化
|
||
|
||
### 数据库
|
||
|
||
默认使用 SQLite,存放在 `backend/.deer-flow/data/`。可切换为 PostgreSQL:
|
||
|
||
```yaml
|
||
database:
|
||
backend: postgres
|
||
postgres_url: postgresql://user:pass@localhost:5432/deerflow
|
||
```
|
||
|
||
### 主要数据表
|
||
|
||
| 表名 | 说明 |
|
||
|------|------|
|
||
| `agents` | 自定义 Agent 元数据(id、name、user_id、published) |
|
||
| `users` | 用户账号 |
|
||
| `thread_meta` | 线程元数据(标题、创建时间等) |
|
||
| `feedback` | 运行反馈和评分 |
|
||
| `scheduled_tasks` | 定时任务配置 |
|
||
|
||
### 数据库迁移
|
||
|
||
使用 Alembic 管理 Schema 变更,应用启动时自动执行:
|
||
|
||
```bash
|
||
# 查看迁移历史
|
||
PYTHONPATH=. uv run alembic history
|
||
|
||
# 手动升级到最新
|
||
PYTHONPATH=. uv run alembic upgrade head
|
||
```
|
||
|
||
### 运行时文件目录
|
||
|
||
```
|
||
backend/.deer-flow/
|
||
├── data/ # SQLite 数据库
|
||
└── users/{user_id}/
|
||
├── memory.json # 个人内存(默认 Agent)
|
||
├── agents/{agent_name}/memory.json # 自定义 Agent 内存
|
||
└── threads/{thread_id}/user-data/
|
||
├── workspace/ # Agent 工作目录
|
||
├── uploads/ # 上传的文件
|
||
└── outputs/ # 生成的输出文件
|
||
```
|
||
|
||
---
|
||
|
||
## 16. 测试
|
||
|
||
### 测试套件
|
||
|
||
```bash
|
||
# 运行所有测试
|
||
make test
|
||
|
||
# 运行特定测试文件
|
||
PYTHONPATH=. uv run pytest tests/test_memory_updater.py -v
|
||
|
||
# 运行特定测试函数
|
||
PYTHONPATH=. uv run pytest tests/test_client.py::TestGatewayConformance -v
|
||
```
|
||
|
||
### 关键测试文件
|
||
|
||
| 文件 | 说明 |
|
||
|------|------|
|
||
| `tests/test_harness_boundary.py` | 确保 harness 层不导入 app 层(CI 必须通过) |
|
||
| `tests/test_memory_updater.py` | 内存提取和去重逻辑 |
|
||
| `tests/test_client.py` | 嵌入式客户端 77 个单元测试,含 Gateway 一致性验证 |
|
||
| `tests/test_client_live.py` | 需要 config.yaml 的集成测试 |
|
||
| `tests/test_docker_sandbox_mode_detection.py` | Docker 沙箱模式检测回归测试 |
|
||
| `tests/test_provisioner_kubeconfig.py` | kubeconfig 处理回归测试 |
|
||
| `tests/conftest.py` | pytest fixtures 和通用配置 |
|
||
|
||
### TDD 原则
|
||
|
||
**每个新功能或 Bug 修复必须附带单元测试**,无例外。
|
||
|
||
- 测试文件命名:`tests/test_<feature>.py`
|
||
- 轻量配置/工具模块优先写不依赖外部服务的纯单元测试
|
||
- 如果模块导致循环导入问题,在 `tests/conftest.py` 中添加 `sys.modules` mock
|
||
|
||
---
|
||
|
||
## 17. 常见问题与排错
|
||
|
||
### 启动失败:找不到 config.yaml
|
||
|
||
确认 `config.yaml` 在项目根目录或 `backend/` 目录中存在。可用环境变量指定路径:
|
||
|
||
```bash
|
||
export DEER_FLOW_CONFIG_PATH=/path/to/config.yaml
|
||
make dev
|
||
```
|
||
|
||
### 模型调用失败
|
||
|
||
1. 确认 `config.yaml` 中对应模型的 `api_key` 环境变量已设置
|
||
2. 确认 `base_url` 可访问
|
||
3. 检查模型提供者包是否安装:缺少时启动日志会给出 `uv add langchain-xxx` 提示
|
||
|
||
### 内存功能不工作
|
||
|
||
检查 `config.yaml` 中:
|
||
```yaml
|
||
memory:
|
||
enabled: true
|
||
injection_enabled: true
|
||
```
|
||
|
||
### 文件上传后 Agent 无法使用
|
||
|
||
确认文件上传到正确线程,且 `UploadsMiddleware` 处于启用状态(默认启用)。上传文件存放在 `/mnt/user-data/uploads/`,Agent 可直接访问。
|
||
|
||
### Windows 下端口占用
|
||
|
||
```bash
|
||
# 查找占用 8001 端口的进程
|
||
netstat -ano | findstr :8001
|
||
|
||
# 终止进程(替换 PID)
|
||
taskkill /PID <PID> /F
|
||
```
|
||
|
||
详见 `docs/BACKEND_RUN_STOP_ZH.md`(Windows 启停专项指南)。
|
||
|
||
### 如何新增 API 路由
|
||
|
||
1. 在 `app/gateway/routers/` 新建路由文件
|
||
2. 在 `app/gateway/app.py` 中导入并挂载路由
|
||
3. 编写对应测试文件 `tests/test_<feature>.py`
|
||
|
||
### 如何新增工具
|
||
|
||
1. 在 `packages/harness/deerflow/community/` 或 `tools/builtins/` 中实现工具函数
|
||
2. 在 `config.yaml` 中的 `tools` 列表添加配置,指定 `use` 类路径和 `group`
|
||
3. 工具会在下次 Agent 初始化时自动加载
|
||
|
||
---
|
||
|
||
*文档最后更新:2026-05-13*
|