你最后一次验证 Skill 是怎么做的?写完一个 Skill,手动触发了几次,输出看起来还不错——然后就上线了。这大概是大多数人验证 Skill 的完整流程。说出来有点惭愧,但确实如此。我们在写普通代码时会写单元测试、跑 CI,但到了 Skill 这里,突然回到了"凭感觉"的时代。问题不是懒。问题是我们不知道 Skill 会以哪些方式悄悄失效,也没有一套语言来描述"什么叫做好"。这篇文章就是要解决这两件事:先把 Skill 的失效路径说清楚,再用这套失效地图反推出验证体系。Skill 会怎么失效?在聊怎么测之前,先想清楚有什么可能出错。Skill 的失效通常沿着四条路径发生,而且往往是静悄悄的——没有报错,只有"结果不对劲"。路径一:根本没触发这是最隐蔽的失效。用户明明说了"帮我格式化一下代码",但 Agent 没有调用你的代码格式化 Skill,而是直接用模型自己的知识瞎改了一通。原因通常在SKILL.md的description字段写得太模糊——太宽泛会和其他 Skill 冲突,太窄又会漏掉很多合理的触发场景。更棘手的是,这种失效在手动测试时很难发现,因为你测试的时候往往用的是最标准的触发语句,而用户在真实场景里的表达千变万化。路径二:触发了,但任务没完成Skill 被调用了,工具也跑了,但最终该做的事没做到。比如:应该创建三个文件,结果只创建了两个;应该执行一段迁移脚本,结果中途退出了。这类失效叫做Outcome 失效,是最直接、影响最大的一类。用户最终看到的就是结果——结果不对,Skill 就等于没用。路径三:结果对了,但过程走歪了这一类更隐蔽。最终输出看起来没问题,但 Agent 的执行路径是错的:调用了不该调的工具、步骤顺序乱了、绕了一大圈弯路才完成任务。举个例子:一个数据库迁移 Skill,正确的顺序应该是"备份 → 迁移 → 验证"。如果 Agent 先迁移再备份,输出文件可能是对的,但下次迁移失败时你就没有可用的备份了。这是 Process 失效,在纯结果导向的验证里完全看不出来。路径四:完成了,但质量不达标任务完成了,过程也对了,但:生成的代码风格和项目规范不一致;Commit message 格式不符合团队约定;用了 500 个 token 完成了本可以用 100 个搞定的任务。这是Style 和 Efficiency 失效,不会直接报错,但会在团队协作和成本控制上慢慢积累成大问题。定义"成功":四个维度的验证目标这四条失效路径,正好对应四类成功标准。确认过这四个维度,才算真正定义清楚了"这个 Skill 应该做到什么"。维度对应失效核心问题Outcome(结果)任务没完成该做的事做了吗?Process(过程)执行路径错误用对工具了吗?顺序对吗?Style(风格)质量不达标输出符合规范吗?Efficiency(效率)资源浪费有没有绕弯路?token 用量合理吗?接下来,针对每个维度,介绍对应的验证方法。验证 Outcome:确定性检查Outcome 是最容易量化的维度,适合用确定性检查(Deterministic Grader)——即通过解析运行日志或检查文件系统状态,来判断任务是否完成。先建一个小测试集不需要几百条用例,10~20 条就够了。但要覆盖三种场景:显式触发:"/use code-formatter 帮我格式化这个文件" 隐式触发:"这段代码格式有点乱,能帮我整理一下吗?" 负样本: "帮我写一个排序算法"(不应该触发格式化 Skill)负样本尤其重要,它检验的是 Skill 有没有被错误触发——过度触发和没触发一样是问题。用 JSON 输出做确定性断言codex exec --json会输出结构化的运行日志(JSONL 格式),包含每次工具调用的详情。针对 Outcome 验证,可以这样检查:importjson,sys# 加载运行日志withopen("run_output.jsonl")asf:events=[json.loads(line)forlineinf]# 检查目标文件是否被创建created_files=[e["path"]foreineventsife.get("type")=="file_write"]expected=["src/index.ts","src/types.ts","README.md"]missing=[fforfinexpected