Skip to main content
一个 skill 只有在被激活时才有帮助。SKILL.md frontmatter 中的 description 字段,是 agent 判断某个任务是否应该加载该 skill 的主要依据。描述过于模糊,skill 就会在该触发时不触发;描述过于宽泛,skill 就会在不该触发时误触发。 这份指南介绍如何系统地测试并改进 skill 的 description,从而提升触发准确性。

skill 触发机制是如何工作的

agent 使用渐进式披露来管理上下文。启动时,它们只会加载每个可用 skill 的 namedescription,信息量刚好足以判断某个 skill 何时可能相关。当用户任务与某个描述匹配时,agent 才会把完整的 SKILL.md 读入上下文,并按其中说明执行。 这意味着 description 承担了整个触发判断的重任。如果描述没有清楚传达这个 skill 什么时候有用,agent 就不知道应该调用它。 还有一个重要细节:agent 通常只会在任务需要超出自身基础能力的知识或能力时,才会去 consult skills。像“读一下这个 PDF”这样简单的一步请求,即使和某个 PDF skill 的描述完全匹配,也未必会触发,因为 agent 用基础工具就能完成。真正能体现高质量描述价值的,往往是那些涉及专业知识的任务,例如陌生 API、领域特定工作流,或者不常见的数据格式。

编写有效的描述

在测试之前,先明确一条好的描述应该长什么样,会很有帮助。这里有几个原则:
  • 使用祈使式表达。 把描述写成对 agent 的指令,例如“在……情况下使用这个 skill”,而不是“这个 skill 会做……”。agent 正在决定是否采取行动,所以你应该直接告诉它什么时候行动。
  • 关注用户意图,而不是实现细节。 描述用户想达成什么,而不是 skill 内部如何实现。agent 匹配的是用户提出的需求。
  • 宁可写得主动一点。 明确列出 skill 适用的上下文,包括用户没有直接点出领域名称的情况,例如“即使用户没有显式提到 ‘CSV’ 或 ‘analysis’ 也应使用。”
  • 保持简洁。 一般来说,几句话到一个短段落最合适:既足够覆盖 skill 的边界,又不会因为描述过长,让 agent 在加载大量 skills 时上下文膨胀。规范对它也有 1024 个字符的硬限制。

设计触发 eval 查询

要测试触发效果,你需要准备一组 eval 查询,也就是一批真实风格的用户提示词,并标注它们是否应该触发你的 skill。
eval_queries.json
建议准备大约 20 条查询:其中 8 到 10 条应该触发,8 到 10 条不应该触发。

应触发的查询

这类查询用于测试描述是否准确覆盖了 skill 的边界。设计时可以沿几个维度变化:
  • 表达方式:有些正式,有些口语化,有些带错别字或缩写。
  • 显式程度:有些直接点出 skill 所属领域(例如“分析这个 CSV”),有些只描述需求而不点名(例如“我老板想要这份数据文件生成一张图表”)。
  • 细节丰富度:混合简短提示词和上下文丰富的提示词,例如短句“分析我的销售 CSV 并做一张图”,以及包含文件路径、列名和背景说明的长消息。
  • 复杂度:变化步骤数量和决策点。既要有单步骤任务,也要有多步骤工作流,用来测试当 skill 所解决的问题被埋在更长任务链中时,agent 是否仍能识别它相关。
最有价值的“应触发”查询,是那些 skill 明明能帮上忙,但从字面上看并不明显相关的情况。正是这些场景,最能体现描述措辞的差异。如果用户本来就精确说出了 skill 的用途,那只要描述写得不是太差,通常都会触发。

不应触发的查询

最有价值的负样本是近似但不匹配的查询,也就是那些和你的 skill 共享某些关键词或概念,但真正需要的却是别的东西。它们测试的是描述是否足够精确,而不只是够宽泛。 对于一个 CSV 分析 skill,较弱的负样本会是:
  • "Write a fibonacci function" — obviously irrelevant, tests nothing.
  • "What's the weather today?" — no keyword overlap, too easy.
更强的负样本示例:
  • "I need to update the formulas in my Excel budget spreadsheet" — shares “spreadsheet” and “data” concepts, but needs Excel editing, not CSV analysis.
  • "can you write a python script that reads a csv and uploads each row to our postgres database" — involves CSV, but the task is database ETL, not analysis.

提高真实性的小建议

真实用户提示词通常会带有很多泛化测试查询里没有的上下文。你可以加入:
  • File paths (~/Downloads/report_final_v2.xlsx)
  • Personal context ("my manager asked me to...")
  • Specific details (column names, company names, data values)
  • Casual language, abbreviations, and occasional typos

测试描述是否会触发

基本做法是:在已安装该 skill 的前提下,把每条查询交给你的 agent 运行,然后观察 agent 是否调用了它。前提是这个 skill 已经被注册,并且 agent 可以发现它。具体怎么做会因客户端不同而有所差异,例如可能通过 skills 目录、配置文件,或者 CLI 参数来实现。 大多数 agent 客户端都会提供某种可观测性能力,比如执行日志、工具调用历史或详细输出,让你能看到一次运行中 consult 了哪些 skills。具体细节要看你的客户端文档。如果 agent 读入了这个 skill 的 SKILL.md,就算触发;如果它直接继续执行而没有 consult 这个 skill,就算未触发。 一条查询在以下情况下算“通过”:
  • should_trigger is true and the skill was invoked, or
  • should_trigger is false and the skill was not invoked.

