mcpField
C
creating-skills

creating-skills

github.com/osmonteroAgent 工作流1590 次安装4 天前更新
代码仓库

关于 creating-skills

creating-skills 是指导 Agent 创建和改进可复用技能的指南。它将测试驱动开发用于流程文档,通过提示词测试、评估和迭代完善技能。

主要功能

  1. 01用提示词测试技能效果
  2. 02定性与定量评估结果
  3. 03依据反馈和基准迭代
  4. 04改进技能描述以优化触发

适用场景

  1. 01根据用户需求起草可复用技能
  2. 02通过评估改进现有技能
  3. 03扩展测试提示词以检查技能表现

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/osmontero/opencode-skills --skill creating-skills

安装后在 Claude Code 中输入/creating-skills确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

LICENSE.txt
render-graphs.js
assets/
eval_review.html
eval-viewer/
generate_review.py
viewer.html
examples/
AGENTS_MD_TESTING.md
references/
graphviz-conventions.dot
persuasion-principles.md
schemas.md
skill-authoring-best-practices.md
scripts/
__init__.py
aggregate_benchmark.py
generate_report.py
improve_description.py
package_skill.py
quick_validate.py
run_eval.py
run_loop.py
utils.py

详细介绍

Skill Creator

用于创建新技能并通过迭代不断改进技能的工具。

核心原则:创建技能就是将测试驱动开发应用于流程文档。 遵循 RED-GREEN-REFACTOR:先在没有技能的情况下运行基准测试(RED——观察 Agent 失败),再编写技能来解决这些问题(GREEN——观察 Agent 遵循要求),最后堵住漏洞(REFACTOR——确保持续遵循要求)。如果你没有观察过 Agent 在没有技能时失败,就不知道这项技能是否教会了正确的方法。

总体而言,创建技能的流程如下:

  • 确定你希望技能完成什么,以及大致应该如何完成
  • 编写技能草稿
  • 创建几个测试提示词,并运行能够使用该技能的 Agent 来处理这些提示词
  • 帮助用户从定性和定量两个方面评估结果
    • 在后台运行测试时,如果还没有定量评估,就起草一些;如果已有评估,可以直接使用,也可以在认为需要调整时修改。然后向用户说明这些评估;如果评估已存在,则说明现有评估
    • 使用 eval-viewer/generate_review.py 脚本向用户展示结果,供他们查看;同时也让他们查看定量指标
  • 根据用户对结果的评估反馈重写技能(如果定量基准测试中显现出明显缺陷,也要据此修改)
  • 重复上述步骤,直到你满意为止
  • 扩大测试集并再次进行测试

使用这项技能时,你的任务是判断用户处于流程的哪个阶段,并帮助他们推进。因此,假设他们说“我想为 X 创建一项技能”,你可以帮助他们明确需求、编写草稿和测试用例、确定评估方式、运行所有提示词,并重复迭代。

另一方面,如果他们已经有技能草稿,你可以直接开始评估和迭代。

当然,你应始终灵活应对。如果用户说“我不需要做一堆评估,跟我一起随便聊聊就行”,你也可以照做。

技能完成后(但顺序仍可灵活调整),你还可以运行技能描述改进工具。我们有一个单独的脚本专门用于优化技能的触发效果。

明白了吗?明白了。

什么是技能

技能是关于经实践验证的技术、模式或工具的参考指南。技能帮助后续的 Agent 实例找到并应用有效的方法。

技能包括: 可复用的技术、模式、工具和参考指南
技能不包括: 讲述你曾经如何解决某个问题的故事

技能类型
  • 技术:有明确步骤可循的方法(例如,condition-based-waiting、root-cause-tracing)
  • 模式:解决问题的思维方式(例如,flatten-with-flags、test-invariants)
  • 参考资料:API 文档、语法指南、工具文档(例如,Office 文档)
何时创建技能

适合创建的情况:

  • 这项技术对你来说并非不言自明
  • 你会在不同项目中再次参考它
  • 该模式具有广泛适用性(而非仅适用于特定项目)
  • 其他人也能从中受益

不适合创建的情况:

  • 一次性解决方案
  • 其他地方已有充分文档说明的标准实践
  • 特定于项目的约定(应放入 AGENTS.md)
  • 可通过正则表达式或验证机械化执行的约束

与用户沟通

技能创建者需要考虑到用户对编程术语的熟悉程度差异很大。如果你还没听说过这件事(这也很正常,这种趋势最近才刚出现),如今 Agent 的强大能力正激励着水管工打开终端,也让父母和祖父母去 Google 搜索“如何安装 npm”。另一方面,大多数用户可能对计算机还算熟悉。

因此,请留意上下文线索,判断应该如何表达!一般来说,给你一些参考:

  • “evaluation”和“benchmark”有些界限模糊,但可以使用
  • 对于“JSON”和“assertion”,除非用户给出明显线索,表明他们了解这些概念,否则使用时应加以解释

