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 文件以了解错误处理逻辑。”

如何实现?

  1. 保持SKILL.md的精简 :严格将其行数控制在500行以内。它应该是一系列高级命令的集合,例如:“1. 验证项目结构。2. 执行迁移脚本。3. 根据模板生成新配置。”
  2. 使用扁平化的子目录 references/ scripts/ assets/ 下的所有文件都应只有一层深度。禁止出现 references/database/v1/schema.md 这样的嵌套。这简化了智能体的路径解析逻辑。
  3. 在指令中明确引用 :在 SKILL.md 中,当需要细节时,使用精确的相对路径进行指令。例如:“若遇到‘模块未找到’错误,请查阅 references/common-js-resolution.md 中的解决方案。” 智能体不会自动加载这些文件,直到它收到这条明确的指令。
  4. 统一的路径格式 :始终使用 正斜杠(/) 和相对路径,无论底层操作系统是什么。这保证了指令在不同环境中的一致性。

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 第一步:发现性验证——测试技能路由

目标:确保你的技能元数据(名称和描述)能精准匹配目标请求,并避免误触发。

操作方法:

  1. 新建一个与你的技能完全无关的LLM对话会话(避免上下文干扰)。
  2. 粘贴以下验证提示词,并替换其中的元数据为你自己的技能信息:
我正基于 agentskills.io 规范构建一个智能体技能。智能体将完全根据下面的YAML元数据来决定是否加载此技能。

name: [你的技能名称,例如:angular-vite-migrator] description: [你的技能描述全文]


请严格基于此描述:
1.  生成3个你100%确信**应该**触发此技能的真实用户提示。
2.  生成3个听起来相似但**绝对不应该**触发此技能的用户提示(例如,用于其他技术栈的类似任务)。
3.  批判性评价这个描述:它是否过于宽泛或模糊?请提供一个优化后的改写建议。

分析LLM的反馈:

  • 如果LLM生成的“应该触发”的提示与你预期不符,说明描述不够准确。
  • 如果LLG生成的“不应触发”的提示看起来也很合理,说明你的描述缺乏足够的排除性语句(负面触发器),需要加强边界定义。

4.2 第二步:逻辑验证——模拟智能体执行

目标:确保 SKILL.md 中的核心指令是确定性的,没有缺失的步骤或模糊的指令,导致智能体需要“脑补”。

操作方法:

  1. 将你的整个技能目录结构(树状图)和 SKILL.md 的完整内容准备好。
  2. 在新的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通常会从你意想不到的角度提出问题,例如:

  1. “如果用户的 package.json 中锁定了某个过时且有安全漏洞的依赖版本,迁移脚本是强制升级还是保持原样?这个决策点在哪里定义?”
  2. “当 scripts/validator.py 运行时,如果网络超时,脚本是返回一个非零退出码,还是输出一段错误文本?SKILL.md 中是否有对应此错误码或文本的错误处理分支?”
  3. “技能假设项目使用Git进行版本控制。如果用户的项目是一个未初始化的Git仓库,甚至使用SVN,指令中‘提交更改’的步骤会失败吗?”

4.4 第四步:架构重构——应用修复并优化

目标:根据前三步的反馈,重构你的技能,强化其健壮性并进一步优化令牌使用。

操作方法: 在回答了边界测试的问题后,给LLM最终的整合指令:

基于我对你边界测试问题的回答,请重写 SKILL.md 文件,并严格遵循渐进式披露设计模式:
1.  保持主 `SKILL.md`  strictly 作为一套高级步骤集,使用第三人称祈使句命令(例如:“执行验证脚本”,“读取配置模板”)。
2.  如果当前文件中有密集的规则、大型配置模板或复杂模式,请将它们移除。告诉我应在 `references/` 或 `assets/` 中创建哪个新文件,并在 `SKILL.md` 中用严格的命令(仅在需要时)替换为指向该文件的引用。
3.  在底部添加一个专门的“错误处理”章节,融入我之前关于脚本失败回退和异常配置处理的回答。

通过这个四步循环,你可以与LLM形成高效的“结对编程”关系,利用其强大的推理和场景生成能力,来查漏补缺,最终打磨出一个真正健壮、可用的生产级技能。

5. 脚本编写与错误处理:构建技能的可靠“双手”

scripts/ 目录中的代码是技能确定性的基石。这里的脚本不是完整的应用程序,而是专为智能体定制的、单一目的的微型命令行工具。

5.1 脚本设计原则

  1. 单一职责 :一个脚本只完成一个明确的任务。例如, validate-structure.py 只检查项目目录是否合规, generate-config.py 只负责根据模板和输入生成最终配置文件。
  2. 完整的CLI接口 :脚本应该通过命令行参数( argparse for Python, process.argv for Node)接收输入,并通过标准输出(stdout)返回结果。这符合智能体与子进程交互的模式。
  3. 无状态与幂等性 :理想情况下,脚本运行不应依赖外部状态,并且多次运行同一命令应产生相同的结果。
  4. 丰富的输出 :脚本不仅是执行者,也是诊断工具。输出应结构化、易读。

一个反面例子(糟糕的脚本):

#!/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 第四步:进行四步验证

  1. 发现性验证 :用LLM测试上述 description ,确保“将Vue项目的测试从Mocha移到Jest”这样的提示不会误触发。
  2. 逻辑验证 :让LLM模拟执行,看它是否会卡在“如何更新 angular.json ”的具体细节上(我们已通过引用模板解决),或对 migrate-test-files.js 的具体转换规则感到困惑(我们已通过引用 api-mapping.md 解决)。
  3. 边界测试 :让LLM提问:“如果用户的测试中使用了Karma特有的 require.context 来动态加载文件,Jest不支持怎么办?” 这提示我们需要在 references/ 中补充关于Jest require.context 替代方案的说明,或在脚本中增加对此情况的检测和提示。
  4. 架构重构 :根据边界测试的反馈,我们可能需要在 SKILL.md 的“错误处理”部分增加一条:“如果脚本检测到无法自动迁移的Karma特定语法,请输出警告并指引用户手动修改,参考 references/advanced-migration.md ”。

通过这样一个完整的案例,你可以看到所有最佳实践如何有机地结合在一起,形成一个清晰、健壮、易于维护的技能模块。这不仅仅是写文档,更是一种为AI时代设计人机协作接口的工程方法。

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