已发布资料基础官方资料 + 个人实践
·21 分钟AI 工具实践
文章/AI 与智能体

Codex Skills 进阶:用 references、scripts 与 evals 建立可验证工作流

Codex 系列第 12 篇:把技术文章 review Skill 升级为包含 references、scripts、evals 和版本记录的可验证目录,并说明它与 Claude Skills 共用的规范、不同的安装路径和运行边界。

文章目录
  1. 一分钟概览
  2. 同一份 Skill,到了 Claude 为什么不能只改目录名
  3. 1. 先定义“可靠”,不要先创建目录
  4. 2. 内容到底应该放在哪里
  5. 3. references:把详细知识变成按需证据
  6. 3.1 一份够用的证据台账
  7. 3.2 references 的三个边界
  8. 4. scripts:把机械判断交给确定性程序
  9. 4.1 先写脚本合同
  10. 4.2 预检脚本做了什么
  11. 4.3 运行真实文章
  12. 4.4 故意让它失败
  13. 5. 不要重复造轮子:仓库检查与 Skill 脚本怎样共存
  14. 6. evals:保存真实任务,不是保存一句“应该很好”
  15. 6.1 哪些字段是官方约定,哪些是本地扩展
  16. 6.2 断言要能被观察
  17. 7. 先校验评估清单,再谈模型行为
  18. 8. 真正的行为评估需要一组对照
  19. 8.1 把每次运行保存成可以比较的证据
  20. 8.2 触发评估和输出评估是两件事
  21. 8.3 本文诚实停在哪里
  22. 9. agents/openai.yaml:把调用策略显式化
  23. 9.1 从 GitHub 安装 Skill 前,先把它当软件审计
  24. 10. 版本化:记录变化,不假装运行时懂 SemVer
  25. 11. 升级后的 SKILL.md 只增加编排,不复制实现
  26. 12. 一份可以直接交给 Codex 的升级任务
  27. 13. 本地验证记录
  28. 14. 最常见的六种失败方式
  29. 14.1 一开始就创建所有目录
  30. 14.2 把长说明移走,却不写召回条件
  31. 14.3 用脚本处理主观判断
  32. 14.4 只写正向 eval
  33. 14.5 在同一对话里测试当前版和基线
  34. 14.6 把每个绿色结果都叫作“验证通过”
  35. 15. 45-60 分钟跟做练习
  36. 0-10 分钟:找出不稳定点
  37. 10-20 分钟:决定放置位置
  38. 20-35 分钟:实现一个最小扩展
  39. 35-45 分钟:建立评估矩阵
  40. 45-60 分钟:跑失败路径并记录边界
  41. 16. 收藏清单
  42. 设计
  43. 脚本
  44. 评估
  45. 安装与共享
  46. 发布
  47. 写在最后
  48. 参考资料
  49. 官方与规范
  50. 社区案例
阅读提要

Codex 系列第 12 篇:把技术文章 review Skill 升级为包含 references、scripts、evals 和版本记录的可验证目录,并说明它与 Claude Skills 共用的规范、不同的安装路径和运行边界。

#Codex#Claude Code#Skills#Agent#SKILL.md

这是 Codex 系列的第 12 篇。

第 11 篇做出了第一个仓库级 Skill:review-technical-article。它已经能告诉 Codex 什么时候审查技术文章、按什么顺序检查、最终怎样给出发布结论。

但“能被调用”只是起点。实际用几次后,会出现更麻烦的问题:

text
事实核对的来源规则越来越长,要不要继续塞进 SKILL.md?
frontmatter、日期和图片路径每次都让模型重新判断,结果能稳定吗?
改了 description 以后,怎样知道 Skill 没有在错误场景里乱触发?
一份 evals.json 通过,是否等于整个 Skill 已经可靠?

这一篇不重新创建另一个玩具 Skill,而是继续改造同一个真实案例。最终目录里会加入 references/scripts/evals/agents/openai.yaml,并用成功样例和故意损坏的样例验证脚本。

项目说明
内容类型Codex Skills 进阶实战
适合读者已完成一个 SKILL.md,准备长期维护或共享工作流的人
跟做前提Node.js 18+、一个可修改的项目目录、基础命令行经验
阅读 / 练习时间阅读约 20-23 分钟,跟做约 45-60 分钟
可带走产物完整 Skill 目录、来源策略、文章预检脚本、7 个触发评估用例
本文案例review-technical-article 1.1.0
官方资料核对日期2026-07-15
本地验证Skill 结构、评估清单、脚本成功路径与失败路径均已实际运行

版本与证据说明

本文按 2026-07-15 的 OpenAI Skills 文档、Agent Skills specification、Anthropic Agent Skills 与 Claude Code 文档整理,并对照 OpenAI、Anthropic 的官方 GitHub 示例。Codex 是本文的实际运行环境,Claude 只用于说明共用规范和产品边界;官方约定与本文项目自定义字段会分开标注。

本文已经验证目录结构和两个确定性脚本,但没有把“评估清单结构通过”写成“模型行为已经通过”。完整行为评估需要在相互独立的干净任务里运行当前 Skill 和基线,再人工比较结果。

一分钟概览