如果不确定,可以简要解释术语;如果不确定用户是否理解,也可以用简短的定义说明。


创建技能

捕捉意图

首先了解用户的意图。当前对话中可能已经包含用户想要捕捉的工作流(例如,他们说“把这个做成一个技能”)。如果是这样,请先从对话历史中提取答案,包括使用的工具、步骤顺序、用户提出的修正以及观察到的输入/输出格式。用户可能需要补充缺失的信息,并应在继续下一步前确认。

  1. 这个技能应该让 Agent 能够做什么?
  2. 这个技能应在什么时候触发?(用户会说什么,或出现什么情境)
  3. 预期的输出格式是什么?
  4. 是否应该设置测试用例来验证技能是否有效?对于输出可客观验证的技能(文件转换、数据提取、代码生成、固定工作流步骤),测试用例很有帮助;对于输出较主观的技能(写作风格、艺术创作),通常不需要。根据技能类型建议合适的默认做法,但让用户决定。
访谈与调研

主动询问边缘情况、输入/输出格式、示例文件、成功标准和依赖项。把这些问题弄清楚后,再编写测试提示词。

检查可用的 MCP;如果有助于调研(搜索文档、查找类似技能、了解最佳实践),则通过子 Agent 并行调研;如果没有子 Agent,则在当前流程中进行。提前准备相关背景信息,减轻用户的负担。

编写 SKILL.md

根据用户访谈,填写以下内容:

  • name:技能标识符。只能使用字母、数字和连字符。对于流程,优先使用动名词形式(动词 + -ing),例如:creating-skills、testing-skills。名称应体现你要做的事或核心要点,而不是泛泛的术语。
  • description:何时触发。这是主要的触发机制。重要:description = 何时使用,而不是技能的用途。 以“Use when...”开头,并包含具体症状、情境和上下文。使用第三人称。绝不要概述技能的流程或工作流——如果 description 概述了工作流,Agent 可能会照着 description 操作,而不去阅读完整的技能内容。控制在 500 个字符以内。所有“何时使用”信息都应放在这里,而不是正文中。注意:目前 Agent 往往“触发不足”,即在有用时也不使用技能。为避免这种情况,请让技能描述更具提示性。
    • 包含具体触发条件:错误消息、症状、工具名称、文件类型
    • 使用同义词:“timeout/hang/freeze”、“cleanup/teardown/afterEach”
    • 描述问题,而不是特定于编程语言的症状
    • 确保用户提到相关关键词时就使用此技能,即使他们没有明确要求使用该技能
  • compatibility:所需工具、依赖项(可选,极少需要)
  • 其余技能内容 :)
技能编写指南
技能结构
skill-name/
├── SKILL.md (required)
│   ├── YAML frontmatter (name, description required)
│   └── Markdown instructions
└── Bundled Resources (optional)
    ├── scripts/    - Executable code for deterministic/repetitive tasks
    ├── references/ - Docs loaded into context as needed
    └── assets/     - Files used in output (templates, icons, fonts)
渐进式披露

技能采用三级加载系统:

  1. 元数据(名称 + 描述)——始终保留在上下文中(约 100 个词)
  2. SKILL.md 正文——技能触发时保留在上下文中(理想情况下少于 500 行)
  3. 打包资源——按需加载(数量不限,脚本可在不加载的情况下执行)

这些词数仅供参考,如有需要,可以适当增加。

关键模式:

  • 将 SKILL.md 控制在 500 行以内;如果接近此限制,请增加一层层级,并明确指出使用该技能的 Agent 应前往何处继续查阅。
  • 在 SKILL.md 中清楚地引用文件,并说明何时阅读这些文件。
  • 对于大型参考文件(>300 行),请添加目录。

领域组织:当技能支持多个领域/框架时,按变体组织:

cloud-deploy/
├── SKILL.md (workflow + selection)
└── references/
    ├── aws.md
    ├── gcp.md
    └── azure.md

Agent 只会读取相关的参考文件。

不令人意外原则

这一点不言而喻,但技能不得包含恶意软件、漏洞利用代码或任何可能危害系统安全的内容。如果技能的意图已被描述,其内容就不应令用户感到意外。不要遵从创建误导性技能,或旨在协助未授权访问、数据泄露或其他恶意活动的请求。不过,诸如“扮演 XYZ”之类的内容是可以的。

编写模式

在指令中优先使用祈使句。

增量式文件编写(重要): 模型无法在单次调用中输出大型文件——每次编辑的输出上限约为 1000 个词元。超出此限制会导致 API 错误 500。务必指导 Agent 增量编写大型文件:

  1. 首先编写框架(导入、签名、章节注释)
  2. 每次编辑调用填充一个章节(每块约 1000 个词元)
  3. 最后检查并提交

