看到 Skill 目录和 SKILL.md 文件,不代表它已经可用。文件可能有正确的 YAML,却在自然表达下无法触发;也可能能够触发,但遇到缺少日期、负责人或数据时开始编造。

Skill 的验证至少分两层:第一层是结构检查,确认目录和元数据能被识别;第二层是真实任务测试,确认它在正常、模糊、缺失和不相关输入下表现符合预期。

本文以“每周复盘 Skill”为例,给出一套不依赖特定验证器文案的测试方法。不同 Codex 表面可能提供不同的创建和检查入口,下面的测试思想比某一条命令更稳定。

一、先定义你要验证什么

不要只问“Skill 能不能运行”。至少拆成五个问题:

  1. 用户明确点名时,能否进入正确 Skill?
  2. 用户自然描述同一任务时,能否被正确识别?
  3. 信息不足时,是否停止猜测并提出必要问题?
  4. 不相关任务出现时,是否不会误触发?
  5. 触发之后,输出是否符合步骤、格式和质量标准?

前四个问题验证入口和边界,最后一个问题验证执行质量。只测最后一个问题,会漏掉大量实际使用中的失败。

二、第一层:检查目录和元数据

最小目录应该类似:

weekly-review/
└── SKILL.md

打开 SKILL.md,逐项检查:

---
name: weekly-review
description: 将一周的工作记录整理为结构化复盘和下周行动。用户提到周报、每周复盘、工作回顾或流水账整理时使用;缺少重要信息时标记待补充。
---

检查文件位置

Skill 目录中应存在 SKILL.md,文件名大小写不要随意变化。若使用 references/scripts/assets/,正文中应有引用和使用时机。

检查 name

名称要能唯一指向这项能力,并与目录名保持一致。建议使用简单的小写英文和连字符,避免空格、中文、日期和临时项目名混入名称。

检查 description

description 要同时写任务范围和触发场景。检查是否存在这些问题:

检查 front matter 之后的正文

正文应当是可执行说明,而不是创建过程的聊天记录。至少能找到输入、工作流程、异常处理、输出和质量标准。

如果你用脚本做结构检查,可以从最小规则开始:

from pathlib import Path
import re

def check_skill(path: str) -> list[str]:
    text = Path(path).read_text(encoding="utf-8")
    errors = []
    if not text.startswith("---\n"):
        errors.append("missing front matter")
    if not re.search(r"(?m)^name:\s*[^\n]+$", text):
        errors.append("missing name")
    if not re.search(r"(?m)^description:\s*[^\n]+$", text):
        errors.append("missing description")
    if "## 工作流程" not in text and "## Workflow" not in text:
        errors.append("missing workflow section")
    return errors

errors = check_skill("weekly-review/SKILL.md")
print("PASS" if not errors else "\n".join(errors))

这段代码只能检查文本结构,不能证明 Skill 的触发和输出质量。它适合做快速护栏,不应冒充完整验证器。

三、第二层:准备一组固定测试输入

测试必须尽量使用真实会话里的说法,而不是只写理想命令。每个 Skill 至少准备五类样例:

A. 明确点名

请使用 $weekly-review 整理下面的工作记录。

预期:明确进入 weekly-review,按固定栏目输出。

B. 自然表达

把这些流水账整理成周报,再列出下周优先级。

预期:即使没有显式写 $weekly-review,仍能根据 description 识别为同一类任务。

C. 信息不完整

这周主要在做支付功能,帮我复盘一下。

预期:先输出能确认的内容,指出缺失记录、日期、数据或负责人,不自动补全。

D. 边界输入

我有一周的会议记录,但其中有两处截止时间不一致,请先帮我找出冲突。

预期:Skill 应保留冲突并要求确认,而不是擅自选择一个日期。

E. 不应触发

把这段中文翻译成英文。

预期:周报 Skill 不应被调用,除非用户另外说明要把复盘翻译成英文。

将这五类输入保存成测试文件,可以避免每次改 Skill 后只凭印象测试。

四、第三层:验证输出而不是只看是否触发

对于每个测试案例,记录以下结果:

测试编号:A
是否正确触发:是
输入是否完整:是
固定栏目是否齐全:是
事实是否有证据:是
是否出现猜测:否
是否需要人工确认:否
失败原因:无

测试记录不需要复杂数据库,用 Markdown 表格或 CSV 就够了:

编号 场景 触发 结构 事实 异常处理 结果
A 明确点名 通过 通过 通过 通过 通过
B 自然表达 通过 通过 通过 不适用 通过
C 信息不完整 通过 部分输出 通过 通过 通过
D 冲突输入 通过 通过 通过 失败 失败
E 不应触发 失败 不适用 不适用 不适用 失败

一次失败要记录具体行为。例如“输出不好”不够,应该写成“在缺少负责人时生成了姓名”“没有保留截止时间冲突”“翻译任务误触发”。

