# DeerFlow Backend DeerFlow is a LangGraph-based AI super agent with sandbox execution, persistent memory, and extensible tool integration. The backend enables AI agents to execute code, browse the web, manage files, delegate tasks to subagents, and retain context across conversations - all in isolated, per-thread environments. --- ## Architecture ``` ┌──────────────────────────────────────┐ │ Nginx (Port 2026) │ │ Unified reverse proxy │ └───────┬──────────────────┬───────────┘ │ │ /api/langgraph/* │ │ /api/* (other) ▼ ▼ ┌────────────────────┐ ┌────────────────────────┐ │ LangGraph Server │ │ Gateway API (8001) │ │ (Port 2024) │ │ FastAPI REST │ │ │ │ │ │ ┌────────────────┐ │ │ Models, MCP, Skills, │ │ │ Lead Agent │ │ │ Memory, Uploads, │ │ │ ┌──────────┐ │ │ │ Artifacts │ │ │ │Middleware│ │ │ └────────────────────────┘ │ │ │ Chain │ │ │ │ │ └──────────┘ │ │ │ │ ┌──────────┐ │ │ │ │ │ Tools │ │ │ │ │ └──────────┘ │ │ │ │ ┌──────────┐ │ │ │ │ │Subagents │ │ │ │ │ └──────────┘ │ │ │ └────────────────┘ │ └────────────────────┘ ``` **Request Routing** (via Nginx): - `/api/langgraph/*` → LangGraph Server - agent interactions, threads, streaming - `/api/*` (other) → Gateway API - models, MCP, skills, memory, artifacts, uploads, thread-local cleanup - `/` (non-API) → Frontend - Next.js web interface --- ## Core Components ### Lead Agent The single LangGraph agent (`lead_agent`) is the runtime entry point, created via `make_lead_agent(config)`. It combines: - **Dynamic model selection** with thinking and vision support - **Middleware chain** for cross-cutting concerns (9 middlewares) - **Tool system** with sandbox, MCP, community, and built-in tools - **Subagent delegation** for parallel task execution - **System prompt** with skills injection, memory context, and working directory guidance ### Middleware Chain Middlewares execute in strict order, each handling a specific concern: | # | Middleware | Purpose | |---|-----------|---------| | 1 | **ThreadDataMiddleware** | Creates per-thread isolated directories (workspace, uploads, outputs) | | 2 | **UploadsMiddleware** | Injects newly uploaded files into conversation context | | 3 | **SandboxMiddleware** | Acquires sandbox environment for code execution | | 4 | **SummarizationMiddleware** | Reduces context when approaching token limits (optional) | | 5 | **TodoListMiddleware** | Tracks multi-step tasks in plan mode (optional) | | 6 | **TitleMiddleware** | Auto-generates conversation titles after first exchange | | 7 | **MemoryMiddleware** | Queues conversations for async memory extraction | | 8 | **ViewImageMiddleware** | Injects image data for vision-capable models (conditional) | | 9 | **ClarificationMiddleware** | Intercepts clarification requests and interrupts execution (must be last) | ### Sandbox System Per-thread isolated execution with virtual path translation: - **Abstract interface**: `execute_command`, `read_file`, `write_file`, `list_dir` - **Providers**: `LocalSandboxProvider` (filesystem) and `AioSandboxProvider` (Docker, in community/) - **Virtual paths**: `/mnt/user-data/{workspace,uploads,outputs}` → thread-specific physical directories - **Skills path**: `/mnt/skills` → `deer-flow/skills/` directory - **Skills loading**: Recursively discovers nested `SKILL.md` files under `skills/{public,custom}` and preserves nested container paths - **WeKnora retrieval skill**: `skills/custom/weknora-knowledge-search` pairs a concise Skill with a stdio MCP server. It retrieves tenant-scoped WeKnora document/FAQ passages through the public API, groups multi-KB calls by embedding model, optionally searches Wiki pages, and can use the local reranker. It does not reject a KB solely because the legacy list API reports `chunk_count=0`; hybrid-search remains the source of truth. For WeKnora's explicit DeerFlow sharing mode, configure `WEKNORA_DEERFLOW_SHARE_TOKEN_FILE`: the MCP uses the restricted `/api/v1/deerflow/*` capability API and can only list/search knowledge bases whose owner enabled sharing; it never receives a user bearer token. Shared document results contain a credential-free `url` pointer, which is never rendered as text: both configured Skill source cards and the generic MCP-result fallback recognize it and provide a “查看原文” button. Selecting it calls DeerFlow's authenticated `/api/weknora/source-context` proxy and displays the hit plus two adjacent chunks while keeping the share token server-side. Shared mode currently excludes Wiki pages. Otherwise use `WEKNORA_API_KEY_FILE` for scoped-key deployments or `WEKNORA_BEARER_TOKEN_FILE` for legacy deployments; never put any credential in `SKILL.md` or a chat prompt. - **File-write safety**: `str_replace` serializes read-modify-write per `(sandbox.id, path)` so isolated sandboxes keep concurrency even when virtual paths match - **Tools**: `bash`, `ls`, `read_file`, `write_file`, `str_replace` (`bash` is disabled by default when using `LocalSandboxProvider`; use `AioSandboxProvider` for isolated shell access) ### Subagent System Async task delegation with concurrent execution: - **Built-in agents**: `general-purpose` (full toolset) and `bash` (command specialist, exposed only when shell access is available) - **Concurrency**: Max 3 subagents per turn, 15-minute timeout - **Execution**: Background thread pools with status tracking and SSE events - **Flow**: Agent calls `task()` tool → executor runs subagent in background → polls for completion → returns result ### Memory System LLM-powered persistent context retention across conversations: - **Automatic extraction**: Analyzes conversations for user context, facts, and preferences - **Structured storage**: User context (work, personal, top-of-mind), history, and confidence-scored facts - **Debounced updates**: Batches updates to minimize LLM calls (configurable wait time) - **System prompt injection**: Top facts + context injected into agent prompts - **Storage**: JSON file with mtime-based cache invalidation ### Tool Ecosystem | Category | Tools | |----------|-------| | **Sandbox** | `bash`, `ls`, `read_file`, `write_file`, `str_replace` | | **Built-in** | `present_files`, `ask_clarification`, `view_image`, `task` (subagent) | | **Community** | Tavily (web search), Jina AI (web fetch), Firecrawl (scraping), DuckDuckGo (image search) | | **MCP** | Any Model Context Protocol server (stdio, SSE, HTTP transports) | | **Skills** | Domain-specific workflows injected via system prompt | ### Gateway API FastAPI application providing REST endpoints for frontend integration: | Route | Purpose | |-------|---------| | `GET /api/models` | List available LLM models | | `GET/PUT /api/mcp/config` | Manage MCP server configurations | | `GET/PUT /api/skills` | List and manage skills | | `POST /api/skills/install` | Install skill from `.skill` archive | | `GET/POST /api/agents` | List visible agents or create a user-owned agent | | `GET/PUT/DELETE /api/agents/{id}` | Read, update, or delete an id-addressed agent | | `GET /api/memory` | Retrieve memory data | | `POST /api/memory/reload` | Force memory reload | | `GET /api/memory/config` | Memory configuration | | `GET /api/memory/status` | Combined config + data | | `POST /api/threads/{id}/uploads` | Upload files (auto-converts PDF/PPT/Excel/Word to Markdown, rejects directory paths) | | `GET /api/threads/{id}/uploads/list` | List uploaded files | | `DELETE /api/threads/{id}` | Delete DeerFlow-managed local thread data after LangGraph thread deletion; unexpected failures are logged server-side and return a generic 500 detail | | `GET /api/threads/{id}/artifacts/{path}` | Serve generated artifacts | | `POST /api/ai-writing/sample/extract` | Extract text from Word/PDF/Markdown/TXT samples for AI-writing imitation mode | | `POST /cop/saveSuperiorTask` | TaskCOP compatibility API (DeerFlow Bearer/session authentication required): create a situation-overview task with a sequential four-digit id (`0001`, `0002`, ...) and return the legacy `{state, msg, data}` envelope | | `POST /api/taskcop/import/tasks` | TaskCOP compatibility API (authenticated): import tasks from a JSON array or `tasks`/`records` envelope; every row's supplied `id`/`taskId` is authoritative and a duplicate id completely replaces the stored task | | `DELETE /cop/tasks/{task_id}` | TaskCOP compatibility API (authenticated): delete one task and its task-scoped situation-report document | | `GET /taskAnalyseSearch/cop-task-three-list` | TaskCOP compatibility API (authenticated): paginated task list for the situation-overview sentiment page (`content`, `taskStatus`, `taskDirection`, `startTime`, `endTime`) | | `GET/POST/PUT /api/task-reports/by-task/{task_id}` | Shared task-scoped situation-report detail. Query, first save, and full update all use the legacy-compatible `{state, msg, data:[{id, taskId, createTime, updateTime, sessionId, contentJson, categoryType}]}` shape; `contentJson` is preserved as a JSON string. Saving a non-empty report automatically moves the matching TaskCOP task to status `25` (the legacy list's “已完成” state). | | `POST /api/task-reports/import/by-task/{task_id}` | TaskCOP detail import (authenticated): accept a `sq-report-mock.json`-compatible `data`/`records` array and atomically replace the selected task's full report. The path task id overrides task ids inside the file. | The separately deployed TaskCOP Vue app uses `POST /api/v1/auth/login/username` directly (its `username`, `userId`, or `yUserId` URL parameter identifies the user), so this compatibility flow does not depend on the retired Consumer login service. It calls the Gateway address configured as `b1ConsumerUrl` directly; it does not use a Vite `/api` reverse proxy. An empty TaskCOP store remains empty; task data is introduced through normal creation or the JSON import API. The Gateway CORS middleware always merges the local TaskCOP Vite origins `http://localhost:8080` and `http://127.0.0.1:8080`, including when `GATEWAY_CORS_ORIGINS` is set for another frontend. `scripts/env.sh` also includes them in its startup default. For a deployment, set `GATEWAY_CORS_ORIGINS` to the exact additional frontend origins that are allowed to call the Gateway. AI writing supports a sample-imitation mode: the frontend can upload or paste a sample article, the Gateway extracts text for document files, and the `ai_writing` graph runs a `sample_analyzer` node before normal intent/research/outline/draft stages. The resulting style profile is injected into outline and draft prompts with explicit guardrails against copying source sentences, facts, names, or data. ### Custom Agents Custom agents are indexed in the `agents` database table. The `id` column is the stable runtime identifier and filesystem directory name (`.deer-flow/agents/{id}/SOUL.md`); `name` is display-only, may be Chinese, and may be duplicated. Rows with `user_id = NULL` are built-in agents, user rows are private unless `published = true`, and users can only update or delete agents they created. ### AI Writing Intranet Retrieval AI 写作的「知识库检索」会直连 `ai_writing.intranet_search_url` 内网 ES/知识库接口,并默认跳过代理环境变量和 HTTPS 证书校验,适配自签名或内部 CA 证书的内网服务。需要强校验时可在 `config.yaml` 里设置 `ai_writing.intranet_verify_ssl: true`。通用检索里的非内置技能在 `ai_writing.researcher_skill_agent: true` 时会用真实 agent 运行时执行技能:以 `ai-writing-researcher` 身份读取该技能的 `SKILL.md`,并按技能要求通过 `bash` 运行脚本,弱模型也会在本轮任务里收到明确的读文件和脚本执行指令。 ### IM Channels The IM bridge supports Feishu, Slack, and Telegram. Slack and Telegram still use the final `runs.wait()` response path, while Feishu now streams through `runs.stream(["messages-tuple", "values"])` and updates a single in-thread card in place. For Feishu card updates, DeerFlow stores the running card's `message_id` per inbound message and patches that same card until the run finishes, preserving the existing `OK` / `DONE` reaction flow. --- ## Quick Start ### Prerequisites - Python 3.12+ - [uv](https://docs.astral.sh/uv/) package manager - API keys for your chosen LLM provider ### Installation ```bash cd deer-flow # Copy configuration files cp config.example.yaml config.yaml # Install backend dependencies cd backend make install ``` ### Configuration Edit `config.yaml` in the project root: ```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 ``` Set your API keys: ```bash export OPENAI_API_KEY="your-api-key-here" ``` ### Running **Full Application** (from project root): ```bash make dev # Starts LangGraph + Gateway + Frontend + Nginx ``` Access at: http://localhost:2026 **Backend Only** (from backend directory): ```bash # Terminal 1: LangGraph server make dev # Terminal 2: Gateway API make gateway ``` Direct access: LangGraph at http://localhost:2024, Gateway at http://localhost:8001 --- ## Project Structure ``` backend/ ├── src/ │ ├── agents/ # Agent system │ │ ├── lead_agent/ # Main agent (factory, prompts) │ │ ├── middlewares/ # 9 middleware components │ │ ├── memory/ # Memory extraction & storage │ │ └── thread_state.py # ThreadState schema │ ├── gateway/ # FastAPI Gateway API │ │ ├── app.py # Application setup │ │ └── routers/ # 6 route modules │ ├── sandbox/ # Sandbox execution │ │ ├── local/ # Local filesystem provider │ │ ├── sandbox.py # Abstract interface │ │ ├── tools.py # bash, ls, read/write/str_replace │ │ └── middleware.py # Sandbox lifecycle │ ├── subagents/ # Subagent delegation │ │ ├── builtins/ # general-purpose, bash agents │ │ ├── executor.py # Background execution engine │ │ └── registry.py # Agent registry │ ├── tools/builtins/ # Built-in tools │ ├── mcp/ # MCP protocol integration │ ├── models/ # Model factory │ ├── skills/ # Skill discovery & loading │ ├── config/ # Configuration system │ ├── community/ # Community tools & providers │ ├── reflection/ # Dynamic module loading │ └── utils/ # Utilities ├── docs/ # Documentation ├── tests/ # Test suite ├── langgraph.json # LangGraph server configuration ├── pyproject.toml # Python dependencies ├── Makefile # Development commands └── Dockerfile # Container build ``` --- ## Configuration ### Main Configuration (`config.yaml`) Place in project root. Config values starting with `$` resolve as environment variables. Key sections: - `models` - LLM configurations with class paths, API keys, thinking/vision flags - `tools` - Tool definitions with module paths and groups - `tool_groups` - Logical tool groupings - `sandbox` - Execution environment provider - `skills` - Skills directory paths - `title` - Auto-title generation settings - `summarization` - Context summarization settings - `subagents` - Subagent system (enabled/disabled) - `memory` - Memory system settings (enabled, storage, debounce, facts limits) Provider note: - `models[*].use` references provider classes by module path (for example `langchain_openai:ChatOpenAI`). - If a provider module is missing, DeerFlow now returns an actionable error with install guidance (for example `uv add langchain-google-genai`). ### Extensions Configuration (`extensions_config.json`) MCP servers and skill states in a single file: ```json { "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" } } }, "skills": { "pdf-processing": {"enabled": true} } } ``` ### Environment Variables - `DEER_FLOW_CONFIG_PATH` - Override config.yaml location - `DEER_FLOW_EXTENSIONS_CONFIG_PATH` - Override extensions_config.json location - Model API keys: `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `DEEPSEEK_API_KEY`, etc. - Tool API keys: `TAVILY_API_KEY`, `GITHUB_TOKEN`, etc. ### LangSmith Tracing DeerFlow has built-in [LangSmith](https://smith.langchain.com) integration for observability. When enabled, all LLM calls, agent runs, tool executions, and middleware processing are traced and visible in the LangSmith dashboard. **Setup:** 1. Sign up at [smith.langchain.com](https://smith.langchain.com) and create a project. 2. Add the following to your `.env` file in the project root: ```bash LANGSMITH_TRACING=true LANGSMITH_ENDPOINT=https://api.smith.langchain.com LANGSMITH_API_KEY=lsv2_pt_xxxxxxxxxxxxxxxx LANGSMITH_PROJECT=xxx ``` **Legacy variables:** The `LANGCHAIN_TRACING_V2`, `LANGCHAIN_API_KEY`, `LANGCHAIN_PROJECT`, and `LANGCHAIN_ENDPOINT` variables are also supported for backward compatibility. `LANGSMITH_*` variables take precedence when both are set. ### Langfuse Tracing DeerFlow also supports [Langfuse](https://langfuse.com) observability for LangChain-compatible runs. Add the following to your `.env` file: ```bash LANGFUSE_TRACING=true LANGFUSE_PUBLIC_KEY=pk-lf-xxxxxxxxxxxxxxxx LANGFUSE_SECRET_KEY=sk-lf-xxxxxxxxxxxxxxxx LANGFUSE_BASE_URL=https://cloud.langfuse.com ``` If you are using a self-hosted Langfuse deployment, set `LANGFUSE_BASE_URL` to your Langfuse host. ### Dual Provider Behavior If both LangSmith and Langfuse are enabled, DeerFlow initializes and attaches both callbacks so the same run data is reported to both systems. If a provider is explicitly enabled but required credentials are missing, or the provider callback cannot be initialized, DeerFlow raises an error when tracing is initialized during model creation instead of silently disabling tracing. **Docker:** In `docker-compose.yaml`, tracing is disabled by default (`LANGSMITH_TRACING=false`). Set `LANGSMITH_TRACING=true` and/or `LANGFUSE_TRACING=true` in your `.env`, together with the required credentials, to enable tracing in containerized deployments. --- ## Development ### Commands ```bash make install # Install dependencies make dev # Run LangGraph server (port 2024) make gateway # Run Gateway API (port 8001) make lint # Run linter (ruff) make format # Format code (ruff) ``` ### Code Style - **Linter/Formatter**: `ruff` - **Line length**: 240 characters - **Python**: 3.12+ with type hints - **Quotes**: Double quotes - **Indentation**: 4 spaces ### Testing ```bash uv run pytest ``` --- ## Technology Stack - **LangGraph** (1.0.6+) - Agent framework and multi-agent orchestration - **LangChain** (1.2.3+) - LLM abstractions and tool system - **FastAPI** (0.115.0+) - Gateway REST API - **langchain-mcp-adapters** - Model Context Protocol support - **agent-sandbox** - Sandboxed code execution - **markitdown** - Multi-format document conversion - **tavily-python** / **firecrawl-py** - Web search and scraping --- ## Documentation - [Configuration Guide](docs/CONFIGURATION.md) - [Architecture Details](docs/ARCHITECTURE.md) - [API Reference](docs/API.md) - [File Upload](docs/FILE_UPLOAD.md) - [Path Examples](docs/PATH_EXAMPLES.md) - [Context Summarization](docs/summarization.md) - [Plan Mode](docs/plan_mode_usage.md) - [Backend Run/Stop Guide (ZH)](docs/BACKEND_RUN_STOP_ZH.md) - [Setup Guide](docs/SETUP.md) --- ## License See the [LICENSE](../LICENSE) file in the project root. ## Contributing See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines.