首页
/ Dify 的 CLAUDE.md / AGENTS.md:为 AI 编程代理编排大型 monorepo 的分层工程指南

Dify 的 CLAUDE.md / AGENTS.md:为 AI 编程代理编排大型 monorepo 的分层工程指南

2026-09-06 16:08:04作者:凌朦慧Richard

Dify 仓库根目录下的 CLAUDE.md 是一份写给 AI 编程代理(Claude Code 及其他遵循 AGENTS.md 约定的工具)看的"工程操作手册":它声明仓库构成、三条仓库级禁忌(gotchas)和前端工作流的引用入口。本文以该文档为核心,逐条结合仓库中真实存在的 Makefileapi/pytest.iniapi/pyproject.toml 和各级子目录 AGENTS.md 进行溯源与展开,读完后你可以完整掌握这套"根级 + 作用域级"分层代理指南是如何约束命令执行、测试策略与环境变量组织的,并能把它移植到自己的 monorepo 中。

1. CLAUDE.md 与 AGENTS.md:一个文件,两个入口

在仓库根目录下,CLAUDE.md 并不是一个独立文件,而是指向 AGENTS.md 的符号链接:

$ ls -la CLAUDE.md AGENTS.md
-rw-r--r-- 1 root root 995 AGENTS.md
lrwxrwxrwx 1 root root   9 CLAUDE.md -> AGENTS.md

这一做法的用意很直接:用同一份事实来源同时服务两类消费者——Claude 系工具读取 CLAUDE.md,而 Cursor、Codex 等遵循 AGENTS.md 约定的工具读取 AGENTS.md,二者永远一致,避免维护两份指南产生漂移。

根级指南全文非常短,只包含三部分:一段项目与仓库构成的总述、一节 Repository Gotchas(仓库级陷阱清单),以及一节 Frontend Workflow(前端工作流)。下面逐条拆解。

2. 仓库总述:六个一级子系统

根指南开宗明义地介绍了 Dify 是什么、这个 monorepo 里有什么:

Dify is an open-source platform for building LLM applications, agentic workflows, and RAG pipelines. This monorepo contains the backend API (api/), frontend application (web/), deployment assets (docker/), standalone agent backend (dify-agent/), CLI (cli/), and end-to-end suite (e2e/).

对照仓库实际目录结构,可以补全一张"地图",帮助任何代理(或新人)快速建立空间感:

路径 职责 关键证据
api/ Flask 后端 API,含 controllers/services/core/tasks/migrations/ api/AGENTS.md 中的架构边界约定
web/ Next.js 前端应用,i18n 资源位于 web/i18n/ web/AGENTS.md 的包契约
docker/ Docker Compose 部署资产与环境变量模板 docker/docker-compose.yamldocker/envs/
dify-agent/ 独立 Agent 运行时(Python) dify-agent/AGENTS.md
dify-agent-runtime/ 沙箱运行时(Go) Makefilebuild-sandbox-runtime
cli/ difyctl TypeScript CLI cli/AGENTS.md
e2e/ Cucumber + Playwright 端到端套件 e2e/AGENTS.md
packages/contracts/ 前后端共享的生成式 API 契约(@dify/contracts e2e/AGENTS.md 中"regenerate @dify/contracts"
sdks/nodejs-client/sdks/php-client/ 对外 SDK sdks/README.md

总述之后紧跟的是根指南最重要的一句路由规则:

Follow the nearest scoped AGENTS.md for the files being changed.(改动哪些文件,就遵循离它们最近的那份 AGENTS.md。)

从源码结构看,这套"就近路由"在当前仓库中对应的完整作用域文件集合为:

AGENTS.md                          # 根级
api/AGENTS.md
cli/AGENTS.md
cli/src/commands/AGENTS.md
dify-agent/AGENTS.md
e2e/AGENTS.md
e2e/features/agent-v2/AGENTS.md
packages/dify-ui/AGENTS.md
web/AGENTS.md
web/features/agent-v2/AGENTS.md

分层的收益在于:根级文件保持极小、不含易过时的细节;子级文件携带模块专属契约;代理按"改动路径"就能命中正确的约束集合,而不需要通读全部文档。

3. Gotcha 一:后端命令一律经由 uv run --project api

根指南的第一条 gotcha:

Run backend commands through uv run --project api <command>.

这句话的底层原因是 api/ 被隔离为一个独立的 Python 项目:它拥有自己的 api/pyproject.tomlapi/uv.lock。如果直接用系统解释器执行 python/pytest,依赖环境与版本都无法保证。因此所有后端工具链都必须经过 uv run --project api 前缀进入该项目的虚拟环境。

根级 Makefile 中的每个目标都严格践行了这条规则,可以直接复制使用:

  • 格式化make formatuv run --project api --dev ruff format ./api
  • 静态检查make checkuv run --project api --dev ruff check ./api
  • 完整 Lintmake lint → 依次执行 ruff format、ruff check --fix、Flask 响应契约 lint(api/dev/lint_response_contracts.py)、lint-imports 导入边界检查,以及 dotenv-linter ./api/.env.example ./web/.env.example——最后一步会校验前后端两份 .env.example 之间变量的一致性,这正是下一节环境变量策略的机器化保障
  • 类型检查make type-check./dev/pyrefly-check-local 加上 mypy,其中 mypy 显式排除了 conftest.pytests/migrations/ 与 swagger 生成脚本,并启用 --check-untyped-defs(见 Makefile
  • 开发环境一键搭建make dev-setup 串联三步——prepare-docker(从 docker/envs/middleware.env.example 复制出 docker/middleware.env 并启动 docker-compose.middleware.yaml 中间件)、prepare-web(复制 web/.env.exampleweb/.env.localpnpm install)、prepare-api(复制 api/.env.exampleapi/.envuv sync --devuv run flask db upgrade 升级数据库)(见 Makefile

4. Gotcha 二:集成测试是 CI-only,本地跑单测

第二条 gotcha:

Backend integration tests are CI-only and are not expected to run locally.

这条规则划清了本地与 CI 的验证边界,api/AGENTS.md 将其进一步细化为可执行命令:

make lint                                  # 格式化 + lint
make type-check                            # 类型检查
make test                                  # 单测
make test TARGET_TESTS=./api/tests/<path>  # 定向测试

并补充两条纪律:"Docker-backed integration suites are normally CI-owned"(Docker 支撑的集成套件归 CI 所有)、"Do not start long-running services as part of routine agent work"(常规代理工作中不要启动长驻服务)。

对照 Makefile 可以看清两条测试通道的实际差别:

  • make test(本地通道)uv run --project api --dev pytest -p no:benchmark --timeout "$${PYTEST_TIMEOUT:-20}" -n auto api/tests/unit_tests api/providers/vdb/*/tests/unit_tests api/providers/trace/*/tests/unit_tests --ignore=api/tests/unit_tests/controllers,随后单独跑 controllers 单测并追加覆盖。并行(-n auto)、默认单测超时 20 秒(可用 PYTEST_TIMEOUT 覆盖)。
  • make test-all(CI 通道):在上述基础上追加两段 Docker 套件——--start-middleware 启动中间件后运行 api/tests/integration_tests/{workflow,tools}api/tests/test_containers_integration_tests(超时升至 180 秒),以及 --start-vdb 运行 Chroma/pgvector/Qdrant/Weaviate 四个向量库的 smoke 测试。

单元测试的本地可运行性由 api/pytest.ini 保障:addopts 注入了覆盖率采集,env 段则预置了一批纯本地 mock 凭据(如 OPENAI_API_KEY = sk-IamNotARealKey...CODE_EXECUTION_ENDPOINT = http://127.0.0.1:8194PLUGIN_DAEMON_URL = http://127.0.0.1:5002),使单测无需任何真实外部服务即可执行。测试目录的物理分层也印证了这一点:api/tests/unit_tests/api/tests/integration_tests/api/tests/test_containers_integration_tests/(需要容器)三者并存,前两者可本地跑,后者 CI-only。

5. Gotcha 三:.env.example 的三层拆分策略

第三条 gotcha 是这份指南中最具信息量的一条:

Keep docker/.env.example limited to variables required for a default Docker Compose deployment to start. Put optional and provider-specific settings in the matching docker/envs/*.env.example file; docker/.env overrides those service-specific env files.

它规定了三条明确的分层规则:

  1. docker/.env.example 只保留"默认 Docker Compose 部署能启动"所必需的变量——保证最小部署面,避免一个巨型样例文件淹没真正的必填项;
  2. 可选变量与服务商专属变量下沉到 docker/envs/ 下按服务命名的 *.env.example 文件——仓库当前约有 37 份这样的分服务样例(如 docker/envs/postgres.env.example 一类的按服务拆分),中间件统一样例即 docker/envs/middleware.env.examplemake dev-setup 的复制源);
  3. 本地覆盖遵循固定优先级:docker/.env > 各服务专属 env 文件

这条约束还有机器化的守护者:make lint 会执行 dotenv-linter ./api/.env.example ./web/.env.example,防止前后端样例文件漂移;而 docker/docker-compose-template.yamldocker/docker-compose.middleware.yamldocker/generate_docker_compose 则说明 compose 文件是由模板/生成器统一产出的,进一步降低了多份 compose 之间环境变量失配的概率。

6. Frontend Workflow:把长规则放在可引用的独立文档里

根指南的最后一节只有两条,但体现了"根级指南不膨胀"的写法:

  • For truncated text disclosure and native title decisions, follow [Truncated Text Disclosure].

其引用目标 web/docs/truncated-text-disclosure.md 是一份自成一体的操作契约,核心结论值得摘录:

  • 原生 title可选的、补充性的产品行为,不是 truncate / line-clamp-* 的机械配套;缺少 title 本身不构成无障碍缺陷;
  • 动手前必须四步走:追踪取值到最终渲染的 DOM 元素 → 识别完整内容披露的既有 owner → 把候选分类为 AUTO / COVERED / SKIP / REVIEW只修改 AUTO 类候选,其余只报告不改码
  • AUTO 必须同时满足一组强条件(单行有界纯文本、无既有 Tooltip/Popover/"展开更多"等披露 owner、不与既有交互竞争等);含敏感信息、无界用户内容、ReactNode、会产生副作用表达式的一律 SKIP
  • 明确禁止:仓库级 missing-title lint 规则、批量自动迁移、ReactNode 转字符串助手函数;测试侧只允许在 title 是显式产品契约时断言它,不得用 getByTitle 来"证明迁移完成"。

此外,根指南总述中的六个子系统各自还有作用域文件可进一步下钻,例如 web/AGENTS.md(i18n 键、consoleQuery/consoleClient 生成式 API、Dify UI 组件契约、Next.js 代理规则块)、cli/AGENTS.mdDifyCommand 继承体系、pnpm tree:gen 命令树生成、基于真实 Hono mock server 的行为测试)、e2e/AGENTS.md(Cucumber 运行时所有权、标签语义如 @smoke/@unauthenticated/@axeE2E_ 前缀资源命名与 LIFO 清理注册)。这些子级指南共同构成了第 2 节"就近路由"规则的落点。

7. 这套分层指南的设计模式小结

CLAUDE.md 出发可以归纳出 Dify 仓库组织 AI 代理指南的几条可复用模式:

  1. 符号链接统一事实来源CLAUDE.md -> AGENTS.md,一份内容服务多个代理工具;
  2. 根级极简 + 就近路由:根级只写"全仓恒真"的最小集合(项目构成、3 条 gotchas、1 个引用),模块细节全部下沉到作用域 AGENTS.md,以"follow the nearest"为路由规则;
  3. 每条规则都有机器化对应物uv run --project api 对应 Makefile 目标;"集成测试 CI-only" 对应 make testmake test-all 的双通道;.env.example 三层拆分对应 dotenv-linter 与 envs 样例目录——规则不是口号,而是能被命令和 lint 守护的契约;
  4. 长规则外链化:像 Truncated Text Disclosure 这样的多页契约独立成文,指南内只留指针,避免根文件随时间膨胀失效。

对于同样使用 AI 编程代理的 monorepo 项目,这套"符号链接入口 → 根级最小集 → 作用域指南 → 命令/lint 守护"的结构,是一份低成本、可验证、可持续演进的参考实现。

登录后查看全文
热门项目推荐
相关项目推荐