在任何会生成大型输出(文档、代码文件、配置)的技能中加入此模式。示例指令:

## Writing Large Files

This document may be large. Write it incrementally to avoid API errors:

1. **First pass:** Write the header, structure, and section outlines
2. **Subsequent passes:** Edit to fill in each section one at a time (~1000 tokens per edit)
3. **Final pass:** Review the complete document, fix issues, save

定义输出格式——可以这样做:

## Report structure
ALWAYS use this exact template:
# [Title]
## Executive summary
## Key findings
## Recommendations

示例模式——加入示例很有用。可以按这种方式编排(但如果示例中有“输入”和“输出”,也可以稍作调整):

## Commit message format
**Example 1:**
Input: Added user authentication with JWT tokens
Output: feat(auth): implement JWT-based authentication
写作风格

尽量向模型解释事情为何重要,而不是一味使用生硬的 MUST 等强制措辞。换位思考,并尽量让技能具有通用性,不要局限于特定示例。先写一份草稿,再以全新的视角审阅并改进。

词元效率(重要)

上下文窗口是共享资源。SKILL.md 中的每个词元都会与对话历史和其他上下文争用空间。

目标词数:

  • 频繁加载的技能:总计少于 200 个词
  • 其他技能:少于 500 个词(仍需简洁)

技巧:

  • 默认假设 Agent 已经非常聪明。 只补充 Agent 尚不了解的上下文。逐项审视:“Agent 真的需要这段解释吗?”
  • 将细节交给工具帮助信息: 不要记录所有标志,改为引用 --help
  • 使用交叉引用: 用名称引用其他技能,而不是重复其工作流。使用 **REQUIRED SUB-SKILL:** Use skill-name 或 **REQUIRED BACKGROUND:** You MUST understand skill-name。切勿使用 @ 语法——它会立即加载文件,消耗上下文。
  • 精简示例: 一个出色的示例胜过许多平庸的示例。不要用 5 种以上的语言实现。不要创建填空模板。
  • 消除冗余: 不要重复交叉引用的技能中已有的内容。不要解释命令中一目了然的内容。不要为同一种模式提供多个示例。
  • 避免时效性信息: 不要加入可能过时的日期。对于已弃用的方法,使用“旧模式”章节。
  • 术语保持一致: 选择一个术语并始终使用。
代码示例

一个出色的示例胜过许多平庸的示例。 根据任务选择最相关的语言(测试技术 → TypeScript/JS,系统调试 → Shell/Python,数据处理 → Python)。好的示例应完整、可运行、注释清晰并解释原因,源自真实场景,且便于改编。

流程图的使用

仅在存在不明显的决策点、Agent 可能过早停止的流程循环,或“何时使用 A 而非 B”的决策时,才使用流程图(graphviz DOT 格式)。切勿将流程图用于参考资料、代码示例、线性说明或没有语义含义的标签。

请参阅 references/graphviz-conventions.dot,了解 graphviz 样式规则。使用 render-graphs.js 将流程图渲染为 SVG,供人类协作者查看:

./render-graphs.js ../some-skill           # Each diagram separately
./render-graphs.js ../some-skill --combine # All diagrams in one SVG
反模式
  • 叙事式示例(“在 2025-10-03 的会话中,我们发现……”)——过于具体,无法复用
  • 多语言稀释(example-js.js、example-py.py、example-go.go)——质量平平,维护负担重
  • 流程图中的代码——无法复制粘贴,难以阅读
  • 泛化标签(helper1、step3、pattern4)——标签应具有语义含义
  • 选项过多——除非必要,否则不要提供多种方法。提供一个默认方案,并留有备用选择。
  • 引用层级过深——将文件引用控制在距 SKILL.md 一层以内。Agent 可能只会部分阅读其他被引用文件中的引用内容。
  • Windows 风格路径——始终使用正斜杠
铁律
NO SKILL WITHOUT A FAILING TEST FIRST

这适用于新建技能,也适用于对现有技能的编辑。动笔前,先在不使用该技能的情况下运行基线场景。观察 Agent 失败,并记录其确切的合理化说辞。然后编写技能,针对这些具体失败加以解决。

没有例外:

  • 不适用于“简单的补充”
  • 不适用于“只是添加一个章节”
  • 不适用于“文档更新”
测试用例

写完技能草稿后,设计 2-3 个真实的测试提示词——即真实用户可能会说的话。与用户分享:“这里有几个我想尝试的测试用例。你觉得合适吗?还是想再添加一些?”(不必使用完全相同的措辞。)然后运行这些测试。

将测试用例保存到 evals/evals.json。暂时不要编写断言——等运行进行期间,再在下一步草拟断言。

{
  "skill_name": "example-skill",
  "evals": [
    {
      "id": 1,
      "prompt": "User's task prompt",
      "expected_output": "Description of expected result",
      "files": []
    }
  ]
}

完整架构请参阅 references/schemas.md(包括稍后添加的 assertions 字段)。

测试所有技能类型

对于专门用于强化规范执行的技能,testing-skills 技能涵盖完整的 RED-GREEN-REFACTOR 流程:编写压力场景、逐字记录合理化说辞、堵住每个漏洞的四个切入点,以及技能被阅读后仍遭违反时的元测试。

不同类型的技能需要采用不同的测试方法:

规范强化型技能(如 TDD、完成前验证等规则/要求):

  • 使用结合 3 种以上压力因素的压力场景进行测试:时间、沉没成本、权威、疲惫
  • 要求明确选择 A/B/C,而非提出开放式问题
  • 找出合理化说辞,并添加明确的反制措施
  • 成功标准:Agent 在最大压力下仍遵守规则

技术型技能(操作指南):

  • 使用应用场景和边缘情况进行测试
  • 测试说明中是否缺少信息或存在漏洞
  • 成功标准:Agent 能将该技术成功应用于新的场景

模式型技能(心智模型):

  • 测试识别能力:Agent 是否知道何时适用该模式?
  • 测试反例:Agent 是否知道何时不应使用该模式?
  • 成功标准:Agent 能正确判断何时以及如何应用该模式

参考型技能(文档/API):

  • 测试检索能力:Agent 能否找到正确的信息?
  • 测试应用能力:Agent 能否正确使用找到的信息?
  • 测试覆盖缺口:是否涵盖常见用例?
  • 成功标准:Agent 能找到并正确应用参考信息
防止合理化找借口

对于要求严守规范的技能,Agent 在压力下会寻找漏洞。明确堵住每一个漏洞:

  1. 明确否定: 不要只陈述规则,还要明确禁止具体的规避方式
  2. 合理化表格: 记录测试期间 Agent 提出的每一种借口
  3. 警示信号列表: 让 Agent 在试图合理化时能轻松自查
  4. 根本原则: 加上“违反规则的字面要求,就是违反规则的精神”,以杜绝“遵守精神还是遵守字面要求”的争论

有关权威、承诺和稀缺性原则如何提高服从度的研究,请参阅 references/persuasion-principles.md。

运行和评估测试用例

运行任何 Python 脚本之前,请先激活 opencode 虚拟环境:

source ~/.local/opencode-venv/bin/activate

本节是一段连续流程 — 不要中途停下。

将结果放在 <skill-name>-workspace/ 中,与技能目录同级。在工作区内,按迭代组织结果(iteration-1/、iteration-2/ 等),并在每个迭代目录中,为每个测试用例创建一个目录(eval-0/、eval-1/ 等)。不要预先创建所有目录 — 按需创建即可。

第 1 步:在同一轮中启动所有运行(使用技能和基线)

对于每个测试用例,在同一轮中启动两个子 Agent — 一个使用技能,一个不使用。这一点很重要:不要先启动使用技能的运行,之后再回来运行基线。一次性启动所有任务,让它们大致同时完成。

使用技能运行:

Execute this task:
- Skill path: <path-to-skill>
- Task: <eval prompt>
- Input files: <eval files if any, or "none">
- Save outputs to: <workspace>/iteration-<N>/eval-<ID>/with_skill/outputs/
- Outputs to save: <what the user cares about — e.g., "the .docx file", "the final CSV">

基线运行(使用相同提示词,但基线取决于上下文):

  • 创建新技能: 完全不使用技能。使用相同提示词,不提供技能路径,并保存到 without_skill/outputs/。
  • 改进现有技能: 使用旧版本。编辑之前,先为技能创建快照(cp -r <skill-path> <workspace>/skill-snapshot/),然后让基线子 Agent 使用该快照。保存到 old_skill/outputs/。

为每个测试用例编写一个 eval_metadata.json(断言暂时可以为空)。根据每个评估项的测试内容为其取一个描述性名称 — 不要只叫“eval-0”。目录也使用这个名称。如果本次迭代使用了新的或修改后的评估提示词,请为每个新的评估目录创建这些文件 — 不要假设它们会沿用之前迭代中的文件。

{
  "eval_id": 0,
  "eval_name": "descriptive-name-here",
  "prompt": "The user's task prompt",
  "assertions": []
}
第 2 步:运行进行期间,起草断言

不要只是等待运行完成 — 可以利用这段时间完成有用的工作。为每个测试用例起草量化断言,并向用户说明。如果 evals/evals.json 中已有断言,请检查并说明它们检查的内容。

好的断言应当可客观验证,并有描述性名称 — 在基准测试查看器中应一目了然,让快速浏览结果的人能立即理解每项断言检查的内容。对于主观技能(写作风格、设计质量),定性评估更合适 — 不要强行为需要人工判断的内容设置断言。

