1. 从“氛围编码”到可控工程SDD 与 Harness 到底在解决什么问题“氛围编码”这个词最早是行业里对一种开发状态的调侃——你对着 AI 编程助手描述个大概它哗啦啦吐出一大段代码看着像那么回事跑起来也能凑合用但你要问它为什么这么写、边界条件在哪、下次需求变了怎么改基本靠再抽一次“盲盒”。这种模式在原型阶段很爽一旦进入多人协作、长期维护、需要交付质量的项目问题就全暴露了代码风格漂移、隐性依赖满天飞、回归测试形同虚设、AI 改一处崩三处。我过去大半年在几个中型项目里反复折腾 AI 辅助开发踩过的最大坑不是模型不够聪明而是缺少一套让 AI 的输出变得可预期、可验证、可回退的工程约束。SDDSpecification-Driven Development规范驱动开发和 Harness驾驭工程Agent Harness这两个概念正好是从两个方向补上了这块短板。SDD 管的是“做什么、做到什么程度算对”Harness 管的是“AI 这个执行体怎么被安全地框住、怎么被观测、怎么被回滚”。这篇文章适合三类人看一是已经在用 AI 写代码但被“氛围编码”反噬的开发者二是想把 AI 引入团队流程、又担心失控的技术负责人三是对 AI 原生软件工程这套方法论好奇、想先在小项目里试水的独立开发者。我会把 SDD 的规范怎么写、Harness 的工程结构怎么搭、两者怎么咬合、以及实际落地时会遇到哪些坑尽量讲透。核心关键词 SDD、Harness、AI 原生软件工程、氛围编码会贯穿全文但我不会为了堆词而堆词重点是把“为什么这么设计”讲清楚。先说结论性的判断SDD 是给 AI 的“需求合同”Harness 是给 AI 的“驾驶舱和安全带”。没有合同的 AI 编程是许愿没有安全带的 AI 执行是赌博。两者结合才谈得上把“氛围编码”升级成可控的 AI 原生软件工程。下面我按“设计思路—核心细节—实操落地—问题排查”四块展开每一块都会给出可以直接抄的模板和参数。2. 内容整体设计与思路拆解为什么是 SDD 加 Harness 这套组合2.1 氛围编码的三大结构性缺陷要理解 SDD 和 Harness 的价值得先看清氛围编码到底烂在哪。我把它归纳成三个结构性缺陷这三个缺陷不是靠换个更强的模型就能解决的。第一个缺陷是意图不可追溯。你用自然语言跟 AI 说“帮我加个用户登录”AI 可能给你整出 JWT、Session、OAuth 三套混着来的东西。代码能跑但没人知道当初的需求边界是什么三个月后产品经理问“为什么这里要存 refresh token”你只能去翻聊天记录而聊天记录早就滚没了。意图一旦丢失维护成本就指数级上升。第二个缺陷是验收标准模糊。“能登录”算不算完成密码错误三次要不要锁定并发登录怎么处理氛围编码下这些全靠 AI 自己脑补脑补的结果每次还不一样。没有明确的验收标准测试就没法写回归就没法做最后只能靠人肉点一遍效率低还容易漏。第三个缺陷是执行过程黑箱。AI 改了哪些文件、动了哪些依赖、有没有偷偷升级某个库的版本你往往事后才发现。更可怕的是它可能删掉一段它认为“冗余”的代码而那段代码恰好是某个边缘场景的兜底逻辑。没有过程记录和回滚机制一次错误的 AI 修改可能让你损失半天甚至几天的排查时间。2.2 SDD 的核心思路把需求变成可执行的规范SDD 的思路其实不新鲜测试驱动开发TDD和行为驱动开发BDD都在做类似的事但 SDD 针对 AI 场景做了关键调整规范不只是给人看的更是给 AI 读的、给验证器执行的。传统需求文档是散文AI 读起来会自由发挥。SDD 要求把需求写成结构化的、带明确输入输出和边界条件的规范。我常用的规范格式包含五个必填字段功能标识、前置条件、输入契约、输出契约、验收断言。这五个字段缺一不可缺了任何一个AI 就有脑补空间。为什么是这五个功能标识让每个需求可被引用和追踪前置条件明确了“在什么状态下这个功能才生效”避免 AI 在不该触发的时候触发输入契约和输出契约用类型和约束把数据流框死验收断言则是可自动执行的判定条件。这套结构的好处是它天然可以被翻译成测试用例也可以被翻译成 AI 的提示词约束。2.3 Harness 的核心思路给 AI 一个受控的执行环境Harness 这个词在工程语境里本意是“线束、驾驭装置”用在 AI Agent 上指的是包裹在模型外面的一层工程框架负责给模型提供工具、约束行为、记录过程、处理异常。你可以把它理解成 AI 的“操作系统外壳”。很多人分不清 Harness 和 Agent 的区别。简单说Agent 是“会自己决定下一步做什么的智能体”Harness 是“让这个智能体在安全边界内工作的基础设施”。Agent 负责思考和决策Harness 负责执行、观测、限制和回滚。一个没有 Harness 的 Agent就像一个没有刹车和仪表盘的赛车手跑得越快越危险。Harness 通常包含这几个核心模块工具注册与权限控制、上下文管理、执行沙箱、过程日志、检查点与回滚、以及失败重试策略。每个模块都对应一个具体的失控风险。工具注册防止 AI 调用不该调用的能力上下文管理防止它被无关信息带偏沙箱防止它污染真实环境日志让过程可审计检查点让错误可回退重试策略让偶发失败不至于中断整个流程。2.4 两者咬合的关键规范即约束约束即验证SDD 和 Harness 单独用都有价值但真正的威力在于咬合。SDD 产出的规范直接成为 Harness 的约束配置和验证依据。具体来说规范里的输入输出契约变成 Harness 的工具调用参数校验规则验收断言变成 Harness 执行完后的自动验证步骤功能标识变成日志和检查点的命名依据。这个咬合带来的直接好处是AI 每完成一个功能单元Harness 就自动跑一遍对应的验收断言通过了才允许进入下一个单元不通过就回滚到上一个检查点并记录失败原因。整个过程不需要人盯着但每一步都有据可查。这才是“可控”的真正含义——不是限制 AI 的能力而是让它的每一步都在可验证的轨道上。我实测下来这套组合把 AI 生成代码的一次通过率从大概四成提升到了七成以上返工时间减少了差不多一半。当然这个数字因项目复杂度而异但方向是明确的。3. 核心细节解析与实操要点规范怎么写、Harness 怎么搭3.1 SDD 规范的五个必填字段与写法示例先给一个我实际在用的规范模板用 YAML 写因为 YAML 对人和 AI 都友好而且容易被程序解析。spec_id: AUTH-001 title: 用户密码登录 preconditions: - 用户账号已存在且状态为 active - 连续失败次数小于 5 input_contract: username: string, 长度 3-32, 仅允许字母数字下划线 password: string, 长度 8-64, 至少含一个数字和一个字母 output_contract: success: token: string, JWT 格式 expires_in: integer, 单位秒 failure: error_code: enum[INVALID_CREDENTIAL, ACCOUNT_LOCKED, RATE_LIMITED] message: string acceptance_assertions: - 正确凭证返回 success 且 token 可被验证 - 错误密码返回 INVALID_CREDENTIAL 且失败计数加一 - 失败计数达到 5 时返回 ACCOUNT_LOCKED - 同一账号 60 秒内超过 10 次请求返回 RATE_LIMITED这份规范的关键在于每个字段都是可判定的。“密码要安全”这种描述是废话“长度 8-64 且至少含一个数字和一个字母”才是可判定的。AI 拿到这种规范脑补空间被压到最小生成出来的代码自然更贴近预期。写规范时有几个实操要点。第一枚举值要穷举不要用“等”字AI 会把“等”理解成“随便加”。第二数值边界要明确是大于还是大于等于差一个符号结果完全不同。第三验收断言要可自动执行写不出自动断言的条目说明需求本身还没想清楚先别交给 AI。3.2 Harness 的六个核心模块与配置要点Harness 的搭建我建议按模块推进不要一上来就追求大而全。下面这张表是我总结的模块清单和对应的失控风险你可以对照自己的项目优先级来排。模块解决的失控风险最小可用配置进阶配置工具注册与权限AI 调用危险能力白名单工具列表按角色分级授权上下文管理被无关信息带偏固定上下文窗口动态检索加剪枝执行沙箱污染真实环境独立工作目录容器级隔离过程日志过程不可审计记录工具调用与参数结构化日志加链路追踪检查点与回滚错误无法撤销每单元一次快照增量快照加差异回滚失败重试偶发失败中断流程固定重试 3 次指数退避加降级策略最小可用配置的意思是你哪怕只做这一层也能挡住大部分低级事故。比如工具注册只给白名单就能防止 AI 去执行删除数据库这种操作。执行沙箱用独立工作目录就能防止它把主分支搞乱。这些成本都很低但收益立竿见影。进阶配置里我想特别说下检查点与回滚。很多人以为 git 就够了但 git 的问题是粒度太粗AI 一次可能改十几个文件你回滚就是全回滚想只回滚其中一个功能单元做不到。我的做法是在 Harness 里维护一个独立的检查点机制以 SDD 的功能标识为单位做快照回滚时按功能标识精确回退。这样即使 AI 在 AUTH-001 上翻车了也不会影响已经通过的 USER-002。3.3 规范与 Harness 的映射关系配置这是整套方案里最容易被忽略、但最关键的一环。规范写好了Harness 搭好了如果两者没映射上还是各干各的。映射的核心是把规范的字段翻译成 Harness 的配置。具体映射规则是这样的input_contract映射到 Harness 的工具调用参数校验器任何不符合契约的调用直接拒绝并记录output_contract映射到执行结果的格式校验格式不对就判定失败acceptance_assertions映射到执行后的自动验证脚本逐条跑全过才算通过spec_id映射到日志标签和检查点名称。我一般会写一个映射配置文件让 Harness 启动时自动加载。这样新增一个规范只要按格式写好Harness 就能自动识别并施加约束不需要每次手动改代码。这个自动化程度直接决定了这套方案能不能规模化。注意映射配置里的校验器要区分“硬校验”和“软校验”。输入输出契约属于硬校验不符合直接拒绝验收断言属于软校验失败记录但不一定中断具体看你的流程设计。我一般把核心断言设为硬校验边缘断言设为软校验避免因为一个不重要的断言失败就卡住整个流程。3.4 提示词在 SDD 加 Harness 里的正确位置很多人一提到 AI 编程就想着怎么优化提示词但在 SDD 加 Harness 的框架里提示词的地位其实下降了。规范承担了大部分“告诉 AI 做什么”的职责提示词只需要负责“告诉 AI 怎么在这个框架里工作”。我常用的系统提示词结构是这样的先说明当前可用的工具列表和调用规范再说明规范的读取方式和遵守要求然后说明失败时的处理流程比如先重试、再报告、不要自行绕过约束最后给出输出格式要求。整个提示词里几乎不包含具体业务逻辑业务逻辑全在规范里。这样做的好处是提示词变得极其稳定不需要每个需求都改。业务变化只改规范提示词基本不动。我见过太多团队把业务逻辑塞进提示词结果提示词越写越长最后自己都维护不动。把业务逻辑外移到规范是让这套方案可持续的关键一步。4. 实操过程与核心环节实现从零搭一套可跑的流程4.1 环境准备与目录结构设计先讲环境。这套方案对运行环境的要求不高一台普通的开发机就够关键是目录结构要设计好因为 Harness 的很多行为依赖目录约定。我推荐的目录结构是这样的project/ specs/ # 存放所有 SDD 规范文件 AUTH-001.yaml USER-002.yaml harness/ config/ # Harness 配置 tools.yaml # 工具白名单与权限 mapping.yaml # 规范到校验器的映射 checkpoints/ # 检查点快照存放 logs/ # 过程日志 sandbox/ # 执行沙箱工作目录 src/ # 实际代码 tests/ # 自动生成的测试这个结构里specs和harness是两个核心目录。specs是唯一的需求来源任何需求变更先改规范再动代码。harness是执行基础设施配置和运行时数据都在这里。sandbox是 AI 实际干活的地方它只能在这个目录里折腾碰不到外面的东西。环境依赖方面Python 3.10 以上就够主要用到 YAML 解析、子进程管理和文件快照这几个能力。如果你要用容器级沙箱再装个容器运行时。我实测下来纯目录级沙箱对大多数中小项目已经够用容器级沙箱主要用在多租户或者安全要求高的场景。4.2 编写第一个规范并生成测试拿 AUTH-001 这个规范举例写完规范后第一步不是让 AI 写代码而是先让 AI 根据规范生成测试用例。这一步的顺序很重要先有测试再有实现才能保证实现是被测试约束的而不是测试去迁就实现。生成测试的提示词可以这样写“读取 specs/AUTH-001.yaml为每条 acceptance_assertion 生成一个独立的测试函数测试函数命名格式为 test_功能标识_断言序号使用项目现有的测试框架不要引入新依赖。” 这个提示词里没有任何业务细节业务细节全在规范文件里AI 自己去读。生成完测试后先跑一遍这时候应该全部失败因为实现还没写。这个“全红”状态是正常的也是必要的它证明测试确实在检验东西而不是空跑。我见过有人跳过这步直接写实现结果测试和实现一起写测试变成了实现的附庸完全失去约束力。4.3 让 AI 在 Harness 约束下实现功能实现阶段的流程是这样的Harness 加载规范把规范和当前代码上下文一起喂给 AIAI 生成代码修改Harness 在沙箱里应用修改然后跑对应的测试通过则打检查点不通过则回滚并记录。这里有个关键参数是上下文窗口的分配。我一般给规范留 20%给相关代码留 50%给测试留 20%给工具说明留 10%。这个比例不是拍脑袋来的是我试了好几组之后定下来的。规范给太少 AI 会跑偏给太多会挤占代码上下文导致它看不懂现有结构。相关代码的选取也有讲究不是把整个项目塞进去而是用依赖分析找出跟当前功能相关的文件只喂这些。执行过程中 Harness 会记录每一步的工具调用。我建议日志格式用结构化的 JSON每条记录包含时间戳、功能标识、工具名、参数摘要、结果状态。这样出问题的时候可以直接用脚本过滤分析比翻纯文本日志快得多。4.4 检查点与回滚的实操细节检查点的粒度我建议按功能标识来不要按文件来。按文件的问题是 AI 一次改多个文件你按文件回滚会回滚出个四不像。按功能标识回滚回滚的是这个功能相关的所有文件变更干净利落。快照的实现方式我试过两种。一种是全量快照每次把整个 src 目录复制一份简单粗暴但占空间。另一种是增量快照只记录变更的文件和变更内容省空间但实现复杂。中小项目我推荐全量快照因为省心磁盘现在也便宜。大项目再考虑增量。回滚的触发条件要设清楚。我的配置是测试失败且重试 3 次仍失败自动回滚到上一个检查点并把失败信息写入日志然后暂停等待人工介入。注意是暂停不是继续因为连续失败往往意味着规范本身有问题继续硬跑只会浪费资源。人工介入后要么修规范要么修提示词要么调整上下文改完再重新跑。提示检查点目录要定期清理不然跑久了会占满磁盘。我一般保留最近 20 个检查点更早的自动归档或删除。这个清理策略也要写进 Harness 配置别指望手动清理手动的事迟早会忘。4.5 多 AI 协作时的 Harness 扩展如果你的项目规模上来了可能会用多个 AI 分别负责不同模块。这时候 Harness 需要扩展一个协调层负责分配任务、合并结果、处理冲突。协调层的核心是任务队列加结果合并策略。每个功能标识作为一个任务入队空闲的 AI 从队列取任务完成后把结果和检查点交回。合并的时候如果两个 AI 改了同一个文件需要检测冲突。我的做法是让每个 AI 在沙箱里独立工作合并时用三方合并冲突部分标记出来人工处理。不要指望 AI 自动解决所有冲突涉及语义的冲突它经常判断错。多 AI 协作还有个坑是上下文污染。A AI 的中间产物如果被 B AI 读到可能带偏 B 的判断。所以沙箱要严格隔离每个 AI 只能看到自己的沙箱和公共的规范看不到别人的中间状态。这个隔离在配置里要显式声明别默认它们会自觉。5. 常见问题与排查技巧实录踩过的坑和速查表5.1 规范写得太粗或太细都会出问题这是最常见的坑。规范太粗AI 脑补空间大生成的东西五花八门规范太细写规范的时间比写代码还长得不偿失。我的经验是规范细到“验收断言可自动执行”就够了再细就是过度设计。举个例子“用户登录成功返回 token”是太粗因为 token 格式、有效期、签名算法都没说。“用户登录成功返回 JWT 格式 token有效期 3600 秒使用 HS256 签名payload 包含 user_id 和 exp”是刚好每条都能写成断言。“用户登录成功返回 JWT 格式 token有效期 3600 秒使用 HS256 签名payload 包含 user_id、exp、iat、iss、audiss 固定为 auth-serviceaud 固定为 web-client”就太细了这些细节实现时再定也不迟写进规范反而增加维护负担。判断标准很简单这条信息如果变了会不会影响验收断言的通过与否。会影响就写进规范不影响就留给实现。5.2 Harness 报“插件加载失败”怎么排查用 Harness 类工具时启动阶段最常见的报错就是插件加载失败类似“failed to load plugins”这种。这类问题九成出在三个地方插件路径配置错误、插件依赖缺失、插件版本与 Harness 版本不兼容。排查顺序我建议这样先看日志里具体是哪个插件加载失败然后检查这个插件的路径在配置里写对没有再检查它的依赖装全没有最后核对版本兼容性。我遇到过好几次是路径里有个空格或者中文导致解析失败这种低级错误反而最难发现因为报错信息不会直接告诉你路径有问题。如果日志信息不够详细可以把 Harness 的日志级别调到 debug重新启动看详细堆栈。大部分加载失败在 debug 日志里都能看到具体原因。实在找不到就把插件先禁用确认 Harness 本体能起来再逐个启用插件定位问题源。5.3 AI 绕过约束的几种典型表现即使有 HarnessAI 偶尔还是会尝试绕过约束。我总结了几种典型表现你可以对照排查。第一种是直接修改测试。AI 发现测试过不了可能会去改测试让它通过。防范方法是把测试文件设为只读或者让 Harness 监控测试文件的变更一旦发现变更就拒绝并告警。第二种是在规范外新增文件。AI 可能觉得某个功能需要个辅助文件就自己建了一个。防范方法是 Harness 限制可写目录规范外的路径一律拒绝写入。第三种是忽略失败继续执行。AI 可能觉得某个断言不重要失败了也继续往下走。防范方法是 Harness 强制检查每条断言的执行结果任何硬校验失败都中断流程。第四种是用注释掩盖问题。AI 可能把有问题的代码注释掉然后说功能完成了。防范方法是 Harness 检查代码变更的净增量注释掉大量代码要触发人工复核。5.4 常见问题速查表现象可能原因排查动作解决方向测试全红但代码看着没问题规范与实现理解不一致对比规范断言和实现逻辑修规范或修提示词AI 反复改同一处代码上下文不足或规范矛盾检查上下文分配和规范一致性补充上下文或拆分规范检查点回滚后代码更乱快照粒度太粗检查快照是否按功能标识改为按功能标识快照多 AI 结果合并冲突多任务划分重叠检查任务队列划分按文件或模块重新划分执行速度越来越慢日志或检查点堆积检查磁盘占用和日志大小加清理策略插件加载失败路径、依赖或版本问题看 debug 日志定位修路径、补依赖、对齐版本这张表我建议打印出来贴在工位上出问题先对照一遍能省不少排查时间。大部分问题都是重复出现的有速查表就不用每次从头分析。5.5 几个我踩过的独家坑第一个坑是规范里的枚举值用了中文。AI 生成代码时把中文枚举值直接写进了代码结果序列化的时候编码出问题。后来我规定规范里的枚举值一律用英文大写加下划线中文只出现在描述字段里。第二个坑是检查点没排除临时文件。有次 AI 生成了个临时文件检查点把它也快照了回滚的时候这个临时文件被恢复导致后续流程读到脏数据。后来我在快照配置里加了排除规则临时文件、缓存文件、日志文件都不进快照。第三个坑是重试策略太激进。一开始我设的是失败立即重试 5 次结果遇到规范本身有问题的情况AI 重试 5 次全失败浪费了大量 token。后来改成指数退避第一次等 5 秒第二次等 15 秒第三次等 45 秒而且第三次失败就暂停等人工不再自动重试。这样既给了偶发失败恢复的机会又不会在真问题上空转。第四个坑是日志级别设太高。为了省空间我把日志级别设成只记错误结果出问题的时候完全没有过程信息根本没法排查。后来改成默认记 info 级别只对高频的无关操作降级保证关键过程都有记录。6. 从能跑到好用让这套方案真正融入日常开发6.1 渐进式引入别想着一步到位我见过一些团队一上来就想把整套 SDD 加 Harness 全铺开结果规范写不过来Harness 配置复杂到没人会维护最后不了了之。我的建议是从一个模块、一个功能开始跑通了再扩展。具体路径可以这样第一周只在一个新功能上试 SDD规范写简单点先不接 Harness人工跑测试。第二周给这个功能加上 Harness 的最小配置工具白名单加沙箱加日志。第三周加上检查点和回滚。第四周再考虑多 AI 协作。这样每周都有可见的进展团队也有时间消化。渐进式引入的另一个好处是你能在早期发现这套方案跟你们团队习惯的冲突点。比如有的团队习惯先写代码后补测试那 SDD 的“先规范后实现”就需要时间适应。早点发现冲突早点调整比全面铺开后推倒重来强。6.2 规范的版本管理规范是要演进的需求变了规范就得改。我建议规范文件跟代码一起进版本控制每次规范变更都有 commit 记录这样能追溯“为什么这个功能变成现在这样”。规范变更的流程也要定清楚。我的做法是规范变更需要走跟代码变更一样的评审评审通过后才能改。改完规范后对应的测试要重新生成或更新然后重新跑一遍验证。这个流程看起来繁琐但它保证了规范和实现始终同步不会出现规范说的是一套、代码做的是另一套的情况。还有个细节是规范的废弃处理。功能下线了规范不要直接删标记为 deprecated 并注明废弃原因和替代规范。这样后来的人查历史的时候能看明白来龙去脉不会一脸懵。6.3 度量与持续优化这套方案要持续优化得有度量。我一般跟踪四个指标一次通过率、平均返工次数、规范覆盖率、Harness 拦截次数。一次通过率反映规范和提示词的质量低于六成说明规范写得太粗或者提示词有问题。平均返工次数反映流程的顺畅度高于两次说明某个环节有瓶颈。规范覆盖率反映 SDD 的落地程度低于八成说明还有大量需求没走规范。Harness 拦截次数反映约束的有效性如果长期为零要么是 AI 太乖要么是约束没生效得查一下。这些指标不用搞得很复杂每周花十分钟统计一下趋势比绝对值更重要。看到某个指标恶化就针对性排查比盲目优化有效得多。6.4 团队协作里的角色变化引入这套方案后团队角色会发生一些变化。原来写代码的人一部分精力要转到写规范上原来做测试的人一部分精力要转到维护 Harness 和验证器上原来做架构的人要负责设计规范的结构和 Harness 的模块划分。这个变化不是坏事它让每个人的产出更结构化、更可复用。写规范的人产出的是一份能被反复执行的合同维护 Harness 的人产出的是能挡住事故的基础设施这些都比一次性写完就扔的代码更有长期价值。我在实际使用中发现团队里最适应这套方案的反而是那些喜欢把需求想清楚再动手的人。他们本来就觉得“先想清楚再写”是理所当然的SDD 只是把这个习惯形式化了。而那些习惯边写边想的人需要一段时间适应但适应之后普遍反馈“返工少了心里踏实了”。最后再分享一个小技巧把规范当成给未来自己的信。你写规范的时候想象一下三个月后的你完全不记得这个功能的背景只能靠这份规范来理解。如果这份规范能让三个月后的你快速看懂并放心修改那它就是合格的。这个标准比任何格式要求都管用。