把代码仓库变成 AI 看得懂的工作台
为什么仓库必须成为唯一事实来源?这一期从目录、文档和渐进式披露入手,把一个“只有人能看懂”的项目改成代理能读的工作台。


Harness 从 0 到 1|第 3 期
从 README 到 AGENTS.md,再到 docs/ 分层,把散落在脑子、聊天记录和旧文档里的规则搬回项目现场。
这套系列面向正在用 Claude Code 、 Codex 、 Cursor 、 OpenCode 或其他编程代理的中国开发者、产品经理和小团队。你不需要先学会复杂的 Agent 框架,先把自己的项目整理成代理能读、能执行、能复查的工作区。
这一期解决什么
为什么仓库必须成为唯一事实来源?这一期从目录、文档和渐进式披露入手,把一个“只有人能看懂”的项目改成代理能读的工作台。
先记住系列路线
- 第 1 期:看见模型能力和执行可靠性之间的差距。
- 第 2 期:建立 Harness 的五子系统地图。
- 第 3~6 期:把规则、状态、范围和验证逐层放回仓库。
- 第 7 期:把一次次手动提示升级成自动循环。
- 第 8 期:当循环长成图,学习路由、并行、回退和人工审批。
下面进入本期正文。建议你打开一个自己正在维护的项目,对照着做,不要只收藏。
你团队的架构决策散落在 Confluence 、 Slack 、 Jira 、和几个资深工程师的脑子里。对人类来说这勉强够用,你可以问同事、搜聊天记录、翻文档,实在不行还能去茶水间堵人。但对 AI agent 来说,不在仓库里的信息等于不存在。
这不是夸张。 Agent 的输入只有三样东西:系统提示和任务描述、仓库里的文件内容、工具执行的输出。你的 Slack 历史、 Jira 工单、 Confluence 页面、和周五下午跟同事聊的架构决定,agent 全都看不到。它不能”去问一下”,也不能”搜一下聊天记录”。它的整个工作世界就是仓库本身,仓库外面的事它一概不知。
所以问题变成了:你给不给它一张足够好的地图?
地图上该画什么
OpenAI 在他们的 harness engineering 文章里把这个问题说得非常直白:仓库里不存在的信息,对 agent 来说等于不存在。 他们把这称为”仓库即规范”原则,即仓库本身就是最高权威的规范文档。
Anthropic 的 long-running agents 文档也强调了类似的观点:持久化状态是长任务连续性的必要条件,跨会话的知识可恢复性直接决定了任务成功率。而这些状态必须存在于仓库中,因为那是 agent 唯一稳定可访问的存储。
你可能会想:“我们团队人少,知识都在大家脑子里,这不也工作得好好的吗?“没错,对人类来说确实可以。但你要用 agent,就得接受一个事实:agent 不能问人。所有它需要知道的东西,都必须写下来,放在它能找到的地方。
这不是”写更多文档”的问题,而是”把决策信息放到正确的位置”的问题。一份在 src/api/ 目录下、 50 行的 ARCHITECTURE.md,比一份在 Confluence 里、 500 页但没人维护的设计文档有用得多。就近放置的价值远大于篇幅长短,因为信息只有在你需要的时候就在手边,才能真正发挥作用。
知识可见性
flowchart LR
Slack["Slack 里的规则"] --> Write["写进仓库文件<br/>AGENTS.md / ARCHITECTURE.md / PROGRESS.md"]
Confluence["Confluence 里的规则"] --> Write
Heads["工程师脑子里的规则"] --> Write
Jira["Jira 里的规则"] --> Write
Write --> Repo["仓库文件"]
Repo --> Agent["新的 agent 会话<br/>直接读仓库"]
Warning["规则不写进仓库<br/>agent 就看不见"] --> Agent
怎么检验你的地图画得够不够好?做一个”全新会话测试”:开一个全新的 agent 会话,只让它看仓库内容,看它能不能回答五个基本问题。
flowchart TB
Q1["这是什么系统?"] --> A1["AGENTS.md / README"]
Q2["怎么组织的?"] --> A2["ARCHITECTURE.md / 模块文档"]
Q3["怎么跑?"] --> A3["Makefile / init.sh / package scripts"]
Q4["怎么验证?"] --> A4["测试、lint、check 命令"]
Q5["现在做到哪了?"] --> A5["PROGRESS.md / 功能清单 / git 历史"]
A1 --> Ready["新的会话不用问人<br/>就能开始工作"]
A2 --> Ready
A3 --> Ready
A4 --> Ready
A5 --> Ready
如果它答不上来,说明地图上有空白。空白的地方,agent 就得自己猜,猜错了就是 bug,猜多了就浪费上下文。每个新会话都要猜一遍,猜的成本远高于一开始就把地图画好。
核心概念
- 知识可见性缺口:项目总知识中不在仓库里的比例。缺口越大,agent 失败的概率越高。你可以这样估算:把脑子里关于这个项目的隐性知识全算上,再看有多少写进了仓库,两者的差距就是可见性缺口。
- 系统记录(System of Record):代码仓库作为项目决策、架构约束、执行状态和验证标准的权威信息源。仓库说了算,别的地方说了不算。如果”此路不通”这个信息只在老张的脑子里,那每次都得问老张。写进仓库,谁都不用问。
- 全新会话测试:上一节说的五个问题。能回答几个,你的地图就画了几分。
- 发现成本:agent 为了在仓库里找到一条关键信息需要消耗多少上下文。信息放得越隐蔽,发现成本越高,留给实际任务的预算越少。关键信息应该放在 agent 最先看到的位置,而不是藏在十层目录深处。
- 知识衰减率:仓库中单位时间内变得过时的知识条目比例。文档和代码脱节是最大的敌人,比没有文档更危险的是过时的文档。
- ACID 类比:把数据库的事务管理原则(原子性、一致性、隔离性、持久性)用到 agent 的状态管理上。后面会展开讲。
怎么画好这张地图
原则 1:知识靠近代码。 一条关于 API 端点认证的规则,应该放在 API 代码旁边,而不是藏在一个巨大的全局文档里。每个模块目录下放一个简短的文档,说清楚这个模块的职责、接口和特殊约束。模块目录本身就是天然的索引,agent 读到代码就能读到约束,不用到处翻找。
原则 2:用标准化的入口文件。 AGENTS.md(或 CLAUDE.md)是 agent 的”着陆页”。它不需要包含所有信息,但必须能让 agent 快速回答”这是什么项目”、“怎么跑”、“怎么验证”这三个问题。 50-100 行就够了。
原则 3:最小但完备。 每条知识都应该有明确的使用场景。如果你删掉某条规则不影响 agent 的决策质量,那这条规则就不应该存在。但全新会话测试中的每个问题都必须有答案。这是一个需要持续调整的平衡,不多不少,刚好够用。
原则 4:和代码一起更新。 把知识更新跟代码变更绑定在一起。最简单的方法:把架构文档放在对应的模块目录里。改代码的时候自然会看到文档,改代码之后 CI 提醒你检查文档是否需要更新。
具体的仓库结构:
project/
├── AGENTS.md # 入口:项目概览、运行命令、硬约束
├── src/
│ ├── api/
│ │ ├── ARCHITECTURE.md # API 层的架构决策
│ │ └── ...
│ ├── db/
│ │ ├── CONSTRAINTS.md # 数据库操作的硬约束
│ │ └── ...
│ └── ...
├── PROGRESS.md # 当前进度:做了什么、在做什么、被什么阻塞
└── Makefile # 标准化的操作命令:setup、test、lint、check
用 ACID 原则管理 agent 状态
这个类比来自数据库的事务管理。你可能会觉得这是在把简单的事情搞复杂,但它确实提供了一个非常实用的框架:
- 原子性:每次”逻辑操作”(比如”添加新端点并更新测试”)用一个 git commit 原子化。中途挂了就
git stash回滚。要么全做,要么不做,没有”做了一半”。 - 一致性:定义”一致状态”的验证谓词,比如所有测试通过、 lint 无报错。 Agent 每次操作后跑验证,不一致的中间状态不要 commit 。操作完系统应该处于可验证的正确状态。
- 隔离性:多个 agent 并发工作时,状态文件要避免竞争条件。简单方案:每个 agent 用独立的进度文件,或者用 git 分支隔离。并发写入同一文件是出问题的常见原因。
- 持久性:关键的项目知识用 git 跟踪的文件持久化。临时状态可以只在会话内存里,但跨会话必须的知识必须写到文件里。脑子里的不算,写在纸上的才算。
一个真实的改造故事
一个团队维护一个包含约 30 个微服务的电商平台。架构决策(服务间通信协议、数据一致性策略、 API 版本化规则)散落在:Confluence(部分过时)、 Slack(难以搜索)、几个资深工程师的脑子里(不可扩展)、以及零星的代码注释(不系统)。
引入 AI agent 后,70% 的任务需要人工干预。几乎每次失败都涉及 agent 违反了某个”所有人都知道但从未写入仓库”的隐性约束。 Agent 没有办法知道它不知道的事情,只能按自己的理解去做,结果就踩了坑。
团队执行了改造:
- 仓库根目录创建
AGENTS.md,写明项目概览、技术栈版本、全局硬约束 - 每个微服务目录下添加
ARCHITECTURE.md,描述该服务的职责、接口和依赖 - 创建集中的
CONSTRAINTS.md,用”禁止/必须”的明确语言记录硬约束 - 每个服务目录添加
PROGRESS.md,记录当前工作状态
改造后:同一 agent 能在冷启动时回答所有关键项目问题,任务完成质量显著提升。
核心要点
- 不在仓库里的知识对 agent 来说等于不存在。把关键决策信息放进仓库是最基本的 harness 投资,画好地图才不会迷路。
- 用”全新会话测试”检验仓库质量:全新会话能不能只看仓库回答五个基本问题。
- 知识要靠近代码、最小但完备、跟代码一起更新。不是写更多文档,是把信息放到正确的位置。
- 用 ACID 原则管理 agent 状态:原子提交、一致性验证、隔离并发、持久化关键知识。
- 知识衰减是最大敌人。过时的文档比没有文档更危险,它会让 agent 走错方向还以为自己是对的。
延伸阅读
- OpenAI: Harness Engineering
- Anthropic: Effective Harnesses for Long-Running Agents
- Infrastructure as Code — Martin Fowler
- ADR: Architecture Decision Records
- The Twelve-Factor App
练习
-
全新会话测试:在你的项目里开一个全新的 agent 会话(不提供任何口头上下文),只让它看仓库内容,然后问它五个问题:这是什么系统?怎么组织的?怎么运行?怎么验证?现在进度如何?记录它答不上来的问题,然后改进仓库让它能答上来。
-
知识外置化量化:列出你的项目中所有对开发工作重要的决策和约束。标注每个条目是在仓库内还是仓库外。算一下你的知识可见性缺口有多大(不在仓库里的占总数的比例)。制定计划把缺口降到 10% 以下。
-
ACID 准则评估:用本讲的 ACID 类比评估你的项目状态管理。原子性:agent 的操作能不能干净地回滚?一致性:仓库有没有”一致状态”的验证?隔离性:多 agent 并发时会不会互相踩脚?持久性:跨会话的知识是不是都持久化了?
你开始认真对待 harness 了,这很好。你建了个 AGENTS.md,把能想到的所有规则、约束、历史教训都塞了进去。一个月后这个文件膨胀到了 300 行,两个月 450 行,三个月 600 行。然后你发现 agent 的表现反而变差了:改一个小 bug,agent 花大量上下文处理无关的部署指令;关键的安全约束埋在第 300 行,被直接忽略了;文件里有三条互相矛盾的代码风格规则,agent 每次随机选一条。
这就是”巨型指令文件”陷阱。觉得什么都有用,什么都往里装,结果想找一条具体规则得把整个文件翻一遍。写了 600 行,但真正跟当前任务相关的可能只有三分之一。
问题的根源:一个恶性循环
最常见的恶性循环是这样的:agent 犯了个错,你说”加条规则防止这个”,加到 AGENTS.md,暂时管用。然后 agent 又犯了另一个错,再加一条。重复下去,文件膨胀到不可控。
这其实是很自然的反应,每次出问题就”加条规则”感觉很合理。但累积效应是灾难性的。让我们看看具体出了什么问题。
上下文预算被吃掉了。 Agent 的上下文窗口是有限的。假设你的 agent 有 200K tokens 的窗口(Claude 的标准),一个膨胀的指令文件可能占掉 10-20K 。看起来还有不少余量?但一个复杂的任务可能需要读几十个源文件,工具执行的输出也占上下文,对话历史也在累积。到真正需要理解代码的时候,预算已经不够了。
中间迷失。 “Lost in the Middle”这篇论文(Liu et al., 2023)清楚地证明了:LLM 对长文本中间部分的信息利用效率显著低于两端。你的 AGENTS.md 有 600 行,第 300 行写的是”所有数据库查询必须用参数化查询”,这是安全硬约束。但它被埋在中间,agent 几乎一定会忽略它。
优先级冲突。 文件里混合了不可违反的硬约束(“不得使用 eval()”)、重要的设计指导(“优先使用函数式风格”)、和某个特定场景的历史教训(“上周修了一个 WebSocket 内存泄漏,注意类似的模式”)。这三条规则的重要性完全不同,但在文件里看起来一模一样。 Agent 没有可靠的信号来区分哪个是红线,哪个只是建议。
维护衰减。 大文件天生难维护。指令过时了没人删,因为删除的后果不确定(“也许别的地方依赖这条规则?”),但加新指令是无成本的。结果文件只增不减,信噪比持续下降。这和软件里的技术债务积累是同一个问题。
矛盾累积。 不同时期加的指令之间开始出现矛盾:一条说”用 TypeScript 严格模式”,另一条说”某些遗留文件允许用 any”。 Agent 每次随机选一条遵循。
核心概念
- 指令膨胀:指令文件一旦占到上下文窗口的 10-15%,就开始挤占代码阅读和任务推理的预算。一个 600 行的
AGENTS.md可能占用 10,000-20,000 tokens,对 128K 的窗口来说就是 8-15% 。 - 长文本中间信息容易被忽略:Liu 等人 2023 年的研究表明,LLM 对长文本中间部分的信息利用效率明显低于两端。埋在 600 行文件第 300 行的关键约束,被忽略的概率非常高。
- 指令信噪比(SNR):文件中与当前任务相关的指令占总指令的比例。做 bug 修复时被要求读 50 行部署指令,SNR 就很低。
- 入口文件:短小的入口文件,作用是引导 agent 去找更详细的文档,而不是自己包含所有内容。 50-200 行就够了。
- 按需展开:先给概要信息,需要的时候再给详细信息。好的 harness 设计和好的 UI 设计一样,不把所有选项一次性砸到用户脸上。
- 分不清轻重:当所有指令以相同格式和位置呈现时,agent 分不清哪些是不可违反的硬约束,哪些只是建议性的软约束。
指令文件架构
flowchart LR
Mono["一个超长 AGENTS.md"] --> MonoLoad["改一个小 bug<br/>也得把部署说明和历史备注全读一遍"]
MonoLoad --> MonoRisk["关键规则埋在中间<br/>很容易漏掉"]
Router["短 AGENTS.md"] --> Topics["按任务去读 API / 数据库 / 测试文档"]
Topics --> RoutedResult["把更多上下文留给代码阅读<br/>和验证"]
flowchart TB
File["600 行指令文件"] --> Top["顶部<br/>快速开始 + 硬约束"]
File --> Mid["中部<br/>第 300 行的安全规则"]
File --> Bot["底部<br/>明确的结束检查清单"]
Top --> Seen["高概率被记住"]
Bot --> Seen
Mid --> Missed["高概率被稀释或忽略"]
拆分思路
核心原则:常用信息放手边,偶尔用的收起来,用不上的别带。
入口文件 AGENTS.md 控制在 50-200 行,只放最常用的东西:项目概览(一两句话说清楚这是什么)、首次运行命令(make setup && make test)、全局硬约束(不超过 15 条不可违反的规则)、指向专题文档的链接(一行描述加适用条件)。
# AGENTS.md
## 项目概览
Python 3.11 FastAPI 后端,PostgreSQL 15 数据库。
## 快速开始
- 安装:`make setup`
- 测试:`make test`
- 完整验证:`make check`
## 硬约束
- 所有 API 必须走 OAuth 2.0 认证
- 所有数据库查询必须用 SQLAlchemy 2.0 语法
- 所有 PR 必须通过 pytest + mypy --strict + ruff check
## 专题文档
- API 设计规范 (`docs/api-patterns.md`) — 添加新端点时必读
- 数据库操作约束 (`docs/database-rules.md`) — 涉及数据库修改时必读
- 测试标准 (`docs/testing-standards.md`) — 编写测试时参考
每个专题文档 50-150 行,按主题放在 docs/ 目录下或对应模块目录旁。 Agent 只在需要时才去读。用收纳袋整理行李的思路:内衣一个袋,洗漱一个袋,充电器一个袋,找东西不用翻整个箱子。
还有些信息直接放在代码里更合适,比如类型定义、接口注释、配置文件里的说明。 Agent 读代码的时候自然能看到,不用再在指令里重复一遍。
每条指令都应该标明来源(“为什么加这条规则?”)、适用条件(“这条规则在什么时候需要?”)、过期条件(“什么情况下可以删掉这条规则?”)。定期审计,删掉过时的、冗余的、矛盾的条目。像管理代码依赖一样管理你的指令,用不上的依赖就该删掉,不然它们只会拖慢系统。
如果某条指令必须在入口文件里,放顶部或底部,不要放中间。“中间迷失”效应告诉我们,LLM 对长文本中间部分的信息利用效率显著低于两端。但更好的做法是把指令放到专题文档里,让 agent 按需加载。
OpenAI 和 Anthropic 都隐性支持拆分的做法。 OpenAI 说入口文件应”短小且以路由为导向”,Anthropic 说长运行 agent 的控制信息应”简洁且高优先级”。两家都在说同一件事:别把什么都塞进一个文件里。
实际案例
一个 SaaS 团队的 AGENTS.md 从最初的 50 行膨胀到 600 行。内容混合了技术栈版本、编码规范、历史 bug 修复笔记、 API 使用说明、部署流程、和团队成员的个人偏好,什么都有,但很难快速找到跟当前任务相关的部分。
Agent 表现开始明显下降:简单 bug 修复任务中 agent 花大量上下文处理无关的部署指令;安全约束”所有数据库查询必须用参数化查询”埋在第 300 行,经常被忽略;三条矛盾的代码风格规则导致 agent 随机选择。
团队做了一次拆分重构:
AGENTS.md裁剪到 80 行:只保留项目概览、运行命令、 15 条全局硬约束- 创建专题文档:
docs/api-patterns.md(120 行)、docs/database-rules.md(60 行)、docs/testing-standards.md(80 行) - 入口文件添加指向专题文档的链接
- 历史笔记要么转成测试用例,要么删除
重构后:同一任务集的成功率从 45% 提升到 72% 。安全约束遵循率从 60% 提升到 95%,因为规则从文件中间移到了入口文件顶部,不再被”中间迷失”了。
核心要点
- “加条规则”是短期的止痛药,长期的毒药。每次加规则前想想,这条规则放专题文档是不是更合适。
- 入口文件是路由器,不是百科全书。 50-200 行,只放概览、硬约束和链接。
- 利用”中间迷失”效应:重要信息放文件顶部或底部,不重要的移到专题文档。
- 像管理技术债一样管理指令膨胀。定期审计,每条指令要有来源、适用条件和过期条件。
- 拆分之后信噪比提升,agent 把更多上下文预算花在实际任务上,而不是处理无关指令。
延伸阅读
- OpenAI: Harness Engineering
- Anthropic: Effective Harnesses for Long-Running Agents
- Lost in the Middle: How Language Models Use Long Contexts
- HumanLayer: Harness Engineering for Coding Agents
- Nielsen Norman Group: Progressive Disclosure
练习
-
信噪比审计:拿你当前的入口指令文件,列出所有指令条目。选 5 个不同的常见任务类型,标注每条指令是否跟该任务相关。计算每个任务类型的 SNR 。那些对大多数任务都是噪声的指令,移到专题文档里。
-
按需展开重构:如果你有一个超过 300 行的指令文件,把它拆成:(a) 不超过 100 行的入口文件,(b) 3-5 个专题文档。重构前后各跑同一组任务(至少 5 个),对比成功率。
-
中间迷失验证:在一个长指令文件里,把一条关键约束分别放在顶部、中间、底部各跑一组任务(每组至少 5 次),看遵循率有没有差别。你可能会惊讶于位置效应有多大。
放到中国团队里,怎么用
国内个人开发者和小团队常见的问题很具体:项目规则散在飞书、微信群和口头约定里;测试命令没人维护;换一个人或换一次会话就要重新解释;模型调用还有额度、网络、数据合规和代码保密边界。 Harness 解决不了这些外部问题,但能把项目内部的规则、状态和验收方式固定下来。
建议先做一个低风险版本:只允许代理读取和修改一个测试仓库;所有写入动作走 Git 分支;涉及生产数据、客户代码、密钥和外部系统时,先人工确认;每次任务结束保留验证结果和变更说明。国内团队最容易忽略的不是模型选择,而是权限和数据流向。
本期动手清单
- 在自己的项目里找出一个反复返工的任务。
- 记录代理从开始到结束实际读了哪些文件、执行了哪些命令。
- 把缺失的规则、状态或验证补成项目文件。
- 用同一个任务再跑一次,只比较结果和返工,不凭感觉下结论。
- 把失败归因到 Harness 的某一层,下一期继续补。
下一期预告
下一期会把本期的概念进一步落成一套文件结构和模板。到时候我们不再讨论“应该怎样”,而是直接从项目根目录开始搭。