起草断言后,更新 eval_metadata.json 文件和 evals/evals.json。同时向用户说明他们会在查看器中看到什么 — 包括定性输出和量化基准测试。

第 3 步:运行完成后,记录计时数据

每当子 Agent 任务完成,你都会收到包含 total_tokens 和 duration_ms 的通知。立即将这些数据保存到运行目录中的 timing.json:

{
  "total_tokens": 84852,
  "duration_ms": 23332,
  "total_duration_seconds": 23.3
}

这是记录这些数据的唯一机会 — 数据通过任务通知传来,不会保存在其他位置。通知一到就立即处理,不要试图等到最后一起处理。

步骤 4:评分、汇总并启动查看器

所有运行都完成后:

  1. 为每次运行评分 — 使用 task 工具启动全局 Agent grader(或直接评分),根据输出评估每项断言。将结果保存到每个运行目录中的 grading.json。grading.json 中的 expectations 数组必须使用 text、passed 和 evidence 字段(不能使用 name/met/details 或其他变体)——查看器依赖这些确切的字段名。对于可以通过程序检查的断言,请编写并运行脚本,而不要靠目测判断——脚本速度更快、更可靠,还可以在后续迭代中重复使用。

  2. 汇总为基准测试 — 从 skill-creator 目录运行汇总脚本:

    python -m scripts.aggregate_benchmark <workspace>/iteration-N --skill-name <name>
    

    该脚本会生成 benchmark.json 和 benchmark.md,其中包含每种配置的 pass_rate、time 和 tokens,以及均值 ± 标准差和差值。如果要手动生成 benchmark.json,请参阅 references/schemas.md,了解查看器所需的确切架构。 将每个 with_skill 版本放在对应的基线版本之前。

    1. 进行分析 — 使用全局 Agent analyzer 阅读基准测试数据,找出汇总统计数据可能掩盖的规律。关注诸如无论是否使用技能都总能通过的断言(无法区分效果)、方差较大的评估(可能不稳定),以及时间和令牌数之间的权衡等情况。
  3. 启动查看器,同时提供定性输出和定量数据:

    nohup python <skill-creator-path>/eval-viewer/generate_review.py \
      <workspace>/iteration-N \
      --skill-name "my-skill" \
      --benchmark <workspace>/iteration-N/benchmark.json \
      > /dev/null 2>&1 &
    VIEWER_PID=$!
    

    对于第 2 次及之后的迭代,还要传入 --previous-workspace <workspace>/iteration-<N-1>。

    **Cowork / 无头环境:**如果 webbrowser.open() 不可用,或环境没有显示器,请使用 --static <output_path> 写入独立 HTML 文件,而不要启动服务器。用户点击“Submit All Reviews”后,反馈会以 feedback.json 文件的形式下载。下载后,将 feedback.json 复制到工作区目录,供下一次迭代读取。

    注意:请使用 generate_review.py 创建查看器;无需编写自定义 HTML。

  4. 告知用户,例如:“我已在浏览器中打开结果。页面有两个标签页——‘Outputs’ 可让你逐个查看测试用例并留下反馈,‘Benchmark’ 显示定量比较。完成后请回到这里告诉我。”

用户在查看器中看到的内容

“Outputs”标签页一次显示一个测试用例:

  • Prompt:给定的任务
  • Output:技能生成的文件;可能时会以内嵌方式呈现
  • Previous Output(第 2 次及之后的迭代):折叠区域,显示上一次迭代的输出
  • Formal Grades(如果已进行评分):折叠区域,显示断言通过/失败情况
  • Feedback:文本框,输入时会自动保存
  • Previous Feedback(第 2 次及之后的迭代):显示在文本框下方的上次评论

“Benchmark”标签页显示统计摘要:每种配置的通过率、耗时和令牌用量,另附各项评估的明细和分析员观察结果。

可通过上一个/下一个按钮或方向键进行导航。完成后,点击“Submit All Reviews”,将所有反馈保存到 feedback.json。

步骤 5:阅读反馈

用户告知已完成后,读取 feedback.json:

{
  "reviews": [
    {"run_id": "eval-0-with_skill", "feedback": "the chart is missing axis labels", "timestamp": "..."},
    {"run_id": "eval-1-with_skill", "feedback": "", "timestamp": "..."},
    {"run_id": "eval-2-with_skill", "feedback": "perfect, love this", "timestamp": "..."}
  ],
  "status": "complete"
}

反馈为空表示用户认为结果没有问题。请重点改进用户提出具体意见的测试用例。

完成后关闭查看器服务器:

kill $VIEWER_PID 2>/dev/null

停止:继续下一个技能之前

编写任何技能后,都必须停止并完成测试和部署流程。

