本文基于 DeerFlow 开源项目(bytedance/deer-flow)2026 年 4 月的最新架构重构,分析其后端从
backend/src/单体结构拆分为packages/harness/deerflow/(框架层)+app/(应用层)的设计意图、实现方式和工程收益。
背景:一个 AI Agent 后端的成长烦恼
DeerFlow 是字节跳动开源的 LangGraph-based AI Agent 系统,支持多工具调用、沙箱执行、MCP 协议集成、技能系统等能力。在早期版本中,所有后端代码都放在backend/src/下,用from src.*统一引用:
backend/ └── src/ ├── agents/ # Agent 编排、middleware、memory ├── models/ # LLM 模型工厂 ├── tools/ # 工具注册 ├── sandbox/ # 沙箱执行 ├── skills/ # 技能加载 ├── mcp/ # MCP 协议 ├── gateway/ # FastAPI REST API ├── channels/ # IM 渠道集成 └── client.py # 嵌入式 Python SDK这个结构在项目初期没有问题,但随着功能膨胀,三个痛点逐渐暴露:
痛点一:复用不可能。如果你想写一个 CLI 工具或 Slack Bot 来调用 DeerFlow 的 agent 能力,你必须把整个src/拉进来——包括 FastAPI、uvicorn、lark-oapi(飞书 SDK)、slack-sdk 这些完全不需要的依赖。client.py(DeerFlowClient SDK)的存在就是这个需求的直接体现,但它被困在了一个包含 Web 框架的包里。
痛点二:依赖方向混乱。client.py本应属于框架层,但它反向 import 了src.gateway.routers.skills和src.gateway.routers.uploads中的函数。框架层依赖了应用层——这是典型的架构腐化信号。
痛点三:LangGraph Server 被迫安装多余依赖。LangGraph Server 只需要跑 agent,但因为src/是一个整体,它必须安装 FastAPI、Slack SDK、飞书 SDK 等完全无关的包。
拆分方案:Harness + App
DeerFlow 团队的解法是把后端拆成两部分:
Harness(线束/框架层)
回答"如何构建和运行 agent"的问题。它是一个可独立发布的 Python 包(deerflow-harness),包含:
- Agent 工厂与生命周期管理
- Middleware pipeline
- 工具系统(内置 + MCP + 社区工具)
- 沙箱执行环境
- 子 agent 委派
- 记忆系统(memory、task memory、tool memory)
- 技能加载与注入
- 模型工厂
- 配置系统
- 嵌入式 Python 客户端(DeerFlowClient)
核心设计原则:对上层应用完全无感知。它不知道也不关心谁在调用它——可以是 Web App、CLI、Slack Bot、或者一个单元测试。
App(应用层)
回答"如何将 agent 呈现给用户"的问题。它不打包、不发布,是项目内部的应用代码:
- Gateway API(FastAPI REST 接口)
- IM Channels(飞书、Slack、Telegram、Discord、微信、企业微信)
- 自定义路由(模型管理、告警分析等)
App 依赖 Harness,但 Harness 绝不依赖 App。
拆分后的目录结构
backend/ ├── packages/ │ └── harness/ │ ├── pyproject.toml # deerflow-harness 包定义 │ └── deerflow/ # import 前缀: deerflow.* │ ├── agents/ # Agent 工厂、middleware、memory │ │ ├── lead_agent/ │ │ ├── middlewares/ # 20+ 中间件 │ │ ├── memory/ # 记忆系统 │ │ └── checkpointer/ │ ├── models/ # LLM 模型工厂 │ ├── tools/ # 工具注册与发现 │ ├── sandbox/ # 沙箱执行环境 │ ├── skills/ # 技能加载 │ ├── mcp/ # MCP 协议 │ ├── community/ # 社区工具(tavily、exa、jina...) │ ├── config/ # 配置系统 │ ├── runtime/ # StreamBridge、RunManager、Store │ ├── guardrails/ # 工具调用授权 │ ├── tracing/ # Langfuse 追踪 │ └── client.py # DeerFlowClient SDK │ ├── app/ # 不打包(import 前缀: app.*) │ ├── gateway/ │ │ ├── app.py # FastAPI 入口 │ │ ├── deps.py # LangGraph runtime 依赖注入 │ │ └── routers/ # REST API 路由 │ └── channels/ # IM 渠道集成 │ ├── pyproject.toml # uv workspace root ├── langgraph.json └── tests/工程实现:uv Workspace
这次拆分的技术基础是uv workspace(类似 npm workspaces / Cargo workspaces 的 Python 版本)。
Workspace Root(backend/pyproject.toml)
[project] name = "deer-flow" version = "0.1.0" dependencies = [ "deerflow-harness", # 依赖 harness 包 "fastapi>=0.115.0", # App 层的依赖 "uvicorn[standard]>=0.34.0", "slack-sdk>=3.33.0", "lark-oapi>=1.4.0", # ... 其他 App 层依赖 ] [tool.uv.workspace] members = ["packages/harness"] # 声明 workspace 成员 [tool.uv.sources] deerflow-harness = { workspace = true } # 本地引用Harness 包(packages/harness/pyproject.toml)
[project] name = "deerflow-harness" version = "0.1.0" description = "DeerFlow agent harness framework" dependencies = [ "langgraph>=1.0.6,<1.0.10", "langchain>=1.2.3", "langchain-openai>=1.1.7", "tavily-python>=0.7.17", "tiktoken>=0.8.0", # ... 纯 agent 框架依赖,没有 FastAPI/IM SDK ] [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = ["deerflow"] # wheel 中只包含 deerflow/ 目录关键点:
deerflow-harness是一个真正的 Python 包,有独立的pyproject.toml,可以被pip install,未来可以发布到 PyPI。- App 层故意不打包。它没有
pyproject.toml,通过PYTHONPATH=.让 Python 找到app.*即可。因为 App 的唯一消费者是 DeerFlow 项目自身,没有独立发布需求。 - 依赖分离是真实的。Harness 的依赖列表里没有 FastAPI、uvicorn、Slack SDK;App 的依赖列表里没有 tavily-python、tiktoken。
Import 规则
两层使用不同的 import 前缀,职责边界一目了然:
# Harness 内部互相引用fromdeerflow.agentsimportmake_lead_agentfromdeerflow.modelsimportcreate_chat_modelfromdeerflow.configimportget_app_config# App 内部互相引用fromapp.gateway.appimportappfromapp.channels.serviceimportstart_channel_service# App 调用 Harness(单向依赖)fromdeerflow.agentsimportmake_lead_agentfromdeerflow.skillsimportload_skills# ❌ 禁止方向:Harness 绝不能 import App# from app.gateway.routers.skills import xxx ← 这在拆分前存在,现在被消除了LangGraph Server 配置
{"graphs":{"lead_agent":"deerflow.agents:make_lead_agent"},"checkpointer":{"path":"./packages/harness/deerflow/agents/checkpointer/async_provider.py:make_checkpointer"}}LangGraph Server 只需要 harness 包,不需要加载 App 层代码。
拆分前的"手术":解除反向依赖
在物理拆分之前,需要先解决client.py中两处从框架层到应用层的反向依赖:
问题 1:client.pyimport 了src.gateway.routers.skills._validate_skill_frontmatter
解决:提取到deerflow/skills/validation.py。这是一个纯逻辑函数(解析 YAML frontmatter、校验字段),与 FastAPI 无关。
问题 2:client.pyimport 了src.gateway.routers.uploads.CONVERTIBLE_EXTENSIONS和convert_file_to_markdown
解决:提取到deerflow/uploads/manager.py。仅依赖markitdown+pathlib,是通用工具函数。
这两步"手术"是拆分的前置条件——不解除反向依赖,物理拆分就无法完成。
实际收益
1. DeerFlowClient SDK 成为一等公民
fromdeerflow.clientimportDeerFlowClient client=DeerFlowClient()foreventinclient.stream("帮我分析一下这篇论文"):print(event)任何 Python 项目只需pip install deerflow-harness,就能嵌入式使用 DeerFlow 的全部 agent 能力——不需要启动 Web 服务器,不需要安装 FastAPI。
2. 部署拓扑简化
Gateway 内置了 LangGraph Runtime(StreamBridge、RunManager、checkpointer、store),不再需要外部的langgraph-cli进程。部署从三进程(nginx + langgraph-cli + gateway)简化为两进程(nginx + gateway)。这在下一篇文章中详细展开。
3. 依赖体积缩减
LangGraph Server 运行时只安装 harness 的依赖,不再被 FastAPI、IM SDK 污染。对于容器化部署,这意味着更小的镜像体积和更快的启动速度。
4. 下游定制更友好
如果你 fork 了 DeerFlow 做定制(比如加多用户隔离、加自定义路由),你的定制代码自然地分布在两层:
- 框架级定制(如 db 模块、通知系统)放在 harness 层
- 产品级定制(如管理后台路由、告警 API)放在 app 层
未来上游更新 harness 层时,app 层的路由基本不会被冲突影响。
5. 为插件化铺路
不同的 app(Web、CLI、Bot)可以各自独立,都依赖同一个 harness。如果 harness 继续增长,还可以进一步拆出deerflow-sandbox、deerflow-mcp等子包。
迁移实操要点
如果你也在维护一个类似的 AI Agent 后端,想做类似的拆分,以下是几个关键注意事项:
- 先解除反向依赖,再做物理拆分。用 grep 扫描所有从框架层到应用层的 import,逐个提取到框架层。
config.yaml中的use字段也要更新。DeerFlow 的工具、沙箱、模型都通过use: deerflow.sandbox.local:LocalSandboxProvider这样的字符串动态加载,路径从src.*改为deerflow.*。- 测试中的
sys.path问题。用 editable install(uv sync)确保deerflow可导入,conftest.py中添加app/到sys.path。 - 全局 rename 要精确。正则匹配
\bsrc\.而不是简单替换src,避免误伤字符串中的src。
总结
DeerFlow 的 Harness/App 拆分不是为了拆而拆,而是解决了一个 AI Agent 项目在成长过程中必然遇到的问题:agent 能力如何从 Web 应用中解耦出来,成为可独立复用的基础设施。
uv workspace 提供了 Python 生态中相对成熟的 monorepo 方案,配合 hatchling 的 wheel 构建,让"框架包 + 应用代码"的分层在工程上可落地。这个模式值得所有正在构建 AI Agent 平台的团队参考。