仓库即规范:当 AI 成为同事,你的代码库必须学会“说话”
仓库即规范:当 AI 成为同事,你的代码库必须学会“说话”
1. 一个让人不安的实验
OpenAI 做过一个实验:3 个工程师,5 个月,从零开始构建一个超过 100 万行代码的产品。整个过程中,没有一行代码是人手写的 。
这不是“AI 写代码”的简单故事。真正的信息藏在细节里:早期进展极其缓慢。不是因为 Codex 的编码能力不行,而是因为它不知道规矩。它不知道项目的依赖结构,不理解架构约束,无法验证自己的产出是否正确。它写出代码,但经常违反设计原则——然后人就得反复 review、反复解释“为什么不能这么做” 。
这和新人入职的体验一模一样:能力没问题,但不了解组织的规矩。
OpenAI 团队最终意识到:问题不在模型,而在环境。他们把大量精力花在一件事上——把规矩写下来,让机器能读懂。架构约束被编码成自定义 Linter 规则,CI 自动拒绝违规代码;一份约 100 行的 AGENTS.md 充当“地图”,告诉 Agent 去哪找关键信息;每个 git worktree 启动独立的应用实例,Agent 通过 Chrome DevTools Protocol 直接验证 UI 。
这个实验的背后,是一条对 AI 时代软件工程影响深远的原则:对 AI 智能体而言,不存在于仓库里的信息,就等于不存在。
OpenAI 把它称为 “repo as spec” ——仓库本身就是最高权威的规格文档 。Anthropic 关于长时运行 Agent 的文档也指向同一结论:持久化状态是长任务连续性的必要条件,而这种状态必须存在于仓库中,因为那是 Agent 唯一稳定、可可靠访问的存储 。
2. 为什么“仓库即规范”是第一性原理
2.1 一个 Agent 到底能看到什么?
要理解这件事,不需要懂 Transformer 或注意力机制。只需要问一个简单的问题:Agent 的信息来源有哪些?
答案只有三个 :
- 系统提示词与任务描述:会话启动时注入的一次性上下文。
- 仓库文件内容:Agent 通过工具读取到的所有文件。
- 工具执行输出:运行命令、读取目录、搜索文件后返回的结果。
就是这些。没有更多。
Slack 里的历史消息、Jira 里的工单、Confluence 的页面、上周五下午你和同事在茶水间敲定的架构决策——Agent 全部看不见。它不能“找人问一下”,也不能“翻聊天记录”。它的整个工作宇宙就是仓库本身 。
用一个不太精确但足够直观的比喻:Agent 就像一个被锁在仓库里的工程师。仓库外面发生的一切,对它来说都不存在。
2.2 人类 vs Agent:隐性知识的代价差异
人类工程师面对“信息不在仓库里”的情况,有一套成熟的应对机制:问同事、翻聊天记录、凭经验猜、在错误中学习。
这套机制效率不高,但能用。而且人类有一种 Agent 永远不具备的能力——耳濡目染。你在一个团队待久了,会不知不觉吸收很多“没人明说”的规矩:代码风格、命名习惯、哪些做法“虽然能跑但会被骂”。
Agent 没有这种能力。OpenAI 团队的描述极其精准:“你没写下来的规矩,它永远不知道。” 一个没有被规范约束的 Agent,会以机器的速度、全天候地重复同样的错误。每一次都犯,因为没有任何机制让它“学会” 。
这就是“跳过文档”的代价在 Agent 时代被急剧放大的原因:人类犯错是慢的、分散的、有社会压力的;Agent 犯错是快的、集中的、无反馈的。
2.3 从“多写文档”到“把信息放对位置”
听到“仓库即规范”,很多人的第一反应是“那我要多写文档”。但这不是问题所在。
真正的问题是:把决策信息放到正确的位置。
一个放在 src/api/ 目录里、只有 50 行的 ARCHITECTURE.md,远比 Confluence 里一份 500 页、没人维护的设计文档有用 。为什么?因为邻近性比篇幅更重要。信息只有在“恰好需要的那一刻就在手边”才真正有用。
这就像一张贴在办公桌上的手绘地图,比一份锁在档案柜里的精美建筑图纸更实用。前者简陋,但你随时能看到;后者专业,但在你需要的时候找不到。
3. 信息可见性缺口:看不见的杀手
3.1 定义一个关键指标
如果我们接受“仓库即规范”是目标,就需要一个度量标准来衡量现状与目标之间的差距。
Knowledge Visibility Gap(知识可见性缺口) :项目中没有存在于仓库里的知识占比 。
这个指标越大,Agent 的失败率越高。因为 Agent 会在信息不完整的情况下做决策,而它的决策依据是你仓库里有什么,不是“大家都知道什么”。
3.2 冷启动测试
怎么知道自己仓库的“地图”画得够不够好?有一个极其简单但有效的测试:冷启动测试。
打开一个全新的 Agent 会话,只给它仓库内容,看它能否回答以下五个基本问题:
- 这个项目是做什么的? 核心目标是什么?
- 如何运行和测试? 构建、测试、部署的命令是什么?
- 代码组织原则是什么? 各目录的职责划分?
- 关键的架构约束有哪些? 哪些事绝对不能做?
- 当前的状态和未完成的工作是什么? 下一步该做什么?
如果 Agent 能回答这五个问题,你的“地图”基本完整。如果回答不了,地图上有空白。而地图上空白的地方,Agent 会开始猜。
猜错的代价是什么?变成 Bug。猜太多的代价是什么?浪费上下文预算。而且,每一个新会话都会重新猜一遍 。
3.3 发现成本与知识衰减
两个相关概念值得牢记:
Discovery Cost(发现成本) :Agent 为了找到一条关键信息,燃烧了多少上下文预算。信息藏得越深,发现成本越高,留给实际任务的预算越少。把关键信息埋在十层目录之下,就像把灭火器锁在地下室的保险柜里——它存在,但你需要的时候找不到 。
Knowledge Decay Rate(知识衰减率) :单位时间内知识条目过时的比例。与代码不同步的文档,比没有文档更危险。 因为它会让 Agent 以为自己知道,然后按照错误的方向行动 。
4. 地图而非手册:仓库的结构设计
4.1 为什么“大而全”的指令文件会死
直觉上,我们倾向于把规范写得越详细越好。但巨型指令文件有三个死因 :
- 挤占上下文:宝贵的 token 被用来堆文档,而不是处理任务。
- 无法维护:一处变更需要在多个地方同步,迟早出现版本漂移。
- 无法验证:模型“承诺”了但不会真正强制执行,写了等于没写。
OpenAI 的经验总结成一句话:给地图,不给百科全书。
4.2 AGENTS.md 的正确形态
AGENTS.md(或 CLAUDE.md)应该是 Agent 的目录页,不是操作手册。大约 100 行就够。它的职责是告诉 Agent:去哪找什么 。
一个典型的结构长这样 :
├── AGENTS.md # 入口:项目概览、运行命令、硬约束
├── src/
│ ├── api/
│ │ ├── ARCHITECTURE.md # API 层架构决策
│ │ └── AGENT.md # API 层的局部规则
│ └── database/
│ └── AGENT.md
├── specs/
│ ├── constitution/ # 长期约束
│ ├── active/ # 当前实现计划
│ └── research/ # 未决探索
└── Makefile # 标准化命令:setup, test, lint, check
核心思想是渐进式披露:入口文件指向更深的文档,Agent 按需深入,而不是一次性吞下所有信息 。
4.3 一个反面案例
以下是 AGENTS.md 中常见的反面写法:
# 项目规范
## 代码风格
- 使用 2 空格缩进
- 函数名用 camelCase
- 组件名用 PascalCase
- 常量用 UPPER_SNAKE_CASE
## 架构约束
- 不要跨层调用
- 不要直接操作数据库
- 不要在生产环境打印敏感信息
...(此处省略 500 行)
问题在哪?这些规则大部分不应该写在文档里,而应该被写成 Linter 规则。 文档里的“不要”是建议,Linter 里的“不要”是法律 。
5. 从文档到约束:机械化执行的力量
5.1 语言承诺的脆弱性
“请注意不要修改生产配置”——把这句话写在 prompt 里,模型大概率会遵守。直到某一次不遵守,造成严重事故。
语言承诺的可靠性远低于代码约束的可靠性。
这不是对模型的不信任,而是对概率系统的正确认知。LLM 生成代码的过程是概率性的——每个 token 都是采样出来的。你不能用概率系统去执行确定性约束 。
5.2 机械化执行的三层架构
正确的做法是把约束从“文档里的建议”转化为“代码层的自动检查”:
第一层:自定义 Linter 规则
OpenAI 团队设计了严格的依赖方向——Types → Config → Repository → Service → Runtime → API——然后把这个约束编码成 Linter 规则。CI 自动拒绝违反规则的代码。不需要在 code review 里口头传达“我们这里不允许跨层调用” 。
关键在于:Lint 错误信息里要内嵌修复指令,让模型看到错误后能自我纠正 :
Error: service/user.ts missing @injectable decorator
Fix: Add @injectable() above the class definition
See: docs/patterns/di.md#injectable
第二层:结构测试
验证关键不变量:API 响应格式是否符合预期、数据库 schema 是否一致、依赖图是否没有循环。这些测试由 Agent 运行,输出确定性的通过/失败信号。
第三层:反馈回路嵌入执行循环
测试、类型检查、浏览器端到端验证要嵌入 Agent 的执行循环内部。Agent 每生成一段代码就自动验证,不通过就自动修复再跑,直到通过为止 。
IBM Research 的数据让这一点更具体:纯 LLM 代码审查只能捕获约 45% 的错误;LLM 和确定性分析工具结合之后,这个数字跳到了 94% 。
5.3 约束不会腐烂
文档会腐烂,因为没人检查它是否还与代码一致。Linter 规则不会腐烂,因为 CI 每次运行都会验证。
一条写在文档里的规则,需要人类去记得、去遵守、去检查。一条 Linter 规则,需要的是 CI 管道跑一次。后者的可靠性高出一个量级,而成本在长期来看更低。
6. 规格驱动开发:把“为什么”写进仓库
6.1 一个让决策不蒸发的框架
“仓库即规范”不只是关于约束和检查,还关乎一件更根本的事:决策为什么会消失,以及如何让它们不消失。
大多数团队的决策过程是这样的:Slack 里讨论 → 达成共识 → 有人写代码 → 代码合入。半年后,有人问“为什么当初选了 PostgreSQL 而不是 MongoDB”,没人记得清楚。于是重新讨论,重新争论,可能得出不同结论 。
规格驱动开发(Spec-Driven Development)的解决思路很简单:让决策留下痕迹 。
6.2 层级结构
一个可操作的层级结构是这样的 :
Repo(应用——永久持续)
└─ Project(一波工作:“MVP”、“v2”、“重设计”)
└─ Stage(一个连贯的块,每个项目 2-5 个)
└─ Spec(一个可实现的任务)
└─ Cycle(Frame → Design → Build → Verify → Ship)
关键点在于:架构、约定、约束、决策存在于 Repo 层级,而不是任何一个任务内部。 在构建 MVP 时做出的决策——“所有日志走一个模块”——被写成一条 DEC-* 记录,18 个月后开始 v2 时它仍然在那里,仍然具有约束力 。
6.3 五阶段循环
每个任务是一个 Spec,经过五个阶段 :
- Frame:为什么存在,以及“完成”的定义是什么。
- Design:方法和权衡;非平凡的选择变成正式决策记录。
- Build:按照 Spec 实现。
- Verify:验收标准满足,测试通过,与过往决策没有漂移。
- Ship:反思,总结成本,归档。
其中 Verify 阶段尤其重要,因为“漂移是沉默的”:代码可以悄无声息地违背一条没人重读的决策。所以这个阶段的一个标准命令是:“哪些过往决策管辖了这次变更触及的文件?”
7. 当仓库不再够用:多仓库场景的策略
7.1 一个真实的问题
如果项目是前后端分离的两个仓库,Specs 应该放在哪里?这是一个架构决策,不是细节问题 。
7.2 两种策略
策略一:中心化 Specs 仓库
即使代码分散在多个仓库,创建一个“设计 Monorepo”来集中存放 Specs、API 契约、架构图和业务规则。Agent 在本地工作区中看到统一的上下文,前端 Agent 可以直接读到后端 API 的 Spec,避免“电话传话”效应 。
策略二:每个仓库独立 Specs
每个仓库有自己的 Specs 和 Agent 配置。适合团队完全独立、Agent 高度专业化(一个只生成 React 组件,一个只生成 Node 端点)的场景。挑战在于:前端 Agent 会自动失去对后端契约变更的可见性,需要 CI/CD 管道自动同步 Specs 。
7.3 建议
考虑到 SDD 的核心是“Agent 基于 Spec 文件做决策”,中心化策略通常效果更好。维护一个统一的 Spec 根目录,简化了 Agent 的 context pinning——不需要配置 Agent 去多个 GitHub 仓库搜索引用,只需指向本地工作区的根目录 。
8. 未解之题与争议
8.1 两个阵营的真实分歧
行业里对这个方向有真实的分歧,不是“所有人都同意”的虚假共识 。
“重 Harness”阵营的证据不少:OpenAI 的 100 万行实验、Stripe 每周通过 Minions Agent 合并 1000+ 个 PR、LangChain 只优化 Harness 不换模型就在 Terminal Bench 2.0 上从 52.8% 升到 66.5% 。
“信任模型”阵营同样有道理。Anthropic 的 Claude Code 团队明确表示设计哲学是“模型之上尽可能薄的包装层”。OpenAI 研究员 Noam Brown 说过,为较弱模型构建的复杂脚手架,会被更强的模型替代 。
8.2 三个值得认真对待的问题
问题一:正确性如何验证? Martin Fowler 指出,OpenAI 的文章缺少对实际行为正确性的验证——100 万行代码跑起来到底对不对?
问题二:遗留代码库怎么办? 从零建一个 AI-native 仓库和改造一个十年历史的老仓库,难度不是一个量级。Harness 改造成本可能过高 。
问题三:减法何时做? Anthropic 提到之前需要的 per-sprint 任务分解,在新模型之后已经不需要了。OpenAI 定期用 Agent 清理 Agent 生成的冗余代码。Harness 不是越复杂越好,而是刚好够用 。
8.3 一个实用的起点
如果你不知道从哪里开始:从最简单的开始,遇到瓶颈再增加复杂度。 一个通宵的 ML 实验用简单的循环就够了;需要持续交付的产品再上多 Agent 方案;等到代码库大到需要“垃圾回收”的时候,再参考 OpenAI 那套体系 。
9. 结语
“仓库即规范”不是一句口号,而是一个可操作的工程原则。它的核心洞察极其朴素:AI Agent 只能看到你给它看的东西。
这个洞察的推论同样朴素,但影响深远:如果你想让 Agent 做对的事,就必须把“什么是对的事”写进它能看到的地方。 不是 Slack,不是 Jira,不是你的脑子里。是仓库。
OpenAI 团队在 5 个月、1500 个 PR 之后得出的结论,值得作为本文的收束:
不要再为单次对话做优化,开始为那个会记住一切的仓库做优化。