请勿:

  • 不经测试就批量创建多个技能
  • 当前技能尚未验证就转到下一个技能
  • 以“批量处理效率更高”为由跳过测试

部署未经测试的技能,就等于部署未经测试的代码。

改进技能

这是整个循环的核心。你已运行测试用例,用户也已查看结果;现在需要根据用户的反馈改进技能。

如何思考改进方向
  1. 从反馈中总结规律。 这里的大方向是,我们要创建能被使用一百万次的技能(也许真的是一百万次,甚至更多,谁知道呢),让它们适用于许多不同的提示词。在这里,你和用户反复迭代的只是少数几个示例,因为这样推进得更快。用户对这些示例了如指掌,因此可以快速评估新输出。但如果你和用户共同开发的技能只适用于这些示例,那它就毫无用处。与其加入繁琐、过度拟合的改动,或严格到令人窒息的 MUST,不如在遇到棘手问题时尝试拓展思路,采用不同的比喻,或推荐不同的工作模式。尝试的成本相对较低,说不定就能找到很好的方案。

  2. 保持提示词精简。 删除那些没有发挥作用的内容。务必阅读对话记录,而不只是看最终输出——如果技能似乎让模型浪费大量时间做无用功,可以尝试删掉导致这种情况的技能内容,看看效果如何。

  3. 解释原因。 尽量解释清楚你要求模型做每件事的原因。如今的大模型很聪明。它们有很强的心智理论能力,在得到良好的引导后,能够超越死板地遵循指令,真正把事情办好。即使用户的反馈简短或带有挫败感,也要尽力理解任务本身、用户为什么这么写,以及他们实际写了什么,然后把这些理解融入指令中。如果你发现自己把 ALWAYS 或 NEVER 全部大写,或采用极其僵化的结构,就要留意了——如果可能,应换一种说法并解释理由,让模型明白你要求的事情为何重要。这样做更人性化、更有力,也更有效。

  4. 留意测试用例中重复出现的工作。 阅读测试运行的对话记录,看看子 Agent 是否都各自编写了类似的辅助脚本,或采用了相同的多步骤处理方式。如果 3 个测试用例都让子 Agent 编写了 create_docx.py 或 build_chart.py,这就强烈表明技能应该包含该脚本。编写一次,将它放入 scripts/,并告知技能使用它。这样一来,今后的每次调用都不必重复造轮子。

这项任务相当重要(我们正努力每年创造数十亿美元的经济价值!),而思考时间并不是瓶颈;请慢慢来,认真仔细地权衡。我建议先写一版修订草稿,然后重新审视并改进。请尽力设身处地理解用户的想法,弄清他们想要什么、需要什么。

迭代循环

改进技能后:

  1. 对技能应用改进
  2. 将所有测试用例(包括基线运行)重新运行到新的 iteration-<N+1>/ 目录中。如果你在创建新技能,基线始终是 without_skill(不使用技能)——每次迭代都保持不变。如果你在改进现有技能,基线可根据具体情况选择:用户提供的原始版本,或上一轮迭代版本。
  3. 启动审阅者,并将 --previous-workspace 指向上一轮迭代
  4. 等待用户审阅并告知你他们已完成
  5. 阅读新反馈,再次改进,然后重复以上步骤

持续迭代,直到:

  • 用户表示满意
  • 所有反馈都为空(看起来一切正常)
  • 改进已无实质进展

高级:盲测比较

如果你想更严格地比较技能的两个版本(例如,用户询问“新版本真的更好吗?”),请使用全局 Agent comparator 和 analyzer。基本思路是:将两个输出交给 comparator Agent,但不告诉它们各自对应哪个版本,让它判断质量。然后使用 analyzer Agent 分析胜出版本的原因。

此步骤是可选的,需要子 Agent,大多数用户都用不上。通常人工审核流程就足够了。


描述优化

SKILL.md 前置内容中的描述字段是决定 Agent 是否调用某项技能的主要机制。创建或改进技能后,请提出优化描述,以提高触发准确率。

步骤 1:生成触发评估查询

创建 20 条评估查询,兼有应该触发和不应该触发的情况。保存为 JSON:

[
  {"query": "the user prompt", "should_trigger": true},
  {"query": "another prompt", "should_trigger": false}
]

查询必须真实可信,且确实是 opencode 用户会输入的内容。不要写抽象请求,而要写具体、明确且包含足够细节的请求。例如,文件路径、用户工作或处境的个人背景、列名和取值、公司名称、URL。可以添加少量背景信息。有些查询可以使用小写字母、缩写、拼写错误或口语表达。查询长度要有所变化,并重点关注边缘情况,而不是一眼就能判断的情况(用户之后有机会确认)。

反例:"Format this data"、"Extract text from PDF"、"Create a chart"

