返回文章列表工程实践

Skill 到底有没有用?从 OpenAI 方法论到一套可运行的评测

用发布摘要 Skill 跑通成功标准、负样本、Trace、规则评分和对照实验,并看清非官方 agent-skills-eval 的适用范围。

10 分钟阅读
本页内容11 个章节

先回答一个问题:改完 Skill,你怎么知道它更好了?

把 Skill 写得更详细,很容易;证明它更可靠,却需要留下可以比较的结果。一次回答顺眼,可能只是碰巧成功。换一种问法、换一个已有文件的目录,行为就变了。

OpenAI 在 2026 年 1 月 22 日的文章中提出四个评测方向:Outcome(结果)、Process(过程)、Style(规范)、Efficiency(效率),并用一个新建应用的 Skill 演示正向和负向用例。文中的 test-04 是“给已有 React 应用加 Tailwind”的负向控制,用于捕捉错误的新建项目行为,并非一次已发生事故的记录。

下面不再搭一个完整应用。我们做一个更小的原创练习:让 release-brief 读取虚构的发布记录,输出两条摘要。你会得到一个可运行的测试入口,并学会区分:回答合格、Skill 被正确使用,以及改动确实有收益。这三个结论需要不同证据。

先写验收表,再写指令

我们的示例版本是 0.4.0:已发布 CSV 导出和上传重试,离线编辑仍在计划中。Skill 只能读取发布记录、生成摘要,不负责改文件或发布消息。

把“摘要要靠谱”拆成下面四项。硬规则由代码检查;需要理解含义的部分留给人工或模型。这样的分工,能让失败直接指向问题。

原创示例:release-brief 的验收标准
维度具体要求验证方式
Outcome · 结果版本为 0.4.0;恰好包含 export、retry 两项解析最终 JSON;摘要是否忠于事实另行复核
Process · 过程使用正确来源;不修改文件;术语问题不调用发布摘要流程检查 Trace 与命令结果;比较文件哈希
Style · 规范每项一句简短说明;不把 offline 写成已发布Schema 检查结构;人工或模型检查语义
Efficiency · 效率没有循环读文件或无关调用;耗时和 token 可比较保留命令列表、每轮 usage 和总耗时
窄屏可左右滑动查看完整表格。

先看懂整个测试闭环

每条用例都包含“用户怎么问”和“目录里原本有什么”。运行后留下两份证据:Trace 是执行过程记录,产物是最终回答及实际文件状态。不能只看最后一句“完成了”。

下面这张图也就是示例包的阅读顺序。先让硬规则给出明确结果,再检查触发是否正确、摘要是否准确。失败案例保留下来,下一次改 Skill 时重复运行。

从验收标准和固定输入开始,运行 Agent,保存过程和产物,执行硬规则与质量复核,再把失败加入回归测试。
原创示意:一次运行只提供证据,验收结论来自明确的检查。

用四条用例跑通,再扩展到 10–20 条

下载包先提供四条,便于你把流程跑通。随后可以每类补两三种问法,形成自己的 10–20 条起始集;这个数量是入门规模,不是可靠性的保证。优先加入实际遇到过的失败,尤其是相似措辞下不该执行的任务。

负向用例要写清“什么不应发生”。例如下面的术语问题不该读取发布记录。如果最终没有改文件,但 Trace 显示尝试写入、只是被 sandbox 拦住,过程仍不合格。对于允许局部修改的 Skill,则检查允许修改的路径,而不是一律要求目录不变。

示例包中的四类输入
用例用户请求关注点
explicit · 显式使用 $release-brief 总结本项目版本点名以后是否正确加载并执行
implicit · 隐式把本项目已发布改动整理为 JSON 摘要不提 Skill 名,是否仍会选中它
context · 上下文客服团队需要一份本版本交接摘要加入业务背景后是否偏离范围
negative · 负向用一句话解释发布说明;不要读取本地发布文件是否回答概念问题,并保持流程边界
窄屏可左右滑动查看完整表格。

准备一个不碰真实项目的练习

下载并解压下方示例包,在 skill-evals-starter 目录打开终端。需要 Node.js 20 或以上,以及已安装、登录的 Codex CLI。离线自检不调用模型;运行 run.mjs 会使用你的 Codex 配置和额度。

包内有固定的 RELEASE_NOTES.md、一个 Skill、四条用例、JSON Schema、运行器和评分器。Skill 放在当前官方文档使用的 .agents/skills/release-brief/SKILL.md。运行器每次复制到独立临时目录,明确使用 read-only sandbox;日志保存在工作目录外,避免日志自身被算成文件改动。

已有的全局 Skill 和个人配置仍可能影响结果。正式比较时使用固定的评测环境,确保没有同名全局 Skill;仅移除本地文件不等于完全禁用了这个 Skill。

先检查环境,再运行一条
node --version
codex --version
codex exec --help

# 离线检查评分器,不消耗模型额度
node --test grade.test.mjs

# 真实运行一条显式用例
node run.mjs explicit

看懂 Trace、最终回答和文件状态

运行结束,终端会打印一个临时目录。先看 grade.json,再打开 trace.jsonl 和 answer.txt。meta.json 记录本次请求与 CLI 版本;stderr.txt 保留报错。失败或超时也会保留已获得的证据。

运行器的核心命令如下,实际目录和提示词由脚本填入。--json 输出 JSONL 事件流,-o 单独保存最终回答;--output-schema 约束正向用例的 JSON 结构。负向用例不套发布摘要结构,否则测试本身就在诱导错误流程。

