AI研发流程初步实践(三):Spec文档管理与决策宪法

在AI辅助开发中,有一件事的成本常常被低估——重复解释。每次新开一个会话,都要重新告诉AI”这个项目的架构是什么样的””为什么选A不选B””哪些约束不能碰”。如果没有文档化的spec(规格说明),你就是在用token和耐心为项目的”失忆”买单。spec的本质是AI辅助开发的”项目记忆”与”决策宪法”——它让AI每次会话都能快速恢复上下文,让人的设计决策不被时间冲淡。

一、概念:为什么需要文档化的spec

要理解spec的价值,先要理解AI辅助开发的一个根本矛盾:人类有长期记忆,AI没有

人类开发者在一周前做了一个设计决策,今天打开代码还记得当初为什么那么选。但AI不会——它每一轮会话都是从零开始的。如果没有spec,AI对项目的理解完全依赖于当前上下文中的零散信息。它无法区分”这是一个深思熟虑的设计”和”这是一次随手的临时方案”。

这会导致一个典型的恶性循环:

  1. 第一轮会话:AI基于自己的”通用最佳实践”给出了设计方案
  2. 你做了修正,AI按你的意见改了
  3. 第二轮会话:AI再次基于”通用最佳实践”给出同样的(已被否决的)方案
  4. 你再纠偏一次
  5. 第三轮:同样的循环再来一遍

问题是: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-redesignapi-rate-limiting0.2.3-learn-system
  • -design.md:后缀表明这是设计文档

所有spec统一存放在一个目录下(如 docs/specs/),不分散在模块目录。原因有二:

  1. 全局检索:一个目录里看到所有设计决策,一眼可知”这个项目做过哪些决策”
  2. 跨模块引用:A模块的spec可能引用B模块的spec,集中存放路径稳定

当目录下文件多了之后(几十份spec),可以按年份或版本分子目录,但不要按模块分子目录——按模块分会破坏时间线,让你难以回答”某段时间这个项目在做什么”。

2.3 spec的生命周期

一份spec从诞生到归档,经历五个阶段:

阶段一:草稿
spec的初稿来自brainstorming阶段的决策表。brainstorming中每条开放问题的”选项 + 决策 + 依据”直接搬进spec对应的章节。此时spec还处于”正在成型”的状态,可能随时修改。

阶段二:待批(self-review + user review)
草稿完成后,进入审核阶段。审核分两步:

  1. self-review:AI自己按检查清单过一遍。self-review不是走形式,需要真的逐项检查:

    • placeholder残留:搜索 TODOTBD待定xxx???,所有占位符必须填实或删除
    • 前后一致性:前文说”支持5种协议”,后文列表只有4种;前文说”默认true”,配置示例里写 false
    • 范围合理:in scope与out of scope划分清晰,每条in scope有对应的验收标准
    • 歧义表述:搜”大致””可能””看情况””视具体情况”——这些词都是歧义信号,要么具体化,要么明确为开放问题
    • 决策依据:每条决策后面有”为什么”。没有依据的决策等于没决策
  2. 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从诞生到归档的完整生命周期:

Spec文档生命周期

2.4 spec与代码的同步

spec与代码的同步,是文档管理中最容易被忽视、也最容易出问题的一环。典型的信号是:代码改了spec没改、spec改了代码没改、两者都改了但方向不一致。

同步的核心原则是三条:

  1. spec变更必须先于代码变更。先改spec,再改代码。这类似于TDD的”先写测试再写实现”——先描述你要做什么,再去做。如果先改了代码再改spec,spec就会变成”对代码的事后解释”,失去”宪法”地位。

  2. 变更记录必须保留。不要直接覆盖原文。在spec里保留变更记录章节,让读者看到”当初这么设计→后来发现不可行→改成了这样”。决策演进本身是有价值的技术债务记录。

  3. 封仓时做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辅助开发中常被低估但至关重要的一环:

  1. 它的价值:Spec是AI的”项目记忆”和”决策宪法”。它让AI跨会话保持决策一致性,让人能够在几个月后理解当初的设计选择。写spec的时间是一次性的,不写spec的重复解释成本是持续性的。

  2. 它的边界:Spec回答”做什么、为什么、不做什么”;design回答”用什么技术方案”;plan回答”按什么顺序、怎么验证”。三类文档职责清晰,不越界。

  3. 它的生命周期:草稿 → self-review + user review → 生效 → 修订 → 归档。每个阶段有明确的状态和质量门,让spec从诞生到退役全程可控。

  4. 方案对比:方案A(无文档)最灵活但无法回溯;方案B(聊天记录)有一定上下文但跨session丢失严重;方案C(结构化spec)最规范但维护成本最高。aptbot选择方案C,并将spec作为产品的一部分与代码同步管理。

写到这里,AI辅助开发方法论的三篇核心文章就完成了。从第一篇的工作流约束(怎么管过程),到第二篇的质量防线(怎么保质量),再到第三篇的spec管理(怎么记决策),这三者构成了结构化AI辅助开发的完整图景。如果你是一个正在将AI引入开发流程的开发者,这三篇方法论的思路可以帮助你避免最常见的坑——那些”看起来对了但实际错了”的时刻。