1. 从一次“多智能体跑飞”说起:DeerFlow 到底解决什么问题
如果你自己搭过多智能体系统,大概率遇到过这种场面:主 Agent 把任务派给子 Agent,子 Agent 又调工具、又写文件,结果上下文越滚越长,摘要一压缩,之前的关键结论全丢了;某个工具报错,整条 run 直接崩掉,前端只看到一个红色错误,中间态全没了。这不是模型不行,而是缺少一套像样的 Agent Runtime。
DeerFlow 就是冲着这类问题来的。它把自己定位成开源的 Super Agent Harness——不是聊天壳子,而是一套带线程、任务、Artifacts、记忆、沙箱和 Subagent 的运行时骨架。前端是工作区,后端拆成 Gateway + Harness,Agent 由模型、工具、状态、中间件链和配置动态拼装。适合谁?想自建多智能体运行时、又不想从零造轮子的开发者。
这篇不空谈架构,我会按“骨架怎么搭 → 配置怎么写 → 怎么验证跑通 → 报错怎么排”的顺序,给你可复制的config.toml、settings.json骨架,以及用 TaoToken 统一 Key/API 通道接入 AI 工具的配置片段。你可以边看边动手。
2. 前置准备:用 TaoToken 统一模型通道,再谈 Harness
DeerFlow 的 Harness 层有一个 Model Factory,负责按运行时参数动态创建 chat model。也就是说,模型不是写死的,而是从配置里读出来的。既然要频繁切换模型、给 lead agent 和 subagent 配不同模型,最省事的做法是让所有模型请求走同一个 API 通道,而不是每个 provider 单独维护一套 Key。
我试过把模型通道统一到 TaoToken:一个 Key 覆盖多种模型,配置里只改模型名,不用动鉴权逻辑。对 DeerFlow 这种“模型名从 config 里解析”的架构特别友好。
先拿 Key。打开控制台创建 API Key:
- 控制台入口:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite
- API Key 管理:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite
拿到 Key 之后,记住两个地址,后面配置里会反复用到:
| 用途 | 地址 |
|---|---|
| 官网 | https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= |
| API Base | https://taotoken.net/api |
注意:API 地址不要加 UTM 参数,只有网页链接才带。配置里填的是
https://taotoken.net/api。
如果你只是想先验证模型通不通,可以直接用模型对话页面发一条消息,确认 Key 有效再往下走:
- 模型对话:https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite
3. 可复制配置:config.toml 与 settings.json 骨架
DeerFlow 的配置分两层:一层是 Harness 运行时的config.toml(模型、沙箱、记忆、子代理),一层是前端工作区的settings.json(线程上下文、模式开关)。下面给的是能直接改改就用的骨架。
3.1 config.toml:模型工厂与运行时开关
# config.toml —— DeerFlow Harness 运行时配置骨架 [model] # 统一走 TaoToken 通道,换模型只改 name provider = "openai_compatible" base_url = "https://taotoken.net/api" api_key = "${TAOTOKEN_API_KEY}" # 从环境变量读取,别硬编码 name = "claude-sonnet" # lead agent 默认模型 thinking_enabled = true reasoning_effort = "medium" [model.subagent] # 子代理单独指定模型,通常用更轻量的 name = "gpt-4o-mini" thinking_enabled = false [token_usage] enabled = true [memory] enabled = true # 记忆更新走异步去抖队列,不阻塞主对话 flush_on_summarize = true [sandbox] provider = "local" host_bash_allowed = false # 默认关闭宿主机 bash,安全第一 max_output_chars = 8000 [subagent] enabled = true max_concurrent = 3 # 对应 SubagentLimitMiddleware [guardrails] enabled = false fail_closed = true几个关键点解释一下。base_url指向 TaoToken 的 API 地址,api_key用环境变量注入,避免把 Key 写进仓库。model.subagent单独配一个轻量模型,是因为子代理通常做的是检索、整理这类活,用大模型既慢又贵。host_bash_allowed = false对应源码里is_host_bash_allowed()的校验,本地沙箱默认不放开宿主机 shell。
3.2 settings.json:前端工作区上下文
{ "context": { "mode": "pro", "thinking_enabled": true, "is_plan_mode": true, "subagent_enabled": false, "thread_id": "" }, "ui": { "show_token_usage": true, "show_artifacts": true, "show_todo_list": true }, "upload": { "max_files": 5, "virtual_path": "/mnt/user-data/uploads" } }这里的context字段会直接映射到运行时配置。对照源码里sendMessage的提交逻辑:mode === "pro"时is_plan_mode为 true,mode === "ultra"时subagent_enabled才打开。所以你想启用子代理,把mode改成ultra,或者手动把subagent_enabled置 true。
3.3 环境变量与启动
# .env export TAOTOKEN_API_KEY="sk-你的key" export DEERFLOW_CONFIG="./config.toml"# 启动后端 Gateway(示例端口) cd backend uvicorn app.gateway.app:app --host 0.0.0.0 --port 8001 # 启动前端工作区 cd frontend pnpm dev --port 3000启动后,Gateway 会暴露 models、threads、skills、memory、subagents 等管理接口,LangGraph Runtime 负责线程和运行,Harness 负责真正的 Agent 执行。前端通过useThreadStream()对接 LangGraph SDK,订阅工具事件和task_running自定义事件。
4. 验证请求:确认 Agent Runtime 真的跑起来了
配置写完不算完,得验证。分三步:先验证模型通道,再验证线程创建,最后验证子代理事件回流。
4.1 验证模型通道
curl -s https://taotoken.net/api/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet", "messages": [{"role": "user", "content": "回复 OK 两个字母"}] }'返回里有choices[0].message.content就说明通道通了。这一步不通,后面 Harness 一定报模型创建失败。
4.2 验证线程创建与流式事件
curl -N -s http://localhost:8001/threads \ -H "Content-Type: application/json" \ -d '{ "assistant_id": "lead_agent", "input": {"messages": [{"type": "human", "content": "列出当前目录文件"}]}, "stream_subgraphs": true, "config": {"recursion_limit": 1000} }'你会看到一串 SSE 事件。重点观察两类:on_tool_end表示工具执行结束,task_running表示子任务在跑。如果只看到消息流、没有工具事件,说明工具没被正确装配,回去检查get_available_tools对应的配置。
4.3 验证子代理回流
把settings.json的mode改成ultra,再发一条需要拆解的任务,比如“帮我调研三个方案并汇总”。正常表现是:主 Agent 调task工具,前端收到task_started,随后子代理后台执行,完成后task_completed带着结果回来。子代理不会递归拿到task工具,这是防止无限套娃的设计。
提示:子代理是异步执行 + 状态轮询,不是同步阻塞。所以你在前端看到的是“任务进行中”,而不是卡住。
5. 本篇常见错排查
配置和验证过程中,最容易踩的坑集中在下面几类。
模型创建失败,报 provider 不识别。多半是config.toml里provider写成了具体厂商名,而 Harness 的 Model Factory 期望的是openai_compatible这类通用协议标识。改成通用协议,base_url指向 TaoToken 的 API 地址即可。
工具报错导致整条 run 崩掉。检查ToolErrorHandlingMiddleware是否在中间件链里。它的作用是把工具异常转成ToolMessage,让模型带着错误上下文继续推理,而不是直接抛异常。如果你自定义了中间件顺序,别把它挤掉。
长对话后记忆丢失。确认memory_flush_hook生效。它的逻辑是在消息被摘要删掉之前,先把“用户输入 + 最终 AI 响应”送进长期记忆队列。如果memory.enabled为 false,或者flush_on_summarize没开,摘要一压缩,旧信息就真没了。
子代理不并发或直接报未知类型。get_subagent_config(subagent_type)返回 None 时会报Unknown subagent type。检查config.toml里子代理类型是否注册,以及max_concurrent是否被SubagentLimitMiddleware限制为 0。
沙箱路径校验失败。DeerFlow 的沙箱不是直接操作宿主机路径,而是先validate_local_tool_path再映射到 skills、ACP workspace 或 user-data。你传的路径如果不在允许的虚拟路径语义内,会被拒绝。上传文件走/mnt/user-data/uploads这类虚拟路径。
前端线程 ID 对不上。线程创建由后端决定,前端只接收真实 thread id。如果你在onCreated之前就手动设置了 threadId,会出现状态错乱。让useThreadStream的onCreated回调去setThreadId。
6. 把 Harness 用起来:从验证到长期编码
跑通之后,你会发现 DeerFlow 的价值不在“能聊天”,而在它把上下文压缩、长期记忆、沙箱、子代理这些生产级问题都做成了可复用的运行时基底。lead agent 是工厂式装配,中间件链顺序有语义,失败被当作系统主路径处理——这些设计决定了它能长期维护,而不是 demo 一把就废。
如果你打算把它用在长期编码或 Agent 协作场景,建议直接上 Coding Plan,把模型通道和额度统一管理,省得每个子代理单独配 Key:
- Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite
接入细节和参数说明看文档,里面有完整的配置字段和调用示例:
- 接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite
如果你用的是 Claude Code 这类编码工具,想让 Harness 里的子代理复用同一套通道,参考这份 Anthropic 接入说明:
- ClaudeCodeAnthropic:https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claudecodeanthropic&utm_campaign=rewrite
最后说个实操心得:调 DeerFlow 的中间件顺序时,别急着加功能,先把ThreadDataMiddleware和SandboxMiddleware放最前,ClarificationMiddleware放最后,中间按“压缩 → 推理 → 记忆”排。顺序对了,很多诡异的状态丢失问题会自己消失。