聊一个我最近反复踩坑的话题:skills的测试。现在各种Agent平台都在推Skills,官方市场和第三方仓库里的技能包越来越多,前端开发skills、superpower skills、自动化测试skills遍地都是,但真正愿意把“测试”这件事认真讲清楚的资料很少。很多人下载一个技能包能跑出结果就万事大吉,结果换个场景就翻车。这篇文章不是给你背概念,我用一个真实的技能包从设计、写测试到跑CI的全过程,聊聊我踩过的坑和现在固定下来的套路。
1. Skills到底怎么测?先从技能包结构说起
1.1 先聊清楚:一个Skills包由什么组成
Skills这个名字在不同平台叫法不太一样,Claude Agent Skills、Codex Skills、GitHub Skills,底层逻辑都差不多:给智能体一个“外挂模块”,告诉它在什么场景下、用什么姿势调用一段能力。这个模块通常不是单一文件,而是一个目录。
我见过太多种目录组织方式,但最合理、也最容易测试的结构大致是这几个部分:
| 目录/文件 | 作用 | 测试关注点 |
|---|---|---|
SKILL.md | 技能包的主入口,包含名称、描述、指令正文 | 描述是否清晰、触发条件是否准确、格式是否合法 |
scripts/ | 放可执行脚本,Python、Shell、Node.js都可以 | 脚本逻辑、入参出参、异常处理、退出码 |
assets/ | 模板、图片、参考文档等静态资源 | 路径引用是否有效、文件是否齐全 |
tests/ | 技能包自己的测试用例 | 覆盖率、断言是否可信 |
CHANGELOG.md/README.md | 变更记录和使用说明 | 版本号、兼容性说明是否同步 |
有些人会把所有指令都塞进SKILL.md,脚本负责干活,模型负责“阅读理解”。这种设计本身没问题,但会给测试带来一个麻烦:SKILL.md 是给人看也给模型看的文本,它的“正确性”没法用传统断言完全覆盖。所以测试一个Skills包,不能只跑脚本,要连文档结构、触发描述、行为一致性一起测。
1.2 为什么“跑通脚本”不等于“技能可用”
我见过不少技能包,脚本单独执行完全正常,但放到Agent里就是触发不了。核心原因在于,Agent调用Skills是一个带不确定性的过程:模型要先把用户请求和技能描述做语义匹配,再决定是否需要调用工具,最后才把脚本的执行结果组织成回复。
这跟普通代码测试有本质区别。普通代码测试是确定性的:输入1+1,断言输出2。但Skills测试是概率性的:同一句话,模型可能这次触发、下次不触发;同一个技能包,在一个平台表现很好,换一个平台就失灵。
所以我把Skills测试拆成三层来看:
- 第一层:静态检查。验证
SKILL.md格式、目录结构、依赖声明、文件引用。这一层是最确定的,用pytest就能拦下80%的低级错误。 - 第二层:单元测试。验证技能包里的脚本逻辑。脚本是确定性的,可以写严格的断言,比如时间解析、参数校验、返回值格式。
- 第三层:行为走查。验证模型在真实对话里会不会正确触发技能、会不会按预期执行。这一层没法用assert解决,要靠一套固定的人工用例清单,定期回归。
这三层缺一不可。只做第一层和第二层,你会得到一个“格式规范、脚本正确,但Agent根本不鸟你”的技能包;只做第三层,你会陷入手工点来点去的泥潭,改一行脚本就要重新测半天。
2. 设计一个可测试的Skill,比测试本身更重要
2.1 把“触发条件”写清楚:description是第一道测试线
很多人写技能包,把精力都放在正文指令上,description随便写一句就完事。但实测下来,description才是决定技能能否被正确触发的最关键字段。模型判断“当前场景要不要调用这个技能”,主要就是读description。
我在自己的技能包里会把description写成这种风格:在什么场景下使用、面向什么任务、不适用于什么情况。甚至可以加几句“如果你接到的是XX类型的请求,才使用本技能;如果用户只是闲聊,不要调用本技能”。这些否定条件特别重要,因为在真实对话中,模型经常会把无关请求误触发到技能上。
为什么要在这里强调测试?因为description等于你给模型画了一个“触发边界”。测试的第一步就是确认边界画对了。我一般会准备10到20条用户输入,一半是应该触发的,一半是不应该触发的,然后在Agent环境里跑一遍,看触发率有多少。
2.2 一个能落地的最简技能包示例:番茄钟助手
光讲抽象概念没意思,我拿一个自己写的“番茄钟助手”技能包来演示。这个技能包功能不复杂:用户告诉它需要多长时间,它计算结束时间并生成一个番茄钟工作周期的待办清单,适合用来演示SKILL.md和脚本怎么配合。
目录结构是这样的:
skills/ pomodoro-helper/ SKILL.md scripts/ pomodoro_calc.py assets/ pomodoro_template.md tests/ test_static_skill.py test_pomodoro_calc.py manual_cases.mdSKILL.md的核心内容大致如下:
--- name: pomodoro-helper description: 当用户需要执行番茄工作法、设置专注时间、安排休息周期时使用。 如果用户只是简单查看时间或闲聊,不要调用本技能。 version: 1.0.0 --- # Pomodoro Helper ## 使用场景 - 用户说“帮我安排一个25分钟的专注周期” - 用户需要计算番茄钟的结束时间、休息时间 ## 操作步骤 1. 调用 pomodoro_calc.py,参数为用户输入的专注分钟数。 2. 脚本会输出一个 JSON,包含 start_time、end_time、break_time。 3. 将 JSON 内容转成阅读友好的文本展示给用户。 ## 注意 - 专注时长必须大于0,小于180。 - 如果脚本返回错误码,直接向用户反馈参数问题,不要继续解释。脚本pomodoro_calc.py并不复杂,核心就一个函数:
#!/usr/bin/env python3 import argparse import json import sys from datetime import datetime, timedelta def calc_pomodoro(duration_minutes: int) -> dict: if duration_minutes <= 0 or duration_minutes > 180: raise ValueError("duration must be between 1 and 180") start = datetime.now() end = start + timedelta(minutes=duration_minutes) break_minutes = max(5, min(duration_minutes // 4, 15)) return { "start_time": start.strftime("%Y-%m-%d %H:%M:%S"), "end_time": end.strftime("%Y-%m-%d %H:%M:%S"), "break_time": break_minutes, "duration_minutes": duration_minutes, } if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--minutes", type=int, required=True) args = parser.parse_args() try: print(json.dumps(calc_pomodoro(args.minutes), ensure_ascii=False)) except ValueError as e: print(json.dumps({"error": str(e)}), file=sys.stderr) sys.exit(1)注意这里我故意做了几件事:参数范围校验、错误输出到stderr、退出码非零。这些都是给测试留的“抓手”,没有它们,自动化测试很难判断失败原因。
2.3 为测试设计的三个钩子:dry-run、verbose、exit code
真正成熟一点的技能包,我会建议在脚本里预留三个东西:dry-run、verbose、有意义的退出码。
dry-run的意思是让脚本只做“预演”,不产生真实副作用。这个在技能包里很重要,因为Agent场景下,技能脚本经常会操作文件、改配置、发请求。如果测试环境里不能安全执行,你就不敢做自动化回归。有了dry-run,测试脚本可以先跑一遍,看到底会做什么操作,再决定要不要放行。
verbose就是详细日志。技能出错的时候,模型只能拿到stdout和stderr里的内容,如果没有足够的日志,模型连“报什么错”都看不出来。我会在技能脚本里默认往stderr打关键步骤,比如“读取到配置”“开始计算”“输出结果”,这样Agent在回复用户时就能把查明的问题一并反馈。
退出码是自动化断言的基础。成功返回0,参数错误返回2,环境不满足返回3,内部异常返回1。测试代码不需要解析日志内容,光看退出码就能判断脚本有没有正常完成。
有人觉得这是过度设计,但我在实际项目里真被坑过:之前有个技能脚本,出错时同样返回0,只是把错误信息写到输出里。结果Agent拿到输出,误以为自己操作成功了,把错误信息直接展示给用户。从那以后,我要求所有技能脚本必须用退出码区分成功与失败。
2.4 确定测试边界:哪些要断言,哪些只做人工复核
写测试之前,先想清楚一件事:什么能用机器断言,什么不能。
SKILL.md的格式、脚本的参数校验、输出JSON结构、退出码,这些是确定性行为,可以自动化断言。但“模型在对话中是否会触发技能”“生成的总结是否符合用户预期”这类行为,本质上是非确定的。你写再多assert也没用,它本来就是一个需要人工观察的指标。
我给技能包划分测试边界时会用一张表:
| 测试内容 | 自动化断言 | 人工复核 |
|---|---|---|
| SKILL.md frontmatter 字段完整 | 是 | 否 |
| 脚本单元测试 | 是 | 否 |
| 输出格式 | 是 | 否 |
| 边界参数与异常输入 | 是 | 否 |
| 模型触发准确率 | 否 | 是 |
| 结果可读性 | 否 | 是 |
| 与其它技能的组合行为 | 否 | 是 |
把范围划清楚之后,自动化回归才不会变成“假绿”。我之前见过一个团队,CI全绿,结果人工走查一测技能几乎不能用。原因就是他们把大量非确定行为硬塞进自动化断言里,指标好看,但没有真正覆盖用户场景。
3. 基于pytest的Skills回归测试实战
3.1 目录与fixture设计
自动化回归我选的是pytest,理由很简单:生态成熟、参数化方便、CI支持好。很多自动化测试框架pytest相关技能包也会依赖这套逻辑。
我的技能包测试目录里会有一个公共的conftest.py,用来管理技能包路径和相关fixture:
import json import subprocess from pathlib import Path import pytest SKILLS_ROOT = Path(__file__).resolve().parents[2] POMODORO_DIR = SKILLS_ROOT / "pomodoro-helper" SCRIPT_PATH = POMODORO_DIR / "scripts" / "pomodoro_calc.py" @pytest.fixture def skill_dir() -> Path: return POMODORO_DIR @pytest.fixture def run_script(): def _run_script(*args: str) -> subprocess.CompletedProcess: return subprocess.run( [sys.executable, str(SCRIPT_PATH), *args], capture_output=True, text=True, timeout=10, ) return _run_script这里有个细节:测试脚本通过subprocess调用技能脚本,而不是直接用import。原因是技能脚本将来可能在别的运行时里执行,比如Node.js或者打包后的二进制,用subprocess能模拟更真实的执行环境。当然纯Python函数用import也没错,just my习惯:把执行和解析分开,测试更接近生产。
3.2 SKILL.md静态检查,先把格式问题拦在门外
SKILL.md看起来是纯文本,但Agent平台解析技能包时,对frontmatter和结构是有要求的。比如frontmatter里必须有name和description,正文里不能有失控的图片引用,脚本路径要真实存在。
这部分我写成一个静态检查测试文件test_static_skill.py:
import re from pathlib import Path import pytest def test_frontmatter_exists(skill_dir): skill_md = skill_dir / "SKILL.md" content = skill_md.read_text(encoding="utf-8") assert content.startswith("---"), "SKILL.md必须包含frontmatter" assert "name:" in content.split("---")[1] assert "description:" in content.split("---")[1] def test_description_has_trigger_and_negative_rules(skill_dir): skill_md = skill_dir / "SKILL.md" content = skill_md.read_text(encoding="utf-8") description = content.split("---")[1] assert len(description.strip()) > 40, "description太短,影响触发准确率" assert "不要" in description or "不要调用" in description, "建议补充负向触发规则" @pytest.mark.parametrize("referenced_path", [ "scripts/pomodoro_calc.py", "assets/pomodoro_template.md", ]) def test_referenced_files_exist(skill_dir, referenced_path): assert (skill_dir / referenced_path).exists(), f"引用的文件不存在: {referenced_path}" def test_script_has_execute_permission(skill_dir): script_path = skill_dir / "scripts" / "pomodoro_calc.py" assert script_path.exists() assert script_path.stat().st_mode & 0o111, "脚本缺少执行权限"这些断言看起来很简单,但能拦住大量低级失误。我见过有人改了一行脚本路径,SKILL.md里的引用没同步,结果模型每次调用都得到一个file not found,排查了半天。这些静态检查跑在CI里,改坏了立刻有红点提示。
3.3 技能脚本的单元测试:给确定性逻辑上保险
脚本逻辑的测试就可以写严格断言了。以番茄钟助手为例,参数范围、时间计算、输出JSON格式都要覆盖到。
import json import pytest def test_valid_input_returns_json(run_script): result = run_script("--minutes", "25") assert result.returncode == 0 payload = json.loads(result.stdout) assert payload["duration_minutes"] == 25 assert payload["break_time"] >= 5 def test_out_of_range_input_fails(run_script): result = run_script("--minutes", "200") assert result.returncode != 0 assert "error" in result.stderr def test_zero_input_fails(run_script): result = run_script("--minutes", "0") assert result.returncode != 0 assert "duration" in result.stderr @pytest.mark.parametrize("minutes,expected_break", [ (5, 5), (25, 6), (45, 11), (60, 15), ]) def test_break_time_rule(run_script, minutes, expected_break): result = run_script("--minutes", str(minutes)) payload = json.loads(result.stdout) assert payload["break_time"] == expected_break注意我在测试里对break_time的计算规则做了参数化断言。这个规则是我在设计技能脚本时自己定的:休息时间取专注时长的四分之一,但最少5分钟、最多15分钟。如果不把规则固化成测试,以后有人为了“优化”随手改了公式,可能导致所有已有对话的记忆错乱。回归测试在这里的作用,就是把隐含规则明确下来。
3.4 Agent行为回归:使用“人工用例清单”做半自动走查
脚本层测试只覆盖了确定性部分,还得解决 Agent 行为验证。我的做法是在技能包里维护一个manual_cases.md,把该触发和不该触发的输入列出来:
# Pomodoro Helper 人工走查清单 ## 应该触发的场景 - [ ] 用户说:帮我开一个25分钟的番茄钟 - [ ] 用户说:我要专注45分钟,休息多久合适? - [ ] 用户说:今天第四轮番茄钟,提醒我 ## 不应该触发的场景 - [ ] 用户说:现在几点? - [ ] 用户说:讲个笑话 - [ ] 用户说:帮我总结这份文档 ## 边界场景 - [ ] 用户说:设置0分钟番茄钟(应报错) - [ ] 用户说:设置200分钟番茄钟(应报错)然后在pytest里用一个标记,把需要人工复核的用例收集出来:
import pytest pytestmark = pytest.mark.manual @pytest.mark.parametrize("case_id", [ "TC-001-should-trigger", "TC-002-should-trigger", "TC-003-should-not-trigger", ]) def test_manual_case(case_id): pytest.skip( f"需要人工在Agent环境执行此用例并记录结果: {case_id}" )这样跑测试时,automated部分和manual部分分开。pytest -m "not manual"走CI全自动;pytest -m manual生成一个人工走查清单,供每次发布前过一遍。
很多人嫌人工走查麻烦。但说实话,模型行为这种动态指标,本来就适合用“固定剧本+定期抽查”的方式来盯,而不是靠一次性调试。你只要形成习惯,每次改动技能包后花十几分钟过一遍清单,就能避免很多线上翻车。
3.5 在CI里让测试自动跑起来
自动化这部分完全可以塞进GitHub Actions。我的技能包仓库里用一个workflow来跑pytest,配置大致如下:
name: skills-test on: push: paths: - "skills/**" pull_request: paths: - "skills/**" jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.12" - run: pip install pytest - run: pytest -m "not manual" --tb=short测试只会在skills/目录有改动时触发,避免无关改动浪费CI时间。--tb=short让失败信息更紧凑,方便快速定位。如果团队用别的方式管理代码,核心思路是一样的:凡是涉及SKILL.md或脚本的改动,必须跑一遍确定性测试。
4. 我踩过的坑:Skills测试常见问题排查
4.1 技能不触发或触发错乱,先查description而不是脚本
有段时间我写了一个“URL缩短技能”,脚本跑得很好,但Agent总是该触发时不触发。我把脚本翻来覆去查了一遍,没发现问题。后来一复盘,问题出在description写得太泛,只写了“处理链接”,模型根本判断不了什么时候算“处理链接”。
排查这类问题,我现在的固定套路是:先看description是否明确包含触发词和否定条件,再看SKILL.md正文里的指令是不是够具体,最后才查脚本。顺序百分之八十能定位问题。
4.2 输出格式漂移:JSON少个逗号,Markdown缩进变了
模型输出天然不稳定。同一个技能包,这次生成的JSON格式规整,下次可能多一段解释文字,再下次直接给个Markdown代码块。如果你的下游系统用严格JSON解析,这里就是最容易崩的地方。
我的对策有两层。第一层,技能脚本内部尽量自己生成结构化数据,不让模型自由发挥格式;第二层,在SKILL.md里给出明确的输出模板,如果模型按照模板输出,格式基本可控。测试时我会专门准备几个“输出格式漂移”用例,比如在模型回复前插入一句无关文本,看解析逻辑会不会依然稳健。
4.3 工具权限过大与参数逃逸
技能包需要调用系统命令时,一定要小心参数逃逸。我之前写过一个技能,把用户输入的文本拼进Shell命令,表面测试都通过,直到来了一个包含分号和管道符的输入,命令直接执行了危险操作。后来我全部改成subprocess列表参数传参,绝不拼shell字符串。
测试脚本里要加这类恶意输入用例:
@pytest.mark.parametrize("bad_input", [ "25; rm -rf /tmp/test", "25 | echo hacked", "$(whoami)", ]) def test_shell_injection_safety(run_script, bad_input): result = run_script("--minutes", bad_input) assert result.returncode != 0这里不是要写漏洞利用脚本,而是验证你用了安全的调用方式。参数传错了可以重来,权限失控是大事。
4.4 测试数据互相污染,技能状态残留
有些技能包会写临时文件、环境变量或者状态缓存。如果不做隔离,测试A产生的状态可能影响测试B的结果。比如某个技能会往用户目录下写配置,我第一版测试跑完,第二次再跑就出现了脏数据。
解决方案是每个fixture里都清理状态。pytest的tmp_path就是一个不错的选择,但技能脚本不一定知道你传进去的是临时目录。更稳妥的做法是在技能脚本里提供--workdir参数,让测试指定workspace,CI跑完直接丢弃整个临时目录。
4.5 一张表速查常见故障
我把经常遇到的问题整理成了排查表,直接抄作业用:
| 现象 | 优先检查 | 常见根因 |
|---|---|---|
| 技能完全不触发 | description与调用条件 | 描述缺乏触发词、被其它技能抢占 |
| 偶尔触发偶尔不触发 | description表达模糊 | 缺少否定条件、描述过长 |
| 脚本执行了但结果错误 | 脚本参数与SKILL.md指令 | 模型传错了参数类型 |
| 输出JSON解析失败 | 脚本是否直接输出结构化数据 | 模型在JSON外又添加了文本 |
| 权限错误 | 脚本运行用户 | 测试环境缺少执行权限 |
| 状态被污染 | 技能脚本对全局环境的影响 | 缺少workdir隔离 |
| 中文乱码 | 编码声明 | stdout未设置utf-8 |
5. 不同场景下的Skills测试速查
5.1 知识问答型:前端开发skills、Linux面试题测试
现在市面上有大量知识型技能包,比如“前端开发skills”和“linux面试题测试”。这类技能的脚本部分往往很薄,核心价值在提示词模板和知识库组织方式上。
测试这类技能,重点不在脚本,而在“信息的准确性和答案的稳定性”。我会准备一组基准问题,跑多次,看答案是否一致,有没有出现一本正经胡说八道。比如设置一个“已知正确答案的问题集”,每次更新技能包都去跑一遍,如果某道题的答案漂移了,大概率是知识库或提示词被改坏了。
5.2 代码生成/自动执行型:pytest、Appium、设备老化测试脚本
代码生成类技能是重灾区。比如一个“自动化测试框架pytest生成技能”,用户让它写pytest用例,它就写一堆看似合理的代码,但根本没法执行。测试这类技能,光靠模型回复判断不够,我通常会把它生成的代码自动拉到沙箱里跑一遍。
Appium自动化测试技能也一样,它可能会生成移动端测试脚本。要验证这类技能,就得准备一台测试机或模拟器,跑通冒烟用例。设备老化测试全自动执行脚本这种技能更直接:不仅生成代码,还要全自动执行老化流程。我会把这类技能拆成两段验证,第一段是生成代码的静态检查,第二段是真实环境的小规模老化演练,先跑10分钟确认无崩溃,再正式跑完整流程。
5.3 硬件与音视频测试:T-Box、RTSP测试流
硬件测试场景下,Skills的测试会更加依赖环境。比如汽车电子测试里常见的T-Box测试技能、HIL和PIL测试技能,它们的脚本往往需要连接硬件设备、读取总线信号、控制测试台架。
这类技能的自动化测试,我建议多做“连接检查”和“参数校验”。脚本执行前先检查设备是否在线、端口是否可访问、测试流地址是否有效。像RTSP测试流、RTMP测试地址这类资源,技能包里一般会内置一堆可供快速验证的地址,测试时就必须确认这些地址是否还活着,不然技能会拿一个失效的地址去“测试”,最后报一个莫名其妙的失败。
我记得有个技能包专门做交流法电阻内阻测试,里面甚至内置了电路原理图。测试它的关键就是确保原理图里的接线定义和脚本里的配置一致,否则生成的报告再漂亮,硬件参数也是错的。
5.4 安全测试与敏感信息检查
安全测试类技能,我用之前总会格外谨慎,尤其那些用来检查APP登录密码是否明文存储、检测接口安全漏洞的技能包。它们往往要扫描代码、抓请求、检查密钥文件。这些操作在生产环境里风险极高。
我的建议是,安全测试技能必须默认开启dry-run模式,所有扫描动作先展示不做,确认无风险后再真正执行。测试用例里要覆盖:目标文件不存在、目标文件过大、目标包含二进制数据等异常场景。这类技能的自动化回归尽量放在隔离环境里,不要直接指向生产系统。
5.5 创作与互动型:分镜skills、网格射击测试网页版、鹈鹕测试提示词
创作类技能,比如“分镜skills”,它的输出是创意内容,没有绝对的对错,但依然有“可用性”问题。我的测试方法是指定同一段输入,连续跑五遍,看生成的分镜结构是否清晰、有没有遗漏关键角色设定、镜头顺序是否合理。这种测试不适合用assert,更适合打个1到5分的可读性评分,定期对比。
互动类技能,比如网格射击测试网页版,就偏向传统前端测试。它本质是一个带UI交互的网页应用,只不过入口被包装成了技能包。测试时要用Playwright这类工具模拟用户点击和键盘操作,验证射击命中判定、计分逻辑和页面响应。这类技能有个特点:脚本逻辑、UI渲染和Agent提示词三层耦合,改任何一层都可能破坏整体,所以回归测试特别重要。
至于“鹈鹕测试提示词”这类的技能包,本质上就是把一套结构化测试模板封装成可复用的提示词。测试起来反而简单,核心是验证模板在不同输入下的稳定性:换一批测试数据,输出的框架结构不能乱。
6. 把Skills测试做成可持续的工程习惯
6.1 用GitHub Skills做版本管理
GitHub Skills本身是GitHub官方用来教学新用户使用Git和Actions的交互式课程,它跟Agent技能包是两个概念,但都被大家叫做Skills。不管哪个生态,版本管理都是必须的。
我给每个技能包单独建仓库,或者在一个大仓库里用子目录管理,版本号写在SKILL.md的frontmatter里。每次改动必须更新版本号和CHANGELOG。这样做的直接好处是,当Agent平台或下游系统缓存了旧版本,你能快速定位是版本没刷新还是技能包本身有bug。
6.2 建立金标准测试集
测试做久了,你会慢慢沉淀出一批“金标准用例”。这些用例不是一次性写出来的,而是从线上事故、用户反馈、模型表现变化里一点点积累的。
我维护技能包时会开一个golden_cases.md,里面只放那些“历史上触发过bug、以后改动绝不能再犯”的场景。比如某个技能曾经因为特殊字符崩溃,我就会把那类输入加进金标准测试集。技能包迭代越勤,金标准测试集越厚,CI的守护能力也越强。
6.3 跨平台一致性:Codex Skills、Reasonix安装新Skills
同一套技能包,在不同平台上的表现是有差异的。Codex Skills、Reasonix安装新Skills、以及其它Agent工具平台的解析规则不完全一致。有的平台对frontmatter字段大小写敏感,有的平台要求描述不能超过多少字,有的平台支持直接执行Markdown里的代码块,有的必须调用外部脚本。
跨平台测试没有捷径,只能搭一个“多平台走查矩阵”:每个平台跑同一套金标准用例,记录触发率和输出质量。我见过有人直接写脚本,把技能包在多个平台上自动安装并跑基本用例,这次测试通过,下次改动前再跑一遍。这个矩阵一旦建立,往后所有技能包的迭代都会安全很多。
6.4 我对Skills测试的最终心得
把Skills测试常态化之后,我的体会是:不要试图一次把所有东西都测到完美。技能包的价值在于快速迭代,测试的目的是让你敢改、改完不怕坏。静态检查守住格式,单元测试守住脚本逻辑,人工走查守住模型行为,三层搭起来,一个技能包就能从“能跑”进化成“能稳定交付”。
如果你刚准备开始给自己的技能包搭测试,我建议从最小闭环入手:先写一个test_static_skill.py,把SKILL.md的格式校验跑起来,再给脚本写几个参数用例。就这两步,已经能拦住我踩过的大部分坑。剩下的人工走查清单可以后面慢慢补,养成习惯远比一次性做到位重要。