Skip to main content

从真正的专业知识开始

技能创建中的一个常见陷阱是要求 LLM 生成技能却不提供特定领域的上下文——仅依赖 LLM 的通用训练知识。结果是模糊、通用的过程(“适当处理错误”、“遵循最佳身份验证实践”),而不是使技能具有价值的具体 API 模式、边缘情况和项目约定。 有效的技能植根于真正的专业知识。关键是将特定领域的上下文馈送到创建过程中。

从实际操作任务中提取

与代理对话完成实际任务,在此过程中提供上下文、修正和偏好。然后将可重用的模式提取到技能中。注意:
  • 有效的步骤 — 导致成功的动作序列
  • 你做出的修正 — 你引导代理方法的地方(例如,“使用库 X 而不是 Y”,“检查边缘情况 Z”)
  • 输入/输出格式 — 数据进入和出来时的样子
  • 你提供的上下文 — 代理尚未知道的项目特定事实、约定或约束

从现有项目工件中综合

当你拥有现有知识体系时,你可以将其馈送到 LLM 并要求它综合出一个技能。从团队实际事件报告和运行手册综合出的数据管道技能将优于从通用“数据工程最佳实践”文章综合出的技能,因为它捕捉了你的模式、故障模式和恢复过程。关键是项目特定材料,而不是通用参考。 良好的源材料包括:
  • 内部文档、运行手册和风格指南
  • API 规范、模式和配置文件
  • 代码审查评论和问题跟踪器(捕捉重复出现的关切点和审查者期望)
  • 版本控制历史,尤其是补丁和修复(通过实际变更揭示模式)
  • 现实世界的失败案例及其解决方案

通过实际执行进行优化

技能的初稿通常需要优化。针对实际任务运行技能,然后将结果——所有结果,而不仅仅是失败——反馈到创建过程中。询问:什么触发了误报?什么被遗漏了?什么可以削减? 即使只进行一次执行后修订的循环也能显著提高质量,复杂领域通常受益于多次循环。
阅读代理执行轨迹,而不仅仅是最终输出。如果代理在不产生结果的步骤上浪费时间,常见原因包括指令过于模糊(代理尝试几种方法后才找到有效的方法)、指令不适用于当前任务(代理仍然遵循它们),或者提供了太多选项而没有明确的默认值。
有关更结构化的迭代方法,包括测试用例、断言和评分,请参阅 评估技能输出质量

明智地使用上下文

一旦技能激活,其完整的 SKILL.md 主体会与对话历史、系统上下文和其他活动技能一起加载到代理的上下文窗口中。技能中的每个 token 都在与该窗口中的其他所有内容争夺代理的注意力。

添加代理缺乏的内容,省略它已知的内容

专注于代理在没有你的技能的情况下不会知道的内容:项目特定约定、特定领域过程、不明显的边缘情况,以及要使用的特定工具或 API。你不需要解释什么是 PDF、HTTP 如何工作,或数据库迁移做什么。
<!-- 过于冗长 — 代理已经知道 PDF 是什么 -->
## 提取 PDF 文本

PDF(便携式文档格式)文件是一种包含
文本、图像和其他内容的常见文件格式。要从 PDF 中提取文本,你需要
使用一个库。推荐使用 pdfplumber,因为它能很好地处理大多数情况。

<!-- 更好 — 直接切入代理独自无法知道的内容 -->
## 提取 PDF 文本

使用 pdfplumber 进行文本提取。对于扫描文档,回退到
使用 pytesseract 的 pdf2image。

```python
import pdfplumber

with pdfplumber.open("file.pdf") as pdf:
    text = pdf.pages[0].extract_text()
```
针对每部分内容问自己:“如果没有这条指令,代理会出错吗?”如果答案是否定的,就删掉它。如果你不确定,就测试它。如果代理在没有技能的情况下已经能很好地处理整个任务,那么该技能可能没有增加价值。有关如何系统地测试这一点,请参阅 评估技能输出质量

设计连贯的单元

