☰
SDD基于规范编程实战:OpenSpec与SuperPowers的Skill协作指南
2026/10/10 21:22:24 网站建设 项目流程

1. 从一次“规范漂移”事故说起:SDD 到底解决什么问题

团队协作里最让人头疼的不是写不出代码,而是同一份需求,三个人写出三套实现。上周我帮一个做智能硬件的朋友排查问题,他们的固件配置模块在两周内被改了四次,每次改完测试都过,但一上产线就出兼容问题。翻 git log 才发现:A 同学按“配置项必须显式声明”写,B 同学按“缺省即继承”写,C 同学干脆把校验逻辑塞进了初始化函数。三个人都没错,错在没有一份机器可读、可被 AI 消费的规范。

这就是 SDD(Spec-Driven Development,规范驱动开发)要解决的核心矛盾:把“口头约定”变成“可执行契约”。传统开发里,规范是写在 Confluence 里的文档,人和 AI 都懒得看;SDD 里,规范是 OpenSpec 定义的结构化文件,技能是 SuperPowers 注册的 SKILL.md,两者通过文件系统耦合,AI 每次动手前先读规范,读完再调技能。

OpenSpec 负责“写什么”,它用 YAML/JSON 描述接口、数据模型、约束条件;SuperPowers 负责“怎么做”,它把可复用的操作封装成 Skill,每个 Skill 一个 SKILL.md,声明触发条件、输入输出、依赖资源。两者结合后,你给 AI 一句“给配置模块加个版本号字段”,它会先查 OpenSpec 里的 schema 定义,再调对应的 Skill 去改代码、跑测试、更新文档——全程不需要你重复解释“我们团队的规矩是……”。

适合谁用?三类人最受益:一是多智能体协作的团队,人和 AI 混编时规范就是共同语言;二是长期维护的老项目,规范文件比口口相传可靠;三是做 Agent 编排的开发者,SKILL.md 本质就是给 AI 看的“入职指南”。下面我从目录结构开始,一步步拆给你看。

2. TaoToken 前置准备:让 Skill 调用有稳定的模型入口

在写 SKILL.md 之前,得先解决一个现实问题:Skill 里的模型调用走哪里。SuperPowers 的技能注册本身不绑定模型,但技能执行时(比如让 AI 读规范、生成代码、跑校验)需要一个稳定的 API 入口。我试过直接把各家模型的 key 硬编码进脚本,结果换模型时改了七个文件,还漏了一个导致线上 401。

TaoToken 在这里的角色是统一模型网关:一个 Base URL、一个 Key,背后可以切不同模型。对 SDD 工作流来说,这意味着 SKILL.md 里写的调用配置不用随模型更换而变。你只需要在环境变量里维护一份配置,所有 Skill 共享。

先拿 Key。访问 https://taotoken.net/api-keys 创建 API Key,建议按项目分 Key,比如sdd-openspec-prod、sdd-skill-dev,方便后面排查是哪个环节出的问题。创建后复制保存,页面只显示一次。

拿到 Key 后,在项目根目录建一个.env文件(记得加进.gitignore):

# .env TAOTOKEN_API_KEY=sk-你的key TAOTOKEN_BASE_URL=https://taotoken.net/api TAOTOKEN_MODEL=claude-sonnet-4-20250514

这里有个坑要提前说:Base URL 不要带末尾斜杠,也不要自己拼/v1。TaoToken 的 API 地址就是https://taotoken.net/api,SDK 会自动处理路径。我见过有人写成https://taotoken.net/api/v1/chat/completions然后报 404,排查半天。

如果你用的是 Claude Code 或 Cline 这类工具,配置方式略有不同。Claude Code 需要在~/.claude/settings.json里配:

