跳到正文
码上手 coding.chengyu.dev

让代码库对智能体友好

智能体的上限,往往由代码库的可读性和反馈速度决定。本课讲一键可跑的脚本、小而快的反馈回路、类型系统、目录与命名、文档就近、AGENTS.md 与 CLAUDE.md 的分工,以及如何用「新员工测试」量化你的代码库。

约 30 分钟 高级 通用Claude CodeCodexCursor 核实于 2026-10-25

学完这一课,你能

  • 能把「新同事入职」标准用在代码库上,找出让智能体反复出错的结构性原因
  • 能设计一条命令跑完全部检查,并让反馈足够快、足够短
  • 能用类型、目录、命名和就近文档降低智能体的探索成本
  • 能在 AGENTS.md 与 CLAUDE.md 之间做合理分工,并为大型仓库做分层配置

同一个智能体,同一个模型,放进两个仓库,表现可以天差地别。A 仓库里,它读完说明文件,跑一条命令确认基线是绿的,改完再跑一遍,十分钟交付。B 仓库里,它不知道测试怎么跑,试了三种命令都失败,在一个四千行的 utils.js 里迷路,最后改了不该改的文件。

差别在代码库,不在智能体。我习惯用一个比喻:智能体是一位每二十分钟入职一次、没有任何记忆的新同事。 对新同事友好的仓库,对智能体也友好;而且智能体对「不友好」的容忍度更低,它不会去茶水间问人。

这一课把「友好」拆成可以动手改的几件事。

一、一条命令跑完所有检查

先问一个问题:一个陌生人 clone 下来,不问任何人,能不能在五分钟内知道怎么跑、怎么测、怎么检查?

智能体需要的是一个确定的入口。Anthropic 在长时任务的 harness 文章里,让初始化智能体专门生成 init.sh:它启动开发服务器,这样后续每个会话就不必再花 token 去琢磨如何跑起应用。你的仓库也该有:

{
  "scripts": {
    "dev": "vite",
    "typecheck": "tsc --noEmit",
    "lint": "eslint .",
    "test": "vitest run",
    "verify": "npm run typecheck && npm run lint && npm test"
  }
}

要点:

  • verify 一条命令,退出码 0 即通过。智能体不用记三条命令的顺序,Stop Hook 和 CI 也能共用它。
  • 环境可复现:提供 .env.example,依赖服务用 docker compose up -d 或开发容器起来。测试依赖「某人电脑上的数据库」,智能体永远修不好。
  • 输出要克制:成功时尽量安静,失败时直接指出哪个文件哪一行。官方成本文档里有个例子:用 Hook 把测试输出过滤成只剩失败项,上下文占用从几万 token 降到几百。
  • worktree 友好:并行会话常用 git worktree,被忽略的文件(.env、本地配置)不会自动带过去。Claude Code 支持在 .worktreeinclude 里声明要复制的被忽略文件。

二、小而快的反馈回路

智能体的工作方式是「改一点,验证一下」。反馈每慢十倍,它能尝试的次数就少十倍,或者你得等十倍的时间。

层 目标耗时 做法
单个文件的测试 几秒 支持按文件、按用例名运行,并写进说明文件
类型检查 十几秒内 增量编译,必要时按包分别检查
完整 verify 几分钟以内 并行、缓存;重量级测试分到独立命令
端到端 分钟级 只在任务收尾时跑

最有杀伤力的是不稳定的测试。一个偶发失败的测试,会让智能体无法区分「我改坏了」和「它本来就会抖」,于是要么反复重试浪费上下文,要么得出错误结论。对智能体友好的第一步,常常是先修掉最抖的那几个测试,或者隔离并标注它们。

三、类型系统:机器可检查的规格

类型是最便宜的验证,也是最好的导航。智能体改动一个函数签名,类型检查会立刻告诉它所有受影响的调用点,不需要靠 grep 碰运气。

  • 开启严格模式(TypeScript 的 strict、Python 的 pyright/mypy 严格配置),先从新代码和核心模块做起。
  • 在系统边界用运行时校验补上类型(如 zod、pydantic),因为外部输入不受类型系统保护。
  • 对强类型语言,装上代码智能插件。官方文档指出,它让智能体通过语言服务器做「跳转到定义」「查找引用」,一次调用替代一轮 grep 加多个候选文件的阅读,改完代码后还会自动报告类型错误。
  • 动态语言项目也不是没救:补类型注解、写清楚数据结构的 schema,本身就是在给智能体提供「别猜」的依据。

四、目录、命名与文件大小

Anthropic 在上下文工程的文章里提到,文件夹层级、命名约定、时间戳这些元数据,是智能体即时检索时判断相关性的线索。换句话说,命名就是索引。

  • 可预测的结构:同类东西放同一位置(src/orders/、src/orders/refund.test.ts),智能体新增功能时能凭已有模式推断落点。
  • 可 grep 的名字:避免 utils2.js、helper.ts、data.py 这种名字;函数名要独特到搜得出来,别让十个文件都有一个叫 handle 的函数。
  • 隔离噪声:生成物、构建产物、vendored 代码不要让智能体读。搜索默认遵循 .gitignore;已提交的生成代码,用 Read 拒绝规则挡掉,例如 Read(./**/dist/**/*)。
  • 控制文件体量:几千行的巨型文件读一次就吃掉一大块上下文。多大算大,没有标准,我的经验是超过一两千行就值得拆,但要按「职责」拆,不要为了行数硬切。

