1. 从“先写清楚”到“让AI干活”:Spec-Kit、SDD与OpenSpec的殊途同归
最近在跟几个技术团队交流时,发现一个挺有意思的现象:大家聊到如何用AI来辅助开发,尤其是生成代码时,总会提到几个听起来很相似但又不太一样的词——Spec-Kit、SDD、OpenSpec。乍一听,感觉都是些新潮的“AI编程”方法论或工具,好像很高深。但当你真正沉下心来,去翻看它们的文档、试用它们的工具,甚至自己踩过几个坑之后,会发现一个非常朴素却又无比核心的共同点:它们都强调,在让AI动手之前,你得先把自己的想法“写清楚”。
这听起来像一句废话,对吧?谁不知道需求要明确?但恰恰是这句“废话”,在AI时代被赋予了全新的、极其关键的意义。在过去,我们写需求文档、设计稿,主要是给人看的,是团队内部沟通的桥梁。人是有理解力、有上下文、能脑补的。但AI没有。你给AI一个模糊的指令,比如“帮我写个登录功能”,它可能给你生成一个最简单的表单,也可能给你一套包含OAuth2、JWT、双因素认证的复杂系统,结果完全不可控。
Spec-Kit、SDD、OpenSpec这三者,本质上都是在解决这个“如何对AI说清楚人话”的问题。它们不是要取代程序员,而是试图建立一套更高效、更精确的“人机协作协议”。今天,我就结合自己这段时间的摸索和实践,来聊聊这三者到底有什么区别,以及为什么说它们的核心思想其实一脉相承。你会发现,理解了这一点,无论是选择工具还是制定团队流程,都会清晰很多。
2. Spec-Kit:面向AI的“结构化需求清单”
我们先从Spec-Kit说起。这个概念相对更“民间”一些,没有特别官方的定义,更像是一种在实践中总结出来的模式。你可以把它理解为一份专门写给AI看的、高度结构化的“需求清单”或“规格说明书”。
2.1 Spec-Kit的核心构成:不止于功能描述
一个典型的Spec-Kit,远不止是罗列“要做什么功能”。它会强制你思考并明确以下几个维度,这些恰恰是AI生成代码时最需要的上下文:
输入与输出契约:这是最基础的部分。你需要明确函数、接口或模块的输入参数(名称、类型、格式、约束、是否可选)和输出结果(数据结构、成功/失败状态码、可能的异常)。例如,不是简单说“验证用户”,而是写成:“输入:
username(字符串,非空,最大长度50),password(字符串,非空,最小长度8,需包含大小写字母和数字);输出:{“success”: boolean, “token”: string|null, “message”: string}”。业务规则与边界条件:这是最容易产生歧义的地方。你需要把那些“理所当然”的业务逻辑显式地写出来。比如,“用户连续登录失败5次后,账户锁定30分钟”、“商品库存为0时,前端显示‘售罄’且按钮置灰”、“只有订单状态为‘待支付’时才能取消”。这些规则如果不写清楚,AI生成的代码很可能遗漏关键校验。
非功能性要求:性能、安全性、兼容性等。例如:“API响应时间P95需小于200ms”、“密码需在传输和存储时加密”、“生成的代码需兼容Python 3.8+”。这些要求会直接影响AI对库的选择和代码的实现方式。
示例与反例:提供1-2个正确的输入输出示例,以及1-2个典型的错误输入示例。这对于AI理解你的意图有奇效。这相当于给AI做了“Few-shot Learning”(小样本学习)。
2.2 实践中的Spec-Kit:一个用户注册场景的拆解
假设我们要用AI生成一个用户注册的后端接口。一个糟糕的指令是:“写一个用户注册的API”。而一个遵循Spec-Kit思想的指令应该是这样的:
# 用户注册接口 Spec-Kit 目标:生成一个Flask框架下的用户注册API端点。 输入: - 方法:POST - 路径:/api/v1/auth/register - 请求体 (JSON): * username: string, 必填,长度3-20,只允许字母、数字、下划线。 * email: string, 必填,需符合邮箱格式。 * password: string, 必填,长度8-32,必须包含大小写字母和数字。 * confirm_password: string, 必填,必须与password字段值相等。 输出: - 成功 (HTTP 201):{“code”: 201, “message”: “User registered successfully”, “data”: {“user_id”: 123}} - 失败 (HTTP 400):{“code”: 400, “message”: “Validation error”, “errors”: [{“field”: “username”, “error”: “Already taken”}]} 业务规则: 1. 用户名和邮箱必须在系统中唯一。 2. 密码需使用bcrypt进行哈希存储,明文密码不得落库或日志。 3. 注册成功后,应自动生成一个激活令牌(JWT格式,有效期24小时),并发送激活邮件(邮件发送逻辑可留空,用TODO注释)。 4. 所有输入必须先进行验证,验证失败立即返回,不进行后续数据库操作。 非功能性要求: 1. 需要基本的请求日志。 2. 数据库操作需使用SQLAlchemy ORM(假设已配置)。 3. 代码需包含适当的异常处理。 示例请求: - 正确:{“username”: “john_doe”, “email”: “john@example.com”, “password”: “Pass1234”, “confirm_password”: “Pass1234”} - 错误:{“username”: “ab”, “email”: “not-an-email”, “password”: “123”, “confirm_password”: “456”}当你把这样一份详细的Spec-Kit交给像Cursor、Claude或GitHub Copilot这样的AI编程助手时,它生成代码的准确性和可用性会呈指数级提升。你得到的将不再是一个需要大量修改的“毛坯房”,而是一个几乎可以直接运行的“精装修”代码片段。
3. SDD:从“测试驱动”到“规格驱动”的范式演进
SDD,全称是Specification-Driven Development,即“规格驱动开发”。这个名字很容易让人联想到我们熟悉的TDD(Test-Driven Development,测试驱动开发)。事实上,SDD可以看作是TDD在AI时代的一种演进和升华。
3.1 TDD的局限与SDD的契机
TDD的核心循环是“红-绿-重构”:先写一个失败的测试(红),然后写最简单的代码让测试通过(绿),最后重构代码优化结构。TDD很棒,它保证了代码的可测试性和设计质量。但它有一个前提:开发者自己很清楚代码最终应该实现成什么样。
在AI辅助编程的语境下,这个前提发生了变化。很多时候,我们可能对一个模块的功能只有模糊的想法,或者我们希望AI能帮我们探索不同的实现方案。这时,先写测试就变得有些困难——你连代码长什么样都不知道,怎么写断言?
SDD巧妙地解决了这个问题。它把TDD中的“测试”前置条件,替换成了更抽象、更偏重描述的“规格”。SDD的循环可以概括为:“规格 -> AI生成 -> 验证 -> 迭代”。
- 规格:首先,用自然语言或结构化的方式(比如我们上面提到的Spec-Kit)详细描述你想要的功能、行为、接口和约束。这个规格是给人看的,也是给AI看的“需求文档”。
- AI生成:将这个规格输入给AI代码生成工具,让它产出初步的代码实现。
- 验证:对生成的代码进行验证。这不仅仅是运行单元测试(当然,如果规格足够细,可以自动生成测试用例),还包括代码审查、静态分析、集成测试等,确保其符合规格要求。
- 迭代:如果验证不通过,或者有新的想法,就回过头来修改和细化规格,然后再次让AI生成。这个过程比手动修改代码更快,因为它是在更高的抽象层级(规格)上进行迭代。
3.2 SDD在团队流程中的落地:以阿里Qoder为例
一些前沿的团队和工具已经在实践SDD。例如,阿里内部孵化的Qoder项目,其理念就非常接近SDD。它鼓励开发者先在一个协作空间中,用Markdown等形式共同撰写功能规格,明确接口定义、数据模型、业务流程和验收条件。这份活的文档不仅是沟通依据,更可以直接作为提示词(Prompt)输入给集成的AI编码助手,一键生成符合团队规范和业务场景的脚手架代码。
SDD带来的最大改变,是将开发的重心从“编写代码”转移到了“定义规格”。程序员的核心能力不再是记忆API或手写算法,而是精准地分析、拆解和表述复杂需求。这要求开发者具备更强的抽象思维、领域建模和沟通能力。同时,它也促进了文档的实时性和准确性,因为文档(规格)直接关联着可执行的产出(代码),文档过时意味着生成物失效,这倒逼团队维护好这份最重要的资产。
4. OpenSpec:开源社区的“人机协作协议”尝试
如果说Spec-Kit是一种模式,SDD是一种方法论,那么OpenSpec则更像一个具体的、正在发展的开源项目或标准倡议。它的目标是创建一种通用的、机器可读的“规格描述语言”或协议,让不同的AI编程工具都能理解同一份需求说明。
4.1 OpenSpec的愿景:打破工具壁垒
目前,不同的AI编程助手(如Cursor、Claude Code、GitHub Copilot)对提示词的理解和响应方式各有不同。你为Copilot优化的提示词,直接扔给Cursor可能效果不佳。这就导致了学习和切换成本。
OpenSpec试图定义一个中间层。你可以用OpenSpec格式来编写你的功能规格,然后这个OpenSpec文件可以被各种支持该标准的工具消费。工具负责将OpenSpec解析成自己擅长的提示词,或者直接基于OpenSpec的结构化信息来生成代码、测试甚至部署配置。
一个理想的OpenSpec文件可能包含以下层次:
- 元信息:项目、模块、版本、作者。
- 组件定义:类、函数、API端点等。
- 接口描述:输入、输出、错误类型,可能使用JSON Schema或类似格式。
- 行为描述:用自然语言或某种领域特定语言描述关键逻辑。
- 约束与要求:性能、安全、依赖等。
- 示例:输入输出对。
4.2 OpenSpec的现状与挑战:从Proposal到实践
目前,OpenSpec还处于比较早期的阶段。你在网上搜到的openspec proposal、openspec官方文档可能更多是一些讨论、草案或某个原型的文档。它的安装(openspec install)和使用教程(openspec使用教程)可能还不像成熟软件那样完善。
它的挑战在于:
- 标准化之难:让整个社区接受并采用一套新标准非常困难。需要平衡表达能力、简洁性和工具实现的复杂性。
- 与现有生态集成:如何与现有的Swagger/OpenAPI(用于API描述)、JSDoc/TypeScript定义等共存和互补?
- AI的理解能力:即使有了结构化描述,AI模型是否真的能更好地利用这些信息?还是说,一份优秀的自然语言描述加上几个示例(即好的Spec-Kit)已经足够?
尽管有挑战,但OpenSpec的方向是值得关注的。它代表了社区对建立更优“人机协作界面”的集体探索。即使它最终没有成为唯一标准,其探索过程中产生的思想和最佳实践,也会被其他工具和模式所吸收。
5. 核心贯通点:为什么“写清楚”如此重要?
分析了三者的不同侧重点后,我们可以清晰地看到那条贯穿始终的主线:“先写清楚,再让AI干活”。这个“写清楚”,在AI编程的语境下,具有前所未有的重要性,原因有三:
5.1 弥补AI的“上下文缺失”与“逻辑跳跃”
人类程序员拥有丰富的隐性知识:行业惯例、团队规范、系统架构、过往的坑。AI没有。如果你只说“创建一个商品服务”,AI不知道你的“商品”是否有SKU、是否有库存概念、价格是整数还是浮点数、是否需要支持多货币。你必须通过详细的规格,将这些隐性知识显式化,为AI补全上下文,防止它基于公共训练数据做出不合理的默认假设。
5.2 提升生成结果的确定性与质量
模糊的需求导致随机的输出。你让AI“写一个排序函数”,它可能给你快速排序、归并排序或冒泡排序。但如果你写明“需要一个稳定的、原地排序的、针对小型整数数组优化的函数”,AI就更可能给出插入排序或计数排序的变种。确定性是工程化的基础。详细的规格能将AI的创造力引导到解决具体问题上,而不是在无限的可能性中随机漫步,从而显著提升生成代码的可用性和质量。
5.3 将开发过程转化为可迭代、可验证的流程
当“规格”成为开发过程的核心工件时,整个工作流就变得清晰且可管理。评审的重点从代码细节(语法、风格)前移到规格设计(逻辑、边界)是否正确。测试用例可以(部分)从规格中自动推导。更重要的是,当需求变更时,你首先修改的是规格文档,然后重新生成代码,这比直接修改代码更不容易引入隐性错误,也更容易评估变更范围。
6. 如何上手:从今天开始实践“先写清楚”
理论说了这么多,具体该怎么开始呢?你不必等待某个工具成熟,现在就可以将这种思想融入你的工作。
6.1 个人实践:改造你的AI编程提示词
下次使用任何AI编程助手时,尝试按照下面的结构来组织你的提示词,你会发现效果立竿见影:
- 角色与上下文设定:“你是一个经验丰富的Python后端开发工程师,正在开发一个电商系统。”
- 任务目标:“请为我生成一个Flask蓝本,用于处理用户购物车。”
- 详细规格(Spec-Kit风格):
- 数据结构:购物车项应包含
product_id(整数)、quantity(整数,大于0)、added_at(时间戳)。 - API端点:
GET /cart:获取当前用户购物车列表,需关联查询商品名称和单价。POST /cart/items:添加商品,需验证商品是否存在及库存是否充足。PUT /cart/items/<item_id>:更新商品数量。DELETE /cart/items/<item_id>:删除商品。
- 业务规则:用户必须登录;购物车数据应持久化到数据库(使用SQLAlchemy模型
Cart和CartItem);添加商品时,若已存在相同product_id,则增加数量而非新建条目。 - 非功能性要求:需要请求参数验证;使用JSON响应;包含基本的错误处理。
- 数据结构:购物车项应包含
- 示例:“例如,对于
POST /cart/items,请求体为{"product_id": 123, "quantity": 2},成功应返回201和新增的购物车项信息。”
6.2 团队协作:引入轻量级规格评审
在团队任务拆解或技术方案设计阶段,增加一个“规格定义”环节。要求负责人在写代码前,先提交一份简明的规格说明(可以是一个Markdown文件),描述清楚新功能的输入、输出、主要逻辑、边界情况和对外影响。团队其他成员对此进行评审。评审通过后,开发者可以基于这份规格,利用AI高效生成代码主干,自己则专注于核心逻辑和集成测试。这不仅能减少返工,还能让新人更快理解系统。
6.3 工具选择:关注能力而非标签
目前并没有一个工具叫“Spec-Kit”,SDD是一种模式,OpenSpec尚在萌芽。因此,我们的重点不应是寻找贴有这些标签的工具,而是评估现有工具是否支持这种工作流。
- Cursor / Cline / 各类AI编程助手:关注它们对多文件上下文的理解能力、自定义指令(Custom Instructions)的灵活性,以及是否支持从注释或文档字符串生成代码。这些能力是实践“先写清楚”的基础设施。
- Qoder / Superpowers等集成平台:关注它们是否提供了结构化的需求录入界面、团队知识库集成,以及能否将需求一键转化为开发任务和代码草稿。
- 文档与代码同步工具:关注像Swagger Codegen这类能从API描述生成代码的工具,其思想是相通的。未来可能会有更通用的“规格即代码”工具出现。
7. 避坑指南:实践中的常见问题与应对策略
在将“先写清楚”付诸实践的过程中,我遇到并总结了一些典型的坑,这里分享给你,希望能帮你少走弯路。
7.1 坑一:规格写得过于冗长或过于简略
这是一个平衡的艺术。过于简略,AI无法理解;过于冗长,AI可能抓不住重点,而且编写成本太高。
- 应对策略:遵循“金字塔原则”。先写一句话总结核心功能(目标),然后列出3-5个关键特性或子任务,再针对每个子任务展开输入输出和关键规则。避免在规格中描述具体的算法实现细节,那是AI或开发者该去思考的。用列表和表格来组织信息,比大段文字更清晰。
7.2 坑二:忽略了边界条件和异常流
这是AI生成代码最薄弱的环节。AI倾向于生成“快乐路径”的代码,对于各种异常情况(网络超时、数据为空、并发冲突)考虑不足。
- 应对策略:在规格中必须单独设立“边界条件与异常处理”章节。主动思考并列出:输入为空或非法怎么办?依赖的服务不可用怎么办?数据库操作失败怎么办?并发操作导致数据不一致怎么办?明确指定重试策略、回滚机制和给用户的错误信息。
7.3 坑三:生成代码后不做审查和测试
盲目信任AI生成的代码是危险的。生成的代码可能存在安全漏洞(如SQL注入)、性能问题、或者与现有系统架构不兼容。
- 应对策略:建立铁律——AI生成的代码必须经过人工审查和测试。审查重点包括:安全漏洞、依赖引入、代码风格一致性、是否符合团队架构规范。然后必须编写或运行针对性的单元测试和集成测试,验证其行为完全符合规格。可以将AI视为一个强大的“初级程序员”,而你则是负责审核和定稿的资深工程师。
7.4 坑四:规格与代码脱节,不再维护
一旦代码生成并运行起来,那份辛苦写好的规格文档很容易被抛在脑后。后续的需求变更直接修改代码,导致规格文档迅速过时。
- 应对策略:将规格文档视为“源代码”的一部分。将其放在项目仓库中(如
/specs/目录),与代码文件一起进行版本管理。任何功能修改,必须先更新规格文档,提交一个“规格变更”的Commit,然后再基于新规格去调整代码。利用CI/CD流程,可以尝试探索将规格文档作为生成测试用例或API文档的源头,增加其“活性”。
8. 未来展望:规格驱动下的开发者角色进化
“先写清楚,再让AI干活”这一模式的普及,正在悄然改变软件开发者的角色定义。未来的开发者,或许可以称为“规格工程师”或“AI协作工程师”。
- 核心能力迁移:从“熟练敲击键盘实现逻辑”向“精准定义问题与边界”迁移。领域建模、系统分析、沟通协调能力变得比以往任何时候都重要。
- 工作重心变化:更多时间花在前期与产品、业务方澄清需求,并将其转化为精密、无歧义的规格说明。编码本身将更多地变为对AI生成结果的审查、调整、集成和测试。
- 工具链演进:我们将会看到更多专注于“规格”阶段的工具出现,比如可视化的规格设计器、能从规格自动生成测试用例的插件、能检查规格一致性和完整性的Linter,以及连接规格与多种AI代码生成服务的中间平台。
Spec-Kit、SDD、OpenSpec,无论它们叫什么,都指向同一个未来:人机协作的界面将变得更加清晰和高效。人类负责战略、创意和定义“做什么”以及“做到什么标准”,AI负责战术、执行和探索“如何做”的多种可能。这场变革已经开始,而起点,就是学会如何“写清楚”。这不仅是给AI下指令的技巧,更是对自己思维的彻底梳理和锤炼。当你能够把一个复杂需求清晰地拆解并表述出来时,问题往往已经解决了一半。剩下的,就让你和AI一起,高效地完成吧。