AI 生成代码的速度已经超过了人阅读代码的速度。 继续把"逐行看懂全部实现"当作主要质量控制手段,只会让人越来越跟不上 Agent。
但问题不只是代码生成太快。每次启动新会话,Agent 还需要重新理解项目是什么、当前走到哪一步、哪些决定已经确认、什么可以做、什么不能做。如果这些信息只存在于对话和人的记忆里,模型越快,跑偏也越快。
所以,AI 原生开发真正需要的不是一个更长的提示词,而是一套完整的开发系统。它至少包含两个互相咬合的闭环:
- 上下文闭环:把规则、规格、状态和历史决策写进仓库,让冷启动的 Agent 能恢复工作上下文;
- 执行闭环:把需求做成可执行事实,把功能拆成可运行的小版本,再通过真实反馈、阶段门禁和回滚机制控制风险。
前者决定 Agent 是否知道该怎么做,后者决定它做出来的东西是否真的可用。只有两个闭环同时存在,代码生成速度才会成为生产力,而不是失控的放大器。

从结构上看,这两个闭环保存的是两类不同的关系。上下文闭环保存项目事实及其关系 :哪些规格有效、哪些决定已被替代、当前处于什么状态;执行闭环保存任务关系:谁依赖谁、什么条件允许推进、哪些工作可以并行、失败后应该回到哪一层、哪些节点必须由人放行。前者外部化"当前哪些事实有效",后者外部化"接下来应该做什么,以及满足什么证据才能推进"。

一、先把模型当作近似无状态函数
设计 AI 原生项目时,一个有用的工程假设是:把模型当作近似无状态函数。 不依赖它记得上一次会话,也不依赖"我们之前说好了"这种口头上下文。每次调用都假设它需要从当前可见材料重新理解任务。
这个假设会直接改变仓库的职责。仓库不再只是存放代码,也要承担 Agent 的操作环境和长期记忆。 你希望 Agent 稳定知道的事情,都应该有明确、可读取、可追溯的载体:
- 项目是什么、使用什么技术栈;
- 各类文件承担什么职责;
- 当前需求处于哪个阶段;
- 哪些规格和契约已经确认;
- 修改某个模块前必须读取什么;
- 完成后运行哪些验证;
- 过去做过哪些决定,哪些旧决定已经失效;
- 哪些动作必须等待人的确认。
围绕这些问题,可以把 Agent 的工作环境分成四类能力:
| 层级 | 解决的问题 | 常见载体 |
|---|---|---|
| 角色与规则 | Agent 应该怎样工作、不能越过什么边界 | System Prompt、AGENTS.md、Rules |
| 外部连接 | Agent 如何访问 Issue、构建、数据库和内部文档 | MCP、受控工具 |
| 任务流程 | 某类任务应该按什么步骤完成 | Skills、脚本、模板 |
| 能力分发 | 一组规则、流程、连接和资源如何安装复用 | Plugin、工具包 |
Rules 负责保底线,Skills 负责提供可重复的做法,Hooks 和脚本负责把关键约束变成机器可以执行的检查。三者不能互相替代: 只有规则,Agent 每次都要重新摸索;只有流程,它可能高效地做错事;只有脚本,又无法处理需要解释和判断的部分。
二、仓库要同时保存事实、过程、状态和经验
AGENTS.md 是索引,不是百科全书
根目录的 AGENTS.md 应该优先回答冷启动时最实际的问题:
- 当前运行环境、技术栈和开发工具;
- 项目地图,以及各类文件的职责;
- 修改某个模块前必须读取的规格和依赖;
- 实现、测试、验收和提交命令;
- 阶段门禁,以及必须等待人的节点;
- 测试报告和垃圾数据清理要求。
它适合做高频红线和导航入口,不适合塞进几千行细节。 架构、测试、安全、Git 等规则按主题分片,处理特定任务时再加载对应文件。这样既减少无关上下文,也避免同一条规则在多处出现不同版本。
过程文档与长期事实必须分开
本轮需求的讨论过程和长期有效的项目契约,生命周期不同,不应该混在一起。
workflow/保存本轮需求如何确认、考虑过哪些方案、为什么选择当前方案;specs/保存长期有效的 API、数据库、模块需求和验收标准;tasks/保存从规格拆出的当前执行单元;memory/保存跨需求仍有价值的决策和架构记录。
过程文档用于留痕,规格文件用于约束当前实现。需求完成后,讨论稿可以归档,但生效的契约必须继续随代码演进。 如果两者混放,Agent 很容易把过期方案当成现行事实。
关键事实还应登记来源:
- 需求来自用户原话、PRD、现有 API、设计稿,还是测试和日志,都应该能追溯;
- 没有来源时也应明确写出"暂无可用来源",而不是让 Agent 自行补全。
来源登记的价值,是迫使不确定性显式暴露,避免一个看似合理、实际不存在的前提污染后续设计和实现。
决策记录需要废止机制
memory/decisions.md 可以记录简单决定,重要架构选择进入 memory/adr/。但决策记录不能只增不改。新决定覆盖旧决定时,必须明确写出覆盖关系。
否则仓库会同时保留两条互相冲突的"有效决定",冷启动的 Agent 只能随机选一条。长期记忆需要谱系:当前规则是什么、它替代了什么、为什么替代。
状态应有唯一的机器来源
需求阶段可以由 workflow-state.json 或同类状态文件表达,例如:
text
需求讨论 → 方案选择 → 实现就绪 → 开发 → 验收 → 提交
这条线性状态机只是最小示例。复杂任务出现并行、条件分支、汇聚和回退时,可以把流程扩展为任务图,让依赖、触发、回退和审批成为显式关系;但无论流程形态如何,当前状态仍应由唯一、可审计的机器来源表达。
状态文件负责告诉脚本和 Hook 当前允许发生什么;对应的 Markdown 文档负责让人理解为什么推进。阶段切换最好保留用户确认原话,而不是只写一个 confirmed: true。这样,"用户已确认"是一条可审计的证据链,而不是 Agent 自己生成的布尔值。
一个最小可用的 AI 原生仓库骨架可以是:
text
my-project/
├── AGENTS.md # 总规则、项目地图、命令和门禁索引
├── workflow-state.json # 当前阶段的唯一机器状态源
├── workflow/ # 本轮需求和方案的确认过程
├── specs/ # 长期有效的契约与验收标准
├── tasks/ # 当前可执行任务
├── memory/
│ ├── decisions.md
│ └── adr/
├── rules/ # 按测试、安全、Git 等主题分片
├── .agents/
│ ├── skills/
│ ├── hooks/
│ └── mcp.json
├── frontend/ # 业务代码,内部结构沿用项目既有规范
├── backend/
├── tests/ # 契约、集成和端到端验证
└── scripts/ # 状态、契约和统一检查入口