先给结论:

  1. SKILL.md 负责判断和编排,不应该变成所有知识的仓库。
  2. references/ 放按需读取的详细知识,scripts/ 放确定性、重复且适合机器执行的步骤。
  3. evals/evals.json 保存真实测试任务,但不会在 Skill 每次触发时自动运行。
  4. 评估至少要覆盖应该触发、不应该触发和需要澄清三类输入。
  5. 行为评估需要三层证据:脚本结果、可观察行为断言、人工 review。
  6. “结构通过”“脚本通过”“行为通过”和“文章事实正确”是四件不同的事。
  7. SKILL.md 的核心格式可以复用,但 Codex、Claude Code、Claude API 的安装位置、配置扩展和运行依赖并不相同。

图 1:从一份 SKILL.md 升级为可验证 Skill 包;判断、知识、确定性处理和回归评估各有职责,SVG 连线带有轻量动态效果图 1:从一份 SKILL.md 升级为可验证 Skill 包;判断、知识、确定性处理和回归评估各有职责,SVG 连线带有轻量动态效果

这次升级后的目录如下:

text
.agents/
└── skills/
    └── review-technical-article/
        ├── SKILL.md
        ├── agents/
        │   └── openai.yaml
        ├── references/
        │   └── source-policy.md
        ├── scripts/
        │   ├── article-preflight.mjs
        │   └── validate-evals.mjs
        └── evals/
            ├── evals.json
            └── files/
                └── sample-codex-skill-tutorial.md

这是一份可以工作的完整目录,不是所有 Skill 的固定模板。一个稳定的 instruction-only Skill 仍然可以只有 SKILL.md。只有当新文件解决了真实问题,才值得拆出去。

下载本文验证过的 review-technical-article 1.1.0 Codex 仓库级示例包

压缩包只包含 Skill 目录和一篇明确标注“故意含错”的评估 fixture,不包含博客正文或项目依赖。它验证于 Codex 和当前博客仓库,不是可以原样上传到所有 Agent 产品的通用包。解压到其他项目以后,仍需安装 Node.js 与 gray-matter,或者把预检脚本改成自包含实现;先运行文中的结构和脚本检查,再决定是否启用隐式调用。

在 npm 项目中可以安装本文实际使用的版本:

powershell
npm install --save-dev gray-matter@4.0.3
node .agents/skills/review-technical-article/scripts/article-preflight.mjs --help

使用 pnpm、Yarn 或 Bun 时换成对应的安装命令。若只需要 instruction、references 和 eval 用例,也可以不运行依赖 gray-matter 的文章预检脚本,但必须把这项验证标成未执行。

本文附件的 SHA-256 为 41815817F52B82BFA755F8E1BEEA1106D69C272338FA3F67165A32D264F128C9。它用于确认下载文件与本文最终复验的压缩包一致,不代表包内 Skill 已完成模型行为评估。

同一份 Skill,到了 Claude 为什么不能只改目录名

Agent Skills 的开放规范让不同 Agent 可以共享 SKILL.mdreferences/scripts/assets/ 这些基本组织方式。但“格式相通”只代表迁移成本较低,不代表安装、权限和运行时完全相同。

维度CodexClaude CodeClaude API / claude.ai
项目级发现位置.agents/skills/.claude/skills/上传 ZIP,或通过 Skills API 管理
共用核心SKILL.md、references、scripts、assets基本相同基本相同,但要满足容器约束
产品专属扩展agents/openai.yamlClaude Code 配置与 PluginSkill ID、服务端版本和产品设置
运行环境随 Codex 入口、sandbox 和 approval 设置变化使用本机文件系统与本机依赖Claude API 无网络且不能在运行时安装包;claude.ai 依设置而异
分发方式仓库目录;跨项目优先 Plugin仓库目录或 Claude Code Plugin每个产品表面分别上传或管理,不会自动同步

因此,迁移时应该先保留通用核心,再为目标产品补适配层:Codex 的 agents/openai.yaml 不属于开放规范,Claude Code 的工具控制也不会因为复制这份文件自动生效。本文附件中的 gray-matter 更是明确的运行时依赖;在不能安装包的容器里,应该换成自包含脚本或确认目标环境已经预装依赖。

这张表解决的是边界问题,不改变本文主线:下面所有命令和实际验证仍以 Codex 仓库级 Skill 为准。

1. 先定义“可靠”,不要先创建目录

第一次写 Skill 时,最容易把“可靠”理解成“写得很详细”。这不够。

对本文这个技术文章审查 Skill,我把可靠拆成四层:

层次要回答的问题证据
结构可靠文件能否被发现,元数据和清单格式是否正确Skill validator、JSON schema 检查
机械可靠日期、字段、路径等确定性检查能否重复得到同一结果脚本输出和退出码
行为可靠应触发时是否触发,不应触发时是否保持安静正向、负向、模糊用例
内容可靠事实、复现步骤和读者价值是否真的成立官方来源、实际运行、人工 review

这四层不能相互替代。

例如,article-preflight.mjs 能确认图片文件存在,却不知道图里是否写错了命令;它能确认摘要不是空字符串,却不知道摘要是否准确;它能确认外链返回了 HTTP 200,却不能证明链接内容支持正文里的主张。

所以本文的目标不是“用脚本替代编辑”,而是:

text
让机器负责适合机器的确定性,
让 Agent 负责需要上下文的判断,
让人保留最终发布责任。

2. 内容到底应该放在哪里