正例:"ok so my boss just sent me this xlsx file (its in my downloads, called something like 'Q4 sales final FINAL v2.xlsx') and she wants me to add a column that shows the profit margin as a percentage. The revenue is in column C and costs are in column D i think"

对于应该触发的查询(8-10 条),请考虑覆盖范围。要用不同说法表达相同意图,有些正式,有些随意。要包含用户没有明确提到技能或文件类型,但显然需要该技能的情况。加入一些不常见的用例,以及该技能会与其他技能竞争但应该胜出的情况。

对于不应该触发的查询(8-10 条),最有价值的是似是而非的情况:这些查询与该技能共享关键词或概念,但实际需要的是其他功能。请考虑相邻领域、容易被简单关键词匹配误触发的模糊表述,以及查询涉及该技能能做的事、但使用其他工具更合适的情况。

最重要的是:避免让不应该触发的查询明显无关。用“编写一个斐波那契函数”作为 PDF 技能的负向测试太容易了,根本测不出什么。负向用例应该真正棘手。

步骤 2:与用户审核

使用 HTML 模板向用户展示评估集:

  1. 从 assets/eval_review.html 读取模板
  2. 替换占位符:
    • __EVAL_DATA_PLACEHOLDER__ → 评估条目组成的 JSON 数组(不要给它加引号——它是 JS 变量赋值)
    • __SKILL_NAME_PLACEHOLDER__ → 技能名称
    • __SKILL_DESCRIPTION_PLACEHOLDER__ → 技能当前的描述
  3. 写入临时文件(例如 /tmp/eval_review_<skill-name>.html),然后打开:open /tmp/eval_review_<skill-name>.html
  4. 用户可以编辑查询、切换“应该触发”状态、添加或删除条目,然后点击“Export Eval Set”
  5. 文件会下载到 ~/Downloads/eval_set.json——如果有多个文件(例如 eval_set (1).json),请检查 Downloads 文件夹,找到最新版本

此步骤很重要——评估查询质量差,会导致描述质量差。

步骤 3:运行优化循环

告诉用户:“这需要一些时间——我会在后台运行优化循环,并定期检查进度。”

将评估集保存到工作区,然后在后台运行:

python -m scripts.run_loop \
  --eval-set <path-to-trigger-eval.json> \
  --skill-path <path-to-skill> \
  --model <model-id-powering-this-session> \
  --max-iterations 5 \
  --verbose

使用系统提示词中的模型 ID(即为当前会话提供支持的模型),确保触发测试与用户实际体验相符。

运行期间,定期查看输出,为用户更新当前迭代次数和分数情况。

此流程会自动处理完整的优化循环。它会将评估集拆分为 60% 的训练集和 40% 的留出测试集,评估当前描述(每个查询运行 3 次,以获得可靠的触发率),然后调用 Agent,根据失败的情况提出改进方案。它会在训练集和测试集上重新评估每个新描述,最多迭代 5 次。完成后,它会在浏览器中打开 HTML 报告,展示每次迭代的结果,并返回包含 best_description 的 JSON——该描述根据测试分数而非训练分数选出,以避免过拟合。

技能触发机制的工作原理

了解触发机制有助于设计更好的评估查询。技能会以名称和描述的形式出现在 Agent 的 available_skills 列表中,Agent 会根据描述决定是否调用某项技能。需要注意的是,Agent 只会在无法轻松独立完成任务时才调用技能——像“读取此 PDF”这样简单且只有一步的查询,即使描述完全匹配,也可能不会触发技能,因为 Agent 可以直接使用基本工具处理这类任务。描述匹配时,复杂、多步骤或专业化的查询通常会可靠地触发技能。

因此,评估查询应当有足够的实质内容,让 Agent 确实能从调用技能中受益。像“读取文件 X”这样的简单查询不是好的测试用例——无论描述质量如何,它们都不会触发技能。

步骤 4:应用结果

从 JSON 输出中获取 best_description,并更新技能的 SKILL.md frontmatter。向用户展示修改前后的内容并报告分数。


打包并展示

检查你是否可以使用 file output 工具。如果无法使用,请跳过此步骤。如果可以使用,请打包技能并向用户提供 .skill 文件:

python -m scripts.package_skill <path/to/skill-folder>

打包后,告知用户生成的 .skill 文件路径,以便他们安装。

没有子 Agent 的环境

在没有子 Agent 的环境中,核心工作流相同(起草 → 测试 → 审查 → 改进 → 重复),但由于这些环境没有子 Agent,部分机制会有所不同。以下是需要调整的内容:

运行测试用例:没有子 Agent 就无法并行执行。对于每个测试用例,先阅读技能的 SKILL.md,然后按照其中的说明自行完成测试提示词。一次只做一个。这不如由独立子 Agent 执行严谨(你编写了技能,又要运行它,因此掌握完整上下文),但仍是一个有用的基本检查,而且人工审查步骤可以弥补这一点。跳过基准测试运行,直接使用该技能按要求完成任务。

