Spec 驱动 AI 开发 v2.1:设计先行、受控实现与真实验证
让 AI 给列表加一个“导出筛选结果”按钮,它可能很快交付一个能下载 CSV 的页面。按钮可点,文件可读,构建也通过了。
但打开文件,里面是全部记录。
这个问题并不难修。真正值得追问的是:为什么任务已经被标成“完成”,最重要的要求却没有被验证?如果此前还生成过需求文档、设计方案和任务清单,这些文档究竟起了什么作用?
我之前在《让 AI Agent 接力开发中大型需求:一套可持续的多会话 Coding 工作流》中尝试用设计文档和工作包支撑跨会话开发,后来又整理了 spec-driven-ai-coding Skill,希望进一步把需求、实现与验收连接起来。
对这套 Skill 做审计和 Review 后,需要调整的恰好也包括流程本身:任务切得过于机械,所有修改都向需求文档回流,公共模块被赋予过多职责,文档检查的能力被说得过满。流程看起来严密,却可能增加维护成本,甚至让错误实现获得一套整齐的说明。
这篇文章于 2026 年 9 月 8 日更新至 v2.1.0,保留 v2.0 的按需规划、受控实现与真实验证原则,并补上前端实践中暴露出的缺口:写 UI 之前先设计,初版之后实际看效果、找问题、修复并复验。
短暂实践后发现,即使功能方向正确,Agent 仍可能在设计文档里写完框架和接口,就直接生成页面。按钮都在,布局却松散;短文本能显示,长错误信息却挡住操作;独立页面看似完整,放回产品又不像同一套界面。这些问题需要在实际渲染和使用中检查,不能只靠代码里存在某个元素来判断。
v2.1 把前端设计和渲染验收接入原有流程。设计细节由 Agent 在已授权范围内自主推进,记录沿用现有文档;核心仍是让 AI 对需求、修改边界和验证证据负责。
一、先决定需要多少流程
“项目级”容易让人联想到一套覆盖整个仓库的 BRD、模块设计和总任务表。实际上,它首先意味着开发必须尊重项目已有的架构、代码基线和协作规则。一次局部修复,同样可以满足这个要求。
开始任务时,Agent 应当先读相关实现、已有约定和验证入口,检查未提交改动,再决定采用什么流程。仓库里已经有答案的问题,例如用哪个组件库、接口错误如何表达,不必重新交给用户选择。
v2.0 把三个判断分开:
S、M、L 是文档预算
S:边界明确的局部变化。 读代码,说明目标与验收,实施并做针对性验证即可,不自动新建 Spec 目录。把已存在的导出函数接到正确筛选条件上,可能就是 S。
M:一个连贯功能。 需要保存需求、设计和可恢复任务计划,默认使用三份短 Markdown 与一个 spec.json。一个带前端入口和保存接口的设置功能可以是 M,跨前后端本身不构成升级理由。
L:多个交付增量或多个协作边界。 增加粗粒度业务规划和必要的模块组织,只展开当前批次。多 Agent 并行是可选执行方式。
与此同时,单文件的资源归属校验修复可以是 S + high risk:文档仍然短,但越权反例和批准依据必须明确。十几个文件的机械重命名,也不必仅因文件数量升为 L。
如果不确定浏览器能否处理目标规模的导出数据,可以先做一个有边界的 spike:约定数据规模、待回答的问题、实验位置、资源限制和结束条件,在隔离环境中测量,再把结论带回设计。实验没有回答的问题继续保留为未知;不要为了填满非功能需求表,直接承诺一个没有依据的延迟指标。
二、Spec 首先要说明怎样才算做对
下面用一个假设场景贯穿后续讨论:现有业务系统已经有记录列表和状态筛选,现在要增加 CSV 导出。当前范围包括页面入口、导出请求和失败反馈,因此按一个 M 级功能规划。
这些需求是为了讲清方法而设定的示例,并非任何项目都应照搬的默认产品行为。
“导出筛选结果”至少还有几个未回答的问题:导出当前页还是全部匹配记录?排序是否一致?没有结果时怎么办?用户可以导出哪些字段?发起请求后又修改筛选条件,以哪一刻为准?
其中一部分可以从项目契约中找到答案,剩下影响产品行为的取舍才需要确认。假设本次确认的范围是:
- 导出点击时的筛选快照对应的全部匹配记录,顺序沿用当前排序。
- 字段固定为当前用户允许导出的列,沿用服务端访问策略。
- 无匹配记录时生成仅含表头的 CSV。
- 导出失败时保留页面筛选与已有结果,提示错误并允许重试。
- 本次沿用已有同步导出容量限制;异步任务、定时导出和自定义列不在范围内。
这时才有了可以讨论的设计输入。若容量限制和目标规模尚不清楚,应先查明或实验,而不是直接把同步方案写成既定结论。
用稳定 AC 连接需求与验证
R 是具体需求,AC 是验收标准。AC 应描述“在什么条件下,执行什么操作,会得到什么可观察结果”。编号用于后续引用,执行状态由任务和验证记录维护。
下面是 v2 需求格式的节选,不是独立可运行的完整 Spec:
注意第一条中的“全部”与“点击时”。只写“导出成功”,就无法区分导出了当前页、全部记录,还是请求发起后新筛选条件对应的记录。
权限也需要独立的可验证要求。例如,构造超出当前用户数据范围的请求时,服务端必须遵循既有契约拒绝请求或限制结果;具体采用哪种语义,应引用项目规范,不能由 Agent 临时决定。CSV 的特殊字符处理、容量上限等,也应根据当前接口承诺形成相应 AC。
当需求、设计、任务和验证连接起来,检查遗漏才有落点:
这里的价值是可追溯:哪条标准没有任务承接,哪项检查不足以证明结果,能够被明确指出。编号本身无法保证需求正确,更不能自动消除遗漏。
三、让文档各自维护一类事实
M 级流程的起点很小:
前三份 Markdown 可以很短。执行记录在真正实施后创建,变更单、探索记录、交接文件等按需补充,不必预先生成一排空文件。
设计应解释本次怎样接入真实系统
导出功能的设计至少需要回答:列表与导出能否复用同一套筛选规则?服务端如何执行访问控制?导出请求如何携带筛选快照?已有 CSV 库是否足够?失败反馈复用哪个组件?
这些答案应指向实际代码路径。若已有 OpenAPI、Schema 或 TypeScript 类型是接口事实来源,就引用它们,并说明本次差异。把同一份协议复制进每个模块文档,反而容易出现几套“最新定义”。
文档中的模块也只是组织需求和职责的方式。modules/module-export/ 不意味着必须在源码里建立同名目录;源码继续遵循项目已有分层。
总览只从任务源生成
旧流程很容易在模块 tasks.md 和总任务表里各维护一次状态。某个 Agent 改了一边,另一边还写着“未开始”,下一轮便不知道该相信谁。
v2 将任务元数据和详情合并在同一个任务块中,以 tasks.md 为唯一任务状态来源。spec.json 不保存第二套任务进度;可选的 task-list-overall.md 由脚本生成,作为查看入口。
一个事实只维护一处,其他地方通过引用或生成得到。 这条约束通常比再增加一轮“记得同步所有文档”的提醒更可靠。
四、写前端之前,先把界面设计清楚
技术设计与界面设计回答不同的问题。React、状态管理和接口约定说明怎样组织实现;用户先看哪里、主要操作放在哪里、列表能显示多少有效内容、错误如何恢复,则决定页面是否好用。前端实施前,两部分都需要有依据。
先找项目参照,再确定本次方案
已有项目应先读目标页面、共享组件和主题 token,在可运行环境里观察最近似的已认可页面。参照要能定位到真实文件和组件变体,不能只留一句“保持项目风格”。新项目没有旧页面时,Agent 可以根据目标用户与主工作流,自主选择布局、密度和视觉基准,不必等待用户给出高保真设计稿。
当前环境有合适的前端或设计 Skill,就读取并使用。例如 qiuye-ui-quality 提供设计参照、空间关系、真实状态和渲染审查流程;项目级 Skill 提供具体品牌、组件与数值。动效或 CSS 专项 Skill 只在当前问题需要时补充,不必一次加载所有前端 Skill。
如果没有合适的已安装 Skill,可读取上面仓库中的 SKILL.md 及其相关引用;无法联网时,使用 spec-driven-ai-coding 内置的前端流程,至少与项目现有同类页面保持一致。这个闭环不以安装新 Skill 为前提,也不能把仅提到 Skill 名称算作已经使用。
设计需要留下足以指导实现的决定。以筛选导出为例,下表是方法示例,具体组件和数值仍应来自实际项目:
先明确主次和空间,再调颜色、阴影与动效。例如导出失败提示应容易发现,但不应挤走大半列表;窄屏重排既要避免遮挡,也要保留操作与内容的关系。单纯做到“没有横向溢出”,不能证明空间分配合理。
M/L 将这些决定写入当前 design.md,已有规范用引用加本次差异;S 可以只记几行参照、目标关系与复验状态。新页面或结构重写需要清楚的布局说明、草图或轻量原型,一个 Tooltip 留白修复则无需完整页面设计。
这些内容属于实施前的设计语义审查,check_spec.py 无法自动判断其质量。已经获得范围内实施授权时,Agent 可以自主确定可逆设计细节;影响产品范围、关键行为或风险的取舍,仍按原有边界确认。设计先行不增加逐项视觉审批。
初版完成后,切换到审查视角
前端任务需要把渲染审查和修复复验纳入本次交付,不能将它们统一推到“以后有时间再打磨”。实际运行页面,确认路由、数据、字体和目标状态就绪,再查看带上下文的截图并操作主要流程。
审查顺序从整体到局部:
- 方向:与参照页面是否属于同一产品,用户能否找到主操作。
- 结构:信息层级、列表密度、横向利用和工作区高度是否合理。
- 细节:同类间距、靠角元素到相邻两边的留白、圆角、基线、截断,以及真实展开的 Tooltip 或菜单外框。
- 交互:真实操作、键盘与焦点、失败恢复、状态切换是否跳动或丢失数据。
- 适配:目标视口、主题与语言中是否出现换行、遮挡或滚动问题。
截图必须实际打开查看,必要时结合 DOM 或 computed-style 测量。元素存在断言能证明按钮被渲染,却不能证明它没有被错误提示遮住;测量得到宽度合法,也不能说明整个面板的留白自然。静态截图同样不能替代点击、键盘和恢复流程。
修复要有复验,结束要有依据
仍以导出页面为例:正常短提示没有问题,长错误信息在窄屏下挡住了重试按钮。记录可以沿着“状态/位置 → 现象 → 原因 → 改动 → 复验”展开:确认是提示区域与操作区域争抢宽度,再按设计关系修正换行和收缩约束,最后重看长短文案、窄视口和键盘焦点。这里描述的是验收方法,并非本文已经运行过的业务测试结果。
优先修方向和结构,再处理局部细节。共享组件变化应检查实际消费页和相关变体,避免一个页面修好了,另一个尺寸又失衡。验证按影响面选择,不强制每次遍历全站或所有状态组合。
完成条件是:本次范围没有已知且能处理的视觉或交互缺陷,适用行为检查通过,最终截图已审阅,证据对应最终代码。没有发现问题时,无需为了凑“两轮优化”再改一次代码;存在可修问题时,也不能仅备注“已知问题”便宣布完成。
M/L 在 tasks.md 中声明 browser 或 manual 类型的 required 渲染检查,在 record 中关联截图、交互步骤、实际代码版本、视口和状态。最后一次源码修改后,应更新受影响证据,即使 Spec 指纹未变化。缺浏览器时,独立可做的实现和检查继续进行,但视觉检查保持未运行,任务保留待验证或阻塞。
结束前清理本次启动的预览、前端服务和测试实例,保留用户原有进程。这也是让下一次接手可以从清楚基线开始的一部分。
五、围绕可验证增量拆任务
任务粒度不适合用“最多 8 个文件、300 行代码、一个会话”硬性规定。文件数少不代表容易验证,长会话也不代表必须在中途人为切断。
更实用的问题是:完成这个任务后,能观察到哪一段真实行为?它依赖什么,又会改到哪里?
在导出案例中,可以先打通一条最小端到端链路:页面传递筛选快照,服务端复用查询与访问规则,返回可读取的 CSV。随后补齐空集、容量边界、失败反馈等当前范围内的情形。最小链路是尽早验证设计的中间增量,不能据此宣布整个功能已经完成。
每个任务需要关联它承接的 AC,并包含可执行的验证计划。例如:
采用 v2 格式时,这些检查会有稳定的 V-EXPORT-01-1 等编号,以及 required 或带理由的 na 标记。不能只写“自测一下”或“运行测试”,把执行方式留给交接时的 Agent 猜测。
一个时刻一个任务,可以连续完成多个任务
Agent 领取任务前,要读当前 AC、相关设计和代码,确认依赖在本工作基线中可用,记录实际写集。任务完成后,可以继续下一个已批准且依赖就绪的任务。
需要停下的时刻是:到达批准边界、出现真实阻塞、缺少必要验证条件,或者需要交接。做完一个任务本身,不必成为强制结束会话的理由。
文件落点也不应被解释成永远不能调整。范围内的内部重排可以同步设计与写集,并说明理由;涉及其他负责人、公共接口或外部行为变化时,再按相应边界处理。
功能变大后采用滚动规划
假设导出之后还要支持异步队列、历史下载和定时任务,此时可以采用 L 级组织:
L 的 brd.md 保存业务目标、范围、关键约束和路线图,里面的 BR 再映射到具体模块需求。当前批次的需求标为 active,后续需求可以是 deferred,不必提前拆到每个按钮或每张表。
每批完成后,在集成版本上验证用户流程,再细化下一批。这样,第一条真实链路能够尽早暴露设计问题,也避免在尚未稳定的未来方案上投入过多文档维护。
六、确认应发生在真正的决策边界
Spec 驱动需要用户掌握方向,也需要 Agent 有足够空间完成已授权的工作。
对于低风险 S 级修改,明确的实施请求通常已经足够。M 默认将需求与当前设计、计划合并确认一次;L 则先确认业务范围,再确认当前批次的实施方案,最后验证批次交付结果。
这对应 CP1、CP2、CP3,但不意味着所有任务都要机械经过三轮等待。用户已经明确授权在指定范围内连续实施时,应记录真实授权来源,然后继续工作。
沿用项目习惯的内部命名、组件复用、可逆的文件组织调整,可以由 Agent 决定并在必要处说明。影响产品范围、数据语义、权限或兼容承诺的取舍,才需要显式提出。高风险工作还需要具体批准,笼统的“不用问我”不能替代不可逆操作的授权。
一个实用的请求可以这样表达:
规划中出现“批准”字段,并不代表批准已经发生。Agent 自己写下的计划也不能成为用户授权依据。spec.json 应记录可定位的真实来源;设计获准实施,也不自动包含线上发布、删除真实数据或对外发送信息等操作许可。
七、修复错误时,保留正确的验收标准
回到开头的问题:AC 要求导出筛选结果,实际导出了全部记录。
正确做法是复现问题,补上能区分这两种结果的回归验证,再修复实现。例如构造两种状态的记录,选中其中一种,读取 CSV 并断言没有混入另一种状态。条件允许时,同一检查应能展示修复前失败、修复后通过。
不应把 AC 改成“支持导出全部记录”,也不必为了修复这个实现偏差给 BRD 升级。
v2 按修改的语义区分四种情况:
分类不能只看提交前缀。“修复体验”也可能改变产品行为,“重构”也可能破坏外部接口。
需求当然可以调整,但应保留变化原因、来源及影响范围。已验收功能发生新的行为变化时,优先追加新需求与任务并关联历史,避免重写旧记录,让过去的证据看起来像是在验证今天的标准。
八、让“完成”有证据可查
文档结构通过、任务验证完成、集成验证通过和用户验收,是不同的事实。
对于筛选导出,单元测试可以证明筛选函数正确;接口检查可以证明测试服务中的请求行为;浏览器操作可以证明筛选状态确实传到了请求里。只有这些检查的范围互相衔接,才有依据判断整条链路是否成立。
区分三类质量检查
结构检查不能替代后两项。即使每条 AC 都引用了某个测试,如果测试只断言 HTTP 200,也仍然无法证明导出的内容正确。
v2.1 的前端设计门属于语义审查,渲染与交互验收属于运行验证。检查器不会自动识别 UI 任务,也不会确认截图已被查看;遗漏渲染计划后获得的结构通过,不能作为 UI 合格依据。
实际记录应包含验证日期、环境、版本和输出。版本可以是提交 SHA;有未提交修改时还需能复核的工作树或补丁指纹。不要只写“最新版测试通过”。
追踪关系应具体到 AC → V → 证据。一条 AC 可以由多项检查共同证明,一项检查也可能覆盖多条 AC。关键是审查者能够找到它验证了什么、观察到了什么,而不只是看到一个日志文件存在。
必要验证缺失时,状态就是待验证
v2 的任务状态包括:未开始、进行中、待验证、阻塞、已完成、废弃。
“待验证”表示实现已到可交付状态,但仍缺必要检查;“阻塞”表示有明确障碍,并应说明解除条件。只有任务 AC 和 required 检查通过、记录完整时,才能标为已完成。已完成也不等于已经合并,更不等于整批已验收。
na 只适用于确实不相关的检查。例如纯服务端函数没有 UI,可以不跑浏览器。若本次修改了导出交互,但当前环境没有浏览器,就应保留浏览器检查为 required,记录未运行,并保持待验证或阻塞。
同样,mock 测试可以证明本层逻辑,无法证明真实服务契约一致;构建通过可以证明构建结果,无法证明点击下载有效。
质量要求按真实场景选择
前端常见的 loading、empty、error、disabled 并不是互斥的“五个页面状态”。导出失败时,列表仍可能有数据,筛选仍然有效,下载按钮已恢复可操作。要验证的是这些维度的实际组合。
静态展示组件无需凭空增加 loading;私有数据接口必须检查访问策略,公开接口也不应被无条件加上登录要求。事务、幂等、并发与迁移验证,则根据当前行为和风险选择。
验证范围也应分层:局部任务运行针对性检查,模块阶段检查关联交互,集成阶段验证跨模块流程并完成项目要求的 CI。项目已有的强制门禁不能因为采用了 Skill 而被跳过。
测试数据应可控并与真实业务隔离。空集、失败、无权限等场景可以使用 fixture、测试账号或受控请求拦截构造,不能通过清空真实数据来制造空态。
九、多 Agent 并行先解决共享资源
把任务命名为“前端模块”和“后端模块”,并不会让它们自动隔离。两个 Agent 仍可能同时修改接口类型、路由注册、依赖锁文件,或者重置同一个测试数据库。
v2 默认串行。只有当前任务契约足够稳定、实际写集可隔离、运行环境不会互相干扰时,才考虑并行。
采用并行时,至少需要明确:
- 协调与集成负责人。 由谁分配任务,确认领取,并最终合并结果。
- 任务真实写集。 列出源码、测试、配置及生成文件,不能只写模块名称。
- 共享资源唯一写者。 锁文件、Schema、公共配置等由一个负责人修改,其他 Agent 提需求或补丁建议。
- 起始基线与依赖确认。 上游任务已完成,还必须确认它的实现已在下游工作基线中可用。
- 集成验证。 在合并后的版本验证跨模块用户流程,并隔离端口、测试账号和数据集。
任务 ID 不是锁,Git 分支也不是锁。两个离线分支都把同一任务写成“进行中”,无法构成原子领取。没有现成协调条件时,串行推进更容易保持状态可信。
common 在这里是可选的。真正共享的约定和能力可以放进去,订单、导出等业务契约则由所属模块维护。当前链路需要哪些公共能力,就先实现哪些,不必先冻结整个未来系统的接口。
检查器可以发现已同步文档快照中的写集冲突,却看不到另一条尚未同步的分支,也不会替团队持有锁、调度 Agent 或合并代码。
十、怎样使用 v2 的配套工具
spec-driven-ai-coding 的工具使用 Python 3.10+ 标准库。它们只操作 Spec 文档,不联网、不执行文档中的测试命令,也不操作 Git 或代签批准。
v2.1 沿用 schema_version: 2、现有 CLI 参数、任务状态与指纹算法。变化集中在前端执行要求、参考流程和模板提示,已有 v2 文档无需格式迁移;当前 UI 任务应补齐缺失设计与验证计划,并重新评估受影响证据,历史记录不能回填成已完成视觉验收。
以下命令假设终端当前目录是 Skill 安装目录,业务项目路径请替换为实际绝对路径。路径含空格时保留引号;脚本拒绝符号链接形式的 Spec 路径,应使用真实目录路径。
生成最小骨架
先预览,再创建一个全新 M 级目录:
脚手架拒绝覆盖已有目录,不会往旧项目里自动追加模块或把 M 静默升级为 L。新骨架有待填写内容,预期可以通过 draft,不能直接通过 ready。
L 级通过 --tier L --modules export,history 指定必要模块,不默认创建 common。模板目录中的文件也不需要全部复制进业务项目。
结构准备、实施批准与完成检查分开运行
draft 允许明确的未完成内容,但会检查结构与引用问题。ready 要求当前需求、任务及验证计划完整且没有当前阻断问题,还需另做语义审查。--require-approval 增加实施前批准检查;通过普通 ready 不代表已获准开发。
done 则检查当前任务完成声明与记录结构,包括 required 项、AC 对应证据以及日期、环境、版本等字段。它不会运行测试,也不会把批次自动改成已验收。
用摘要提示过期状态
v2 区分三种摘要:scope_digest 跟踪当前范围与风险,用于批准;task_digests 跟踪任务计划和关联 AC,用于完成记录;increment_digest 跟踪当前有效任务集合,用于批次验收。
它们可以提示范围、任务或验收依据变化后,旧状态需要重新评估。但这些摘要不校验源码,也不是数字签名。即使文档摘要没有变化,只要代码变了,仍然需要重新运行受影响检查。
检查器同样无法验证批准人的真实身份、判断日志是否如实记录、确认 Git 依赖关系,或证明业务实现符合设计。它负责减少结构性漏项,结论的真实性仍然依赖执行和审查。
需要总览时,再运行:
生成器默认输出到终端;--write 只覆盖带有生成标记的总览,拒绝覆盖旧的人工台账。没有 Python 环境时,可以按规范人工检查,并明确说明没有运行脚本。
十一、从已有项目开始
在真实仓库中,不必先给所有历史功能补文档。选择当前需求,复用已有代码与规范,采用最小合适流程即可。
如果已有 v1 文档,仍可沿用原来的需求、设计和任务台账,并应用 v2 的分流、变更分类与真实验证原则。升级 Skill 不等于必须迁移业务项目。 v2 检查器要求 spec.json 和新版任务、AC、record 格式,不能拿旧结构执行后声称兼容通过。
确实需要机械门禁时,再选择迁移:保存基线,暂停并行编辑,保留原 ID 与来源,转换当前活跃需求,并整理已有证据。无法核对版本和结果的“已完成”任务应退回待验证,不能通过回填一份“通过”记录补齐格式。
跨会话恢复时,交接只需留下当前任务、代码基线与未提交改动、必要入口、已执行证据、未验证或阻塞项,以及下一可执行动作。已有 tasks 和 record 可以引用,不必再复制一份全量进度表。接手的 Agent 仍需核对代码与文档是否一致。
获取 Skill 与核对版本
源码位于 qiuye-skills 的 spec-driven-ai-coding 目录。支持相应安装器的环境可以从仓库获取:
这条命令取得的是远程仓库当时的版本,不固定为本文的 v2.1.0。安装后应核对 SKILL.md 的 metadata.version、CHANGELOG.md 和脚本参数。更新时完整替换 Skill 包,避免新指令与旧模板、脚本混用,也避免同名新旧版本同时被宿主扫描。
进一步阅读可以从包内的 分流与规划、执行与变更、质量门 和 文档格式 开始。在线内容会继续演进,具体行为以使用的版本为准。
写在最后
Spec 驱动值得保留的,是一条能够被检查的开发过程:先明确结果,依据真实代码选择方案,在授权范围内持续实施,最后用证据说明做到哪一步。
有些任务只需要几行验收说明,有些功能需要三份短文档,多批次工作才需要更完整的组织。无论采用哪种规模,正确的 AC 都不应被错误实现改写,未运行的检查都不应被涂成绿色。
v2.1 进一步把前端设计、实际渲染审查和修复复验接入交付过程。至于它在不同模型、宿主和真实团队中能改善多少质量,仍需要实际评估;新增行为场景是待运行的评估设计,脚本测试通过也不能证明模型必然遵循这些要求。
下一次 Agent 说“完成了”,我们应当能沿着当前任务找到明确的验收标准、实际验证版本和对应结果。能把这件事做扎实,文档才真正参与了交付。