从“能运行”到“可交付”,Skill正在复刻软件工程二十年前走过的路
大家好,我是某互联网公司的测试架构师。
上个月,团队里一个同事跑来跟我说:“老大,我那个测试用例生成的Skill,昨天还好好的,今天突然不行了。我没改任何东西啊。”
我问他:“你换模型了?”
他愣了一下:“哦,好像是自动更新了……”
他没改Skill,但模型变了。大模型版本从Claude Sonnet 4.0切到了4.5,Skill的行为就跟着漂了——同样的输入,昨天输出40条用例,今天只输出25条。
他没改一行代码,Skill却“退化”了。
这个问题让我想了很久:当Skill本身也需要回归测试的时候,我们是不是把简单问题搞复杂了?
一、先看一个真实案例:改了一行描述,Skill“悄悄”变了
这不是我编的,是阿里开源skill-up那篇文章里记录的一个真实案例。
团队维护了一个代码发布Skill,它会读取发布内容、生成上线步骤、验证方案和回滚计划,同时调用内部工具创建发布任务。
开发者觉得输出太啰嗦,修改了几行描述,希望输出更简洁。从代码Diff来看,这次改动似乎没有任何风险。
但在部分输入下,Agent不再调用发布工具了——它只输出了一段建议性的文字,而不是实际创建发布任务。
文档仍然正确,脚本也没有报错,但Skill的核心行为已经变了。
没有固定的回归用例,这个问题直到用户反馈后才暴露出来。
代码评审看不出来,脚本跑不出错,但Skill确实“坏”了。
这还不是最夸张的。换一个Agent引擎,行为可能完全不一样——同一个Skill在Claude Code里运行正常,换到Codex后却漏掉了关键检查项。
二、为什么Skill比普通代码更需要回归测试?
有人可能会说:“普通代码改了一行也得做回归测试啊,Skill有什么特殊的?”
特殊在:影响Skill行为的变量太多了。
一个Skill的行为,受到至少8种因素的影响:
SKILL.md中的自然语言描述
工具名称和工具说明
Agent引擎的执行机制
大模型版本与参数
用户输入的具体措辞
上下文长度与历史会话
文件、脚本和运行环境
外部API与MCP工具返回结果
即使只是修改SKILL.md中的一句话,也可能改变Agent的工具选择、执行顺序和输出结果。
传统代码是确定性的——同样的输入,永远产生同样的输出。Skill是非确定性的——你没改它,它都可能因为模型版本变化而“退化”。
这就是为什么Skill需要回归测试:不是因为它容易写错,而是因为它太容易“不知不觉地变”了。
三、但等等,我们是不是在过度工程化?
看到这里,你可能会想:“这不就是给每个Skill写一套测试用例吗?测试用例本身不也是Skill写出来的?这是套娃吗?”
这个问题问得特别好。
表面上看,这确实像套娃——Skill生成测试用例,测试用例又来测Skill。但这和“用AI测AI”有本质区别。
Skill评测的核心,是把“确定性验证”从“模型推理”中剥离出来。
你可以用LLM Judge来评估输出质量,但关键行为的验证——工具是否被调用、文件是否被创建、关键步骤是否被执行——这些应该是确定性的、可脚本化的。
一个好的Skill评测集,应该包含:
用例类型
说明
正常成功路径
标准输入下的标准输出
参数缺失
缺少必填参数时的行为
输入歧义
模糊指令下的处理
用户要求跳过流程
非标准操作顺序
工具调用失败
外部依赖异常时的降级
权限不足
越权操作的拦截
超时和重试
异常恢复机制
危险操作确认
高风险操作的二次确认
无法完成时的降级策略
任务失败时的兜底
历史缺陷回归
每发现一个线上问题,补充一条对应用例
这些不是让AI“猜”的,是写死的、可重复的、确定性的检查。
就像你不会让AI来验证“1+1=2”,Skill评测里那些“确定性操作”,也应该用脚本或规则来验证。
四、业界怎么做的?阿里skill-up和Google的实践
2026年7月,阿里开源了skill-up——专门面向Agent Skill的评测与演进工具。
它的核心逻辑很简单:用声明式YAML写评测用例,跨多个Agent引擎跑评测,让AI自动修复失败的Skill或补充评测用例,然后重新跑——形成一个“评测到进化”的闭环。
skill-up支持三种评测策略:
Judge类型
适用场景
rule_based
可量化验证:文件是否存在、正则匹配、退出码
script
需要自定义逻辑:调用外部脚本做复杂校验
agent_judge
需要语义判断:Agent输出是否符合预期行为
Google的做法更直接。在Google的Agent Skills体系中,每个Skill提交时,流水线自动执行三类检查:Linters(静态检查)、Link Checkers(链接检查)、EVAL.yaml(评估套件)。
Google还建立了第二道防线:每周持续评估——定期跑评估任务,检测回归。上周还90分的Skill,这周可能因为上游API变更掉到60分。
评估即合约:每个Skill诞生时必须自带“什么算成功”的定义(EVAL.yaml),评估不是事后补救,而是合并的前置条件。
五、那到底算不算“把简单问题搞复杂了”?
回到标题的问题:当Skill也需要回归测试,我们是不是把简单问题搞复杂了?
我的答案是:不是我们搞复杂了,是事情本身变复杂了。
Skill正在从“个人Prompt资产”变成“需要版本管理、自动化测试和持续回归的软件工程资产”。软件工程走过的老路——从“先跑起来”到“能稳定运行”——Skill正在重新走一遍。
如果你只有一个Skill,偶尔用用,确实不需要回归测试。
但如果你有几十个Skill在支撑团队的质量体系,每个Skill都在持续迭代,那没有回归测试就是在裸奔。
我们的选择从来不是“要不要做回归测试”,而是“什么时候开始做”——是等出了P0事故再做,还是在事故发生之前就把防线建好。
六、避坑指南:别把简单问题搞复杂
如果你决定开始给Skill做回归测试,有几点建议:
坑一:一上来就想覆盖所有场景
从最核心的3-5个关键行为开始,而不是一口气写50条评测用例。先让“最重要的行为”有保障,再逐步扩展。
坑二:评测集只覆盖成功路径
很多团队写评测用例只会写“帮我生成一份发布计划”,然后检查是否输出了“发布计划”几个字。
解法: 评测集要覆盖失败场景、边界场景、异常场景。参数缺失时Skill怎么处理?工具调用失败时怎么降级?这些才是真正容易出问题的地方。
坑三:用LLM Judge验证一切
LLM Judge适合评估“输出质量”这类主观判断,但不适合验证“工具是否被正确调用”这类确定性行为。
解法: 确定性操作用rule_based或script验证,LLM Judge只用于需要语义判断的场景。不要把确定性和非确定性混在一起测。
坑四:评测集建完就不管了
Skill在变、模型在变、业务在变,评测集也需要跟着变。
解法: 每发现一个线上问题,补充一条对应的回归用例。评测集不是一次性工程,是持续积累的资产。
最后
从“能运行”到“可交付”,Skill正在经历软件工程二十年前走过的路。
不是我们故意把简单问题搞复杂了——是当Skill从“个人玩具”变成“团队基础设施”的时候,它自然就需要配套的质量保障体系。
一个人写一个Skill,可以靠手测。十个人维护五十个Skill,就必须靠自动化回归。
这个问题从来不是“要不要做”,而是“什么时候开始做”。
我建议你现在就开始。从最核心的3条评测用例开始,先让关键行为有保障,再慢慢扩展。
不然,等Skill“悄悄”退化到用户来投诉的时候,就晚了。