Skill 变复杂以后,第一个设计问题不是“如何拆文件”,而是“这条内容属于谁”。

图 2:Codex Skill 内容放置决策;先按职责在 AGENTS.md、SKILL.md、references、scripts、evals 与 MCP 或 App 之间选择图 2:Codex Skill 内容放置决策;先按职责在 AGENTS.md、SKILL.md、references、scripts、evals 与 MCP 或 App 之间选择

我现在使用下面这张决策表:

内容更合适的位置例子
整个项目长期遵守的规则AGENTS.md构建命令、目录约束、博客分类规则
一类任务的触发、步骤与输出SKILL.md技术文章 review 的审查流程
只在部分任务里需要的详细知识references/来源优先级、证据台账字段
可确定计算、重复执行的处理scripts/frontmatter、日期、图片路径检查
修改 Skill 后需要重复验证的任务evals/正向、负向、模糊触发用例
实时访问外部系统和执行动作MCP / App读取 GitHub PR、发送消息、查询数据库
面向 Codex 界面的名称、提示与调用策略agents/openai.yaml展示名称、默认 Prompt、隐式调用开关

这里有两个常见误区。

第一,references/ 不是把 SKILL.md 随便拆小。参考文件应该可以被一句明确条件召回,例如“文章包含版本敏感或安全相关事实时读取来源策略”。如果正文只写“按需读取相关资料”,Agent 仍然不知道什么时候读。

第二,scripts/ 不是“看起来更工程化”的装饰。若步骤需要综合语境、判断论证是否成立,脚本很可能不合适;若结果可以通过解析和规则稳定算出,才适合脚本。

3. references:把详细知识变成按需证据

第 11 篇的 SKILL.md 里已经有一句:

text
Verify material claims with primary sources.

方向没错,但真实 review 里还会遇到:

  • 官方文档与社区教程冲突时信谁?
  • 博客里的亲身经验算不算证据?
  • 哪些主张值得逐条记录,哪些只是普通叙述?
  • 链接能打开,是否等于它支持正文?
  • 版本敏感事实需要记录什么日期?

如果全部继续写进主文件,Skill 每次触发都要加载一大段来源规范,即使任务只是检查一个不含版本事实的静态算法教程。

因此我增加:

text
references/source-policy.md

它只在文章包含“版本敏感、存在争议、安全敏感或产品特定主张”时读取。核心优先级是:

text
当前官方文档
→ 官方仓库 / release / specification / 安全公告
→ 原始研究或维护者资料
→ 社区教程与 issue 讨论
→ 作者个人判断

低优先级来源不是不能用。社区 issue 很适合补充真实故障,作者经验也可能非常有价值;问题在于不能把它们写成官方保证。

3.1 一份够用的证据台账

参考文件还定义了一个小型 evidence ledger:

字段含义
Claim能独立核对的最小主张
Source class官方文档、官方仓库、标准、社区或作者判断
Source直接支持该主张的 URL 或本地文件
Checked onYYYY-MM-DD 核对日期
Statusverified、contradicted、partially supported、unverified
Note版本边界、冲突、推断或剩余不确定性

例如,本文关于评估目录的记录可以写成:

ClaimSource classChecked onStatusNote
Agent Skills 的创建指南建议把测试任务放进 evals/evals.json公开规范的官方指南2026-07-15verified这是 authoring convention
Codex 每次调用 Skill 都会自动运行该文件2026-07-15contradicted不能这样表述
activation 是官方运行时字段本项目自定义2026-07-15unverified as official仅用于本文校验脚本

这张表的价值不是让文章显得严谨,而是迫使作者把三个相近概念分开。

3.2 references 的三个边界

不要重复项目规则。 博客的分类、构建命令和发布流程已经在 AGENTS.md,来源策略不再复制。

不要形成深层引用链。 SKILL.md 指向一份具体参考文件,比“参考文件 A 再让 Agent 去找 B、C、D”更可控。

不要无条件加载。 如果每次都需要读,内容可能就应该留在 SKILL.md;如果只在少数场景需要,才适合渐进式加载。

4. scripts:把机械判断交给确定性程序

技术文章 review 中有一批问题非常适合脚本:

  • frontmatter 必填字段是否齐全;
  • dateupdated 是否为真实日期;
  • updated 是否早于 date
  • 发布检查时 draft 是否已经是 false
  • 标签是否为空或数量明显失控;
  • 本地图片和文件链接是否存在;
  • 图片 alt 是否为空;
  • 外部链接是否至少可以访问。

这些问题如果只交给模型,每次都要重新扫描文本,还可能漏掉隐藏在长文后半段的路径。

但以下问题不应该交给这个脚本:

  • 命令是否适合当前 Codex 版本;
  • 引用页面是否真的支持正文结论;
  • 教程是否值得收藏;
  • 图是否帮助理解;
  • 一段个人判断是否有足够上下文。

4.1 先写脚本合同

我没有直接从正则开始,而是先约定命令接口:

text
Usage: node article-preflight.mjs <article.md> [options]

Options:
  --publish  要求 draft: false,并启用发布态警告
  --remote   尝试检查外部 HTTP 链接是否可达
  --json     输出结构化 JSON
  --help     显示帮助

Exit codes:
  0  没有验证错误
  1  发现文章错误
  2  参数错误或脚本内部失败