决定技能应涵盖的内容就像决定函数应做什么:你希望它封装一个连贯的工作单元,并能与其他技能良好组合。范围过窄的技能迫使单个任务加载多个技能, risking 开销和冲突指令。范围过宽的技能变得难以精确激活。查询数据库并格式化结果的技能可能是一个连贯的单元,而同时也涵盖数据库管理的技能可能试图做得太多。

旨在适度细节

过于全面的技能弊大于利——代理难以提取相关内容,并且可能会追求由不适用于当前任务的指令触发的无效路径。简洁的、分步的指导配合工作示例往往优于详尽的文档。当你发现自己涵盖每个边缘情况时,考虑是否大多数最好由代理自己的判断来处理。

使用渐进式披露构建大型技能

规范 建议将 SKILL.md 保持在 500 行和 5,000 个 token 以下——仅需代理每次运行所需的核心指令。当技能确实需要更多内容时,将详细的参考材料移动到 references/ 或类似目录中的单独文件中。 关键是告诉代理何时加载每个文件。“如果 API 返回非 200 状态码,读取 references/api-errors.md”比通用的“详见 references/ 获取详情”更有用。这让代理按需加载上下文而不是预先加载,这正是 渐进式披露 的设计工作方式。

校准控制

并非技能的每个部分都需要相同级别的规定性。使指令的具体性与任务的脆弱性相匹配。

使具体性与脆弱性相匹配

给予代理自由,当多种方法有效且任务容许变化时。对于灵活的指令,解释为什么比僵化的指令更有效——理解指令背后目的的代理能做出更好的上下文相关决策。代码审查技能可以描述要查找的内容而不规定确切步骤:
## 代码审查过程

1. 检查所有数据库查询是否存在 SQL 注入(使用参数化查询)
2. 验证每个端点上的身份验证检查
3. 查找并发代码路径中的竞态条件
4. 确认错误消息不泄露内部细节
规定性要强,当操作脆弱、一致性很重要或必须遵循特定序列时:
## 数据库迁移

确切运行此序列:

```bash
python scripts/migrate.py --verify --backup
```

不要修改命令或添加额外标志。
大多数技能都有混合。独立校准每个部分。

提供默认值,而非菜单

当多种工具或方法可行时,选择一个默认值并简要提及替代方案,而不是将它们作为平等选项呈现。
<!-- 选项太多 -->
你可以使用 pypdf、pdfplumber、PyMuPDF 或 pdf2image...

<!-- 清晰的默认值带逃生通道 -->
使用 pdfplumber 进行文本提取:

```python
import pdfplumber
```

对于需要 OCR 的扫描 PDF,改用带有 pytesseract 的 pdf2image。

倾向于过程而非声明

技能应该教代理如何处理一类问题,而不是为特定实例生产什么。比较:
<!-- 具体答案 — 仅对此确切任务有用 -->
`customer_id` 上将 `orders` 表连接到 `customers`,过滤
`region = 'EMEA'`,并对 `amount` 列求和。

<!-- 可重用方法 — 适用于任何分析查询 -->
1.`references/schema.yaml` 读取模式以查找相关表
2. 使用 `_id` 外键约定连接表
3. 将用户请求中的任何过滤器应用为 WHERE 子句
4. 根据需要聚合数字列并格式化为 markdown 表格
这并不意味着技能不能包含具体细节——输出格式模板(参见 输出格式模板)、像“永不输出 PII”这样的约束以及特定于工具的指令都是有价值的。重点是即使个别细节是具体的,方法也应该泛化。

有效指令的模式

这些是构建技能内容的可重用技术。并非每个技能都需要所有这些——使用适合你任务的技术。

陷阱部分

许多技能中价值最高的内容是一列陷阱——违背合理假设的特定于环境的事实。这些不是一般性建议(“适当处理错误”),而是对代理在不被告知的情况下会犯的错误的具体纠正:
## 陷阱

- `users` 表使用软删除。查询必须包括
  `WHERE deleted_at IS NULL`,否则结果将包含已停用的账户。
