资讯动态

SpecCoding + Harness 实战:给 Vibe Coding 装上可交付的「验收骨架」

发布时间:2026/9/28 11:52:18 来源:尧图企业网站定制
1. 为什么 Vibe Coding 需要一个「验收骨架」Vibe Coding 这个词这两年被聊得很多核心意思就是你不再一行行敲代码而是把意图丢给 Claude Code 或 Cursor让模型帮你把功能「生成」出来。它确实快快到很多人第一次用的时候会有点上头——半小时一个接口、一小时一个页面感觉生产力翻了好几倍。但问题也恰恰出在这里。生成快不代表交付稳。我见过太多这样的场景需求口头对一下Cursor 开干代码能跑联调一开边界条件全炸安全扫一眼密钥硬编码在配置里架构评审更狠直连数据库、绕过网关、分层被揉成一锅粥。这不是模型不够聪明而是缺少两样东西——规格Spec和护栏Harness。SpecCoding 解决的是「写什么、不写什么、怎么算通过」的问题它把模糊需求压成机器可读的约束面接口契约、验收用例、任务清单。Harness 解决的是「AI 能碰哪里、不能碰哪里」的问题它约束的是行为空间不是灵感本身。两者合起来就是给 Vibe Coding 装上一副可交付的「验收骨架」。这篇文章面向的是已经在用 Claude Code / Cursor 做开发、但被「能跑但不该合」的差分坑过的同学。我会给出可复制的config.toml与settings.json骨架、一份验收清单模板并完整演示一次从模糊需求到通过校验的动作。适合谁独立开发者、小团队 Tech Lead、以及任何想把 AI 编码从「灵感式」推进到「可审计」的人。2. TaoToken 前置把模型调用收进可控入口在讲 Spec 和 Harness 之前得先把模型调用这条链路理清楚。因为无论你的规格写得多好如果模型调用本身是散的、不可观测的那 Harness 就无从下手。TaoToken 在这里扮演的角色是统一的模型调用入口。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 端点是 https://taotoken.net/api 。它的价值不在于「多一个中转」而在于让你的 Claude Code、Cursor、以及后续的 CI 校验脚本都走同一个可配置、可审计的出口。为什么这对 SpecCoding Harness 很重要因为 Harness 的第一层约束就是「调用边界」。如果每个开发者本地各配一套 key、各走一条链路那你在 Rules 里写的「禁止越层调用」根本落不了地。统一入口之后你才能在config.toml里把模型、超时、重试、以及后续的审计字段集中管理。你需要先拿到 API Key入口在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 。拿到之后不要硬编码进任何仓库文件而是走环境变量注入。这一步本身就是 Harness 的一部分——密钥不进仓库是第一条硬规则。如果你只是想先验证模型通不通可以用模型对话页面快速试一下 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。确认链路没问题之后再往下做 Spec 和 Harness 的配置。3. 可复制配置config.toml 与 settings.json 骨架这一节是全文的技术核心。我会给出两份可直接复制的骨架一份是config.toml用于统一模型调用与 Harness 参数一份是settings.json用于 Claude Code / Cursor 的项目级约束。3.1 config.toml模型调用与 Harness 参数# config.toml —— 放在仓库根目录供本地与 CI 共用 [model] provider taotoken base_url https://taotoken.net/api api_key_env TAOTOKEN_API_KEY # 只读环境变量禁止写死 default_model claude-sonnet timeout_seconds 60 max_retries 2 [harness] # 目录边界AI 只能在这些目录内生成/改写 allowed_paths [src/, tests/, docs/specs/] # 禁止触碰的路径 denied_paths [infra/, secrets/, .env, migrations/] # 依赖白名单新增依赖必须在此列表内 dependency_whitelist [fastapi, pydantic, httpx, pytest] # 禁止模式命中即阻断 forbidden_patterns [ AKIA[0-9A-Z]{16}, # 硬编码密钥 jdbc:mysql://, # 直连数据库 0.0.0.0/0, # 全开放安全组 ] [review] # Review 三关开关 correctness true security true architecture true # 架构规则失败是否阻断合并 block_on_arch_fail true [ci] run_unit_tests true run_static_check true run_secret_scan true这份config.toml的关键设计点有三个。第一api_key_env只读环境变量任何把 key 写进文件的 PR 都会被 secret scan 拦下。第二allowed_paths和denied_paths构成目录边界AI 生成差分时如果越界Harness 直接红灯。第三forbidden_patterns是正则级别的禁止模式命中即阻断不给你「下个迭代再还」的机会。3.2 settings.jsonClaude Code / Cursor 项目级约束{ project: { name: speccoding-harness-demo, spec_dir: docs/specs, rules_file: .cursor/rules/architecture.mdc, claude_md: CLAUDE.md }, cursor: { rules: [.cursor/rules/architecture.mdc], skills_dir: .cursor/skills, require_spec_before_edit: true }, claude_code: { read_spec_first: true, forbid_cross_layer: true, run_min_verify_after_edit: true, compact_keep_spec: true }, review_gates: { correctness: [unit_test, boundary_case], security: [secret_scan, authz_check], architecture: [layer_check, gateway_check, dependency_whitelist] } }settings.json里最值得说的是require_spec_before_edit和read_spec_first。这两个开关强制 AI 在动手之前先读 Spec避免它凭「看起来像对」的直觉去改代码。compact_keep_spec则是针对 Claude Code 的/compact场景——上下文被压缩时Spec 里的验收点不能被压掉否则约束就丢了。3.3 验收清单模板把下面这份模板放进docs/specs/feature.md每个需求一份AI 和人共用同一份验收标准。# Spec: 功能名 ## 目标 - 一句话说明这个功能要解决什么问题 ## 非目标 - 明确列出这次不做什么防止 AI 顺手重构 ## 接口契约 - 输入 - 输出 - 失败态 ## 验收用例 | 用例 | 输入 | 期望输出 | 边界条件 | |------|------|----------|----------| | 正常 | ... | ... | 无 | | 边界 | ... | ... | 空值/超长/并发 | ## 验收命令 - pytest tests/test_feature.py -v - pre-commit run --all-files ## 架构约束 - 必须走网关禁止直连 DB - 新增依赖必须在白名单内这份模板的写法有个原则可判定。写「尽量高可用」等于没写写「p99 ≤ 500ms失败重试 2 次」才能进门禁。Spec 是契约不是说明书。4. 验证请求从模糊需求到通过校验的完整动作光有配置不够得跑一遍才知道骨架能不能用。这一节我演示一次完整动作从一句模糊需求开始到 Spec 落地、AI 生成、Harness 校验、CI 通过。4.1 模糊需求假设产品同学丢来一句话「给用户列表接口加个按注册时间筛选的功能要快。」这句话就是典型的 Vibe Coding 起点——信息量约等于零。如果直接丢给 Cursor它会给你生成一个能跑的版本但边界条件、分页、时区、索引全凭它猜。4.2 压成 Spec按第 3.3 的模板把它压成可判定的规格# Spec: 用户列表按注册时间筛选 ## 目标 - 支持按注册时间区间筛选用户列表 ## 非目标 - 不做排序切换 - 不做导出 ## 接口契约 - 输入start_time, end_timeISO8601含时区 - 输出分页用户列表 - 失败态start_time end_time 返回 400 ## 验收用例 | 用例 | 输入 | 期望输出 | 边界条件 | |------|------|----------|----------| | 正常 | 2024-01-01 ~ 2024-06-30 | 列表非空 | 无 | | 边界 | 空区间 | 空列表 | start end | | 异常 | start end | 400 | 参数校验 | ## 验收命令 - pytest tests/test_user_filter.py -v ## 架构约束 - 必须走网关禁止直连 DB - 新增依赖必须在白名单内4.3 让 AI 按 Spec 生成在 Claude Code 里先贴 Spec 路径再下指令# 在 Claude Code 会话中 先读 docs/specs/user_filter.md按验收用例生成实现与测试。 只改 src/user/ 和 tests/ 下的文件禁止动 infra/。这一步的关键是「先读 Spec」。settings.json里的read_spec_first会强制这个动作。生成完之后AI 会给出差分你过一遍 Review 三关。4.4 Harness 校验本地跑一遍校验脚本模拟 CI 门禁# 1. 单元测试 pytest tests/test_user_filter.py -v # 2. 静态检查 ruff check src/ tests/ # 3. secret 扫描 gitleaks detect --source . --no-git # 4. 架构规则校验读 config.toml 的 forbidden_patterns python scripts/harness_check.py --config config.tomlharness_check.py是个几十行的小脚本核心逻辑就是读config.toml遍历差分文件检查路径是否越界、是否命中禁止模式、新增依赖是否在白名单内。命中任意一条就返回非零退出码CI 直接红灯。4.5 成功结果全部通过时输出大概长这样[harness] allowed_paths check: PASS [harness] denied_paths check: PASS [harness] dependency whitelist: PASS [harness] forbidden patterns: PASS [harness] unit tests: 3 passed [harness] secret scan: no leaks [harness] architecture gate: PASS到这一步这个差分才算「可交付」。注意这里没有任何一步是「我觉得没问题」全是机械执行。CI 负责不信任任何人包括 AI 和你自己。5. 本篇常见错排查配置跑起来之后最容易踩的坑集中在下面几类。我按出现频率排一下。第一类Spec 写了但 AI 不读。症状是生成的代码和 Spec 对不上。原因通常是settings.json里的read_spec_first没开或者 Spec 路径没在会话里显式给出。排查方法在 Claude Code 里问一句「你读了哪个 Spec 文件」如果它答不上来就是没读。第二类Harness 误报。症状是明明没问题的代码被forbidden_patterns拦下。最常见的是正则写太宽比如jdbc:mysql://把测试里的 mock 字符串也命中了。排查方法把forbidden_patterns逐条单独跑定位是哪条规则误伤然后收窄正则。第三类密钥进了仓库。症状是 secret scan 红灯。原因多半是本地调试时图省事把 key 写进了config.toml。正确做法是永远走api_key_env本地用.env且.env在.gitignore里。如果已经提交了先轮换 key再清理历史。第四类CI 通过但架构漂移。症状是测试全绿但代码直连了 DB 或绕过了网关。原因是block_on_arch_fail被设成了false或者架构规则没进 CI。排查方法确认config.toml里block_on_arch_fail true且 CI 脚本真的调用了harness_check.py。第五类/compact之后约束丢失。症状是长会话里 AI 突然开始越层改代码。原因是上下文压缩把 Spec 里的验收点压掉了。排查方法确认compact_keep_spec true并且在/compact之前把关键验收点重新贴一遍。这几类坑有个共同点都不是模型的问题而是 Harness 配置没到位。修配置比换模型便宜得多。6. 把 Spec 和 Harness 接进你的日常链路写到这里方法论其实已经清楚了Vibe 负责速度Spec 负责方向Harness 负责边界Review 负责硬问题CI 负责不信任任何人。但要让这套东西真正跑起来还得把它接进你现有的工具链。如果你主要用 Claude Code 做长期编码和 Agent 编排建议把 Coding Plan 用起来它更适合这种需要持续上下文、多轮迭代的场景 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。配合本文的settings.jsonread_spec_first和compact_keep_spec能显著降低长会话里的约束漂移。如果你还在验证阶段想先确认模型输出质量再决定要不要接 CI可以用模型对话页面快速试几轮 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。确认没问题之后再回到config.toml把default_model固定下来。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有完整的端点说明和参数列表。API Key 管理在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 记得定期轮换别让一个 key 用到底。最后给一个我自己的习惯下一个需求先写半页 Spec再开 Claude Code / Cursor把三条架构禁止项写进 Rules让 CI 替你挡掉「能跑但不该合」的差分。速度会回来翻车会少。工具可以换方法不散。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