这个接口体现了 Agent 脚本应有的几个特征:

  1. 非交互式,调用后不等待用户输入。
  2. 默认只读,不修改文章。
  3. --help 能独立说明输入、输出与退出码。
  4. 数据可以输出 JSON,诊断信息有明确错误代码。
  5. 失败可被上层工作流判断,而不是只打印一句“有问题”。

脚本依赖 Node.js 18+ 和当前博客仓库已经安装的 gray-matter。这个前提被写进 Skill;如果运行环境缺失依赖,Agent 应该披露“未运行”,不能假装通过。

这也是一个明确的可移植性取舍:本文做的是仓库级 Skill,它可以复用项目已有依赖;若准备通过 Plugin 分发给其他项目,应把脚本改成自包含实现,或使用可锁定版本的运行方式,并重新跑完整评估。把目录复制走不等于完成迁移。

4.2 预检脚本做了什么

实现逻辑可以压缩成下面这段伪代码:

js
parse frontmatter
check required fields, dates, draft state, tags and body

strip fenced code blocks
collect Markdown images and links
check local targets with the file system

if --remote:
  check external URLs with timeout
  report network failures as warnings

print JSON
exit 1 when deterministic errors exist

这里特意把远程链接失败设为 warning。原因很现实:限流、登录墙和反爬策略都可能让一个有效页面暂时返回 403 或超时。脚本可以证明“这次请求没确认成功”,不能直接宣布“文章引用失效”。

4.3 运行真实文章

从仓库根目录执行:

powershell
node .agents/skills/review-technical-article/scripts/article-preflight.mjs content/blog/2026-07-14-codex-skills-introduction.md --publish --json

正文优先给单行、正斜杠版本,因为它在 PowerShell、Bash 和多数命令执行器里都更容易直接复用。若在本地把命令拆成多行,再使用当前 shell 对应的续行语法,不要把 PowerShell 的反引号写进 Skill 的通用说明。

2026-07-15 的实际结果摘录:

json
{
  "ok": true,
  "mode": "publish",
  "errors": [],
  "warnings": [],
  "counts": {
    "errors": 0,
    "warnings": 0,
    "images": 3,
    "local_links": 0,
    "external_links": 7
  }
}

这证明第 11 篇的 frontmatter、本地图片和发布状态通过了这套机械规则。它没有证明第 11 篇里每一条 Codex 事实都正确,也没有证明文章对每个读者都有价值。

4.4 故意让它失败

只测试成功样例,很容易把“脚本能运行”误当成“脚本能拦错”。我又创建了一个临时损坏样例:

yaml
---
title: "Broken fixture"
date: "2026-02-30"
updated: "2026-01-01"
draft: true
summary: "short"
category: "AI 与智能体"
tags: ["Codex"]
---

![missing image](/media/not-found.png)

发布模式实际返回:

text
errors:
  frontmatter.missing   缺少 series
  frontmatter.date      日期不存在
  publish.draft         发布检查仍为草稿
  image.missing         本地图片不存在

warnings:
  frontmatter.tags-range
  publish.summary-length

exit code: 1

成功路径和失败路径都符合预期以后,这个脚本才算完成最小验证。

5. 不要重复造轮子:仓库检查与 Skill 脚本怎样共存

当前博客本来就有:

text
scripts/check-content.mjs

它一次检查整个 content/blog,适合 CI 或发布前全量校验。新的 article-preflight.mjs 一次检查一篇文章,适合 Skill 在 review 过程中获得结构化证据。

两者有部分重叠,但调用场景不同:

工具范围典型调用者适合时机
scripts/check-content.mjs整个博客npm script、CI、部署流程全站构建与发布
article-preflight.mjs单篇文章review Skill编辑、审稿、单篇发布判断

如果两个脚本以后开始复制大量业务逻辑,就应该提取共享模块。当前只共享少量基础规则,保持独立更容易理解,也不会让一个仓库级 Skill 反向控制整个站点构建。

这个判断很重要:增加 scripts/ 不代表要把仓库已有工具全部重写一遍。

6. evals:保存真实任务,不是保存一句“应该很好”

Agent Skills 的评估指南建议在 Skill 目录里使用:

text
evals/evals.json

测试用例至少包含任务 promptexpected_output,也可以附带输入文件。指南还建议先从少量真实且有差异的任务开始,并把当前 Skill 与没有 Skill 或旧版本的基线作对照。

本文建立了 7 个用例,而不是只写一个最容易通过的正向 Prompt。

显式发布审查用例附带 evals/files/sample-codex-skill-tutorial.md。这篇 fixture 故意写错仓库级 Skill 路径和隐式调用默认值,并保留 draft: true 与一张缺失图片,用来检查事实审查与确定性预检是否都能发现问题。它不是参考资料,也不得发布。

类型数量代表场景期望
正向3中英文技术教程审查、显式调用应触发完整 review
负向3从零写文章、只改错别字、单一事实核对不应触发
模糊1“帮我看看这篇文章”先结合上下文推断或澄清

其中一个用例的简化版本如下:

json
{
  "id": "implicit-chinese-review",
  "prompt": "从读者角度 review 这篇技术教程,判断是否值得收藏,命令能不能复现,没问题再告诉我是否适合发布。",
  "expected_output": "Invoke the Skill for a substantive review.",
  "assertions": [
    "The response leads with concrete findings.",
    "The response evaluates reproducibility and practical payoff.",
    "The response states a publication gate."
  ],
  "activation": "required",
  "invocation": "implicit"
}