五、文档就近:写在被读到的地方

给智能体的文档,核心是在它需要的时候出现,且不占不需要的时候的上下文。

  • 根目录一份,子目录各一份。Claude Code 会加载工作目录及所有上级目录的 CLAUDE.md,子目录里的则在智能体读到该目录文件时按需加载。Codex 则是从仓库根目录一路向下合并到当前目录,每个目录最多取一个文件。两者思路相同:规则靠近代码。
  • 写 why,不写 what:代码已经说明了做了什么;说明文件应该记录那些读代码读不出来的东西,比如「这里不能用事务,因为……」「金额必须是整数分」。
  • 架构决定记录(ADR):一个决定一篇短文,写背景、选择、被放弃的方案。智能体最容易「好心」重构掉你有意为之的设计,ADR 是最好的挡箭牌。
  • 文档要有人维护:过期的文档比没有更糟。官方建议把对说明文件的修改当成普通 PR 评审;也可以用 Stop Hook 让智能体在会话结束时提出说明文件的更新建议。

六、AGENTS.md 与 CLAUDE.md 怎么分工

多款工具各有自己的规则文件,维护多份会走样。当前的局面是:

工具 读什么 说明
Claude Code CLAUDE.md;仅当没有任何 CLAUDE.md 时才读 AGENTS.md(v2.1.277 起) 两者都有时只读 CLAUDE.md,除非 CLAUDE.md 里用 @AGENTS.md 导入
Codex AGENTS.md(含 ~/.codex/AGENTS.md 全局文件) 默认合并上限 32 KiB;同目录可用 AGENTS.override.md 覆盖
Cursor AGENTS.md,或 .cursor/rules/ 下的 .mdc 规则 官方建议单条规则不超过 500 行;规则可用 globs 按文件范围附加

我的建议是以 AGENTS.md 为唯一正文,其余文件做薄薄一层:

<!-- CLAUDE.md -->
@AGENTS.md

## Claude Code 专属
- 改完一批代码后运行 `npm run verify`,通过后再汇报
- 压缩时保留已修改文件清单和最近一次失败的测试输出

这样 Codex、Cursor 读的是 AGENTS.md,Claude Code 通过导入读到同一份内容,只有 Claude 才有的约定放在 CLAUDE.md 里。注意导入的内容和主文件一样占用上下文,所以正文仍要精简;真正只有部分目录才需要的规则,放进子目录的说明文件或带 paths: 的规则里。

大型仓库还有几个官方提供的杠杆:从子目录启动智能体只会加载该目录及上级的说明文件;claudeMdExcludes 可以跳过无关团队的说明文件;worktree.sparsePaths 让并行会话只检出需要的目录。

七、护栏:把「文档里的规矩」变成机器检查

写在文档里的规则是建议,写进检查里的才是规则。每当评审里第三次出现同一条意见,就该把它自动化:

  • 格式化与 import 排序:编辑后 Hook 或 pre-commit;
  • 「不能直接改生成文件」:PreToolUse Hook 退出码 2 拦截,或权限规则;
  • 架构边界(路由层不许直接写 SQL):用 lint 规则或依赖检查工具;
  • 让报错信息教智能体怎么改:自定义 lint 规则的错误文案,写成「这里应调用 queries/ 下的函数,见 docs/db.md」,智能体读到报错就知道该怎么修,比文档更可靠。

量一量:新员工测试

怎么知道你的仓库友不友好?别凭感觉,做个测试:开一个全新的会话,只允许它读仓库里已有的文档,让它从零开始跑通构建与测试,并实现一个很小的功能,记录它每一次卡壳。

代码库友好度体检(新员工测试) Claude Code

请扮演第一天入职的工程师,对本仓库做一次「新员工测试」。

规则:只能使用仓库里已有的 README、AGENTS.md、CLAUDE.md 和代码本身,不要问我任何问题,不要修改任何文件。

任务:

  1. 弄清楚如何安装依赖、启动项目、运行单个测试、运行全部检查,把你最终成功的命令列出来;
  2. 回答:新增一个同类的接口或模块,应该放在哪个目录,参考哪个现有实现;
  3. 找出一个你认为最容易被改坏的地方,并说明仓库里有没有保护它的测试或文档。

每次卡壳(命令失败、文档与现实不符、找不到入口、不知道约定)都记录下来:发生在哪一步、浪费了多少次尝试、缺少什么信息。

最后输出一张「摩擦清单」,按修复成本从低到高排序,每项给出建议的修法(补一行文档、加一个脚本、修一个测试、拆一个文件)。

摩擦清单里的前五项,通常就能带来比换更贵的模型更明显的提升。做完修复再测一次,数字变化就是你的收益。

小测

一个仓库同时有 AGENTS.md 和 CLAUDE.md,但 CLAUDE.md 里没有任何导入语句。Claude Code 默认会读取哪些内容?

小测

时间有限,只能改善代码库的一件事来提升智能体的表现。下面哪一项通常收益最大?

动手清单

0/5

延伸阅读:CLAUDE.md 与记忆、Hooks 自动化、实战:搭建项目脚手架。最后一课把这些放到团队尺度:团队落地。

参考来源

工具更新很快,若与官方文档不一致,以官方为准。

学完了吗?

标记完成会记录在本机浏览器,计入你的学习进度和连续天数。

Esc

输入关键词开始搜索,例如「CLAUDE.md」「MCP」「部署」