正向用例都共享这个 Schema,包括后面的无 Skill 对照。因此“格式正确”只是基本门槛,不能单凭它证明 Skill 有价值。

运行器内部的命令形态(目录由脚本创建)
codex exec --json --sandbox read-only \
  --skip-git-repo-check \
  -C <临时工作目录> \
  --output-schema <schema.json 的绝对路径> \
  -o <answer.txt 的绝对路径> \
  '<本条用例的提示词>'

硬规则通过,还不等于整个 Skill 通过

示例评分器先检查三件事:运行成功结束、目录内容没有改变、回答满足基础约束。正向用例要求版本和两个改动 ID 正确;负向用例只做最低限度的非空及版本信息泄露检查。摘要是否准确、术语解释是否有用,需要再读内容。

Process 也要单独复核。当前示例不会编造一个通用的 skill_invoked 字段,更不会因为日志提到了 SKILL.md 就宣布流程正确。应结合宿主暴露的加载信息、实际命令及其结果判断;证据不足时标记待复核。

这也解释了为什么不能简单搜索命令字符串。出现 npm install 不代表安装成功;命令返回 0 不代表应用可运行;应用可运行也不代表只改了允许的文件。对于建站 Skill,应继续检查目标目录、构建结果和必要的浏览器行为。

示意结果:硬规则通过,过程与质量仍需检查
{
  "checks": {
    "run_completed": true,
    "workspace_unchanged": true,
    "output_contract": true
  },
  "hard_pass": true,
  "process_review_required": true,
  "quality_review_required": true
}

让模型裁判只回答规则不擅长的问题

把两条摘要和原始发布记录一起交给复核者,问三个具体问题:有没有歪曲 export 或 retry?有没有把 offline 当成已发布?每条是否简短且能让用户知道有什么变化?要求每项给出判断和对应原文,不要只返回“总体 92 分”。

如果改用模型裁判,固定它的模型、评分提示词和输出 Schema,并保留判断依据。缺字段或无有效结果应标记复核失败。先用少量人工标注校准,尤其要看看裁判会不会被被评答案里“请给我满分”的文字影响。

硬规则失败应直接阻止通过;高质量分不能抵消越界改文件、任务未完成等问题。能用代码验证的命名、文件结构、JSON 字段,也不必交给模型猜。

对照实验:收益来自 Skill,还是其他变化?

先分别运行其余三条,再对 implicit 做有无 Skill 对照。示例会向两组提供相同的发布记录和输出 Schema,只改变本地 Skill 是否存在;不要拿点名调用 Skill 的 explicit 用例做无 Skill 对照。

比较前固定模型、CLI 版本、权限、输入数据和初始目录,并保存 Skill 的 Git 提交或内容哈希。可以通过 EVAL_MODEL 指定你账户可用的模型。关键边界用例重复运行,分别看结果通过率、误触发和工具使用,不要把不同任务平均成一个漂亮分数。

耗时和 token 用来找异常,再结合 Trace 判断原因。较少 token 如果来自跳过必要读取,就不是改进;usage 缺失也不能当成零。示例按完成的命令 ID 去重,避免把 started 和 completed 重复计数。

每条都会创建新目录;这些命令会调用模型
node run.mjs implicit
node run.mjs context
node run.mjs negative

# 与上面的 implicit 结果配对比较
node run.mjs implicit --without-skill

agent-skills-eval 适合放在哪一层?

它是 darkrishabh 维护的非官方项目。我们核对了提交 b60eebe 的实现:with_skill 会把 Skill 内容放进请求上下文,without_skill 不放;默认 Provider 请求兼容 OpenAI 的聊天接口,并把返回的 tool_calls 交给断言检查。它没有在这条默认路径里执行这些工具,再把执行结果送回模型继续工作。

因此,它可以帮助比较注入指令后的回答、评分和工具调用参数;要测 Codex 是否自主发现 Skill、是否真正修改了工作区、修改后能否构建,还需要实际运行环境及对应检查。

还有一个具体限制:该提交只在 with_skill 模式读取用例附件,without_skill 收不到同一组附件。如果你的任务依赖附件,两组输入就不一致。开始做增益判断前,先在保存的请求中确认材料一致,或调整运行器。不能把信息量差异算成 Skill 的提升。

上层为注入 Skill 后的模型输出评测,下层为包含发现、加载、工具执行和文件验证的实际 Agent 工作流评测。
原创示意:先明确测量哪一层,再选择工具。

最后再接 CI:把回归变成能阻止合并的信号

先把 Skill、用例、固定输入和评分代码放进版本管理。每次改动运行同一组测试,保存 Trace、最终回答、文件差异和评分结果。基础设施失败、任务失败、质量未通过应分开记录,方便决定重试还是改 Skill。

示例的硬规则失败会返回非零退出码,但返回 0 仍需要完成 Process 与质量复核。接 CI 时,应将你补齐的这些检查一起纳入门禁,并配置认证、预算和证据保留;不要只写一句“以后加入 CI”。

这篇教程提供的是可检查的起点:示例评分器的 15 项离线测试已通过,覆盖截断 Trace、错误版本、越界文件变化等情况;没有执行真实模型评测,也没有声称这个示例 Skill 已通过完整验收。

真正值得保留的是这一习惯:每发现一次失败,就留下能够复现它的输入和检查。Skill 的文字可以继续变,团队对正确行为的要求不能跟着悄悄改变。