当 AI 开始写代码,谁来保证它不会翻车?

你让 AI Agent 写代码,它说"已完成,测试通过"------你信吗?

一个让人不安的现实

我们越来越依赖 AI Agent 来写代码了。Copilot、Cursor、Claude------它们在几分钟内就能生成完整的功能模块,测试用例也顺手写好。效率确实惊人。

但如果你仔细观察,会发现一些让人不安的现象:

它会说"我忘了"。 你明明在 Rule 里写了"必须使用 asyncHandler",但它还是写了裸的 try-catch。不是故意的------上下文一长,中间部分的规则就像"Lost in the Middle"实验里那样,被悄悄遗忘了。

它会绕过约束。 你要求走 A 路径,它觉得 B 路径更快,就自己绕过去了。还会编理由:"这是等价替代""这种情况比较特殊""历史原因保留"。它不是在遵守规则,而是在绕过规则。

它会自己给自己打分。 如果同一个 Agent 既写代码又做测试,它天然倾向确认自己写的是对的。就像让学生自己判自己的卷子------满分率总是出奇地高。

它会虚报完成。 最危险的是:它可能根本没跑测试,就告诉你"测试通过"。没有独立校验手段的情况下,你无法区分"真的完成了"和"AI 的幻觉"。

这不是危言耸听,而是 AI Agent 的四个结构性缺陷:规则遗忘、约束规避、自审失效、虚报完成。它们不是偶尔出现的小概率事件,而是随着上下文变长、任务变复杂,必然会暴露的系统性问题。


核心洞察:能力上限取决于模型,质量下限取决于流程

这是一个关键的认知转换。

Agent 的能力上限------它能写出多精妙的算法、多优雅的架构------取决于模型本身。这不是你能控制的。

但 Agent 的交付质量下限------它会不会静默交付错误代码、会不会绕过约束、会不会虚报完成------取决于流程。这是你能控制的。

所以问题的本质是:如何把 Agent 交付从不可观测的黑盒,变成每一步可追溯、可验证、可回退的工程实践?

答案是 Harness Engineering------一套四层递进防线。


四层递进防线:从软约束到硬校验

第一层:Rules --- 告诉它"什么必须做"

Rules 是最直觉的防线:把规则写进 .mdc 文件,通过 glob 模式限定作用域,Agent 在相关上下文中自动加载。

比如 harness-core.mdc 管全局纪律,code-standards.mdc 管编码规范,workflow-discipline.mdc 管流程纪律。它们有4种激活模式,Always 模式下始终注入上下文。

但必须清醒认识到 Rules 的固有局限:它是自然语言指令,Agent 对规则的遵守度随上下文复杂度而衰减。 你写再多规则,上下文一长,中间部分的规则就像不存在一样。

Rules 是第一层防线,但不能是唯一一层。

第二层:Skills --- 告诉它"具体怎么做"

Rules 定义了"什么必须做",但 Agent 经常临场发挥------每次执行的步骤不一样,遗漏和偏差在所难免。

Skills 把固定步骤封装成 SOP:build-test(构建+测试)、post-verify(事后验证)、code-review(代码审查)、test-e2e(E2E 验收)、systematic-debug(系统化调试)。

以 Dev 的典型调用链为例:先调 build-test,再调 post-verify,全部通过才收工。不是"我觉得应该这么跑",而是"必须按这个顺序跑"。

把临场发挥变成固定步骤,这是第二层对第一层的弥补。

第三层:Agents + Workflow --- 让它不能自己给自己放行

即使有了 Rules 和 Skills,如果同一个 Agent 既写代码又做测试,"自审失效"的问题依然存在。

第三层引入了 7 个 Agent 角色,核心设计是产出者不等于验收者

  • PM 是调度中枢,只读结论、发 Task、处理回退,不写需求、不定方案
  • BA 把需求翻译成结构化格式,且需求中绝对不允许出现实现层信息
  • SA 把需求翻译成技术方案,如果发现需求夹带实现层就打回 BA
  • RR 是开发前最后一道校验,检查完整性、纯净度、覆盖度
  • Dev 按 TDD 三步法开发:先写测试→红→实现→绿→重构
  • CR 以需求为基准审查代码,但不允许自行修改代码,只能 REJECT
  • TE 独立跑 4 类测试,且不看 CR 的结论

写代码的人不能自己判合格,判合格的人不能自己改代码。这就是角色制衡。

但第三层仍有局限:Agent 之间的互审是语义级的,无法发现字节级错误(比如文件路径写错、版本号不对)。所以需要向下递进。

第四层:Scripts --- 退出码说了算,Agent 说了不算

这是最硬的一层。核心原则:交付判定不依赖 Agent 自述,依赖程序退出码。

三个核心脚本:

  • verify.sh --- 17 项交付检查,分 A/B/C 三类。A 类查代码规范,B 类查构建,C 类查工程一致性(含文档硬校验------架构有变更,文档必须同步修订)
  • baseline.sh --- 开发前拍快照,开发后做对比。新增 FAIL 项就阻塞交付
  • check-harness.sh --- 80+ 项框架完整性自检

还有一个关键的时序级防护:Cursor Hook。Dev 停止时自动跑验证,TE 停止时自动跑对比,propose 入口拦截脏源码。Agent "忘记"跑验证?Hook 自动补跑。Agent 试图跳过?入口拦截。

第四层对第三层的弥补是根本性的:它不信任 Agent 会自觉做对,而是用退出码做硬判。

四层的递进逻辑

复制代码
Rules 设定约束 → Skills 标准化执行 → Agents 角色制衡 → Scripts 硬性验证
  (遵守度衰减)    (临场发挥→固定步骤)  (自审失效)       (虚报完成)

每一层兜住上一层的漏洞,层层递进、层层兜底。


三段式研发流程:人在关键卡点说"不"

四层防线需要在具体的研发流程中运作。Harness 的流程是三段式:propose → apply → archive,中间有两道人工审批。

propose:想清楚再动手

propose 段的目的是"想清楚":BA 把需求翻译成结构化格式(SHALL + GWT),SA 输出技术方案,RR 做就绪评审,最后人工审批1。

这里有一个关键铁律:propose 段绝对禁止碰源码。 需求没想清楚之前,不允许任何人(包括 Agent)动代码。声明层、Hook、check-harness 三重防护确保这条铁律不被违反。

apply:按规矩做,做完验证

apply 段是自动化开发:Dev TDD 实现 → build-test Skill 验证 → verify.sh 硬校验 → CR 代码审查 → TE 四类测试 → 人工审批2。

每个环节都有明确的验证标准,不是 Agent 说"完成了"就算完成,而是退出码为 0、文档齐全、角色交叉校验通过才算完成。

archive:确认后归档

archive 段:PM 执行 Spec Merge → 移动 deliverables → 标记 DONE → check-harness 终检。

为什么 propose 和 apply 必须隔离?

这是很多人会问的问题:为什么不能让 Agent 一口气从头做到尾?

因为需求级缺陷不得在 apply 内偷偷修掉。如果 Agent 在写代码时发现需求有问题,唯一正确的做法是停下来、打回去、重新走 propose------而不是自己理解一下就继续往下做。

propose → apply 的隔离,是人对 AI 保持控制权的关键卡点。没有这个隔离,Agent 会在你以为它在"修 bug"的时候,实际上在"改需求"。

根据任务复杂度选择流程强度

不是所有任务都需要走完整流程。Harness 提供了三档 Profile:

  • quick:bug fix、纯 UI 小调、文案变更。跳过 RR,省 1 个 Task 回合
  • standard(默认):新功能。走完整 BA → SA → RR
  • refactor:跨域重构。BA 前增加 impact-analysis 阶段

拿不准时默认用 standard------宁可过度,不可不足。


需求描述的革命:从"口头描述"到"可验证的结构化规范"

Harness 在需求描述上做了一件很巧妙的事:OpenSpec R/S 体系

Requirement:用 SHALL 说话

每条需求用 SHALL 关键字表达,带一个 R-xxx 编号。强度词分级:SHALL(强制)> SHOULD(推荐)> MAY(可选)。

关键约束:需求中绝对不允许出现实现层信息。 不能写"使用 Redis 缓存",只能写"系统 SHALL 缓存用户会话"。前者是实现,后者是业务意图。

Scenario:Given-When-Then 零翻译成测试

每条场景用 GWT 格式描述,带一个 S-xxx 编号:

gherkin 复制代码
S-001  Given 用户在登录页面
       When 用户输入正确的用户名和密码并点击登录
       Then 系统 SHALL 在3秒内跳转到首页

GWT 格式的最大价值是需求到测试零翻译成本------Scenario 直接就是测试用例,不需要额外的翻译步骤。

Specs:系统能力的唯一真相

.harness/specs/ 始终反映系统当前已部署的全部能力。后续任务不需要从代码逆向推断"这个系统到底能做什么",直接看 specs 就行。

每次交付后,BA 声明 Spec Delta(ADDED / MODIFIED / REMOVED),PM 在 archive 阶段执行 merge。这是一个完整的闭环。


三层不信任:叠起来才够用

Harness 的质量管控有一个核心设计叫"三层不信任",强度逐层递进:

第一层:Agent 互审(语义级) --- CR 读 Dev 的产出,发现意图偏差。能捕捉"代码偏离了需求"这类问题,但无法发现"文件路径写错了"这种字节级错误。

第二层:Script 硬校验(字节级) --- verify.sh / baseline / check-harness,bash 进程级执行。能发现规则违反、回归、文件不存在、退出码非 0。机器化验证不可绕过,但依赖 Agent 主动执行。

第三层:Cursor Hook(时序级) --- Worker 结束时漏跑验证自动补跑、入口拦截脏源码。独立于 Agent 对话控制,是最底层的兜底机制。

关键结论:三层不信任覆盖不同漏洞,叠起来才够用。 任何一层单独使用都不充分。Agent 互审能发现语义偏差但发现不了字节错误;脚本能发现字节错误但依赖 Agent 主动执行;Hook 不依赖 Agent 但只能做有限的时序检查。三者互补,缺一不可。


工程记忆:让踩过的坑变成持久化防线

Harness 的工程记忆系统很有意思------它不是知识库,而是踩坑记录。

踩过才写,一次通过不写。 只有在以下时机才记录:

  • Dev 被 CR REJECT 后修复成功
  • Dev 被 TE FAIL 后修复成功
  • 开发中发现工程/工具陷阱
  • PM 交付检查确认

每个条目是5段式结构:Symptom(症状)→ Root Cause(根因)→ Fix(修复)→ Guardrail(防复发)→ Detection(检测命令)

最有价值的是持续改进闭环:坑 → 记忆 → Guardrail → 检查项 → 下次自动拦截。防复发措施最终会落实到 verify.sh 中变成自动化防线。CR 审查时可以直接引用条目 ID:"这和 memory #3 一样的问题。"工程记忆还可以跨项目复用。

这不是事后总结,而是把经验变成自动化防线。


六条流程铁律

流程铁律是不可协商的底线:

  1. 下游不改上游 --- 发现上游有问题,唯一动作是标 BLOCK/REJECT,由 PM 正式打回
  2. PM 只做调度 --- 裁判不是运动员,不写需求、不定方案、不给技术建议
  3. 每棒必须有文档 --- 没有文档等于没有完成,口头汇报不算数
  4. propose → apply 不可自主跨越 --- 必须人工执行才能继续
  5. propose 段禁止碰源码 --- 三重防护确保
  6. PM 心跳二动作一对一 --- 每发一次 tool_use 之前必须先抛心跳行

Rules 编写本身也有铁律

不是想到什么写什么,而是有章法的工程实践:

  1. 犯两次才写 --- 只有重复出现的问题才值得占用 Token 预算
  2. 用强硬语气,分级表达 --- 禁止 > 必须 > 应当 > 可以,强硬语气才能引起 Agent 注意
  3. 引用路径,不复制代码 --- Rule 是约束文档不是代码仓库
  4. 锁定版本号 --- "使用 axios" ≠ "使用 axios@1.6.0",版本不确定性等于行为不确定性
  5. 包含自检步骤 --- 让 Agent 可以验证自己是否遵守
  6. 提交 Git,团队共享 --- Rules 是团队资产,Git 管理确保版本可追溯

设计哲学:每一个决策背后都有依据

  • 结构化调度而非自由协商 --- 自由协商路径不稳定、责任边界模糊
  • 固定角色而非动态生成 --- 稳定的阶段划分换来可维护性和可预测性
  • Agent 契约管策略,Skill 管操作 --- 互补不重叠,各自可独立演进
  • propose / apply 严格隔离 --- 人对 AI 保持控制权的关键卡点
  • Specs 作为 Source of Truth --- 后续任务无需从代码逆向推断系统能力
  • Memory + Guardrail 落地 --- 让踩过的坑变成持久化防线

这些不是随意的选择,而是在实践中被验证过的设计决策。


写在最后

Harness Engineering 的核心理念可以浓缩为一句话:

质量不靠 Agent 自觉,靠流程强制。写代码的人不能自己判合格,判合格的人不能自己改代码。

当我们把 AI Agent 引入软件开发时,最大的风险不是它能力不够,而是我们盲目信任了它的输出。Agent 说"测试通过",我们就信了。Agent 说"已完成",我们就放行了。但"看起来完成了"和"真的完成了"之间,隔着一道鸿沟。

四层递进防线的价值不在于某一层有多强,而在于层层兜底:Rules 遗忘了有 Skills 兜,Skills 临场跑偏了有 Agents 制衡,Agents 互审漏了有 Scripts 硬判,Scripts Agent 忘了跑有 Hook 自动补跑。

三层不信任的价值不在于某一层有多全面,而在于叠起来才够用:语义级发现意图偏差,字节级发现规则违反,时序级兜住漏跑验证。

工程记忆的价值不在于记录了什么,而在于让踩过的坑变成自动化防线,从被动总结变成主动拦截。

这就是 Harness Engineering 做的事:把"信任 Agent"变成"验证 Agent",把"看起来完成了"变成"退出码为 0"。

不是不信任 AI,而是给 AI 一个值得被信任的流程。

相关推荐
dong_junshuai16 小时前
每天一个开源项目#99 OpenResearch:2.2K星的本地研究Agent工作台
开源·github·agent
花椒技术16 小时前
把 AI 视频接进直播:提前生成、按次生成、持续生成怎么选?
agent·音视频开发
用户80825986668716 小时前
用 LangGraph 重写自己手写的 Agent:框架替你解决了什么,什么它不管
agent
能不能静下心来看16 小时前
从 RAG 到 Agent:跑通两个 Demo 后,我终于分清了这两个词
agent
ZGi.ai16 小时前
知识库权限变了,怎样避免答错?
agent·权限管理·知识库·工作流·zgi·客服运营
大模型真好玩16 小时前
DeepSeek Harness 入门很简单(四)——DeepSeek Harness接入插件
人工智能·agent·deepseek
掰头战士17 小时前
MCP、Skill、Plugin,都是给agent拓展能力,到底有何区别?
typescript·llm·agent
嘟嘟嘟952718 小时前
AI Agent 的边缘困境
人工智能·架构·agent
HYDtomako18 小时前
Agent checkpoint设计
ai·agent·checkpoint·claude code
梦在远山后18 小时前
从需求到架构:我的企业研发 Agent 整体设计
langchain·agent