AI智能体技能开发:结构化指令与工程化实践指南
在人工智能领域,智能体(Agent)通过执行特定任务来扩展其能力,而技能(Skill)是实现这一目标的核心模块。技能的本质是一套结构化指令集,它遵循明确的工程化规范,确保智能体能够精确理解并高效执行复杂操作。其技术价值在于解决了传统自然语言指令的模糊性,通过渐进式披露(Progressive Disclosure)和上下文管理(Context Management)机制,显著提升任务执行的可靠性和
1. 项目概述:为AI智能体编写高质量技能的最佳实践
如果你正在为Claude、GPTs或其他AI智能体开发技能(Skills),你很可能已经发现,让一个智能体稳定、可靠地执行复杂任务,远比写一段简单的提示词要困难得多。智能体技能的本质,是创建一套能被AI精确理解、高效执行的“操作手册”或“工作流”。这不仅仅是写文档,更是设计一套与AI思维模式相匹配的交互协议。
我最近深度实践了基于 mgechev/skills-best-practices 这套方法论,它彻底改变了我对智能体技能开发的认知。过去,我们习惯于编写冗长的、面向人类的说明文档,然后期望AI能“读懂”并执行。结果往往是智能体要么遗漏关键步骤,要么在上下文窗口耗尽时“失忆”,或者因为指令模糊而“幻觉”出错误的操作。这套最佳实践的核心,正是为了解决这些问题:它通过一套严谨的工程化规范,确保技能 可发现、可执行、可维护 ,并且能 极致节省宝贵的上下文令牌(Tokens) 。
简单来说,它教你如何将模糊的需求,转化为智能体能精准“点击”的按钮,并将复杂的操作流程,拆解成智能体能一步步“踩准”的脚印。无论你是为团队内部构建自动化助手,还是开发面向用户的智能体应用,掌握这套方法都能让你的智能体从“玩具”升级为“工具”。接下来,我将结合自身实践,为你拆解这套最佳实践的每一个核心环节。
2. 技能结构与设计哲学:从“文档”到“可执行蓝图”
传统的API文档或操作手册是给人看的,人们可以跳跃阅读、联系上下文、进行推理。但AI智能体,特别是基于大语言模型的智能体,其“阅读”和理解方式有本质不同。它们严重依赖清晰、无歧义的结构化指令,并且受限于上下文窗口的大小。因此,技能的设计必须遵循一套全新的范式。
2.1 核心目录结构:像组织代码一样组织技能
一个专业的技能,其文件结构必须是标准化和最小化的。这不仅是出于整洁,更是为了引导智能体高效地加载和检索信息。强制性的结构如下:
my-angular-migrator/
├── SKILL.md # 【大脑】元数据与核心指令(<500行)
├── scripts/ # 【双手】可执行代码(Python/Bash),设计为微型CLI
├── references/ # 【参考资料】补充上下文(API文档、备忘单)
└── assets/ # 【素材库】输出模板或静态文件
每个目录都有其不可替代的使命:
- SKILL.md :这是技能的“大脑”和入口。它不包含细节,只提供最高层的导航和决策逻辑。想象成项目经理的甘特图,只说明“何时做什么”,不说明“具体怎么做”。
- scripts/ :这里是技能的“双手”。只存放用于处理 确定性、重复性且易出错 任务的微型脚本。例如,解析一个特定格式的配置文件、执行一组复杂的正则表达式替换、或调用一个带有特定参数的CLI命令。关键原则是: 一个脚本只做一件事,并通过标准输出(stdout)和错误输出(stderr)与智能体通信 。绝对不要在这里放库代码或业务逻辑。
- references/ :这是技能的“参考资料库”。用于存放智能体在执行过程中可能需要查阅的详细信息,例如完整的API模式(Schema)、错误代码列表、第三方工具的配置选项说明等。这些信息不应该堵塞主指令流。
- assets/ :这是技能的“素材库”。用于存放生成最终输出所需的模板,例如一个配置文件的Jinja2模板、一个JSON响应的结构示例,或者一张系统架构图。
实操心得 :在初期,很容易想把所有东西都堆进
SKILL.md。一个有效的检查方法是:问自己“智能体在执行第一步时,需要知道第三步的细节吗?”如果答案是否定的,就把那些细节移到references/或assets/中。这能立竿见影地减少主文件的令牌消耗。
2.2 渐进式披露与上下文管理
这是本套实践中最关键的设计模式,直接决定了技能的效率和可靠性。核心思想是: 智能体只有在需要时,才去加载具体信息 。你不能让智能体像人类一样“扫一眼”全部资料,你必须明确地告诉它:“现在,请去读取 references/error-codes.md 文件以了解错误处理逻辑。”
如何实现?
- 保持SKILL.md的精简 :严格将其行数控制在500行以内。它应该是一系列高级命令的集合,例如:“1. 验证项目结构。2. 执行迁移脚本。3. 根据模板生成新配置。”
- 使用扁平化的子目录 :
references/、scripts/、assets/下的所有文件都应只有一层深度。禁止出现references/database/v1/schema.md这样的嵌套。这简化了智能体的路径解析逻辑。 - 在指令中明确引用 :在
SKILL.md中,当需要细节时,使用精确的相对路径进行指令。例如:“若遇到‘模块未找到’错误,请查阅references/common-js-resolution.md中的解决方案。” 智能体不会自动加载这些文件,直到它收到这条明确的指令。 - 统一的路径格式 :始终使用 正斜杠(/) 和相对路径,无论底层操作系统是什么。这保证了指令在不同环境中的一致性。
2.3 编写面向智能体的指令,而非人类
这是思维模式的根本转变。你需要用智能体能最优解的方式与它沟通。
- 使用逐步编号的指令 :将工作流定义为严格的、按时间顺序排列的步骤序列。如果存在条件分支,必须清晰地映射出来。
- 差 :“你可以尝试构建项目,如果需要调试,记得生成source map。”
- 优 :“步骤3:构建项目。执行命令
npm run build。 子步骤3.1 :如果用户需要调试,则附加--source-map参数。否则,继续执行步骤4。”
- 提供具体模板,而非描述 :智能体极其擅长模式匹配。不要用段落描述一个JSON应该长什么样,而是在
assets/中放一个response-template.json文件,然后在指令中说:“请严格按照assets/response-template.json的结构组织你的输出。” - 使用第三人称祈使句 :以给智能体直接下达命令的方式写作。
- 差 :“我会提取用户ID。”(这是第一人称自述)
- 差 :“你应该提取用户ID。”(这是建议)
- 优 :“提取请求头中的‘X-User-ID’字段。”(这是明确的命令)
- 保持术语一致性 :在整个技能文件中,对同一概念使用完全相同的术语。例如,在Angular技能中,始终使用“模板”(template),而不是混用“HTML”、“标记”(markup)或“视图”(view)。不一致的术语会混淆智能体。
3. 元数据优化:让智能体“发现”你的技能
智能体在决定是否调用一个技能时,最初只能看到 SKILL.md 文件中的YAML Frontmatter(通常是 name 和 description 字段)。如果这两个字段没写好,你的技能对智能体来说就是“隐形”的。
3.1 严格的命名规范
name 字段并非随意填写,它必须遵循机器可读的严格约定:
- 长度 :1-64个字符。
- 字符 :只能包含小写字母、数字和连字符(-)。
- 格式 :不允许连续的两个连字符(如
my--skill)。 - 关键约束 :
name字段的值 必须 与技能所在的父目录名 完全一致 。例如,如果name是angular-vite-migrator,那么这个技能文件必须位于angular-vite-migrator/SKILL.md。这是许多技能加载器的工作机制,违反会导致技能无法被识别。
3.2 编写触发优化的描述
description 字段是你唯一的“广告位”,必须在最多1024个字符内完成两件事: 准确吸引正确的请求,明确拒绝错误的请求 。
- 用第三人称描述能力 :以“该技能…”或直接描述功能开头。
- 包含“负面触发器” :明确说明在什么情况下 不应 使用此技能。这是避免技能误触发的关键。
| 描述示例 | 评价与解析 |
|---|---|
| 差: “处理React相关任务。” | 过于模糊 。智能体无法判断这是创建组件、修复bug还是优化性能。几乎任何涉及React的请求都可能误触发。 |
| 中: “使用Tailwind CSS创建React组件。” | 有所改进 ,指明了技术和范围,但依然缺少边界。如果用户想修改一个现有组件的逻辑(而非样式),该触发吗? |
| 优: “使用Tailwind CSS创建新的React函数式组件。当用户请求构建UI界面、添加新的可视化元素时使用。 不要 将其用于修改现有组件的业务逻辑、处理Vue/Svelte项目,或编写纯CSS。” | 优秀 。清晰说明了能力(创建)、技术栈(React, Tailwind CSS)、正面触发场景(构建UI)。更重要的是,明确排除了修改逻辑、其他框架等场景,极大减少了误判。 |
注意事项 :撰写描述时,要站在智能体路由决策的角度思考。智能体看到的是一堆技能的描述列表和一个用户问题,它必须快速做字符串匹配和意图理解。你的描述越像一组精准的关键词过滤器,路由就越准确。
4. 技能验证实战:与LLM协作进行质量保障
技能是给AI用的,因此最好的测试工具也是AI。你不能只写完了事,必须通过系统性的验证来确保技能指令清晰、无歧义,并能优雅处理边界情况。以下是我在实践中总结的四步验证法。
4.1 第一步:发现性验证——测试技能路由
目标:确保你的技能元数据(名称和描述)能精准匹配目标请求,并避免误触发。
操作方法:
- 新建一个与你的技能完全无关的LLM对话会话(避免上下文干扰)。
- 粘贴以下验证提示词,并替换其中的元数据为你自己的技能信息:
我正基于 agentskills.io 规范构建一个智能体技能。智能体将完全根据下面的YAML元数据来决定是否加载此技能。
name: [你的技能名称,例如:angular-vite-migrator] description: [你的技能描述全文]
请严格基于此描述:
1. 生成3个你100%确信**应该**触发此技能的真实用户提示。
2. 生成3个听起来相似但**绝对不应该**触发此技能的用户提示(例如,用于其他技术栈的类似任务)。
3. 批判性评价这个描述:它是否过于宽泛或模糊?请提供一个优化后的改写建议。
分析LLM的反馈:
- 如果LLM生成的“应该触发”的提示与你预期不符,说明描述不够准确。
- 如果LLG生成的“不应触发”的提示看起来也很合理,说明你的描述缺乏足够的排除性语句(负面触发器),需要加强边界定义。
4.2 第二步:逻辑验证——模拟智能体执行
目标:确保 SKILL.md 中的核心指令是确定性的,没有缺失的步骤或模糊的指令,导致智能体需要“脑补”。
操作方法:
- 将你的整个技能目录结构(树状图)和
SKILL.md的完整内容准备好。 - 在新的LLM会话中,输入以下提示词:
以下是我的 SKILL.md 完整草案及其支持文件的目录结构。
[这里粘贴你的目录树,例如: ├── SKILL.md ├── scripts/migrate.py └── assets/config-template.yaml
[这里完整粘贴你的 SKILL.md 内容]
请你扮演一个刚刚触发此技能的自主智能体。模拟你基于一个具体用户请求(例如:“请将我的Spring Boot项目从Java 11升级到Java 17”)逐步执行的过程。
对于每一步,请写出你的内心独白:
1. 你具体要做什么?
2. 你正在读取或运行哪个具体的文件/脚本?
3. **标记任何执行阻碍**:指出指令中模糊、缺失,迫使你不得不猜测或“幻觉”内容的确切行号及原因(例如:“第15行提到‘更新配置文件’,但未指明是 `application.properties` 还是 `application.yml`,也未提供模板位置”)。
分析执行模拟报告: 重点关注LLM指出的“执行阻碍”。每一个阻碍点都是一个潜在的故障点。你需要根据这些反馈,回头补充缺失的信息、澄清模糊的指令,或将复杂的操作封装到 scripts/ 下的确定性的脚本中。
4.3 第三步:边界情况测试——主动攻击你的设计
目标:主动发现技能在异常、边缘情况或非标准环境下的脆弱点。
操作方法: 在逻辑验证之后,要求LLM转换角色:
现在,请切换角色。扮演一个苛刻的质量测试员。你的目标是“攻破”这个技能。
请向我提出3到5个非常具体、具有挑战性的问题,关于 SKILL.md 中可能存在的边界情况、失败状态或缺失的回退方案。重点关注:
* 如果 `scripts/` 下的某个脚本因为环境依赖缺失而失败,技能流程如何应对?
* 如果用户的输入项目结构不符合技能预设的“标准模板”(例如,有一个非标准的目录布局),技能会如何反应?
* 我的指令中是否隐含了对用户环境(如特定版本的工具)的假设?
请只提出这些编号的问题,暂时不要修复它们,等待我的回答。
LLM通常会从你意想不到的角度提出问题,例如:
- “如果用户的
package.json中锁定了某个过时且有安全漏洞的依赖版本,迁移脚本是强制升级还是保持原样?这个决策点在哪里定义?” - “当
scripts/validator.py运行时,如果网络超时,脚本是返回一个非零退出码,还是输出一段错误文本?SKILL.md 中是否有对应此错误码或文本的错误处理分支?” - “技能假设项目使用Git进行版本控制。如果用户的项目是一个未初始化的Git仓库,甚至使用SVN,指令中‘提交更改’的步骤会失败吗?”
4.4 第四步:架构重构——应用修复并优化
目标:根据前三步的反馈,重构你的技能,强化其健壮性并进一步优化令牌使用。
操作方法: 在回答了边界测试的问题后,给LLM最终的整合指令:
基于我对你边界测试问题的回答,请重写 SKILL.md 文件,并严格遵循渐进式披露设计模式:
1. 保持主 `SKILL.md` strictly 作为一套高级步骤集,使用第三人称祈使句命令(例如:“执行验证脚本”,“读取配置模板”)。
2. 如果当前文件中有密集的规则、大型配置模板或复杂模式,请将它们移除。告诉我应在 `references/` 或 `assets/` 中创建哪个新文件,并在 `SKILL.md` 中用严格的命令(仅在需要时)替换为指向该文件的引用。
3. 在底部添加一个专门的“错误处理”章节,融入我之前关于脚本失败回退和异常配置处理的回答。
通过这个四步循环,你可以与LLM形成高效的“结对编程”关系,利用其强大的推理和场景生成能力,来查漏补缺,最终打磨出一个真正健壮、可用的生产级技能。
5. 脚本编写与错误处理:构建技能的可靠“双手”
scripts/ 目录中的代码是技能确定性的基石。这里的脚本不是完整的应用程序,而是专为智能体定制的、单一目的的微型命令行工具。
5.1 脚本设计原则
- 单一职责 :一个脚本只完成一个明确的任务。例如,
validate-structure.py只检查项目目录是否合规,generate-config.py只负责根据模板和输入生成最终配置文件。 - 完整的CLI接口 :脚本应该通过命令行参数(
argparsefor Python,process.argvfor Node)接收输入,并通过标准输出(stdout)返回结果。这符合智能体与子进程交互的模式。 - 无状态与幂等性 :理想情况下,脚本运行不应依赖外部状态,并且多次运行同一命令应产生相同的结果。
- 丰富的输出 :脚本不仅是执行者,也是诊断工具。输出应结构化、易读。
一个反面例子(糟糕的脚本):
#!/bin/bash
# 糟糕的脚本:逻辑混杂,输出不清晰
if [ -f “package.json” ]; then
npm install
npm run build
echo “done”
else
echo “no package.json”
fi
问题 :将安装依赖和构建两个步骤耦合;成功时只输出“done”,失败信息不明确;没有提供任何中间状态或错误码。
一个正面例子(良好的脚本):
#!/usr/bin/env python3
import json, sys, subprocess, os
import argparse
def main():
parser = argparse.ArgumentParser(description=”验证并构建Node项目。”)
parser.add_argument(‘—skip-install’, action=’store_true’, help=’跳过npm install步骤’)
args = parser.parse_args()
# 1. 检查核心文件
if not os.path.exists(‘package.json’):
print(json.dumps({“status”: “error”, “code”: “FILE_MISSING”, “message”: “未找到 package.json 文件”}))
sys.exit(1)
# 2. 可选安装依赖
if not args.skip_install:
print(json.dumps({“status”: “info”, “message”: “正在安装依赖…”}))
result = subprocess.run([‘npm’, ‘install’], capture_output=True, text=True)
if result.returncode != 0:
print(json.dumps({“status”: “error”, “code”: “INSTALL_FAILED”, “details”: result.stderr}))
sys.exit(result.returncode)
# 3. 执行构建
print(json.dumps({“status”: “info”, “message”: “开始构建项目…”}))
result = subprocess.run([‘npm’, ‘run’, ‘build’], capture_output=True, text=True)
if result.returncode == 0:
print(json.dumps({“status”: “success”, “message”: “项目构建成功。”, “output”: result.stdout}))
else:
print(json.dumps({“status”: “error”, “code”: “BUILD_FAILED”, “details”: result.stderr}))
sys.exit(result.returncode)
if __name__ == “__main__”:
main()
优点 :
- 清晰的CLI参数 :支持
--skip-install。 - 结构化JSON输出 :智能体可以轻松解析
status,code,message,details字段。 - 明确的错误码 :
FILE_MISSING,INSTALL_FAILED,BUILD_FAILED,方便在SKILL.md中做条件分支处理。 - 遵循Unix惯例 :成功退出码为0,失败为非0。
5.2 在技能中集成错误处理
在 SKILL.md 中,你不能假设脚本永远成功。必须设计完整的错误处理流程。
在SKILL.md中的错误处理章节示例:
## 错误处理与故障排除
执行本技能时,如遇问题,请按以下流程诊断:
1. **脚本执行失败**:
* **现象**:`scripts/` 下的脚本返回非零退出码或输出中包含 `”status”: “error”`。
* **操作**:读取脚本输出的 `code` 和 `details` 字段。
* **分支判断**:
* 若 `code` 为 `FILE_MISSING`:请确认用户当前目录是否正确,并提示用户提供有效的项目路径。
* 若 `code` 为 `DEPENDENCY_CONFLICT`:请查阅 `references/dependency-resolution.md` 中的冲突解决指南,并尝试建议的解决方案。
* 若 `code` 为 `NETWORK_TIMEOUT`:请提示用户检查网络连接,并询问是否重试或使用离线模式(如果支持)。
2. **用户输入不符合预期**:
* **现象**:技能要求的输入参数缺失或格式错误。
* **操作**:立即停止当前步骤,向用户清晰说明缺失的信息或格式要求,并引用 `references/input-schema.md` 中的示例。
3. **环境不兼容**:
* **现象**:脚本或指令中隐含的工具(如 `node >= 18`, `python3`)未安装或版本过低。
* **操作**:在执行关键步骤前,先运行 `scripts/env-checker.py` 进行环境预检。如不满足,优先引导用户解决环境问题。
通过将错误逻辑从模糊的自然语言描述,转化为基于明确错误码和条件分支的指令,你极大地提升了智能体处理异常情况的能力,使其行为更加可预测和可靠。
6. 从理论到实践:一个完整的技能构建案例
让我们以一个具体的例子——“将Angular项目从Karma迁移到Jest测试框架”——来串联以上所有原则。
6.1 第一步:项目初始化与元数据定义
首先,创建技能目录并编写 SKILL.md 的Frontmatter。
目录结构:
angular-karma-to-jest-migrator/
├── SKILL.md
├── scripts/
│ ├── check-angular-version.py
│ └── migrate-test-files.js
├── references/
│ ├── jest-config-options.md
│ └── karma-jest-api-mapping.md
└── assets/
└── jest.config.js.template
SKILL.md 开头部分:
name: angular-karma-to-jest-migrator
description: “将Angular CLI项目从Karma单元测试框架迁移到Jest框架。当用户希望更新测试运行器、获得更快的测试速度、或使用Jest的现代特性(如快照测试)时使用。不要将其用于非Angular项目、端到端(E2E)测试迁移(应使用Cypress或Playwright),或仅仅是为了安装Jest而不移除Karma。”
6.2 第二步:编写核心指令(SKILL.md主体)
遵循渐进式披露原则,主文件只包含导航和决策逻辑。
## 迁移执行流程
1. **环境与项目验证**
* 执行 `scripts/check-angular-version.py` 以确认项目使用Angular CLI版本 >= 12(Jest builder的推荐版本)。
* 检查 `angular.json` 中是否已存在 `”test”` 构建器配置为 `”@angular-devkit/build-angular:karma”`。
2. **安装Jest依赖**
* 运行命令:`npm install --save-dev jest jest-preset-angular @types/jest`。
* 运行命令:`npm uninstall karma karma-chrome-launcher karma-jasmine karma-jasmine-html-reporter @types/jasmine @types/jasminewd2 jasmine-core jasmine-spec-reporter`。
3. **更新Angular配置**
* 将 `angular.json` 中 `projects.[project-name].architect.test` 下的 `builder` 字段从 `”@angular-devkit/build-angular:karma”` 替换为 `”@angular-devkit/build-angular:jest”`。
* 删除与Karma相关的 `options`(如 `karmaConfig`),并根据 `assets/jest.config.js.template` 创建或更新项目根目录下的 `jest.config.js` 文件。**注意**:详细配置选项请参阅 `references/jest-config-options.md`。
4. **迁移测试文件语法**
* 对于 `src/` 目录下的每个 `.spec.ts` 文件,执行 `scripts/migrate-test-files.js [file-path]`。
* 此脚本将处理常见语法转换,例如:
* 将 `beforeEach(() => { … })` 的导入和用法调整为Jest风格。
* 将 `it(‘should …’, async(() => { … }))` 转换为 `it(‘should …’, async () => { … })`。
* **更多API映射规则**,请查阅 `references/karma-jest-api-mapping.md`。
5. **验证与运行**
* 运行 `npm test` 以执行测试。
* 检查控制台输出,确保所有测试通过。如有失败,请根据错误信息对照 `references/karma-jest-api-mapping.md` 进行调试。
6.3 第三步:创建支持文件
-
scripts/check-angular-version.py:解析package.json,检查@angular/cli版本,并以JSON格式输出结果和提示。 -
scripts/migrate-test-files.js:接收文件路径参数,使用AST(抽象语法树)或安全的正则表达式,进行精确的语法替换。 -
references/jest-config-options.md:详细列出jest.config.js中所有适用于Angular的配置项及其说明。 -
references/karma-jest-api-mapping.md:一个对照表,列出Karma/Jasmine API到Jest API的等价替换(如spyOn->jest.spyOn,expect(x).toBeTruthy()->expect(x).toBeTruthy()(相同,但注意细微差别))。 -
assets/jest.config.js.template:一个预设好的、针对Angular项目优化的Jest配置模板。
6.4 第四步:进行四步验证
- 发现性验证 :用LLM测试上述
description,确保“将Vue项目的测试从Mocha移到Jest”这样的提示不会误触发。 - 逻辑验证 :让LLM模拟执行,看它是否会卡在“如何更新
angular.json”的具体细节上(我们已通过引用模板解决),或对migrate-test-files.js的具体转换规则感到困惑(我们已通过引用api-mapping.md解决)。 - 边界测试 :让LLM提问:“如果用户的测试中使用了Karma特有的
require.context来动态加载文件,Jest不支持怎么办?” 这提示我们需要在references/中补充关于Jestrequire.context替代方案的说明,或在脚本中增加对此情况的检测和提示。 - 架构重构 :根据边界测试的反馈,我们可能需要在
SKILL.md的“错误处理”部分增加一条:“如果脚本检测到无法自动迁移的Karma特定语法,请输出警告并指引用户手动修改,参考references/advanced-migration.md”。
通过这样一个完整的案例,你可以看到所有最佳实践如何有机地结合在一起,形成一个清晰、健壮、易于维护的技能模块。这不仅仅是写文档,更是一种为AI时代设计人机协作接口的工程方法。
更多推荐




所有评论(0)