6.1 哪些字段是官方约定,哪些是本地扩展

这里必须把边界写清楚。

evals/evals.json 是 Agent Skills 创建与评估指南推荐的目录和文件。promptexpected_output 与可选 files 属于通用测试任务信息。

本文额外使用了:

  • skill_version:记录这批用例对应的 Skill 版本;
  • evaluated_on:记录检查日期;
  • assertions:保存可观察的验收语句;
  • activation:标记 required、forbidden 或 clarify;
  • invocation:标记 explicit 或 implicit。

后面这些是本文评估工作流的本地元数据。不要因为它们写在 evals.json 里,就暗示 Codex 运行时会自动读取或执行。

6.2 断言要能被观察

差的断言:

text
输出应该高质量。
文章 review 应该有帮助。

这类句子几乎无法稳定判定。

更好的断言:

text
输出必须给出 Ready to publish、Ready after revision 或 Not ready。
Findings 使用 P0-P3 严重级别,并给出可执行修改。
只要求纠正错别字时,不应输出完整发布评分卡。

断言不是越细越好。若把每个标题、每个词序都锁死,Skill 只要做了合理表达调整也会被判失败。应该锁定读者真正依赖的行为和产物。

7. 先校验评估清单,再谈模型行为

手写 JSON 很容易出现重复 id、漏字段或只覆盖正向案例。于是我增加了第二个确定性脚本:

text
scripts/validate-evals.mjs

它检查:

  • skill_name、版本和日期格式;
  • 至少三个用例;
  • id 唯一;
  • prompt、expected output 和 assertions 非空;
  • required、forbidden、clarify 三类触发覆盖;
  • explicit、implicit 两种调用覆盖。

命令:

powershell
node .agents/skills/review-technical-article/scripts/validate-evals.mjs --json

实际结果:

json
{
  "ok": true,
  "cases": 7,
  "errors": [],
  "note": "Schema and coverage only; model behavior was not executed."
}

最后这句 note 不是客套话,而是最重要的边界。

校验脚本只证明“评估清单结构符合本文约定”。它没有向 Codex 发送 7 个任务,也没有判断输出是否满足断言。

8. 真正的行为评估需要一组对照

图 3:Codex Skill 评估闭环;正向、负向和模糊用例分别在当前 Skill 与基线的干净上下文中运行,再经过断言、脚本与人工审查图 3:Codex Skill 评估闭环;正向、负向和模糊用例分别在当前 Skill 与基线的干净上下文中运行,再经过断言、脚本与人工审查

一轮完整评估应该这样做:

  1. 固定要测试的 Skill 版本和 evals.json
  2. 为每个 case 创建一个全新任务,运行当前 Skill。
  3. 再创建另一个全新任务,在不加载该 Skill 或使用旧版 Skill 的条件下运行同一输入。
  4. 保存输出、工具调用、脚本结果和失败信息。
  5. 检查可机械判定的 assertions。
  6. 人工 review 事实质量、读者价值和风险。
  7. 记录当前版本比基线好在哪里,又引入了什么副作用。

为什么一定要干净上下文?

因为 Agent 会使用当前对话里已经出现的规则和结论。若在同一任务里先解释“这个 Skill 应该怎样工作”,再测试它是否知道怎样工作,测试本身已经把答案泄露给了模型。

8.1 把每次运行保存成可以比较的证据

不要只在聊天窗口里凭印象对比。先在 Skill 目录旁边建立独立工作区:

text
review-technical-article-workspace/
└── iteration-1/
    └── implicit-chinese-review/
        ├── with_skill/
        │   ├── output.md
        │   └── notes.json
        └── baseline/
            ├── output.md
            └── notes.json

当前版本在一个全新任务里显式运行:

text
这是一次独立 eval run,不要修改 Skill 或输入文章。

使用 $review-technical-article。
测试任务:从读者角度 review 输入教程,判断是否值得收藏、
命令能否复现,以及是否适合发布。
输入:<article-path>
保存:<workspace>/iteration-1/implicit-chinese-review/with_skill/output.md

同时记录:
- 是否加载了目标 Skill
- 执行了哪些确定性脚本
- 脚本退出码
- 未能核对的事实

基线要在另一个全新任务里运行同一段测试任务。最稳妥的做法是使用一个不包含当前 Skill 的独立测试目录,并保持输入文章、项目规则和验收条件一致;若比较旧版本,则把旧 Skill 快照放在另一个隔离目录中。

不要让同名的新旧 Skill 同时处于一个发现范围。OpenAI 当前文档明确说明,同名 Skill 不会自动合并,选择器里可能同时出现两个,测试就无法确认究竟加载了哪一份。

如果当前环境无法保证隔离,就把结果标成“baseline 未运行”,不要用同一任务里的第二次回答代替基线。

8.2 触发评估和输出评估是两件事

一个 Skill 可能触发正确,但输出很差;也可能输出模板漂亮,却在不该出现时频繁抢任务。

