本文说明如何在仓库内以最小依赖完成 Skill 的“静态单元测试”与“端到端评估”。结合系统化的测试原则,我们的目标是以确定性信号(行为与产物)构建可复现、可比较、可在 CI 守门的质量闭环,兼容任意 CLI 型开源 Code Agent(如 OpenCode),使团队从“凭感觉的手动验证”走向“结构化、可复现、可对比”的工程化治理。
Skill 创作门槛低、数量爆发,但高质量(稳定、可复用、可维护) Skill 的生产仍缺乏系统方法。常见问题包括:触发不稳定(漏触/误触)、步骤偏离、环境污染(如翻译结果污染代码库)、风格约定无法保证。 当缺乏度量时,改动难以判断是改进还是回归。因此,我们遵循软件工程的 TDD 原则,为 Skill 建立测试闭环:“只评结果、不评路径”。
我们通过以下两个层面生成可复现的度量信号:
评估时主要关注以下成功维度:
usage.md 对比)。测试框架通过目录约定实现多技能的隔离与调度,核心由统一的主控脚本、各技能独立的配置沙盒以及静态规则集组成。
./unit-test/opencode-skill-eval.sh./unit-test/evals/agent/run.sh./unit-test/evals/agent/checks.js./unit-test/evals/agent/parse-usage.js./unit-test/skills/<skill>/config.sh./unit-test/tests/run_static.py./unit-test/tests/<skill>/checks.py./unit-test/fixtures/<skill>/input.md静态测试不依赖 Agent 与大模型的推理,通过 Python 脚本前置拦截格式错误、死链接与敏感信息,从而阻断低级错误流入端到端环节,有效降低评估成本与噪音。
http:// 或 https://,锚点 # 例外)http(s) 外链)# 说明:运行静态单测,自动按 SKILL 分发,输出结构化 JSON(overall_pass/score/逐项布尔)
python3 ./unit-test/tests/run_static.py doc-reviewer
overall_pass:所有检查通过为 truescore:通过项比例(0–1)OpenCode 等 CLI Agent)端到端评估将 Agent 视为黑盒,通过捕获其 CLI 运行时的标准输出(JSONL 事件流)来重构行为轨迹,进而对工具调用顺序、Token 消耗及最终生成产物执行严格的代码级断言。
评估框架依赖全局环境变量来注入必要的 API 凭证与基础的 Agent 启动指令。
# 说明:如果 Agent 需要 LLM 提供方,按需设置,例如:
export OPENAI_API_KEY=your-key
# 说明:设置 CLI Agent 命令为环境变量,并开启 JSON 事件输出
export AGENT_CMD='opencode run --format json --print-logs'
主控脚本通过读取 SKILL 环境变量进行执行路由,拉起 Agent 并将标准输出重定向为 JSONL 轨迹文件,同时自动挂载对应技能的临时沙盒工作区。
# 说明:执行端到端评估,需通过环境变量指定技能(如 doc-reviewer, md-translator)
# 注意:不要将技能名称作为脚本的位置参数传入,否则会触发防呆报错
SKILL=doc-reviewer bash ./unit-test/opencode-skill-eval.sh all
# 产出文件默认位于:
# - 轨迹:./unit-test/evals/artifacts/doc-reviewer.jsonl
# - 报告与产物:./unit-test/evals/reports/doc-reviewer/
我们将“是否成功”的主观判断固化为 Node.js 脚本或 Bash 钩子断言。通过解析 JSONL 轨迹中的 command_execution 与文件操作记录,不仅能校验产物,还能精准捕获 Agent 是否陷入循环重试(“折腾”),并将其作为 CI 拦截红线。
# 说明:解析轨迹并断言关键产物。主控脚本默认会优先执行 config.sh 的 skill_after_artifact_checks 钩子,
# 若未定义则回退使用通用的 checks.js 断言器。
SKILL=doc-reviewer node ./unit-test/evals/agent/checks.js \
./unit-test/evals/artifacts/doc-reviewer.jsonl \
./unit-test/evals/reports/doc-reviewer
doc-reviewer)
hasOutline/hasContent:各类报告是否生成structureOk:报告结构是否符合要求score/overall_pass:确定性行为评分与总判定单次评估运行后将生成不可变的行为轨迹、沙盒隔离的临时产物以及多维度的资源消耗报告。这些确定的物理文件构成了故障排查与 CI 自动化守门的数据基础。
./evals/artifacts/${SKILL}.jsonl(可被技能配置覆盖)OpenCode 执行 Skill 的全过程事件;末尾追加 opencode stats 的统计信息。./unit-test/evals/reports/${SKILL}(可被技能配置覆盖)fixtures 目录。./unit-test/evals/reports/${SKILL}/usage.mdconfig.sh 中的 skill_after_artifact_checks 钩子(按技能定制),若未定义则回退调用通用的 node ./unit-test/evals/agent/checks.js。# 说明:示例输出(不同 Agent 版本可能存在增删字段)
# 你可以将该 JSON 直接采集到 CI 日志中用于守门判断
{
"hasOutline": true,
"hasContent": true,
"hasAssets": true,
"hasFormat": true,
"structureOk": true,
"score": 1,
"overall_pass": true
}
主控脚本的第一个位置参数 (MODE) 决定了 Agent 的系统提示词 (Prompt) 注入策略,支持内置的全量测试与针对特定功能模块的子集测试。
content:仅执行“内容评审”,生成 1 个报告;JSONL 中只包含该评审类型的相关事件。all(默认):执行四类评审,生成 4 个报告;JSONL 覆盖所有类型事件;适合完整端到端评估。在流水线中结合静态校验与行为断言,可建立拦截 Skill 能力退化的自动化屏障。对于存在非确定性输出的模型,建议引入 pass@k 多次采样策略以平衡通过率与稳定性。
run_static.py 的 overall_pass 设为必过。checks.js(或技能自定义钩子)的 overall_pass 设为必过。为了确保框架的可扩展性,新增一个技能的测试只需遵循基于目录的约定,实现配置注入与断言钩子即可,无需修改主控核心脚本。
./unit-test/fixtures/<skill-name>/ 目录下准备输入样本(如 input.md)。这是 Agent 执行任务的源数据,框架运行时会自动将它们拷贝到沙盒目录,以防止原始数据被污染。./unit-test/tests/<skill-name>/ 下创建静态规则。主调度器 run_static.py 会自动扫描该目录,执行无依赖的快速验证(如检查 SKILL.md 的 Frontmatter 完整性)。config.sh)
在 ./unit-test/skills/<skill-name>/ 下创建 config.sh,利用 Bash 钩子覆盖默认行为:
build_target_doc:定义输入文档的拷贝与沙盒路径。build_prompt:定义注入给 Agent 的测试指令。skill_after_artifact_checks:定义专属的 Node.js/Bash 行为断言(检查文件是否存在、格式是否合规等)。SKILL=<skill-name> bash ./unit-test/opencode-skill-eval.sh all 触发端到端运行,并通过 usage.md 和 JSONL 日志验证 Token 消耗与重试行为是否符合预期。