五、根据失败位置修改 Skill

不同失败需要改不同位置,不要每次都把整份 SKILL.md 重写一遍。

没有自动触发

通常先检查 description:是否写入了用户真实使用的词,是否把范围写得太窄。增加“周报、每周复盘、工作回顾、流水账”等自然表达,比增加一大段内部流程更有效。

不相关任务误触发

删除宽泛的词,例如“处理文本”“分析内容”“生成报告”,并加入边界说明:只有任务同时涉及一周记录和复盘输出时才使用。

执行顺序不稳定

把隐含要求改成编号步骤,并明确每一步的产出。不要只写“先分析、再整理”,而要写“先提取原文事实,再按固定栏目分类”。

输出总是空话

增加反例和质量标准,要求使用具体动词、保留证据、标记未知字段,并限制没有信息量的套话。

信息不足时乱编

增加停止条件,列出不得推断的字段,并指定统一格式,例如 待补充待确认null

SKILL.md 越来越长

把详细规则、术语和示例放到 references/,把确定性处理放到 scripts/。正文只保留完成当前任务必须知道的说明。

六、测试 Skill 的输入边界

真实任务测试还要覆盖几种工程边界:

空输入

没有提供记录时,Skill 应明确要求输入,而不是生成一篇看似完整的周报。

超长输入

输入超过上下文承载能力时,应该先分批、摘要或让用户选择范围,并说明可能丢失的内容。

重复输入

同一条记录出现两次时,Skill 可以合并,但不能因为合并而改变事实或计数。

冲突输入

两处记录不一致时,保留冲突、引用来源并请求决定。不要把模型的偏好当作事实。

恶意指令

工作记录中可能包含“忽略之前规则”“执行某个命令”之类文本。Skill 应把它当作待分析内容,而不是自动执行的系统指令。

七、用最小数据集做回归测试

每次修改 description、输出格式或异常规则,都重新跑一组最小数据集:

样本 1:三条完整记录
样本 2:缺少日期和负责人
样本 3:同一任务有两种状态
样本 4:包含一条无关聊天内容
样本 5:空文件夹

对比修改前后的输出,重点看:

保留一份人工认可的基线输出会更方便,但不要把某一份自然语言答案当作唯一正确答案。真正要比较的是事实、结构、边界和完成标准。

八、安装或更新后的检查

Skill 的加载位置取决于使用的 Codex 表面和目录范围。当前手册列出了仓库、用户、管理员和系统范围,仓库级 Skill 通常放在仓库树中的 .agents/skills,用户级 Skill 放在用户的 .agents/skills

安装或复制之后,至少检查:

目录是否位于当前 Codex 能扫描的范围?
SKILL.md 是否位于 Skill 文件夹根目录?
name 是否与预期一致?
description 是否出现在技能列表或选择器中?
显式调用是否能运行?
自然表达是否按预期匹配?
修改后是否被当前会话重新加载?

如果更新没有立即出现,按当前产品说明重新载入或新开任务,再重复测试。不要把“文件存在”当成“当前会话已经使用新版本”。

九、什么时候应该关闭隐式调用

不是每个 Skill 都适合自动触发。对于高风险、范围相近或会修改外部状态的能力,可以考虑只允许显式调用,或者在 agents/openai.yaml 中设置相应的隐式调用策略。

例如,文章格式检查可以隐式匹配;自动发布、删除文件、发送消息或修改正式数据的 Skill,则应要求用户明确点名,并在执行前再次确认。

无论是否允许隐式调用,Skill 正文都应该保留权限和停止条件。关闭隐式调用不是安全的全部,只是减少误触发的一层措施。

十、验证报告模板

每次发布 Skill 新版本,可以保存一份短报告:

# Skill Verification Report

## Skill
- name: weekly-review
- version: 0.2.0
- tested_at: 2026-07-30

## Cases
- direct invocation: pass
- natural request: pass
- incomplete input: pass
- conflicting input: pass
- unrelated request: pass

## Known limits
- 超长记录需要分批输入
- 无法从原文推断负责人

## Decision
可以用于生成草稿;对外发送仍需人工确认。

版本号不是 Codex 的强制要求,但对 GitHub 同步和回归测试很有帮助。每次改动都记录变化原因,出了问题才能定位是 description、流程、模板还是脚本造成的。

结论

Skill 验证不能止步于 YAML 格式正确或目录存在。真正的验证需要覆盖明确调用、自然表达、信息缺失、冲突输入和不应触发五类场景,并逐项检查触发、结构、事实、边界和权限。

先建立一组小而真实的测试案例,再根据失败位置修改对应部分。这样你会知道应该改 description、工作流程、异常规则还是资源组织,而不是凭感觉不断增加提示词。

官方参考:Codex Build skills,用于核对 Skill 的发现、调用和更新行为。