维度观察什么失败例子
触发召回正向任务是否加载明确要求技术 review 却没使用 Skill
触发精度负向任务是否保持安静只改错别字却跑完整审查
边界处理模糊任务是否先推断或澄清没有文章内容就给发布结论
输出合同必要结构是否出现没有严重级别和发布门槛
实际收益相比基线是否减少遗漏模板更长,但事实核对没有改善

因此,description 的评估不能只看“能不能触发”。它同时要控制召回率和误触发率。

如果 Skill 准备跨入口或跨模型使用,还要把运行环境作为评估变量,而不是把所有结果混在一起:

记录维度示例为什么要记
surfaceCodex App、CLI、IDE、Claude Code不同入口的发现、权限和工具可能不同
model实际准备支持的模型和推理设置同一个 description 的召回稳定性可能变化
runtimeWindows、macOS、Linux、容器路径、命令和依赖可用性不同
skill_revisionGit commit、版本或目录快照避免结果对应不到实际文件
trigger_resultinvoked、skipped、clarified单独评价是否正确召回
output_resultassertions、人工评分、失败原因单独评价输出是否真的改善

Anthropic 的当前建议是至少准备三个真实评估,并在计划使用的模型上分别测试;OpenAI 则强调用测试 Prompt 检查 description 的触发行为。两边的方法可以互相借鉴,但目前没有一个 evals.json 会被 Codex 和 Claude 自动用同一种 runner 执行。通用的是用例和证据组织方式,产品调用与隔离仍需要各自实现。

8.3 本文诚实停在哪里

本文已经完成:

  • 7 个评估任务的设计;
  • 正向、负向、模糊和显式、隐式覆盖;
  • manifest 结构与覆盖校验;
  • Skill 目录快速验证;
  • 两个脚本的真实成功和失败运行。

本文没有声称完成:

  • 7 个 case 的当前 Skill 与基线双跑;
  • 自动判断全部行为 assertions;
  • 跨 Codex App、CLI、IDE 的一致性比较;
  • 跨 Codex 与 Claude Code、Claude API 的运行对照;
  • 不同模型或推理设置下的统计稳定性。

写下“尚未验证”比给一张虚假的全绿表更有价值。下一轮维护可以从这里继续,而不是误以为质量问题已经被证明不存在。

9. agents/openai.yaml:把调用策略显式化

第 11 篇已经生成了界面元数据:

yaml
interface:
  display_name: "技术文章 Review"
  short_description: "Review technical tutorials for accuracy and practical value"
  default_prompt: "请使用 $review-technical-article 审查这篇技术文章..."

这一篇增加:

yaml
policy:
  allow_implicit_invocation: true

OpenAI 当前的 Skills 文档支持用这个策略控制隐式调用。默认值是 true,所以这里即使不写也能隐式触发;显式写出,是为了让维护者看到这是一个经过判断的策略,不是遗忘。

为什么本文保持 true

  • 这个 Skill 只读文章和资料;
  • 脚本也是只读检查;
  • 即使误触发,主要代价是输出变长,而不是修改外部系统;
  • 用户经常会自然地说“review 一下是否适合发布”,隐式召回有实际价值。

如果 Skill 会删除文件、发布内容、发消息、操作付费资源或修改远程数据,我会优先考虑:

yaml
policy:
  allow_implicit_invocation: false

这样它仍可被显式调用,但不会只因为一句含糊描述就自行启动高影响工作流。

9.1 从 GitHub 安装 Skill 前,先把它当软件审计

隐式调用只是运行阶段的一层控制。第三方 Skill 本身可以携带脚本、外部链接和工具指令;Plugin 还可能包含 MCP 配置、commands、hooks 与其他可执行入口。仓库公开不等于代码已经替你审计过,star 数也不能代替权限检查。

我会在安装前完成这份最小检查:

  1. 阅读完整的 SKILL.md,确认描述的任务与实际步骤一致。
  2. 检查 scripts/、依赖清单和所有外部 URL,特别留意网络请求、凭据读取、文件删除与远程写入。
  3. 若是 Plugin,继续检查 .codex-plugin/plugin.json、MCP、hooks、commands 和权限声明,不能只看 skills/
  4. 核对每个目录的许可证。一个仓库可以同时包含开源与仅源码可见的内容。
  5. 固定到可追踪的 commit 或 tag,不依赖会持续变化的远程默认分支。
  6. 先在测试仓库、最小权限和 sandbox 中运行,再逐步开放网络、凭据和写权限。

Anthropic 官方把 Skill 明确视为需要像软件一样审计的能力;OpenAI 的 Plugin 结构也说明一个分发包可以携带的不只是说明文件。对社区仓库,正确姿势不是拒绝使用,而是把来源、版本、代码和运行权限一起纳入验收。

10. 版本化:记录变化,不假装运行时懂 SemVer

本文在评估清单里使用:

json
{
  "skill_name": "review-technical-article",
  "skill_version": "1.1.0",
  "evaluated_on": "2026-07-15"
}

这里的 1.1.0 是维护约定:

  • 1.0.0:第 11 篇的 instruction-only 工作流;
  • 1.1.0:增加 references、只读 scripts、eval manifest 和调用策略;
  • 未来若输出合同发生不兼容变化,再考虑提升 major。

它帮助我把评估结果对应到具体文件状态,但不代表 Codex 运行时会读取 skill_version 或按 SemVer 选择 Skill。

Skill frontmatter 里也记录了 metadata.version: "1.1.0",Node.js、gray-matter 和可选网络依赖则写在主文件的资源说明中。Agent Skills specification 允许客户端使用自定义 metadata,但不保证每个客户端都按相同方式解释版本,所以它仍然只是维护信息。

这里还存在一个真实的生态差异:开放规范允许 metadata,而 OpenAI 当前 Skill Creator 的作者指引倾向让 frontmatter 只保留 namedescription。本文实测当前 Codex quick validator 可以接受 metadata.version,但为了获得最大的客户端兼容性,也可以把版本只放在 evals.json、CHANGELOG 和 Git tag 中。无论选择哪种方式,都不要让业务逻辑依赖 Agent 自动理解这个版本号。

真正可追溯还需要:

  • Git commit 或可比较的文件快照;
  • 测试日期和运行环境;
  • 用例、输出与断言结果;
  • 已知未验证项;
  • 修改原因,而不只是版本号。

版本号是索引,不是证据。

11. 升级后的 SKILL.md 只增加编排,不复制实现

主文件新增的关键内容不是一大段脚本源码,而是资源使用条件:

text
Bundled Resources

- 遇到版本敏感、争议、安全或产品事实时,读取 source-policy.md。
- 本地 Markdown 且 Node 与依赖可用时,运行 article-preflight.mjs。
- 维护 Skill 时才运行 validate-evals.mjs。
- 正常文章 review 不加载 evals/evals.json。

工作流最前面还增加了 deterministic preflight:

text
1. 按 Agent Skills 约定,以 Skill 根目录的相对路径引用脚本;若命令执行器使用其他工作目录,再解析实际路径。
2. 只有用户询问发布就绪时才加 --publish。
3. 只有确实需要网络检查时才加 --remote。
4. 把脚本错误与编辑判断分开报告。
5. 脚本通过不代表文章正确或值得发布。

这段编排解决了两个问题。

第一,Codex 不需要每次重新发明命令和参数。第二,脚本结果不会混进 editorial findings,让读者误以为“路径存在”与“内容合理”拥有相同证据等级。

12. 一份可以直接交给 Codex 的升级任务

如果你已经有第 11 篇那样的最小 Skill,可以从下面这份任务开始,而不是手工逐个建文件:

text
请升级 .agents/skills/<skill-name>,目标是让它可以被持续验证。

先阅读现有 SKILL.md 和项目 AGENTS.md,不要覆盖已有有效规则。

需要交付:
1. references/:只放按条件加载的详细知识,并在 SKILL.md 写清读取条件。
2. scripts/:只实现确定性、重复、非交互的步骤;提供 --help、结构化输出、明确退出码和安全默认值。
3. evals/evals.json:包含正向、负向、模糊案例,覆盖显式和隐式调用。
4. 一个只校验 eval manifest 的脚本,输出中明确它没有执行模型行为。
5. agents/openai.yaml:根据副作用决定是否允许 implicit invocation。
6. 兼容性说明:在 Skill 中写明目标 Agent、运行时、依赖、网络和平台限制。

验收:
- Skill 结构校验通过。
- 每个包含验证逻辑的脚本至少验证一个成功样例和一个失败样例。
- 区分官方字段与本项目自定义评估字段。
- 所有 Skill 内部路径使用正斜杠,并验证目标运行环境具备所需依赖。
- 不把脚本通过写成事实正确,不把 manifest 通过写成行为通过。
- 给出未完成的行为基线测试清单。

这份 Prompt 的重点不是目录名,而是每个文件的职责和验收边界。

13. 本地验证记录

本文写作前实际运行了以下检查:

检查实际结果能证明什么不能证明什么
Skill Creator quick validateSkill is valid!frontmatter 与基本目录有效Skill 在真实任务中表现好
validate-evals.mjs --json7 cases,0 error本地清单格式和覆盖完整7 个任务已被 Codex 执行
损坏的 eval manifest7 errors,exit 1版本、日期、断言和覆盖错误可被拦截模型输出质量
第 11 篇 --publish --json0 error,0 warning发布元数据和本地资源通过文章事实全部正确
损坏 fixture 发布检查4 errors,2 warnings,exit 1脚本能拦住设计中的错误覆盖所有 Markdown 边缘语法
SVG 转 PNG3 张均为 2400×1350静态回退图可生成页面响应式布局一定无误

这里仍有两个残余风险。

一是 Markdown 链接语法有很多边缘情况,当前脚本面向本博客常用写法,不是完整 Markdown parser。二是外链检查受网络和站点策略影响,所以只作 warning。

这两个限制已经写进文章和脚本行为,不需要为了“全绿”而隐藏。

14. 最常见的六种失败方式

14.1 一开始就创建所有目录

references/scripts/assets/ 不会增加可靠性,只会增加维护噪声。先从最小 Skill 开始,遇到具体压力再拆。

14.2 把长说明移走,却不写召回条件

SKILL.md 只写“需要时参考资料”几乎没有帮助。应该写清“文章包含时间敏感或安全相关主张时读取 source-policy.md”。

14.3 用脚本处理主观判断

正则可以找缺图,不能判断图是否帮助理解。若脚本只能靠越来越多模糊启发式猜测,任务可能应该留给 Agent 和人。

14.4 只写正向 eval

“明确点名 Skill 时能触发”是最低难度。真正影响日常体验的往往是误触发,所以负向和模糊任务不可缺少。

