优化 skill 描述
如何改进技能的描述,使其能在相关提示下可靠触发。
技能只有在被激活时才有用。SKILL.md 前置元数据中的 description 字段是代理决定是否为给定任务加载技能的主要机制。描述过于简略会导致技能在该触发时不触发;描述过于宽泛则会导致它在不该触发时触发。
本指南介绍如何系统地测试和改进技能描述,以提高触发的准确性。
1. 技能触发的工作原理
代理使用 渐进式披露 来管理上下文。启动时,它们只加载每个可用技能的 name 和 description——足以判断技能何时可能相关。当用户任务与 description 匹配时,代理会将完整的 SKILL.md 读入上下文并遵循其指令。
这意味着 description 承担了触发的全部责任。如果 description 没有传达技能的适用场景,代理就不知道去调用它。
一个重要细节:代理通常只在任务需要它们自身无法处理的知识或能力时,才会考虑技能。像 “读取这个 PDF” 这样简单、一步到位的请求,即使描述完美匹配,也可能不会触发 PDF 技能,因为代理可以用基础工具处理。涉及专业知识——不熟悉的 API、领域特定工作流或非通用格式——的任务,才是精心编写的描述能发挥作用的场景。
2. 编写有效的描述
在测试之前,了解好的描述是什么样的会很有帮助。以下是一些原则:
- 使用祈使语气。将描述表述为对代理的指令:“当……时使用此技能”,而不是 “此技能执行……”。代理需要决定是否行动,所以告诉它何时行动。
- 关注用户意图,而非实现细节。描述用户试图达成什么,而不是技能的内部机制。代理是根据用户提出的需求进行匹配的。
- 宁可“强势”一些。明确列出技能适用的上下文,包括用户没有直接提及领域的情况:“即使用户没有明确提到‘CSV’或‘分析’”。
- 保持简洁。几句话到一小段通常就足够了——长度要足以涵盖技能的适用范围,又足够短,不至于在多个技能中膨胀代理的上下文。 agentskills.io 规范 强制规定了 1024 个字符的硬限制。
3. 设计触发评估查询
为了测试触发,你需要一组评估查询——这些查询是真实的用户提示,并标注了它们是否应触发你的技能。
[ { "query": "我有个电子表格在 ~/data/q4_results.xlsx,C 列是收入,D 列是支出——你能添加一个利润率列,并把低于 10% 的标出来吗?", "should_trigger": true }, { "query": "把这个 json 文件转成 yaml 最快的方法是什么", "should_trigger": false }]目标大约 20 个查询:8-10 个应触发和 8-10 个不应触发。
3.1 应触发查询
这些查询测试描述是否捕捉了技能的适用范围。请从多个维度变化:
- 措辞:一些正式,一些随意,一些包含拼写错误或缩写。
- 明确性:一些直接命名技能的领域(“分析这个 CSV”),另一些描述需求而不命名它(“我老板想从这个数据文件里看个图”)。
- 详细程度:混合简洁提示和富含上下文的提示——简短的“分析我的销售 CSV 并做图”与包含文件路径、列名和背景故事的较长消息。
- 复杂度:变化步骤数和决策点的数量。包括单步任务和多步工作流,以测试当目标任务隐藏在更大链中时,代理能否识别技能的相关性。
最有价值的应触发查询是那些技能会有帮助,但从查询本身来看关联并不明显的情况。这些是描述措辞起关键作用的案例——如果查询已经明确要求技能所做的,那么任何合理的描述都会触发。
3.2 不应触发查询
最有价值的负例测试是近似匹配(near-misses)——与技能共享关键词或概念,但实际需要不同内容的查询。这些测试描述是否精确,而不仅仅是宽泛。
对于 CSV 分析技能,弱的负例是:
"写一个斐波那契函数"—— 明显无关,无测试价值。"今天天气怎么样?"—— 无关键词重叠,太简单。
强的负例:
"我需要更新我的 Excel 预算电子表格中的公式"—— 共享“电子表格”和“数据”概念,但需要的是 Excel 编辑,而非 CSV 分析。"你能写一个 Python 脚本读取 CSV 并把每一行上传到我们的 PostgreSQL 数据库吗"—— 涉及 CSV,但任务是数据库 ETL,而非分析。
3.3 真实性技巧
真实用户提示包含通用测试查询所缺乏的上下文。请包含:
- 文件路径(
~/Downloads/report_final_v2.xlsx) - 个人背景(
"我经理让我...") - 具体细节(列名、公司名称、数据值)
- 口语化表达、缩写和偶尔的拼写错误
4. 测试描述是否触发
基本方法:在安装了技能的代理中运行每个查询,观察代理是否调用该技能。确保技能已注册且可被代理发现——具体方式因客户端而异(例如,技能目录、配置文件或 CLI 标志)。
大多数代理客户端提供某种形式的可观测性——执行日志、工具调用历史或详细输出——让你能查看运行期间咨询了哪些技能。请查阅客户端文档了解详情。如果代理加载了你的 SKILL.md,则表示技能已触发;如果代理未咨询它就直接进行,则表示未触发。
一个查询“通过”的条件是:
should_trigger为true且技能被调用,或should_trigger为false且技能未被调用。
4.1 多次运行
模型行为是非确定性的——同一个查询可能在某次运行中触发技能,但下一次不触发。每个查询运行多次(3 次是一个合理的起点),并计算触发率:技能被调用的运行比例。
一个应触发查询,如果其触发率高于阈值(0.5 是一个合理的默认值),则通过。一个不应触发查询,如果其触发率低于该阈值,则通过。
20 个查询,每个 3 次,就是 60 次调用。你需要将其脚本化。以下是通用结构——请将 check_triggered 中的 claude 调用和检测逻辑替换为你代理客户端提供的相应方式:
#!/bin/bashQUERIES_FILE="${1:?Usage: $0 <queries.json>}"SKILL_NAME="my-skill"RUNS=3
# 此示例使用 Claude Code 的 JSON 输出来检查 Skill 工具调用。# 请将此函数替换为你代理客户端的检测逻辑。# 如果技能被调用,应返回 0(成功),否则返回 1。check_triggered() { local query="$1" claude -p "$query" --output-format json 2>/dev/null \ | jq -e --arg skill "$SKILL_NAME" \ 'any(.messages[].content[]; .type == "tool_use" and .name == "Skill" and .input.skill == $skill)' \ > /dev/null 2>&1}
count=$(jq length "$QUERIES_FILE")for i in $(seq 0 $((count - 1))); do query=$(jq -r ".[$i].query" "$QUERIES_FILE") should_trigger=$(jq -r ".[$i].should_trigger" "$QUERIES_FILE") triggers=0
for run in $(seq 1 $RUNS); do check_triggered "$query" && triggers=$((triggers + 1)) done
jq -n \ --arg query "$query" \ --argjson should_trigger "$should_trigger" \ --argjson triggers "$triggers" \ --argjson runs "$RUNS" \ '{query: $query, should_trigger: $should_trigger, triggers: $triggers, runs: $runs, trigger_rate: ($triggers / $runs)}'done | jq -s '.'如果你的代理客户端支持,一旦结果明确(代理要么咨询了技能,要么开始工作而未使用它),你可以提前停止运行。这可以显著减少运行完整评估集所需的时间和成本。
5. 使用训练/验证拆分避免过拟合
如果你针对所有查询优化描述,就有过拟合的风险——编写出的描述仅适用于这些特定措辞,而在新查询上失败。
解决方案是拆分查询集:
- 训练集(约 60%):用于识别失败并指导改进的查询。
- 验证集(约 40%):留出的查询,仅用于检查改进是否具有泛化性。
确保两个集合都包含应触发和不应触发查询的适当比例——不要不小心把所有正例都放在一个集合中。随机打乱,并在各迭代中保持拆分固定,以便进行同类比较。
如果你使用类似上述的脚本,可以将查询拆分为两个文件——train_queries.json 和 validation_queries.json——并分别针对每个文件运行脚本。
6. 优化循环
- 评估当前描述在 训练集和验证集 上的表现。训练结果指导你的修改;验证结果告诉你这些修改是否具有泛化性。
- 识别失败在 训练集 中:哪些应触发查询没有触发?哪些不应触发查询触发了?
- 仅使用训练集的失败来指导修改——无论你自己修改描述还是提示 LLM,都要将验证集结果排除在流程之外。
- 修改描述。专注于泛化:
- 如果应触发查询失败,说明描述可能过于狭窄。扩大范围或添加关于技能适用场景的上下文。
- 如果不应触发查询误触发,说明描述可能过于宽泛。增加关于技能 不 做什么的特定说明,或明确此技能与相邻能力之间的边界。
- 避免添加失败查询中的具体关键词——那是过拟合。相反,找到这些查询所代表的一般类别或概念,并针对该类别进行调整。
- 如果经过几次迭代仍无进展,尝试从结构上重新构思描述,而不是增量调整。不同的表述方式或句子结构可能突破微调无法解决的问题。
- 检查描述是否保持在 1024 个字符的限制内——描述在优化过程中往往会变长。
- 重复步骤 1-3,直到所有 训练集 查询都通过,或你不再看到有意义的改进。
- 选择最佳迭代根据其验证通过率——验证集 中通过查询的比例。请注意,最佳描述可能不是你生成的最后一个;早期的迭代可能比后期过拟合到训练集的迭代具有更高的验证通过率。
五次迭代通常足够。如果性能没有提升,问题可能出在查询本身(太容易、太难或标签不佳),而非描述。
skill-creator 技能可以端到端地自动化此循环:它拆分评估集、并行评估触发率、使用 Claude 提出描述改进建议,并生成一个实时 HTML 报告供你在运行时观看。
7. 应用结果
选定最佳描述后:
- 更新
SKILL.md前置元数据中的description字段。 - 确认描述不超过 1024 字符限制。
- 验证描述能按预期触发。手动尝试几个提示作为快速健全性检查。如需更严格的测试,编写 5-10 个新查询(混合应触发和不应触发),并通过评估脚本运行——由于这些查询从未参与优化过程,它们能真实地检验描述是否具有泛化性。
修改前后:
# 修改前description: Process CSV files.
# 修改后description: > 分析 CSV 和表格数据文件——计算汇总统计量、 添加派生列、生成图表,并清理杂乱数据。当用户有 CSV、TSV 或 Excel 文件,并希望探索、转换或可视化数据时使用此技能,即使用户没有明确提到“CSV”或“分析”。改进后的描述在技能具体做什么(汇总统计、派生列、图表、清理)方面更明确,在适用场景(CSV、TSV、Excel;即使没有明确关键词)方面更宽泛。
8. 后续步骤
一旦技能能可靠触发,你就需要评估它是否能产生良好的输出。请参阅 skill 评估 ,了解如何设置测试用例、对结果进行评分和迭代。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!