{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的key", "ANTHROPIC_MODEL": "claude-sonnet-4-20250514" } }

Cline 的 MCP 配置则在cline_mcp_settings.json里,后面第 3 节会给完整片段。Codex 用户改~/.codex/auth.json:

{ "OPENAI_API_KEY": "sk-你的key", "OPENAI_BASE_URL": "https://taotoken.net/api" }

三件套记住:Base URL + Key + Model ID,缺一个都跑不通。Model ID 建议先用claude-sonnet-4-20250514验证,稳定后再换其他。想先确认模型通不通,可以去 https://taotoken.net/models 用对话界面发一句“你好”,能回就说明 Key 和网络都没问题。

3. 可复制配置:SKILL.md 目录结构 + OpenSpec 模板 + SuperPowers 注册

这一节是全文最干的部分,直接给能抄的配置。先看整体目录结构,我按“规范层 / 技能层 / 资源层”三层组织:

project-root/ ├── openspec/ # 规范层 │ ├── specs/ │ │ ├── config-module.yaml # 配置模块规范 │ │ └── api-contract.yaml # 接口契约 │ └── changes/ │ └── add-version-field.yaml # 变更提案 ├── skills/ # 技能层 │ ├── skill-creator/ │ │ └── SKILL.md │ ├── config-validator/ │ │ ├── SKILL.md │ │ ├── scripts/ │ │ │ └── validate_config.py │ │ └── references/ │ │ └── schema.md │ └── superpowers.json # 技能注册表 └── .env

OpenSpec 规范文件模板。以配置模块为例,openspec/specs/config-module.yaml:

spec: name: config-module version: 1.2.0 description: 设备配置模块的字段定义与校验规则 entities: ConfigItem: fields: - name: key type: string required: true pattern: "^[a-z][a-z0-9_]{2,31}$" - name: value type: any required: true - name: version type: integer required: true min: 1 description: 配置版本号,每次修改递增 - name: inherited type: boolean default: false description: 是否从父配置继承 constraints: - id: C001 rule: "version 必须单调递增" severity: error - id: C002 rule: "inherited=true 时 value 可为空" severity: warning changes: - id: add-version-field status: proposed affects: [ConfigItem.version] rationale: 支持配置回滚与审计

这份规范的关键在于约束可被程序读取。constraints里的 rule 不是给人看的散文,而是 Skill 执行时能解析的断言。changes段记录变更提案,AI 改代码前先读这里,避免“改了但没记录”。

SKILL.md 模板。以config-validator为例:

--- name: config-validator description: 校验设备配置是否符合 OpenSpec 规范。当用户需要验证配置文件、检查字段类型、或确认版本号递增规则时使用。支持 YAML/JSON 格式输入,输出违规项列表与修复建议。 --- # Config Validator ## 何时使用 - 用户提交配置文件需要校验 - CI 流水线中作为质量门禁 - 修改 OpenSpec 规范后回归验证 ## 输入 - `config_path`: 配置文件路径(必填) - `spec_path`: OpenSpec 规范路径,默认 `openspec/specs/config-module.yaml` - `strict`: 是否将 warning 视为 error,默认 false ## 执行步骤 1. 读取 spec_path,解析 entities 与 constraints 2. 读取 config_path,逐字段比对类型与 required 3. 执行 constraints 中的 rule 断言 4. 输出 JSON 格式结果:`{ "passed": bool, "violations": [...] }` ## 依赖资源 - `scripts/validate_config.py`:核心校验逻辑 - `references/schema.md`:字段类型对照表 ## 模型调用配置 - Base URL: `https://taotoken.net/api` - Model: `claude-sonnet-4-20250514` - Key: 从环境变量 `TAOTOKEN_API_KEY` 读取

注意 description 里把触发条件写全了——“校验配置”“检查字段类型”“确认版本号递增”都是用户可能说的原话。SuperPowers 靠这段文字决定是否激活该技能,写窄了技能永远不触发,写宽了到处误触发。

SuperPowers 技能注册。skills/superpowers.json:

{ "version": "1.0", "skills": [ { "name": "config-validator", "path": "skills/config-validator/SKILL.md", "enabled": true, "triggers": ["校验配置", "validate config", "检查字段"], "priority": 10 }, { "name": "skill-creator", "path": "skills/skill-creator/SKILL.md", "enabled": true, "triggers": ["创建技能", "生成 SKILL.md"], "priority": 5 } ], "model": { "base_url": "https://taotoken.net/api", "model_id": "claude-sonnet-4-20250514", "api_key_env": "TAOTOKEN_API_KEY" } }

如果你用 Cline 的 MCP 模式,配置写在cline_mcp_settings.json:

{ "mcpServers": { "superpowers": { "command": "node", "args": ["./skills/superpowers-server.js"], "env": { "TAOTOKEN_BASE_URL": "https://taotoken.net/api", "TAOTOKEN_API_KEY": "sk-你的key", "TAOTOKEN_MODEL": "claude-sonnet-4-20250514" } } } }

三件套再次出现:Base URL、Key、Model ID。Cline 里如果只填了 Key 没填 Base URL,会默认走官方地址然后报local proxy failed,这个错后面第 5 节细说。

4. 验证请求:从规范到技能落地跑一遍

配置写完不验证等于没写。这一节我带你跑一次完整流程:改规范 → 触发技能 → 校验通过。

先准备一个待校验的配置文件test-config.yaml:

items: - key: device_name value: "sensor-01" version: 1 inherited: false - key: sample_rate value: 100 version: 0 inherited: false

注意第二条version: 0,这违反了规范里min: 1的约束,我们看技能能不能抓出来。

第一步,确认模型入口通。用 curl 发一个最小请求:

curl -X POST https://taotoken.net/api/v1/messages \ -H "Content-Type: application/json" \ -H "x-api-key: $TAOTOKEN_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -d '{ "model": "claude-sonnet-4-20250514", "max_tokens": 100, "messages": [{"role": "user", "content": "回复 OK"}] }'

返回里如果有"content": [{"type": "text", "text": "OK"}],说明 Key 和 Base URL 都对。如果返回 401,先检查 Key 有没有多余空格;如果返回model not found,去 https://taotoken.net/models 确认 Model ID 拼写。

第二步,手动跑校验脚本。先不经过 AI,直接执行scripts/validate_config.py:

# scripts/validate_config.py import yaml, json, sys, os def load_spec(path): with open(path) as f: return yaml.safe_load(f) def validate(config_path, spec_path): spec = load_spec(spec_path) with open(config_path) as f: config = yaml.safe_load(f) violations = [] entity = spec['entities']['ConfigItem'] field_map = {f['name']: f for f in entity['fields']} for idx, item in enumerate(config.get('items', [])): for fname, fdef in field_map.items(): if fdef.get('required') and fname not in item: violations.append({ "index": idx, "field": fname, "rule": "required", "severity": "error" }) if fname in item and 'min' in fdef: if item[fname] < fdef['min']: violations.append({ "index": idx, "field": fname, "rule": f"min={fdef['min']}", "actual": item[fname], "severity": "error" }) return {"passed": len(violations) == 0, "violations": violations} if __name__ == "__main__": result = validate(sys.argv[1], sys.argv[2]) print(json.dumps(result, indent=2, ensure_ascii=False)) sys.exit(0 if result["passed"] else 1)

执行:

python scripts/validate_config.py test-config.yaml openspec/specs/config-module.yaml

预期输出:

{ "passed": false, "violations": [ { "index": 1, "field": "version", "rule": "min=1", "actual": 0, "severity": "error" } ] }

第三步,让 AI 通过技能自动修复。在支持 SuperPowers 的客户端里输入:“用 config-validator 校验 test-config.yaml,把违规项修掉”。AI 会先读 SKILL.md 了解流程,再读 OpenSpec 规范拿到约束,然后调脚本跑校验,最后根据 violations 改文件。修复后的test-config.yaml里version变成 1,再跑一次脚本返回"passed": true。

这一步验证了三件事:规范文件能被解析、技能能被触发、模型入口稳定。三者缺一,SDD 工作流就断链。

5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth

配置类问题 90% 集中在四个报错上,我按出现频率排。

401 Unauthorized。最常见的原因是 Key 没生效。检查顺序:.env文件有没有被加载(Python 用python-dotenv,Node 用dotenv);环境变量名有没有拼错,TAOTOKEN_API_KEY不是TAOTOKEN_KEY;Key 有没有过期或被删。如果用的是 Claude Code,settings.json里的ANTHROPIC_API_KEY和 shell 里的TAOTOKEN_API_KEY是两个变量,别混。还有一种隐蔽情况:Key 复制时带了换行符,用echo $TAOTOKEN_API_KEY | wc -c看长度对不对。

local proxy failed。这个错通常出现在 Cline 或 Claude Code 里,本质是客户端想走本地代理但代理没起来。如果你没配代理,检查settings.json里有没有残留的HTTP_PROXY或HTTPS_PROXY环境变量。TaoToken 的 API 地址是直连的,不需要额外代理配置。把ANTHROPIC_BASE_URL明确写成https://taotoken.net/api就能绕过本地代理逻辑。

reading choices 报错。完整报错一般是Cannot read properties of undefined (reading 'choices'),说明返回体里没有choices字段。两种可能:一是 Base URL 写成了 OpenAI 格式但实际调的是 Anthropic 格式接口,或者反过来。TaoToken 同时支持两种格式,但路径不同——Anthropic 格式走/v1/messages,OpenAI 格式走/v1/chat/completions。二是 Model ID 写错,返回了错误对象而不是正常响应。先curl确认返回结构,再改客户端配置。

OAuth 相关报错。Claude Code 首次启动会尝试 OAuth 登录,如果你已经配了 API Key,需要在settings.json里加"forceApiKey": true,否则它会优先走 OAuth 流程然后失败。Codex 的auth.json里如果同时有OPENAI_API_KEY和 OAuth token,也会冲突,删掉 OAuth 相关字段即可。

排查通用套路:先 curl 后客户端,先环境变量后配置文件。curl 通了说明服务端没问题,问题在客户端配置;curl 不通说明 Key 或网络有问题。这个顺序能省一半时间。

6. 把规范编程工作流跑成日常习惯

最后说点实操层面的经验。SDD 工作流最大的敌人不是技术,是规范写完就没人更新。我见过团队把 OpenSpec 文件建得漂漂亮亮,两周后代码和规范完全对不上,AI 读了规范反而生成错误代码。

三个习惯能避免这个问题。第一,规范变更必须走 changes 段,每次改specs/下的文件,同步在changes/里加一条提案,记录改了什么、为什么改。第二,SKILL.md 的 description 定期回看,用户说话方式会变,触发词也要跟着调,我一般每月扫一遍触发日志,把没命中的说法补进去。第三,校验脚本进 CI,validate_config.py这种脚本不要只靠人手动跑,挂到 pre-commit hook 里,规范违规直接挡在提交前。

如果你想把技能调用固定到长期项目上,Coding Plan 比按量付费更省心,模型入口和额度都稳定。需要看完整接入文档的话,https://taotoken.net/doc 里有各客户端的配置示例。模型对话界面在 https://taotoken.net/models ,调 SKILL.md 的 description 时可以用它快速试触发效果。

这套流程跑顺之后,你会发现 AI 不再是“每次都要重新解释需求”的工具,而是读得懂团队规矩的协作者。规范是契约,技能是手脚,模型入口是神经,三者接上,SDD 才算真正落地。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询