这不是要求所有项目复制同一棵目录树。目录多不多不重要,重要的是:新会话只读仓库,就能回答"现在进行到哪、为什么这么做、接下来该做什么"。
三、把设计和需求做成可执行事实
仓库提供了工作环境,下一步是让需求成为 Agent 可以比较和验证的目标。
对于界面型产品,第一步不应是让 Coding Agent 直接写正式代码,而是先做一份可运行的 UI/UX 原型。原型交付的不只是截图,还应该尽量包含:
- HTML,用来表达页面和交互关系;
- CSS,用来固化颜色、字号、间距和尺寸规范;
- React 等组件代码,用来表达界面拆分方式;
- 模拟数据,用来表达页面依赖的数据结构;
- 权限、空状态、禁用状态和异常反馈等关键业务状态。
业务规则如果只写在长篇说明里,Agent 很容易遗漏或产生多种解释。 能够通过模拟数据和交互状态表达的规则,尽量直接放进原型;文字负责边界和例外,原型负责让主要规则可以被看见、被操作。
此时设计稿不再只是"参考图",而是实现的直接参照物。 Coding Agent 面对的是一套可运行、可截图比较、可由人实际操作的目标。
需求评估技能适合通过连续追问和多模型讨论把问题想透,但生成的访谈记录和方案推演往往很长,很难直接交给人阅读或交给 Agent 实现。因此,PRD 在保留完整过程材料之外,还应附一份极简简报,只回答三个问题:产品解决什么问题、这一版做什么、暂时不做什么。简报是需求收敛后的确认文档,应放进仓库,让没有参与讨论的人也能快速理解并复述最终结论。
四、第一版要足够小,而且必须能运行
原型确认后,再把功能交给 Coding Agent 实现。第一版只做一个很小的可运行切片,例如一个主界面和一条核心交互,而不是一次生成十个页面。
功能越少,Agent 同时理解的状态、依赖和异常分支越少,结果通常越稳定。 一次生成十个页面,看起来节省了十轮沟通,实际上会把十组错误叠在一起,让人无法判断问题来自需求、设计、架构还是实现。
每个版本至少满足三个条件:
- 可以独立运行。 人能亲手操作,而不是只看代码或截图;
- 只增加一种主要不确定性。 新页面、真实数据接入和架构调整尽量不要同时发生;
- 有明确验收边界。 做到了什么、哪些能力暂时不做,都写进当前规格。

这条流程表面上比"一次生成完整产品"慢,实际上压缩了每轮的不确定性。问题更容易定位,失败更容易回退,Agent 也不会在错误方向上高速堆积实现。
五、问题要回到产生它的那一层
人在运行版本时,通常会发现两类问题:
- 实现问题:崩溃、状态错误、性能异常,或者代码没有遵守已经确认的设计;
- 设计问题:信息层级不清、交互不自然、布局在真实数据下失效。
实现问题直接在代码层修复。设计问题则先回到设计工具修改原型,再让 Agent 比较设计稿变化并更新实现。
为了省事直接在正式代码里修设计问题,会让设计和产品逐渐分叉:设计稿展示旧产品,代码里堆着只有当前维护者知道的例外。后续每一轮迭代都要为这份分叉付费。
设计问题改设计,规格问题改规格,实现问题改代码。前面改对了,后面再同步跟进。不要想通过在代码实现层打补丁的方式解决所有问题。

这也是 workflow/ 与 specs/ 分开的实际意义:讨论过程解释决策,长期规格约束实现,代码负责兑现规格。三层各自承担不同责任。
六、用硬门禁控制 Agent 的推进速度
Coding Agent 最危险的时候往往不是做得慢,而是推进得太快。 它可以在几分钟内完成实现、测试、重构和下一阶段拆解,而人还没有判断上一阶段的方向是否正确。
仅在提示词里写"请等待确认"并不稳定。 阶段推进应该同时依赖三类证据:
- 对应文档已经存在,内容达到当前阶段要求;
- 状态文件允许进入下一阶段;
- 需要人工判断的节点保留了用户确认原话。

Rules 告诉 Agent 不应该越界,Hook 和脚本让越界动作无法通过。比如需求没有确认就不生成实现计划,方案没有选定就不拆任务,验收没有通过就不提交或发布。
门禁也保护人的注意力。人不必追踪 Agent 的每个动作,只需要在需求、设计、可运行版本和最终验收几个关键节点做判断。Agent 负责高速探索和执行,人负责方向、边界和放行。
七、用反馈回路代替全面逐行审核
当 AI 写得比人读得快,质量控制的重点要从"我是否理解每一行"转向两个问题:
- 系统是否满足已经确认的规格;
- 失败时能否及时暴露、定位和回退。
有效的测试必须回答两个问题:这次实现是否符合规格,有没有破坏原有功能? 一个更稳的流程是:
text
Spec → Task → 可观察验收条件 → AI Coding → Run & Check
↑ │
└── Fix & Retry ┘
是否先写测试,应由风险和行为稳定程度决定。AI 很容易快速生成只覆盖 happy path、断言又很弱的自证式测试,因此不必教条地追求所有代码都测试先行。但每一项关键行为都必须有与风险相称的验证:
- 复杂、稳定的核心逻辑:用单元测试保护边界、状态转换和关键不变量;
- 模块与真实依赖的协作:用集成测试验证数据库、服务和外部接口;
- 前后端共享契约:用契约测试检查 Schema 和字段一致性;
- 关键用户路径:用 E2E 或浏览器自动化运行真实流程;
- 界面和体验问题:由人实际操作,结合截图和可观察状态验收;
- 测试本身的可信度:必要时用变异测试、故障注入或真实缺陷反证弱断言。

单元测试、集成测试和 E2E 不是只能选择一种。项目越接近核心业务、逻辑越复杂,越需要核心单测;越是跨模块、CRUD 和页面密集场景,越应该提高集成、契约和 E2E 的比重。测试结构应该跟随风险,不应该为了倒置或遵守某种金字塔而倒置。
静态检查、类型检查和测试输出还要让 Agent 自己看见。反馈越短、错误越具体,它在当前会话内闭环的问题越多。关键用户路径必须真的运行过,不能只因为代码编译或测试文件存在,就推断功能已经可用。
测试跑完也不代表工作结束。Agent 应该生成可复查的报告,并清除测试产生的账户、文件和数据库记录。普通规格和决策继续使用 Markdown;需要展示趋势、分布和多维指标的测试或分析报告,可以使用 HTML 和图表。格式不是重点,重点是结果可审计、环境可恢复。
在资源有限的本地环境里,完整浏览器回归和重型设计工具同时运行可能影响反馈速度。可以在普通迭代里使用浏览器插件或轻量交互验证,把完整 Playwright 回归留给关键节点。工具可以替换,真实用户路径不能省略。
八、稳定之后,再做性能审查和结构调整
功能通过验收后,不一定马上进入下一个需求。让 Agent 审查性能和结构,通常比继续堆功能更划算,但前提是已有可运行版本作为参照。
例如在一个 macOS 项目的第一版中,界面使用 NSScrollView。内容增多后内存明显上涨,性能分析建议改用 NSTableView。这类问题很难在静态设计稿里发现,必须先有真实数据和可运行版本,才能判断是否值得改变实现。
重构也要控制风险。对于边界明确但历史复杂的模块,与其原地拆除并重建,不如先新增一个实现,验证后再替换旧路径。这样可以比较新旧结果,失败时快速退回,也避免同时破坏现有行为和参照物。
但并行实现只是迁移手段。替换完成后必须删除旧路径,不能让两套实现永久共存。
每个有文件变化的实现任务还应该留下清晰边界:编辑前识别已有和并发变更,只包含当前任务相关修改,运行与改动相称的验证,再形成独立提交或等价的可回退记录。不要擅自推送、改写历史,也不要为只读任务创建空提交。
九、用"新会话六问"检验系统是否真的成立
目录存在不等于系统有效。 最直接的测试,是启动一个没有口头背景的新会话,让 Agent 只读仓库,然后回答六个问题:
- 项目是什么;
- 当前需求走到哪一步;
- 现在被允许做什么;
- 应该按什么流程做;
- 做完如何验证;
- 本轮经验应该写到哪里。
如果六个问题都能回答,说明事实、过程、状态和经验已经形成闭环。答不上来时,不要继续堆更多抽象目录,而要定位究竟缺少哪类信息:项目索引、当前状态、有效契约、验证入口,还是决策记录。
我在 travel-ledger-admin 项目中用这六问检查过一套类似骨架。项目地图、阶段状态、允许动作、默认流程和经验回写都能从仓库恢复,但验证仍是最弱的一环:契约检查没有机器兜底,根目录缺少完整的 E2E 链路,CI、可观察性和测试规则也不完整。
这个结果反而说明,最容易被省略的并不是目录和文档,而是"让结果真正可验证"的最后一公里。 状态机、规格和 Rules 可以阻止 Agent 胡乱推进,却不能证明产品已经工作。最终仍然要回到可运行版本、真实用户路径、可观察反馈和可恢复环境。
收个尾
AI 原生开发不是让 Agent 替人连续写更多代码,而是重新划分人、模型和仓库的责任:
- 仓库保存事实、过程、状态和经验;
- Agent 负责高速探索、实现、验证和修复;
- 人负责需求、设计、边界和阶段放行;
- 测试、Hook、状态机和提交记录提供可观察、可审计、可回退的反馈。
这套系统可以压缩成一句话:
把仓库变成 Agent 可以恢复上下文的工作环境,把目标做成可执行的事实,把功能拆成可运行的小版本,把问题送回正确的层,再用门禁和反馈回路控制推进。

只要上下文闭环和执行闭环同时成立,代码生成得再快,也不会快到失控。