审查结果:如果无法打开浏览器(例如,主机没有显示器,或者你在远程服务上),则完全跳过浏览器审查环节。改为直接在对话中展示结果。对于每个测试用例,展示提示词和输出。如果输出是用户需要查看的文件(例如 .docx 或 .xlsx),请将其保存到文件系统,并告知用户文件位置,以便他们下载并检查。直接询问反馈:“看起来怎么样?有什么需要修改的吗?”

基准测试:跳过定量基准测试——它依赖基准对比,在没有子 Agent 的情况下没有意义。重点收集用户的定性反馈。

迭代循环:和之前一样——改进技能、重新运行测试用例、征求反馈,只是中间不经过浏览器审查。只要有文件系统,你仍然可以将结果整理到迭代目录中。

描述优化:本节需要使用 Agent CLI 工具(具体来说是 agent CLI with prompt capability),也就是说,需要具备提示词功能的 CLI。如果你的环境中没有此工具,请跳过本节。

盲测比较:需要子 Agent。跳过。

打包:package_skill.py 脚本可在任何装有 Python 且有文件系统的环境中运行。你可以在任何地方运行它,用户可以下载生成的 .skill 文件。

更新现有技能:用户可能是让你更新现有技能,而不是创建新技能。在这种情况下:

  • 保留原名称。 记下技能的目录名称和 name frontmatter 字段,并保持不变。例如,如果安装的技能是 research-helper,则输出 research-helper.skill(而不是 research-helper-v2)。
  • 编辑前先复制到可写位置。 已安装技能的路径可能是只读的。将其复制到 /tmp/skill-name/,在该目录中编辑,并从副本打包。
  • 手动打包时,先暂存到 /tmp/,然后再复制到输出目录——直接写入可能会因权限不足而失败。

Cowork 专属说明

如果你在 Cowork 中,主要需要了解以下事项:

  • 你可以使用子 Agent,因此主要工作流(并行生成测试用例、运行基线、评分等)都能正常进行。(不过,如果遇到严重的超时问题,可以改为按顺序运行测试提示词,而不是并行运行。)
  • 你没有浏览器或显示界面,因此生成评测查看器时,请使用 --static <output_path> 写入独立的 HTML 文件,而不要启动服务器。然后提供一个链接,供用户点击并在浏览器中打开该 HTML 文件。
  • 注意:确保 Agent 在运行测试后始终生成评测查看器,再重申一次:运行测试后,应始终先生成评测查看器,让人类查看示例,然后再自行修订技能并尝试进行修正,使用 generate_review.py(不要编写自己的定制 HTML 代码)。重要:请在自行评估输入之前生成评测查看器。要尽快让人类看到这些内容!
  • 反馈的处理方式有所不同:由于没有运行中的服务器,查看器中的“Submit All Reviews”按钮会将 feedback.json 下载为文件。之后你可以读取该文件(可能需要先申请访问权限)。
  • 打包可正常使用——package_skill.py 只需要 Python 和文件系统。
  • 描述优化(run_loop.py / run_eval.py)在 Cowork 中应该也能正常运行,因为它通过子进程调用具备提示词功能的 agent CLI,而不是使用浏览器;但请等到技能完全完成且用户认可其质量后再进行。
  • 更新现有技能:用户可能是要更新现有技能,而不是创建新技能。请遵循上文 opencode 部分的更新指南。

参考 Agent

以下全局 Agent 可用于技能评估:

  • grader — 根据技能测试输出评估断言
  • comparator — 对两个技能输出进行盲测 A/B 比较
  • analyzer — 分析某个版本胜出的原因并评估模式

references/ 目录中还有其他文档:

  • references/schemas.md — evals.json、grading.json 等文件的 JSON 结构
  • references/skill-authoring-best-practices.md — Anthropic 官方编写指南:简洁性、自由度、渐进式披露、描述撰写和发布前检查清单
  • references/persuasion-principles.md — 关于为何防护性语言对约束规范的技能有效
  • references/graphviz-conventions.dot — 技能中流程图的样式规则

这里再重复一次核心循环,以便强调:

  • 弄清楚技能的用途
  • 起草或编辑技能
  • 使用可访问该技能的 Agent 运行测试提示词
  • 与用户一起评估输出:
    • 创建 benchmark.json 并运行 eval-viewer/generate_review.py,帮助用户审阅输出
    • 运行定量评测
  • 重复上述流程,直到你和用户都满意
  • 打包最终技能并交付给用户。

如果你有 TodoList,请添加相应步骤,确保不会遗漏。如果你在 Cowork 中,请特别将“创建 evals JSON 并运行 eval-viewer/generate_review.py,以便人类审阅测试用例”添加到 TodoList,确保完成。

祝你好运!

评论

支持 Markdown