AI 帮我写代码之后,我整理了一套人机协作的提案流程
先说一个有点绕的事实:这篇文章发布之后,你在这个博客右下角问 AI 助手「这个项目怎么开发的」,它会检索到这篇文章,然后用这篇文章里描述的流程,向你解释它自己是怎么被开发出来的。
我觉得这个自洽挺迷人的,所以把这个流程单独成文。它解决的问题是:AI 写代码很快,但「快」不等于「对」,怎么在享受速度的同时不失去对项目的控制。
问题:AI 的默认行为是「立刻开始写」
如果你直接把「给我写一个 RAG 后端」丢给 AI,它会立刻开始输出代码。代码能跑,但里面塞满了它替你做的决定:目录结构、依赖版本、接口字段、错误处理策略。这些决定单独看都合理,合起来是不是你要的东西,要等几千行代码落地之后才知道——那时候的返工成本是真实存在的。
所以这个项目里,我强制 AI 走了一个流程:每个模块先出提案,我确认,然后才允许写代码。
提案机制:写代码之前先写「打算怎么写」
仓库里有一个 提案记录/ 目录,整个项目攒了五份:项目初始化、RAG 核心管道、API 接口、前端聊天组件、Astro 工程化。每份提案的格式固定:
- 目标:这个阶段做完,什么东西变成可用的
- 任务范围:一张表,逐项列出任务和产出文件,哪些本次实施、哪些明确不做
- 技术方案:关键代码骨架、协议格式、目录结构,直接写在提案里
- 状态:待确认 / 已确认并实施完成
拿 API 接口那份提案举例,它在我看到任何实现代码之前,就定死了这些东西:请求体的 Schema 长什么样、SSE 每帧的 JSON 格式、流式管道的步骤顺序、以及「stats 统计接口这次不做」。我审提案的时候改了分块策略的参数、砍掉了一个用不上的端点,成本是改文档里的几行字——如果这些决定是在代码里改,成本是另一个量级。
提案还有一个隐藏价值:它是天然的进度存档。每个阶段结束时提案状态翻转为「已实施完成」,项目走到哪一步、每步做了什么取舍,全部可查。这比翻 git log 的语义密度高得多。
文档驱动:doc/ 目录是项目的骨架
提案不是唯一的文档。整个 doc/ 目录形成了一条链:
PRD文档 → 前端开发文档 → 智能体开发流程与规范 → 后端部署文档 → 上线检查清单
每一份的读者都不是「未来的我」,而是「下一次会话的 AI」。这是文档驱动在 AI 协作时代的新含义:AI 没有记忆,每次对话都是第一次见面,文档就是它的长期记忆。开发文档里写清了技术栈版本、目录约定、命名规范,AI 生成的每一批代码都落在同一个约束框架里,不会每隔几小时换一种风格。
最典型的例子是 frontmatter 规范:文章元数据的五个字段、category 只能是哪四个值,写死在开发文档里。后来构建时的 Zod 校验、索引脚本的解析逻辑、和我写的所有文章,全部对齐这一份定义,三方没出过一次偏差。
接口契约先行:联调不扯皮的唯一办法
前后端是并行开发的——严格说,是同一个 AI 在写两边,但中间隔着我的确认。能并行的前提是契约先定稿。
SSE 协议在动手前就写进了开发文档,四个字段定死:content(文本增量)、done(是否最后一帧)、sources(相关文章,{title, url} 数组,只在最后一帧出现)、degraded(降级标记)。前端拿着这份契约,用 ?mock=1 的假流式数据先把整个聊天窗做完;后端拿着同一份契约实现推送。两边汇合的时候,一次对接成功,没有一轮「你字段名是不是改了」的扯皮。
当然,契约定死了不代表实现不会错——后来那个 CRLF 换行符的 bug(单独写过)恰恰是「两端各自符合自己对契约的理解,但理解不一致」。所以现在的认识是:契约要定到字节层。JSON 字段是契约,帧分隔符也是契约,后者当初没写进文档,代价是两天。
工具链:不是一个 AI,是两个
这个项目实际用了两套 AI 工具,分工很明确:
- 后端:Trae + GLM 5.3。后端的活偏逻辑和管道:RAG 检索、SSE 推送、限流器、部署脚本。Trae 作为 IDE 形态的 AI 编程工具,在多文件上下文和终端命令执行上很顺手,配 GLM 5.3 的模型能力,后端的五个模块(初始化、RAG 管道、API 接口、部署、测试)全是这个组合产出的。
- 前端:Kimi K3。前端的活偏「手感」:Astro 工程化、聊天窗的状态机、轨道悬浮球、流式渲染的逐字效果。这类需求需要大量来回打磨交互细节,Kimi K3 在前端代码的完成度和设计还原上表现更好。
代码之外,AI 还包了一个我原本打算花钱外包的活:Logo 设计。过程就是提案流程的缩小版——AI 先给了 4 个设计方向,我选定「K + 轨道」;再在 6 个 K 字变体里选定一笔连写;然后 AI 生成图像,v1 笔画过粗被我打回,v2 恢复连笔后定稿,最后裁出纯图标版做 favicon。品牌概念也是一起聊出来的:Kalpa 是梵语「劫波」,宇宙的一个纪元,配上 Code,寓意用代码记录跨越时间的技术思考。轨道环这个元素后来还反哺了前端——聊天入口的悬浮球就是沿着轨道绕行的卫星,Logo 的静态设计在页面上动了起来。
用两个工具不是刻意的,是顺手演化出来的,但回头看有个意外收获:它变相验证了文档驱动的价值。两个 AI 之间没有任何共享记忆,换工具等于换了一个完全不了解项目的「新人」。能让新人十分钟上手干活的,不是口头交接,而是 doc/ 目录里那条文档链——新工具读完开发文档和提案记录,生成的代码和前一个工具的产出能对上同一个约束框架。如果当时图省事没写文档,换工具的代价就是重新解释一遍项目。
分工的真实边界
两天跑下来,人和 AI 的实际分工长这样:
AI 负责:几乎全部代码实现、文档初稿、提案初稿、测试用例、报错后的修复方案。
我负责:所有「要不要」的决定(上不上 Dify、用什么模型、分块策略选哪种)、所有「对不对」的验收(每条链路的实际行为测试)、以及所有「值不值」的权衡(mock 模式值不值得留在线上)。
这个边界不是设计出来的,是踩出来的。中间有几次我偷懒跳过了提案确认,让 AI 直接写,结果都是返工——AI 的实现永远逻辑自洽,但自洽的方向未必是我要的方向。提案机制的全部意义就是把方向校准这件事,从「改代码」提前到「改文档」。
复盘
很多人讨论 AI 编程时纠结「它写的代码你敢不敢用」。这个项目给我的答案是:代码敢不敢用不是问题,决策敢不敢给它才是。当所有关键决策都经过提案被我确认,代码本身反而成了最不需要担心的部分——它只是被执行过的决定。
这套流程对一个人 + AI 的小项目可能显得重。但回头看,五份提案加六份文档,写作时间加起来不到两小时,挡住的是至少三次大规模返工。而且它们现在还在工作:你问右下角的助手任何一个架构问题,它检索到的答案,就是当时这些文档里的句子。
流程的产物是代码,文档的产物是流程。后者活得久得多。