14.5 在同一对话里测试当前版和基线

前一次输出会给后一次提供规则和答案,结果不能作为干净对照。每个 run 都要使用独立任务。

14.6 把每个绿色结果都叫作“验证通过”

最危险的表述是:

text
evals.json 校验通过,所以 Skill 已验证。

更准确的是:

text
评估清单结构与覆盖通过;
模型行为基线测试仍待执行。

证据说到哪,结论就停到哪。

15. 45-60 分钟跟做练习

不要一上来复制本文整个目录。选择你已经使用过至少两次的 Skill,再按这个节奏升级。

0-10 分钟:找出不稳定点

记录最近两次使用里重复出现的问题:

  • 哪段知识总要重新解释?
  • 哪个机械检查总会漏?
  • 哪种相似任务不应该触发?
  • 输出里哪个字段是下游真正依赖的?
  • 最终准备在哪个 Agent、入口和运行环境里使用?

只选一个最明显的问题。

10-20 分钟:决定放置位置

用图 2 的决策顺序判断:

text
项目规则 → AGENTS.md
任务编排 → SKILL.md
详细知识 → references/
确定性处理 → scripts/
回归任务 → evals/
外部动作 → MCP / App

写不清职责就先不要拆。

20-35 分钟:实现一个最小扩展

二选一即可:

  • 增加一份只在特定条件加载的 reference;
  • 增加一个只读、非交互、带 --help 和退出码的 script。

同时把调用条件写回 SKILL.md

35-45 分钟:建立评估矩阵

至少写 4 个任务:

  1. 一个显式正向;
  2. 一个自然语言正向;
  3. 一个相似但不应触发的负向;
  4. 一个信息不足的模糊任务。

每个用例至少写一条可观察断言。

若计划跨入口使用,再为用例记录 surfacemodelruntime 和 Skill revision;不需要第一轮就覆盖所有组合,但必须知道这次结果属于哪一个环境。

45-60 分钟:跑失败路径并记录边界

  • 让脚本处理一个合法输入;
  • 故意制造一个错误输入;
  • 校验 eval manifest;
  • 写下哪些行为没有运行;
  • 在另一个干净任务里准备基线测试。

练习完成的标准不是“目录和本文一样”,而是你能回答:

text
每个新增文件解决了什么问题?
它的结果能证明什么?
它不能证明什么?

16. 收藏清单

以后升级 Skill,可以按这份顺序检查:

设计

  • Skill 仍然只解决一个清楚的任务。
  • SKILL.md 只保留触发、编排和输出合同。
  • reference 有明确读取条件,没有复制 AGENTS.md
  • script 只承担确定性、重复处理。
  • 外部实时动作没有被误塞进本地脚本。

脚本

  • 非交互、默认只读、有 --help
  • 输入、输出、依赖和退出码明确。
  • Skill 内部路径使用正斜杠,目标环境能够提供所需依赖。
  • 结构化数据走 stdout,诊断信息清楚。
  • 成功样例与失败样例都实际运行。
  • 网络失败与内容错误没有混为一谈。

评估

  • 有正向、负向和模糊任务。
  • 同时覆盖显式与隐式调用。
  • 断言可以观察,不依赖模糊的“高质量”。
  • 当前 Skill 与基线使用独立干净任务。
  • 结果记录了 surface、model、runtime 和 Skill revision。
  • 机械断言、人工判断和未验证项分别记录。

安装与共享

  • 已审查 SKILL.md、scripts、外部 URL 和依赖。
  • Plugin 的 MCP、hooks、commands 和权限入口也经过检查。
  • 已核对许可证,并固定到可追踪的 commit 或 tag。
  • 第一次运行使用测试仓库、sandbox 和最小权限。
  • 已区分通用 Skill 核心与 Codex、Claude 的产品专属配置。

发布

  • 官方事实有来源和核对日期。
  • 本地扩展没有写成 Codex 运行时保证。
  • 版本号能对应具体文件状态。
  • 没有用“清单通过”代替“行为通过”。
  • 最终高影响动作仍由人验收。

写在最后

第 11 篇解决的是“怎样不再反复写同一段 Prompt”。第 12 篇解决的是更长期的问题:

text
当这套能力开始被重复使用,
怎样知道它今天仍然按预期工作?

答案不是把 SKILL.md 写到无限长,也不是给目录塞满文件。更可持续的做法是把职责拆清楚:

  • references 保留需要时才加载的知识;
  • scripts 提供可重复的机械证据;
  • evals 保存真实任务与回归边界;
  • 人工 review 负责事实、质量和风险;
  • 版本记录把结论对应到具体状态。

下一篇进入第 13 篇:Plugins、MCP 与 Apps:什么时候让 Codex 连接外部工具。届时会继续用同一套判断方法,区分“给 Agent 一套可复用说明”“把能力打包分发”和“连接需要认证的实时外部系统”。

参考资料

官方与规范

社区案例

社区仓库只用于观察目录组织和应用场景,当前路径、字段和产品行为仍以官方资料与实际运行结果为准。使用 GitHub 示例时还要逐目录核对许可证:例如 Anthropic 官方仓库中的多数 Skill 使用 Apache 2.0,但 docxpdfpptxxlsx 属于 source-available,并不能因为仓库公开就统一称为开源。