主题
系统整体架构
本章目标:
- 认识 DeerFlow 2.0 的四大运行组件 —— Nginx(2026)、Frontend(3000)、Gateway(8001)、Provisioner(8002),以及它们的端口与职责。
- 理解后端 harness/app 双层分工:
deerflow.*是可发布的 agent 框架,app.*是 Gateway/channels 应用层,依赖方向单向。- 跟踪一次浏览器请求如何经 Nginx 反向代理流入 Gateway,再经 RunManager + StreamBridge 驱动 LangGraph agent runtime 并以 SSE 流式返回。
TL;DR
DeerFlow 2.0 是一个基于 LangGraph 的 super agent harness,部署形态为四个容器:Nginx 做统一入口反向代理,Frontend 跑 Next.js 界面,Gateway 是 FastAPI 应用并内嵌 agent runtime,Provisioner 在 Kubernetes 沙箱模式下按需创建沙箱 Pod。后端代码按 harness(deerflow.*,框架)与 app(app.*,Gateway 与 IM channels)严格分层,app 可依赖 deerflow 但反向被 CI 禁止。所有对话请求通过 /api/langgraph/* 进入 Gateway,由 RunManager 登记运行、run_agent() 在后台 task 中驱动 make_lead_agent 构建的 LangGraph 图、StreamBridge 把事件解耦地推给 SSE 端点。这张组件—分层—请求流的地图贯穿全 wiki 后续各章。
Overview
DeerFlow 没有把 agent runtime 做成独立的 LangGraph Platform 服务,而是把它内嵌进 Gateway 进程。这样做的动机是简化部署与状态共享:make dev、Docker dev、生产三种模式都用同一套 RunManager + run_agent() + StreamBridge,无需额外维护一个 LangGraph Server 进程。Nginx 把对外的 /api/langgraph/* 路径重写成 Gateway 原生的 /api/* 路由,让前端的 useStream Hook 以为自己在和标准 LangGraph Platform 对话 docker/nginx/nginx.conf:43-44。
后端的 harness/app 分层是为了让 agent 框架可独立发布(deerflow-harness 包,见 backend/packages/harness/pyproject.toml:1-3),同时让 FastAPI/IM 应用层依赖它而不污染它。langgraph.json 把图入口直接指向 harness 内的工厂函数 deerflow.agents:make_lead_agent,checkpointer 也指向 harness 模块,只有 auth 钩子落在 app 层 backend/langgraph.json:8-16。
Architecture
四个组件在 docker-compose 中各为一个 service,通过 deer-flow bridge 网络互通,只有 Nginx 对宿主暴露端口。
| 组件 | 端口 | 角色 | Source |
|---|---|---|---|
| Nginx | 2026(可由 PORT 覆盖) | 统一反向代理,路径路由,SSE/分块透传 | docker/docker-compose.yaml:27-42 |
| Frontend | 3000 | Next.js 生产服务,通过 gateway:8001 内部地址访问后端 | docker/docker-compose.yaml:45-61 |
| Gateway | 8001 | FastAPI + uvicorn 多 worker,内嵌 agent runtime | docker/docker-compose.yaml:63-74 |
| Provisioner | 8002 | K8s 沙箱模式下创建/销毁沙箱 Pod,带健康检查 | docker/docker-compose.yaml:117-146 |
后端进程内部分两层,依赖方向单向(app → deerflow,反向被 CI test_harness_boundary.py 拦截):
Components / Subsystems
Nginx —— 统一入口反向代理(:2026)
职责:单一对外端口,按路径把请求分流到 Gateway 或 Frontend,并保证 SSE/流式不被缓冲。
关键点:
- 用 nginx 变量
$gateway_upstream/$frontend_upstream在请求时解析 Docker 服务名,避免容器重启后上游 IP 失效 docker/nginx/nginx.conf:28-29。 - 全局关闭代理缓冲与缓存(
proxy_buffering off; proxy_cache off;),为流式响应铺路 docker/nginx/nginx.conf:32-33。 /api/langgraph/把前缀重写成/api/,配 600s 超时与chunked_transfer_encoding on支撑长跑 agent 与 SSE docker/nginx/nginx.conf:43-64。/api/sandboxes单独走provisioner:8002,用变量延迟解析,使得 Provisioner 容器未启动时 Nginx 仍能启动 docker/nginx/nginx.conf:196-205。- 兜底:其余
/api/走 Gateway,所有非 API 请求走 Frontend(带 WebSocket upgrade) docker/nginx/nginx.conf:209-239。
Frontend —— Next.js 界面(:3000)
职责:提供 Web 聊天界面。容器内通过 DEER_FLOW_INTERNAL_GATEWAY_BASE_URL=http://gateway:8001 直连后端,默认经 Nginx 同源访问。
关键点:BETTER_AUTH_SECRET 为前端会话安全必需项,由 compose 注入 docker/docker-compose.yaml:54-56。前端技术栈细节见第 28 章。
Gateway —— FastAPI 应用 + 内嵌 runtime(:8001)
职责:对外提供 REST API(models/mcp/skills/uploads/threads/runs 等)与 LangGraph 兼容的运行生命周期,并在同一进程内驱动 agent。
关键文件 / 关键点:
create_app()注册全部 router,并按顺序挂载AuthMiddleware(失败关闭式鉴权兜底)→CSRFMiddleware→ 可选CORSMiddlewarebackend/app/gateway/app.py:214-324。lifespan启动时先加载AppConfig,再用langgraph_runtime(app)上下文初始化全部 runtime 单例,然后做 admin 引导与 IM channel 启动 backend/app/gateway/app.py:160-211。langgraph_runtime()用AsyncExitStack依次构建 StreamBridge、持久化引擎、checkpointer、store、各 Repository、RunManager(store=...),挂到app.state上 backend/app/gateway/deps.py:41-97。- AuthMiddleware 对非公开路径强制校验 cookie+JWT,成功后把 user 写入
request.state.user与deerflow.runtime.user_contextcontextvar,供仓储层做属主过滤 backend/app/gateway/auth_middleware.py:52-70。鉴权与 CSRF 细节见第 14 章。
Agent Runtime —— RunManager / run_agent / StreamBridge
职责:把 HTTP 创建的"运行"登记、在后台异步执行 LangGraph 图、并把流式事件解耦推给 SSE 消费者。这是"内嵌 runtime"的核心,等价于 LangGraph Platform 的 Queue + StreamManager。
关键文件 / 关键点:
RunManager是带 asyncio 锁的内存运行登记表,可选挂RunStore持久化;create_or_reject()在锁内一次性完成 inflight 检查与插入,消除 TOCTOU,并支持reject/interrupt/rollback策略 backend/packages/harness/deerflow/runtime/runs/manager.py:42-53 manager.py:224-290。run_agent()在 asyncio task 里跑agent.astream(stream_mode=[...]),手动注入 runtime context(thread_id/run_id/app_config),按 abort 事件中断,异常时发error事件,finally 必发publish_endbackend/packages/harness/deerflow/runtime/runs/worker.py:120-134 worker.py:282-403。注意events模式在 Gateway 内不支持(需astream_events无法与 values 快照共存) worker.py:154-159。StreamBridge抽象类把生产者(worker)与消费者(SSE 端点)解耦:publish/publish_end/subscribe(支持Last-Event-ID重连与心跳哨兵) backend/packages/harness/deerflow/runtime/stream_bridge/base.py:37-69。deerflow.runtime包统一再导出 checkpointer/runs/store/stream_bridge 公共 API backend/packages/harness/deerflow/runtime/init.py:8-13。Runtime 与 StreamBridge 深入见第 15 章。
LeadAgent —— LangGraph 图入口
职责:被 langgraph.json 注册为图 lead_agent,根据运行配置动态选模型、装配中间件链、加载工具与系统提示。
关键点:make_lead_agent(config) 是 langgraph.json 指定的工厂入口 backend/langgraph.json:8-9 backend/packages/harness/deerflow/agents/lead_agent/agent.py:343-347;deerflow.agents 包导入时预热 enabled-skills 缓存以减少请求路径上的同步文件 IO backend/packages/harness/deerflow/agents/init.py:7-10。LeadAgent 与中间件链分别见第 10、12 章。
Provisioner —— 沙箱供应器(:8002,可选)
职责:仅在沙箱配置为 provisioner/Kubernetes 模式时启动;按 sandbox_id 在宿主 K8s 上创建 Pod + NodePort Service,backend 通过 {NODE_HOST}:{NodePort} 直连沙箱。
关键点:暴露 POST/DELETE/GET /api/sandboxes 与 /health;通过挂载的 ~/.kube/config 连宿主集群 docker/provisioner/app.py:11-30。compose 健康检查每 10s 探测 :8002/health docker/docker-compose.yaml:142-146。沙箱系统架构见第 17 章。
Data Flow
下图展示一次浏览器对话请求从输入到 SSE 流式返回的完整链路。
编号步骤说明:
1-2. 浏览器请求经 Nginx,/api/langgraph/ 前缀被重写为 /api/,并应用 600s 超时与关闭缓冲 docker/nginx/nginx.conf:43-64。
- AuthMiddleware 校验 cookie+JWT 并把 user 注入 contextvar backend/app/gateway/auth_middleware.py:52-70。
4-6. 路由层经 start_run 调 RunManager.create_or_reject() 登记运行并按多任务策略处理 inflight backend/packages/harness/deerflow/runtime/runs/manager.py:224-290;thread_runs router 是薄 HTTP 层,委托给 app.gateway.services backend/app/gateway/routers/thread_runs.py:22-28。
7-12. run_agent() 标记 running、发 metadata、用 agent.astream 驱动图,每个分块 serialize 后 publish 到 StreamBridge backend/packages/harness/deerflow/runtime/runs/worker.py:178-309。
13-15. SSE 帧经 Nginx 原样透传给浏览器;无论成功失败,finally 都 publish_end 并写最终状态、延迟 cleanup backend/packages/harness/deerflow/runtime/runs/worker.py:366-403。
Common Pitfalls / Tips
eventsstream_mode 在 Gateway 内不可用:它需要astream_events(),无法与values快照共存,worker 会记录日志并跳过。前端应使用values+messages-tuplebackend/packages/harness/deerflow/runtime/runs/worker.py:154-159。- CORS 默认同源:经 Nginx 2026 同源访问时无需 CORS;拆分前后端或端口转发时必须用
GATEWAY_CORS_ORIGINS显式 opt-in,CORSMiddleware 与 CSRFMiddleware 共用同一来源清单 backend/app/gateway/app.py:313-324。 - IM channels 走 SDK 而非内部直调:channels 通过
langgraph-sdkHTTP 客户端访问 Gateway;Docker compose 内localhost指向 gateway 容器自身,需用http://gateway:8001(DEER_FLOW_CHANNELS_GATEWAY_URL)docker/docker-compose.yaml:102-103。 - harness 不能 import app:
deerflow.*反向引用app.*会被 CI 的test_harness_boundary.py拦截;新代码若在 harness 内需要应用层能力,应通过依赖注入(如RunContext)传入 backend/app/gateway/deps.py:139-152。 - Provisioner 缺席不阻塞启动:Nginx 用变量延迟解析
provisioner:8002,本地/无 K8s 部署可不启动 Provisioner docker/nginx/nginx.conf:194-205。
References
- docker/docker-compose.yaml —— 定义 nginx/frontend/gateway/provisioner 四个 service 及其端口、卷、网络。
- docker/nginx/nginx.conf —— 路径路由与 SSE 透传规则,
/api/langgraph/*重写逻辑所在。 - backend/app/gateway/app.py —— FastAPI 应用工厂,中间件挂载顺序与 lifespan 启动流程。
- backend/app/gateway/deps.py ——
langgraph_runtime()装配全部 runtime 单例并挂到app.state。 - backend/packages/harness/deerflow/runtime/runs/manager.py —— 运行登记表 RunManager 与多任务并发策略。
- backend/packages/harness/deerflow/runtime/runs/worker.py ——
run_agent()后台执行图并向 StreamBridge 推流。 - backend/langgraph.json —— 图入口、checkpointer、auth 的注册声明。
Related Pages
| 页面 | 关系 |
|---|---|
| 09-Harness与App分层边界 | 深入本章提到的 harness/app 依赖方向与 CI 边界守卫 |
| 13-Gateway-API与路由体系 | 展开 Gateway 各 router 与 create_app() 路由全貌 |
| 15-Runtime运行时与StreamBridge | 详解 RunManager/run_agent/StreamBridge 的 SSE 与重连机制 |
| 17-沙箱系统架构 | 展开 Provisioner 与沙箱 Provider 的完整体系 |
| 10-LeadAgent与Agent工厂 | 深入 make_lead_agent 工厂与图构建 |