多次运行

模型行为具有非确定性。同一条查询,这次可能触发 skill,下次可能不触发。因此每条查询都应运行多次(3 次是一个不错的起点),并计算触发率,也就是触发 skill 的运行次数占总运行次数的比例。 如果一条“应触发”查询的触发率高于某个阈值(0.5 是一个合理默认值),它就算通过;反过来,“不应触发”查询的触发率若低于该阈值,则算通过。 如果有 20 条查询、每条跑 3 次,那就是 60 次调用。你大概率会希望把这个流程脚本化。下面是一种通用结构,你可以把其中的 claude 调用和 check_triggered 中的检测逻辑替换成你自己的 agent 客户端实现:
如果你的 agent 客户端支持,一旦结果已经明确,就可以提前终止这一轮运行。也就是说,只要 agent 已经 consult 了 skill,或者已经在未 consult 的情况下开始工作,这一轮就没必要继续跑完。这样能显著降低整套 eval 的时间和成本。

用 train / validation 切分避免过拟合

如果你用全部查询一起优化描述,就有过拟合风险,也就是写出了一个只对这些特定表达有效、但一换新表达就失效的描述。 解决方案是把查询集拆分成两部分:
  • Train set(约 60%):用来发现问题并指导你改进的查询。
  • Validation set(约 40%):提前留出来,只用来检查改进是否真的具备泛化能力的查询。
要确保两个集合里都按比例混合“应触发”和“不应触发”的查询,不要不小心把所有正样本都放进同一个集合里。先随机打乱,然后在多轮迭代中保持这次切分不变,这样你比较的才是同一基准上的变化。 如果你使用的是像上面那样的脚本方式,可以把查询拆成两个文件:train_queries.jsonvalidation_queries.json,再分别运行脚本。

优化闭环

  1. 评估当前描述在 train 和 validation 两个集合 上的表现。train 结果用于指导改动,validation 结果用来判断这些改动是否具备泛化性。
  2. train set识别失败样本:哪些“应触发”的查询没有触发?哪些“不应触发”的查询却触发了?
    • 只有 train set 中的失败样本可以用来指导改动。无论是你自己改描述,还是让 LLM 帮你优化,都不要把 validation set 的结果带入这个过程。
  3. 修订描述。 重点是做泛化而不是死记:
    • 如果“应触发”的查询没有触发,说明描述可能太窄。你需要适度扩大范围,或者补充说明这个 skill 在什么情况下有帮助。
    • 如果“不应触发”的查询被误触发,说明描述可能太宽。你需要补充这个 skill 不做什么,或者更清楚地划定它和相邻能力之间的边界。
    • 不要把失败查询里的特定关键词直接塞进描述里,那就是过拟合。应该去提炼这些查询背后的通用类别或概念,并针对那个层面做修订。
    • 如果几轮下来都卡住了,不要只做微调,可以尝试从结构上重写描述。换一种 framing 或句式,有时比局部修补更有效。
    • 同时检查描述是否仍然低于 1024 字符限制。因为在优化过程中,描述很容易越写越长。
  4. 重复步骤 1 到 3,直到 train set 全部通过,或者你已经看不到有意义的提升。
  5. 根据 validation pass rate,也就是 validation set 中通过查询的比例,选出最佳版本。注意,最好的描述未必是最后一版;有时中间某一版的 validation 表现反而优于后续那些过拟合到 train set 的版本。
通常迭代五轮左右就足够了。如果效果一直不提升,问题可能不在描述,而在于查询本身设计得有问题,比如过于简单、过于困难,或者标注不准确。
skill-creator 这个 Skill 可以把这套闭环完整自动化:它会拆分 eval 集、并行评估触发率、使用 Claude 提出描述改进建议,并生成一个可实时查看的 HTML 报告。

应用优化结果

选定最佳描述后:
  1. 更新 SKILL.md frontmatter 中的 description 字段。
  2. 确认描述仍低于1024 字符限制
  3. 验证这个描述是否按预期触发。你可以先手动试几条 prompt 做快速 sanity check。若要更严格地测试,可以另外再写 5 到 10 条全新的查询(混合“应触发”和“不应触发”),然后跑一次 eval 脚本。因为这些查询从未参与过优化过程,所以它们能更真实地检验描述是否具备泛化能力。
优化前后对比:
改进后的描述对这个 skill 做什么 说得更具体了(汇总统计、派生列、图表、清洗),同时也对 什么时候适用 说得更完整了(CSV、TSV、Excel,甚至在没有明确关键词时也应触发)。

下一步

当你的 skill 已经能够稳定触发之后,下一步就该评估它的输出质量了。可以参考评估 skill 输出质量,了解如何建立测试用例、给结果打分并继续迭代。