- 用户 ID 在数据库中是 `user_id`,在 auth 服务中是 `uid`
  在 billing API 中是 `accountId`。这三者指代相同的值。
- 只要 Web 服务器运行,`/health` 端点就返回 200,
  即使数据库连接断开。使用 `/ready` 检查完整
  服务健康状态。
将陷阱保留在 SKILL.md 中,代理在遇到情况之前会阅读它们。如果你告诉代理何时加载它,单独的参考文件也可以,但对于不明显的问题,代理可能无法识别触发器。
当代理犯了你必须纠正的错误时,将纠正内容添加到陷阱部分。这是迭代改进技能最直接的方法之一(参见 通过实际执行进行优化)。

输出格式模板

当你需要代理以特定格式生成输出时,提供模板。这比用散文描述格式更可靠,因为代理能很好地对具体结构进行模式匹配。短模板可以内联生活在 SKILL.md 中;对于较长的模板,或仅在某些情况下需要的模板,将它们存储在 assets/ 中并从 SKILL.md 引用,以便它们仅在需要时加载。
## 报告结构

使用此模板,根据具体分析需要调整部分:

```markdown
# [分析标题]

## 执行摘要
[关键发现的单段概述]

## 关键发现
- 发现 1 附带支持数据
- 发现 2 附带支持数据

## 建议
1. 具体可操作的建议
2. 具体可操作的建议
```

多步骤工作流的清单

明确的清单帮助代理跟踪进度并避免跳过步骤,特别是当步骤有依赖关系或验证门时。
## 表单处理工作流

进度:
- [ ] 步骤 1:分析表单(运行 `scripts/analyze_form.py`
- [ ] 步骤 2:创建字段映射(编辑 `fields.json`
- [ ] 步骤 3:验证映射(运行 `scripts/validate_fields.py`
- [ ] 步骤 4:填充表单(运行 `scripts/fill_form.py`
- [ ] 步骤 5:验证输出(运行 `scripts/verify_output.py`

验证循环

指示代理在继续之前验证自己的工作。模式是:开展工作,运行验证器(脚本、参考清单或自我检查),修复任何问题,并重复直到验证通过。
## 编辑工作流

1. 进行编辑
2. 运行验证:`python scripts/validate.py output/`
3. 如果验证失败:
   - 审查错误消息
   - 修复问题
   - 再次运行验证
4. 仅在验证通过时继续
参考文档也可以作为“验证器”——指示代理在最终确定之前对照参考检查其工作。

计划 - 验证 - 执行

对于批量或破坏性操作,让代理以结构化格式创建中间计划,对照真实来源验证,然后才执行。
## PDF 表单填充

1. 提取表单字段:`python scripts/analyze_form.py input.pdf``form_fields.json`
   (列出每个字段名称、类型以及是否必填)
2. 创建 `field_values.json` 将每个字段名称映射到其预期值
3. 验证:`python scripts/validate_fields.py form_fields.json field_values.json`
   (检查每个字段名称是否存在于表单中,类型是否兼容,以及
   必填字段是否缺失)
4. 如果验证失败,修订 `field_values.json` 并重新验证
5. 填充表单:`python scripts/fill_form.py input.pdf field_values.json output.pdf`
关键成分是步骤 3:一个验证脚本,对照真实来源(form_fields.json)检查计划(field_values.json)。像“字段 ‘signature_date’ 未找到 — 可用字段:customer_name, order_total, signature_date_signed”这样的错误能为代理提供足够的信息进行自我纠正。

捆绑可重用脚本

迭代技能 时,比较测试用例之间的代理执行轨迹。如果你注意到代理每次运行都独立地重新发明相同的逻辑——构建图表、解析特定格式、验证输出——那是一个信号,表明应该编写一个经过测试的脚本一次并将其捆绑在 scripts/ 中。 有关设计和捆绑脚本的更多信息,请参阅 在技能中使用脚本

后续步骤

一旦你拥有了一个可用的技能,两份指南可以帮助你进一步完善它: