AI研发流程初步实践(三):Spec文档管理与决策宪法
在AI辅助开发中,有一件事的成本常常被低估——重复解释。每次新开一个会话,都要重新告诉AI”这个项目的架构是什么样的””为什么选A不选B””哪些约束不能碰”。如果没有文档化的spec(规格说明),你就是在用token和耐心为项目的”失忆”买单。spec的本质是AI辅助开发的”项目记忆”与”决策宪法”——它让AI每次会话都能快速恢复上下文,让人的设计决策不被时间冲淡。
一、概念:为什么需要文档化的spec
要理解spec的价值,先要理解AI辅助开发的一个根本矛盾:人类有长期记忆,AI没有。
人类开发者在一周前做了一个设计决策,今天打开代码还记得当初为什么那么选。但AI不会——它每一轮会话都是从零开始的。如果没有spec,AI对项目的理解完全依赖于当前上下文中的零散信息。它无法区分”这是一个深思熟虑的设计”和”这是一次随手的临时方案”。
这会导致一个典型的恶性循环:
- 第一轮会话:AI基于自己的”通用最佳实践”给出了设计方案
- 你做了修正,AI按你的意见改了
- 第二轮会话:AI再次基于”通用最佳实践”给出同样的(已被否决的)方案
- 你再纠偏一次
- 第三轮:同样的循环再来一遍
问题是:AI不记得上一轮会话中被否决的方案。每一次否决都是”第一次”否决。
Spec文档就是打破这个循环的工具。它把设计决策从”会话中的一段对话”固化为”一份可被反复读取的文档”。AI每次会话读到spec,就知道”这个项目用A方案不用B””这条约束是硬性的不能碰””这个功能属于v0.3版本当前不实现”。
除此之外,spec还有一个更重要的隐含价值:写出来才发现没想清楚。脑子里觉得”这个功能就这么做”,落到spec里要写”输入是什么、输出是什么、错误怎么处理、与现有模块怎么交互”,写着写着就发现某个分支根本没想过。Spec是把模糊想法逼成清晰决策的工具。
二、通用设计方案:spec全生命周期管理
2.1 spec、plan、design的边界
在任何文档体系中,最大的混乱来源是职责不清。spec、plan、design三类文档容易混淆,混淆会导致AI越界——plan里出现设计理由、design里出现任务清单、spec里出现实现代码。
清晰的边界划分是这样的:
| 文档类型 | 回答的问题 | 内容 | 是否含代码 |
|---|---|---|---|
| spec | 做什么、为什么、不做什么 | 范围、目标、验收标准、决策依据 | 否 |
| design | 用什么技术方案实现 | 架构图、接口签名、数据结构、算法 | 可选(伪代码/接口签名) |
| plan | 按什么顺序、每一步怎么验证 | subtask清单、验证命令、依赖关系 | 否(仅验证命令) |
spec 是决策性的。它回答”我们要做什么””为什么这么做””我们不做什么”。它的读者是人和AI——需要理解项目方向和设计约束的人。
design 是技术性的。它回答”用什么技术方案实现”。架构图、接口签名、数据模型、关键算法都在design文档里。它是spec和plan之间的桥梁——从spec的”做什么”翻译到plan的”怎么做”。
plan 是执行性的。它回答”先做什么、后做什么、每一步怎么验证”。subtask清单 + 验证命令是plan的核心。plan里不允许出现实现代码。
最常见的越界是:spec里写实现细节(应挪到design或实现阶段)、plan里写设计理由(应回spec)、design里写任务清单(应挪到plan)。一旦越界,文档职责模糊,AI不确定某条信息是”约束”还是”建议”,执行时就会打折扣。
一个简单的判断方法:拿一段内容问”这是约束、是步骤、还是技术选择?”——约束归spec,步骤归plan,技术选择归design。
2.2文件命名与组织
Spec文件的命名需要同时支持时间回溯和主题检索。标准命名格式:
1 | YYYY-MM-DD-<topic>-design.md |
YYYY-MM-DD:创建日期,按时间排序后就是项目设计决策的历史时间线<topic>:主题短词,如auth-redesign、api-rate-limiting、0.2.3-learn-system-design.md:后缀表明这是设计文档
所有spec统一存放在一个目录下(如 docs/specs/),不分散在模块目录。原因有二:
- 全局检索:一个目录里看到所有设计决策,一眼可知”这个项目做过哪些决策”
- 跨模块引用:A模块的spec可能引用B模块的spec,集中存放路径稳定
当目录下文件多了之后(几十份spec),可以按年份或版本分子目录,但不要按模块分子目录——按模块分会破坏时间线,让你难以回答”某段时间这个项目在做什么”。
2.3 spec的生命周期
一份spec从诞生到归档,经历五个阶段:
阶段一:草稿
spec的初稿来自brainstorming阶段的决策表。brainstorming中每条开放问题的”选项 + 决策 + 依据”直接搬进spec对应的章节。此时spec还处于”正在成型”的状态,可能随时修改。
阶段二:待批(self-review + user review)
草稿完成后,进入审核阶段。审核分两步:
self-review:AI自己按检查清单过一遍。self-review不是走形式,需要真的逐项检查:
- placeholder残留:搜索
TODO、TBD、待定、xxx、???,所有占位符必须填实或删除 - 前后一致性:前文说”支持5种协议”,后文列表只有4种;前文说”默认true”,配置示例里写
false - 范围合理:in scope与out of scope划分清晰,每条in scope有对应的验收标准
- 歧义表述:搜”大致””可能””看情况””视具体情况”——这些词都是歧义信号,要么具体化,要么明确为开放问题
- 决策依据:每条决策后面有”为什么”。没有依据的决策等于没决策
- placeholder残留:搜索
user review gate:self-review通过后,提交用户审核。用户没点头之前,不允许进入plan阶段。这道门不是形式主义——AI写spec时经常把”未来版本”的内容写进当前spec,或用模糊词掩盖未决策的问题。human review是把这些”软错误”逼出来的最后机会。
阶段三:生效
user review通过后,spec成为后续plan与实现的”宪法”。任何实现决策与spec冲突,要么改实现,要么改spec,不能”私下偏离”。spec在生效状态下是权威的。
阶段四:修订
spec不是写完就冻结的。实现过程中会发现某些决策不可行,需要调整。修订规则:
- 变更必须留痕——在spec里加”变更记录”章节,记录日期 + 变更点 + 原因
- 重大变更(范围调整、架构变更)要重新过user review
- 过时的决策在spec里标注”v0.x.y已变更,参见YYYY-spec”
阶段五:归档
版本发布后,spec归档为该版本的设计记录。归档不是删除,是标记为”历史版本的设计依据”。归档后spec不再生效,但未来回溯时可以查询。
下图展示了spec从诞生到归档的完整生命周期:

2.4 spec与代码的同步
spec与代码的同步,是文档管理中最容易被忽视、也最容易出问题的一环。典型的信号是:代码改了spec没改、spec改了代码没改、两者都改了但方向不一致。
同步的核心原则是三条:
spec变更必须先于代码变更。先改spec,再改代码。这类似于TDD的”先写测试再写实现”——先描述你要做什么,再去做。如果先改了代码再改spec,spec就会变成”对代码的事后解释”,失去”宪法”地位。
变更记录必须保留。不要直接覆盖原文。在spec里保留变更记录章节,让读者看到”当初这么设计→后来发现不可行→改成了这样”。决策演进本身是有价值的技术债务记录。
封仓时做spec与代码的对账。版本发布前,逐条检查spec的验收标准是否与代码行为一致。发现的差异,要么改代码要么改spec,不能留”已知差异”带进发布版本。
2.5何时该写spec、何时不必
不是所有改动都需要写spec。判断标准决定了spec体系的可持续性——过度写spec与不写spec一样有害。
该写spec的场景:
- 系统性变更——新增模块、重构架构、引入依赖、调整核心抽象
- 跨版本规划——路线图、版本规划、多版本兼容策略
- 涉及多个模块协同的功能
- 有重要决策需要记录的改动(半年后还需要知道”为什么这么选”)
不必写spec的场景:
- trivial改动——改个文案、修个typo、调整常量值
- 单点bug修复——修一个明确的小bug
- 纯实验性探索——还没决定要不要做的试验
判断尺度:”这个改动会影响哪些模块?””半年后还需要知道为什么这么改吗?”——影响多模块、需要长期记忆的,写spec;局部、一次性的,直接改。
过度spec的问题在于:给每个typo都写spec,spec的价值被稀释,重要的设计文档淹没在噪音里。Spec要写在该写的地方,让它成为”重要决策的索引”而非”所有改动的流水账”。
2.6 spec作为协作媒介
Spec不只是写给AI的,也是团队协作的媒介:
- PR review依据:reviewer看PR时,对照spec判断”实现是否符合设计”。PR偏离spec要么改PR要么改spec。
- 新人onboarding文档:新人入项目,先读最新版本的spec,再读代码。Spec是”设计意图”,代码是”设计落地”,先读意图再看落地,理解更快。
- 跨团队对齐:多个团队或协作者共享同一份spec,保证实现方向一致。
即使是个人项目,把AI当作协作者,spec也是你与AI之间的契约。每次会话开始把spec喂给AI,比每次重新解释省心得多。
三、市面其他方案对比
围绕”AI辅助开发中的文档管理”,市面上的实践大致可以归纳为三种方案。
3.1方案A:无文档化,全部靠对话记忆
这是最普遍的做法——不开文档、不写spec,所有需求、决策、设计全部在聊天会话中完成。每次开会话就是一次新的”从零解释”。
设计特点:
- 零维护成本:不需要花时间写文档
- 最灵活:需求变更是”直接告诉AI”,不需要更新文档
- 完全依赖对话历史:当前会话中一切信息都在,但跨会话全部丢失
- 适合一次性任务:完成任务后不需要再回顾
适用场景:一次性脚本、快速原型、临时任务。做完即弃,不需要后续维护。
局限性:一旦任务需要跨多轮会话完成,或者需要在几周后回顾,问题就暴露了。你花了大把时间重复解释同样的事情,AI也在重复犯同样的错误。决策无法回溯——两周后你问自己”当时为什么这么选”,没有任何记录。
3.2方案B:需求记录在聊天会话中
比方案A好一点——用户会在聊天过程中记录一些关键需求,或者在会话结束时让AI整理一份纪要。但这些记录通常留在聊天平台里,不是结构化的文档。
设计特点:
- 聊天作为记录载体:需求和决策记录在对话中,有关键词可搜索
- 有一定上下文保留:下次会话可以引用上一轮的聊天记录
- 非结构化:信息分散在对话中,没有统一格式和组织
- 跨session可用性视工具而定:有些平台支持跨会话搜索,但大部分不支持
适用场景:中小型项目,团队可以使用聊天平台的历史记录功能。
局限性:信息仍然容易丢失。聊天记录不是结构化文档,找一条关键决策可能需要翻几十页对话。而且AI对聊天记录的理解也是”概率性”的——它可能漏掉重要约束,也可能高估某条随口说说的想法。跨session的上下文”衰减”严重,几轮会话之后早期决策几乎被遗忘。
3.3方案C:文档化spec全生命周期管理
这就是本文详述的方案——用结构化的spec文档管理所有设计决策,从brainstorming到归档全流程覆盖。
设计特点:
- 结构化文档:spec有统一格式、命名规范、目录组织
- 全生命周期管理:从草稿、审核、生效、修订到归档
- 文档即契约:spec是AI和人之间的共同约定
- 跨session可用:任何新会话先读spec,瞬间恢复上下文
- 可回溯:历史spec保留决策演进的完整记录
适用场景:长期迭代的产品项目、多人协作团队、需要可持续维护的项目。
代价:维护成本最高。写一份好的spec需要时间,审核需要时间,同步需要时间。对于一些快速变化的项目,spec可能刚写完就要改,文档维护成本可能超过收益。
3.4对比总结
| 维度 | 方案A(无文档) | 方案B(聊天记录) | 方案C(结构化spec) |
|---|---|---|---|
| 维护成本 | 最低 | 低 | 高 |
| 跨会话可用性 | 无 | 有限 | 高 |
| 信息可回溯性 | 无 | 低 | 高 |
| 决策依据保留 | 无 | 有(但难找) | 完整记录 |
| 灵活性 | 最高 | 中 | 低(变更流程化) |
| 适合项目 | 一次性任务 | 中小型项目 | 长期迭代项目 |
| 团队协作 | 难 | 中 | 好 |
三种方案对应三种项目生命周期。方案A适合”写完即弃”,方案B适合”做一阵子”,方案C适合”做一辈子”。关键是要清楚自己的项目属于哪一类。
四、aptbot的设计特点
4.1为什么选方案C
aptbot是一个开源学习型AI Agent项目。它的生命周期不是”写出来就跑”,而是长期迭代——v0.1、v0.2、v0.3……不断的版本演进。没有spec,每一次版本迭代都需要重新理解上一版本的架构设计,成本指数级上升。
但aptbot选择方案C还有更深层的原因:教学需要。aptbot的代码本身是教学材料,它的spec同样也是。读者看aptbot的spec,能学到”一份合格的spec应该包含什么””设计决策怎么记录””方案的优缺点怎么分析”。Spec不仅是aptbot给自己的记忆,也是给读者的教材。
4.2 aptbot的独特做法
决策表驱动的spec写作:aptbot的spec不是从空白开始写的,而是从brainstorming阶段的决策表转化而来。决策表中每条开放问题的”选项 + 决策 + 依据”直接成为spec对应章节的内容。这保证了spec中的每条决策都有据可查。
self-review的agent角色切换:aptbot在self-review阶段会让AI切换角色——从”spec的作者”变成”挑剔的架构师”来review自己写的spec。视角转换能暴露更多问题。这比”AI自己review自己的产出”效果更好。
变更记录作为独立章节:每份spec都有”变更记录”章节,格式为”日期 | 变更内容 | 变更原因”。这不是事后追加,而是spec的固有结构。从一开始就有这个章节,团队就不会觉得”记录变更是额外工作”。
Archive标记而非删除:归档后的spec不会被移除,而是在frontmatter中标记 status: archived。这些归档spec保留在仓库里,任何时候都可以回溯查询。即使某条决策被推翻,推翻的记录也在——后来的开发者能读到”当初为什么选A→后来发现A不行→改成了B”的完整叙事,而不是只看到B。
spec与spec之间的引用关系:一份spec可能引用另一份spec的决策。例如”API认证策略”的spec会引用”用户数据模型”的spec。aptbot在spec中维护引用链接(参见:YYYY-MM-DD-user-model-design.md),让跨spec的决策网络可追溯。
4.3与其他方案的差异
和三种方案相比,aptbot在spec管理上最大的差异是”把spec也当作代码来管理“。
在方案A和方案B中,文档是”附属品”——代码是主角,文档是辅助。在方案C的典型实践中,文档是”并行品”——代码和文档并行维护,各有各的流程。
在aptbot中,spec本身就是产品的一部分。spec的版本管理和代码的版本管理走同一套流程——提交PR、review、合并。spec的修改触发和代码修改相同的CI检查(格式校验、链接检查等)。Spec和代码在同一个仓库、同一个分支、同一个迭代周期里,天然同步。
这个设计哲学的背后是aptbot对”什么是项目”的理解:项目 = 代码 + 设计决策 + 迭代历史。三个要素缺一不可,而spec是”设计决策”的载体。
五、发展方向
更智能的spec生成:当前spec主要依赖brainstorming决策表转化为文本。未来可以让agent在完成一个迭代后,自动分析代码变化与spec的差距,生成spec更新建议。不需要人逐字逐句更新,agent先出一版draft,人审核确认。
spec与代码的双向绑定:当前spec引用代码、代码有注释,但两者之间没有自动化的双向链接。未来可以在spec中标注”本条决策对应的文件/函数”,在代码中标注”此实现对应的spec条目”,让agent可以在代码变更时自动检测对应的spec是否需要更新。
活的spec:当前的spec是静态markdown文件。未来可以引入”活的spec”概念——spec中的接口签名和数据模型直接从代码中提取,保持实时同步。spec不再是”写完可能过时”的静态文档,而是”随时与代码一致”的动态视图。
可视化spec网络:随着spec数量增长,spec之间的引用关系会形成网络。可视化这个网络,让开发者一眼看到”这个决策影响了哪些模块””这个模块被哪些spec约束”,对于大型项目非常有价值。
spec质量的自动化评估:当前self-review是手动或半自动的。未来可以开发spec质量检查器——检查每条决策是否有依据、是否有验收标准、是否存在歧义表述、范围是否合理。把spec审核从”人工检查”变成”自动检查 + 人工确认”。
小结
Spec文档管理是AI辅助开发中常被低估但至关重要的一环:
它的价值:Spec是AI的”项目记忆”和”决策宪法”。它让AI跨会话保持决策一致性,让人能够在几个月后理解当初的设计选择。写spec的时间是一次性的,不写spec的重复解释成本是持续性的。
它的边界:Spec回答”做什么、为什么、不做什么”;design回答”用什么技术方案”;plan回答”按什么顺序、怎么验证”。三类文档职责清晰,不越界。
它的生命周期:草稿 → self-review + user review → 生效 → 修订 → 归档。每个阶段有明确的状态和质量门,让spec从诞生到退役全程可控。
方案对比:方案A(无文档)最灵活但无法回溯;方案B(聊天记录)有一定上下文但跨session丢失严重;方案C(结构化spec)最规范但维护成本最高。aptbot选择方案C,并将spec作为产品的一部分与代码同步管理。
写到这里,AI辅助开发方法论的三篇核心文章就完成了。从第一篇的工作流约束(怎么管过程),到第二篇的质量防线(怎么保质量),再到第三篇的spec管理(怎么记决策),这三者构成了结构化AI辅助开发的完整图景。如果你是一个正在将AI引入开发流程的开发者,这三篇方法论的思路可以帮助你避免最常见的坑——那些”看起来对了但实际错了”的时刻。