Appearance
用嘴编程会腐烂:把 AI 编码变成有护栏的工程
第二部 · Agent 实践 · 第23章
撰写日期:2026-07-07
结论
“随便和 AI 说几句就能跑出一个程序”只在玩具项目里成立。项目一复杂,AI 犯错概率就随代码量上升——这里改好、那里就坏,最后花掉大量 token,程序勉强能跑,代码却已经没人能读懂,连“还能不能继续加功能”都说不准。
根因不在模型不够聪明,而在两点:一是需求本来就没想清楚,二是所有代码都堆在同一段越来越长的上下文里。前者靠先对齐再动手解决,后者靠把知识沉到文件、让每次会话只做一件小事解决。
这篇把一次“从零让 AI 写一个 FC 模拟器”的公开实践,抽象成一套可复用的结构化 AI 编码方法。它对 AI 产品经理有两重价值:既是自己驾驭 AI 编码的工作流,也是设计“AI 写代码类产品”时可以照搬的产品结构。
为什么长上下文会让质量崩塌
这是理解整套方法的前提。AI 写出的代码都活在上下文里,项目一大,上下文窗口越拉越长——不仅又慢又贵,更危险的是窗口逼近上限时模型会自动总结压缩历史,而压缩很可能把正在编写模块的关键细节丢掉,于是越写越容易出 bug。
| 失效环节 | 表现 | 对策 |
|---|---|---|
| 需求模糊 | AI 写出的东西总差一口气,反复改成一堆烂代码 | 先用文档把需求钉死,再动手 |
| 上下文膨胀 | 越写越慢越贵,模型开始忘细节 | 每个会话只做一件事,做完就清 |
| 自动压缩丢信息 | 总结历史时丢掉正在写的模块细节 | 关键信息落到文件,不依赖聊天历史 |
| 弱类型语言太灵活 | AI 自由发挥引入隐性错误 | 用类型检查 + 单测做强约束 |
核心机制:文档即上下文
整套方法只有一个中心思想——把每一步的成果浓缩进文件,让下一步在干净的新会话里、基于文件而不是聊天历史继续工作。
这样做同时解决三件事:省 token、防止模型幻觉、让任何一步都可以随时换个新会话重来。它和 Agent Workflow 与评估 里“可恢复”的要求是同一件事的两种说法:状态不在对话里,在文件里。
| 阶段 | 落地文件 | 这一步只回答 |
|---|---|---|
| 需求 | proposal.md | 到底要做什么 |
| 概要设计 | 需求文档内的“功能需求”章节 | 分成哪些模块、模块间什么关系 |
| 详细设计 | 每模块一份设计文档 | 每个模块具体怎么实现 |
| 任务拆分 | 每模块一份任务清单 + 总 progress.md | 做到哪了、还差什么 |
| 实现 | 每模块一个代码文件 + 一个测试文件 | 按设计和任务把代码写出来 |
四步流程
text
需求 (proposal.md,让 AI 主动提问)
-> 概要设计 (划分独立模块)
-> 详细设计 (每模块一份,新会话)
-> 任务拆分 (每模块 checklist + progress.md,新会话)
-> 实现 (监工 Agent 派发子 Agent,每模块独立上下文)每一步之间都开新会话:因为上一步的讨论成果已经沉到文件里了。这条纪律贯穿始终,是控制上下文长度的根本手段。
四步共用一个提问结构(目标 / 输入 / 输出 / 步骤),并在不确定的步骤让 AI 主动向人提问——这部分作为可复用模板单独整理,见 结构化编码的四段式 Prompt。
监工 Agent + 子 Agent 架构
实现阶段是上下文压力最大的地方。最直觉的做法——把整份任务清单塞给一个 Agent 顺序实现——恰恰最糟:整个程序都挤在同一个上下文里,必然触发多次压缩,质量难保、花费还高。
更好的结构是分层:
| 角色 | 职责 | 上下文特征 |
|---|---|---|
| 监工 Agent | 读 progress.md,为每个模块派发子 Agent,跟踪整体进度 | 只装进度,不装实现细节,始终短 |
| 子 Agent × N | 各自负责一个模块的实现、单测与验证 | 只装自己模块的设计和任务,互不干扰 |
关键约束:整个实现过程全自动、无人参与,人唯一能下命令的时刻,是监工 Agent 最开始收到的那个 prompt。所以这个 prompt 必须同时写清监工做什么、每个子 Agent 做什么,会相当复杂——复杂到它本身也值得让 AI 来生成(用一个“生成 prompt 的 prompt”,见上面链接的模板文档)。
这和 Agent 产品操作系统 的分层思路一致:把长任务切成互不污染的短上下文,是多 Agent 协作最实在的收益,而不是“Agent 数量多”本身。
质量护栏:每行代码都要有测试和类型检查
弱类型语言(Python/JS)灵活,AI 又爱自由发挥,两个不确定性叠加,光靠“看起来对”兜不住。所以在写第一行业务代码之前,护栏就要立好:
| 护栏 | 作用 | 何时立 |
|---|---|---|
| 类型检查(如 mypy) | 运行前抓出类型层面的逻辑错误 | 建工程时就装好 |
| 语法/风格检查(如 ruff) | 统一风格,挡低级错误 | 建工程时就装好 |
| 单元测试(如 pytest) | 每个模块一个测试文件,覆盖每行代码 | 写代码时同步生成 |
要求写进监工 prompt:每一行代码都要有对应单测,并且必须通过类型检查和语法检查,子 Agent 才算完成一个模块。上面那次实践最终产出了每模块一个代码文件 + 一个测试文件、近两百个测试全通过的结果。
测试和类型检查真正的价值不在“证明现在是对的”,而在未来加新功能时不破坏旧功能。没有这层回归防线,AI 每加一个特性都可能悄悄弄坏另一个——这正是“用嘴编程”最后代码腐烂的机制。
顺带一个语言选择的产品判断
“用什么语言”对 AI 编码不是中立选择,而是一个可以列清楚的权衡:
| 取向 | 收益 | 代价 |
|---|---|---|
| 选 AI 最擅长的语言(Python/JS) | 模型训练语料多、第三方库全,少造轮子、少幻觉 | 语言本身弱类型,需外挂类型检查补安全 |
| 选强约束语言(如 Rust) | 语法严格带来的安全性 | AI 生成的熟练度低,连编译通过都更费劲 |
我的判断是:既然代码由 AI 写,就优先选它最熟的语言把“写得出、写得对”的概率拉满,再用类型检查和单测把弱类型丢掉的安全补回来——把安全从“语言默认给”转成“工程流程给”,比让 AI 硬啃不擅长的语言更划算。
我的判断
这套方法看起来是编码技巧,本质是 Context 管理:它把“别让上下文太长”这条抽象原则,落成了一套具体动作——分步、落文件、开新会话、分层派 Agent、立测试护栏。
对 AI 产品经理,有两点可直接迁移:
- 面向自己:任何交给 AI 的复杂任务,都值得先问“状态存在对话里还是文件里”。存在文件里,任务才可拆、可恢复、可换会话重来。
- 面向产品:设计 AI 生成类产品(写代码、写文档、做设计)时,真正的壁垒不是调一次模型有多强,而是有没有这套“需求文档 → 设计 → 任务 → 分层执行 → 自动验证”的结构在背后兜底。模型会一直变强,但可拆解、可验证、可持续迭代的工程结构,才是产出质量长期变好的基础。