Table of contents
Open Table of contents
1. 什么是仓库?
对于 Agent 来说,仓库是一个面向 AI Agent 的核心概念:它是 Agent 执行任务时唯一的、具备最高权威的「单一事实来源」(Single Source of Truth)和「记录系统」(System of Record)。
Agent 刚进入工作区时,它具备的启蒙知识只有仓库中的内容。OpenAI 在 Harness Engineering 一文中把这一点说得很直白:仓库里不存在的信息,对 Agent 来说等于不存在。 他们把这称为「仓库即规范」原则——仓库本身就是最高权威的规范文档。
1.1 仓库自检:五个问题
进入工作区的 Agent,若能够根据仓库中的内容回答以下五个问题,才说明仓库配置是合格的:
- 项目目的是什么?(要解决什么问题、交付什么)
- 如何启动/安装?(依赖、启动命令、环境要求)
- 如何验证?(测试、lint、
make check等) - 当前进度与阻塞是什么?(做到哪、卡在哪)
- 关键架构决策及原因是什么?(为什么这样设计)
2. AGENTS.md 的正确用法
工作区出现 bug 时,我们习惯在 AGENTS.md 里加一条维护性规则。规则越来越多,意外情况也会增多,常见问题包括:
- 上下文有上限。 一条奇怪指令可能导致上下文膨胀,迫使 Agent 读取大量源文件。
- 中间迷失(Lost in the Middle)。 Liu et al., 2023 证明:在冗长的
AGENTS.md(例如 600 多行)中,首尾内容被更重视,中间提示反而被弱化。 - 优先级冲突。 Agent 无法判断模糊指令的优先级——语法风格、禁用方法等规则,读取后不知道谁更重要。
- 维护衰减。 大文件难维护;过时规则没人删(「也许别的地方依赖这条?」),加新规则却零成本。文件只增不减,信噪比持续下降——与软件技术债是同一问题。
- 矛盾累积。 不同时期的指令互相矛盾:一条说「TypeScript 严格模式」,另一条说「某些遗留文件允许 any」。Agent 每次随机选一条遵循。
正确用法
- 一个入口文件作为路由,不要把所有情况挤进一个文件。
- 尽量简短精练,50–200 行通常足够(OpenAI 实践约 ~100 行作目录/map,指向
docs/等深层文档)。 - 按需读取下一步相关文件,而不是一口气把所有选项丢给 Agent。
3. 跨对话上下文连接(长任务处理)
长任务中常见的问题:
- 上下文窗口有限。 不管模型宣称多大的窗口(128K、200K、1M),长任务总会用完。用完之后要么压缩(丢信息),要么重置(开新会话),两种方式都可能丢东西。
- State 文件缺失。 两个会话之间需要 state 文件记录进度、to-do 还差什么。会话交接时还会丢失「为什么这样设计架构」的中间层意义——下一段对话只看到完整代码,不知道设计动机。
3.1 核心概念
| 概念 | 说明 |
|---|---|
| 状态持久化文件 | 让新会话无歧义恢复到上次离开的地方(进度日志、验证记录、下一步行动) |
| 重建成本 | 新会话恢复到可执行状态所需的时间;好的 harness 能把重建成本从 15 分钟压到 3 分钟 |
| 漂移(Drift) | Agent 的理解与仓库实际状态之间的偏差;每次会话边界都会引入漂移 |
| 上下文焦虑 | Anthropic 观察到的现象:Agent 接近上下文限制时表现异常,过早结束任务以避免信息丢失(见 Anthropic 长任务 harness 设计) |
| 压缩 vs 重置 | 压缩:同一会话内摘要化,保留「是什么」但可能丢「为什么」;重置:开新会话从持久化状态重建,状态干净但依赖工件完备性 |
核心思路:把 Agent 当成每次会话都会清空短期记忆的工程师。 每次「下班」前必须把关键信息写下来,让下一个「接班」的 Agent 能快速上手。
3.2 工具 1:PROGRESS.md
让下一个上下文知道上一个会话做了什么、解决了什么问题——本质是 to-do 完成情况。
# 项目进度
## 当前状态
- 最新 commit: abc1234 (feat: add user preferences endpoint)
- 测试状态: 42/43 通过 (test_pagination_edge_case 失败)
- Lint: 通过
## 已完成
- [x] 用户模型和数据库迁移
- [x] 基础 CRUD 端点
- [x] 认证中间件集成
## 进行中
- [ ] 分页功能 (90% - 边界条件测试失败)
## 已知问题
- test_pagination_edge_case 在空结果集时返回 500
- 需要确认是否要在列表中包含已删除用户
## 下一步
1. 修复分页边界条件 bug
2. 添加"是否包含已删除用户"的查询参数
3. 更新 API 文档
3.3 工具 2:DECISIONS.md
解决跨会话中「设计意义」的缺失——让下一个会话知道上一个会话为什么这样设计、有什么好处、解决了什么问题。没有 DECISIONS.md,下一个会话会花费多余的上下文去推理前一个会话的设计意图。
3.4 工具 3:Git
给工作区的 Agent 使用 git 的权利。在保证版本可回溯的前提下,git 提交作为检查点——每完成一个原子工作单元就提交,commit message 要说清楚做了什么和为什么。这是免费的、自动版本化的状态快照。
3.5 工具 4:Session Lifecycle 初始化
与员工交接类似:init.sh 或 harness 的初始化流程。在 AGENTS.md 里写明每次「上班」和「下班」的流程:
## 每次会话开始时(上班)
1. 读 PROGRESS.md 了解当前状态
2. 读 DECISIONS.md 了解重要决策
3. 跑 make check 确认仓库处于一致状态
4. 从 PROGRESS.md 的"下一步"部分继续工作
## 每次会话结束前(下班)
1. 更新 PROGRESS.md
2. 跑 make check 确认一致状态
3. 提交所有已完成的工作
3.6 混合策略
- 短任务(30 分钟以内):可在同一会话内完成。
- 长任务(跨会话):必须用进度文件和决策日志维持连续性。
- 判断标准:若任务需要的上下文超过窗口的 60%,就开始准备交接。
3.7 压缩 vs 重置:如何选择
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 压缩 | 探索性任务、需保持方向的长上下文 | 继承上下文,保持开发方向 | 占用上下文空间;可能继承上下文焦虑 |
| 重置 | 前期 plan loop、头脑风暴后的执行阶段 | 干净开始,无上下文焦虑 | 缺失 DECISIONS.md 中的中间层设计信息 |
Anthropic 的实际数据(来源):对于 Sonnet 4.5,上下文焦虑足够严重,压缩单独不够用,上下文重置成为 harness 设计的关键组件;对于 Opus 4.5,该行为大幅减弱,可以不依赖重置而靠压缩管理上下文。这意味着:harness 设计需要对目标模型有具体理解,而不是套用通用模板。
4. 初始化的重要性
会话开启时若没有良好约束,Agent 会把 80% 的推理资源花在「如何写代码」,只剩 20% 用于基座打磨。长对话时,下一个会话的 Agent 不知道测试架构和上一会话设计的功能是什么,测试架构可能不完整,第二轮需要更多上下文去改正。最容易被忽略的是隐式假设埋下的雷——测试框架、目录组织、依赖管理等决策若不显式记录,后续会话可能做出矛盾选择(例如第一轮选 Vitest,第二轮又引入 Jest)。
好的初始化应做到四点:能启动、能测试、能说明状况、能让下一轮接手。
4.1 初始化的核心概念
- 产出应是开发框架,不是业务代码。 框架包含:能启动、能测试、能说明状况、能服务下一轮会话。
- 需要脚手架模板,让 Agent 不必每轮从零理解整个项目。
- 实践中的初始化包括:
- 可运行环境(依赖、启动命令)
- 可测试的测试框架(至少一例测试实例用于 verify)
- 启动就绪清单(见下)
- 任务分解(描述明确,非模糊功能列表)
- Git 框架(提供检查点)
# 初始化契约
## 启动命令
- 安装依赖:`make setup`
- 启动开发服务器:`make dev`
- 运行测试:`make test`
- 完整验证:`make check`
## 当前状态
- 所有依赖已安装并锁定
- 测试框架已配置(Vitest + React Testing Library)
- 示例测试通过(1/1)
- Lint 规则已配置(ESLint + Prettier)
## 项目结构
- src/ — 源代码
- src/components/ — React 组件
- src/api/ — API 客户端
- tests/ — 测试文件
4.2 两种初始化方式对比(React 前端示例)
| 方式 | 第一会话 | 第二会话 |
|---|---|---|
| 混合方式 | 脚手架 + 首个功能同时做;无显式启动/测试文档、无进度文件 | 约 20 分钟推断项目结构、测试框架、构建流程 |
| 独立初始化 | 只做初始化:目录结构、测试框架、示例测试、就绪清单、任务分解、初始 commit | 重建时间 < 3 分钟,直接从任务列表开始 |
5. 给任务划清边界
多个任务并行远不如逐个任务可靠。假设 Agent 上下文容量为 C,同时进行 k 个任务时,每个任务约分到 C/k 的推理资源;若某任务需要超过 C/k,该任务可能无法完成。任务执行最重要的是稳定性——有效安排边界,让 Agent 逐个完成。
5.1 核心概念
| 概念 | 定义 |
|---|---|
| 过度延伸(Overreach) | 一次会话中激活的并行任务数量超过最优值。可同时做 5 个功能但 0 个跑通,就是 overreach。注意:任务「过大」属于 Scope 划分不当,不是 overreach。 |
| 不足完成(Under-finish) | 已启动的任务中,通过端到端验证的比例低于阈值。写了代码但没跑通测试,就是 under-finish |
| WIP 限制 | 来自 Kanban,限制同时在进行的任务数。对 Agent,WIP=1 是最安全的默认值 |
| 完成证据(Completion Evidence) | 任务从「进行中」到「已完成」必须满足的可验证条件 |
| 范围表面(Scope Surface) | DAG 结构,节点是工作单元,边是依赖关系;状态:未开始、进行中、阻塞、已通过 |
| 完成压力(Completion Pressure) | WIP 限制 + 完成证据要求共同产生的约束力 |
为何 WIP 过大有问题? 一次会话激活过多并行任务时,容易进入 overreach(做很多事但都没做好),随后滑向 under-finish,Agent 疲于用上下文修修补补——这应落实到每轮会话的指令设计。
5.2 正确的任务边界划分
1. 强制 WIP=1
在 AGENTS.md 中规定:
## 工作规则
- 每次只做一个功能点
- 当前功能点端到端验证通过后,才能开始下一个
- 不要在实现功能 A 时"顺便"重构功能 B
2. 每个功能点需有验证三元组
一个功能完成以行为验证通过为准,需有测试审核。每个功能用三元组描述:
{
"id": "F03",
"behavior": "POST /cart/items with {product_id, quantity} returns 201",
"verification": "curl -X POST http://localhost:3000/api/cart/items -H 'Content-Type: application/json' -d '{\"product_id\":1,\"quantity\":2}' | jq .status == 201",
"state": "passing",
"evidence": "commit abc123, test output log"
}
状态可通过状态机实现:未开始、进行中、阻塞挂起、通过。
3. 把范围表面外部化
用机器可读文件(JSON 或 Markdown)记录所有任务状态。任何新会话都能直接读取,知道:哪个任务在做?什么行为算完成?已通过什么验证?