deerflow-code/offline-backend-20260512/backend/docs/houduankai.md
2026-09-07 18:24:55 +08:00

826 lines
26 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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*