看到 Skill 目录和 SKILL.md 文件,不代表它已经可用。文件可能有正确的 YAML,却在自然表达下无法触发;也可能能够触发,但遇到缺少日期、负责人或数据时开始编造。
Skill 的验证至少分两层:第一层是结构检查,确认目录和元数据能被识别;第二层是真实任务测试,确认它在正常、模糊、缺失和不相关输入下表现符合预期。
本文以“每周复盘 Skill”为例,给出一套不依赖特定验证器文案的测试方法。不同 Codex 表面可能提供不同的创建和检查入口,下面的测试思想比某一条命令更稳定。
一、先定义你要验证什么
不要只问“Skill 能不能运行”。至少拆成五个问题:
- 用户明确点名时,能否进入正确 Skill?
- 用户自然描述同一任务时,能否被正确识别?
- 信息不足时,是否停止猜测并提出必要问题?
- 不相关任务出现时,是否不会误触发?
- 触发之后,输出是否符合步骤、格式和质量标准?
前四个问题验证入口和边界,最后一个问题验证执行质量。只测最后一个问题,会漏掉大量实际使用中的失败。
二、第一层:检查目录和元数据
最小目录应该类似:
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 的发现、调用和更新行为。