一站式了解Agent Skills:从SKILL.md到scripts/references/assets的落地拆解
1. 为什么你的 Agent 总是“记不住”流程从一次 Excel 导出翻车说起如果你正在搭技能包大概率遇到过这种场景让 Agent 把一份销售数据导出成固定格式的 Excel第一次跑得挺好第二次列名顺序变了第三次干脆把汇总行塞到了表头。你反复在对话里强调“按模板来”它每次都能给你一点新惊喜。问题不在模型笨而在于你把“流程知识”塞进了每次都要重新解释的对话里而不是打包成一个可复用、可渐进加载的单元。Agent Skills 就是来解决这件事的。简单说它是一套模块化能力扩展机制把领域指令、元数据和资源脚本、模板、参考文档打包成一个目录Agent 在启动时只看到每个技能的name和description判断当前任务相关时才把完整的SKILL.md读进上下文执行阶段再按需加载scripts/、references/、assets/里的东西。这套“发现—激活—执行”的三层加载架构核心价值是省上下文、保一致性。它适合谁适合正在给 Claude Code、Cursor 这类 AI 应用扩展能力的开发者尤其是那些希望把“我们团队就是这么干的”固化成 SOP 的人。你可以把它理解成游戏里的技能栏平时你只记得技能名字和它大概干嘛用真到打怪那一刻才展开具体招式。本文会从目录结构讲起给出SKILL.md模板、三类目录的示例配置并完整演示一次技能加载与调用验证帮你跑通最小可用技能。整个验证过程我会用 TaoToken 提供的模型接入来做这样你能直接复制配置跑起来。2. TaoToken 前置准备把模型接入这步先铺平在写技能之前得先有一个能稳定调用模型的入口否则你连“技能有没有被激活”都验证不了。TaoToken 在这里扮演的是模型接入层它提供兼容 OpenAI 风格的 API 地址你拿到 Key 之后把 Base URL 指向https://taotoken.net/api就能在本地脚本或 AI 应用里发起对话请求。对于技能调试来说这一点很关键——你需要一个能反复调用、方便打印原始响应的通道才能确认 Agent 到底有没有读到你的SKILL.md。先说清楚要准备的三件套这也是后面所有配置的基础配置项值说明Base URLhttps://taotoken.net/api兼容 OpenAI 接口风格不要带多余路径API Key在控制台创建形如sk-开头只显示一次务必保存Model ID按控制台可用列表填例如对话类或编码类模型填错会直接 404获取 Key 的路径很直接打开https://taotoken.net/api-keys这是 API Keys 管理页登录后创建一个新 Key复制出来存到环境变量里。我习惯用环境变量而不是硬编码避免 Key 跟着代码进仓库export TAOTOKEN_API_KEYsk-你的key export TAOTOKEN_BASE_URLhttps://taotoken.net/api如果你更想先手动感受一下模型对话可以打开https://taotoken.net/chat直接试一句确认账号和额度正常。这一步不是必须的但能帮你排除“到底是技能写错了还是 Key 没生效”这类混淆问题。接下来是技能目录的落点。不同 AI 应用读取技能的路径不一样Claude Code 常见的是用户级目录~/.claude/skills/项目级则放在仓库内的.claude/skills/。我建议调试阶段先用项目级目录方便跟着代码一起版本管理mkdir -p .claude/skills/excel-export/scripts mkdir -p .claude/skills/excel-export/references mkdir -p .claude/skills/excel-export/assets到这里前置就铺完了一个可调用的模型入口加一个空的技能目录骨架。下一节我们把SKILL.md和三类目录填满写成可以直接复制的配置。3. 可复制配置SKILL.md 模板与 scripts/references/assets 三件套这一节是全文的核心我会给出一个完整可复制的技能包。技能名叫excel-export目标是把一份 JSON 数据按固定列顺序导出成 Excel并附带一个模板文件作为格式基准。先看整体目录结构.claude/skills/excel-export/ ├── SKILL.md ├── scripts/ │ └── export_excel.py ├── references/ │ └── COLUMNS.md └── assets/ └── template.xlsx3.1 SKILL.md元数据必须精确正文分点写SKILL.md是唯一必需的文件它由 YAML 前置元数据加 Markdown 正文组成。元数据里的name和description是 Agent 判断“要不要激活这个技能”的唯一依据所以描述必须写清楚“做什么”和“什么时候用”。下面这份可以直接复制--- name: excel-export description: Export structured JSON data to a fixed-format Excel file with predefined column order. Use when the user asks to export data to Excel, generate a spreadsheet report, or mentions xlsx output with a required column layout. license: MIT metadata: author: dev-team version: 1.0 --- # Excel Export Skill ## 使用场景 当用户要求把数据导出为 Excel且需要固定列顺序和表头格式时使用本技能。 ## 步骤 1. 读取输入 JSON确认字段完整。 2. 按 references/COLUMNS.md 定义的列顺序重排字段。 3. 调用 scripts/export_excel.py 生成 xlsx。 4. 用 assets/template.xlsx 作为格式基准保留表头样式。 ## 输入输出示例 输入{rows: [{name: A, amount: 10}]} 输出output.xlsx列顺序为 name, amount。 ## 边界情况 - 字段缺失时补空字符串不跳过该行。 - 数值字段统一转为数字类型避免文本格式。 - 行数为 0 时仍生成带表头的空表。注意name的约束最多 64 字符只能小写字母、数字和连字符不能以连字符开头或结尾。description最多 1024 字符不能为空。这两条踩过坑的人不少写错了技能直接不加载。3.2 scripts自包含、有错误信息scripts/放可执行代码语言取决于你的运行环境Python、Bash、JavaScript 都常见。关键是脚本要么自包含要么把依赖写清楚并且错误信息要能看懂。下面这个脚本用openpyxl生成 Excel# scripts/export_excel.py import json import sys from openpyxl import Workbook COLUMNS [name, amount, date] def export(input_path: str, output_path: str) - None: try: with open(input_path, r, encodingutf-8) as f: data json.load(f) except FileNotFoundError: print(f[ERROR] 输入文件不存在: {input_path}, filesys.stderr) sys.exit(1) except json.JSONDecodeError as e: print(f[ERROR] JSON 解析失败: {e}, filesys.stderr) sys.exit(1) wb Workbook() ws wb.active ws.append(COLUMNS) for row in data.get(rows, []): ws.append([row.get(col, ) for col in COLUMNS]) wb.save(output_path) print(f[OK] 已生成 {output_path}共 {len(data.get(rows, []))} 行) if __name__ __main__: if len(sys.argv) ! 3: print(用法: python export_excel.py input.json output.xlsx, filesys.stderr) sys.exit(1) export(sys.argv[1], sys.argv[2])3.3 references 与 assets按需加载越小越好references/放 Agent 需要时才查阅的文档。这里放一份列定义让脚本和文档保持单一事实来源!-- references/COLUMNS.md -- # 列定义 | 列名 | 类型 | 说明 | | --- | --- | --- | | name | string | 名称缺失补空 | | amount | number | 金额转数字 | | date | string | 日期ISO 格式 |assets/放静态资源比如模板、图片、查找表。这里放一个template.xlsx作为格式基准。实际项目里你可以用脚本生成一个空模板python -c from openpyxl import Workbook; wbWorkbook(); wb.active.append([name,amount,date]); wb.save(.claude/skills/excel-export/assets/template.xlsx)到这里三件套齐了。SKILL.md负责“什么时候用、怎么用”scripts/负责“真正干活”references/和assets/负责“按需补充细节”。这种拆分的好处是Agent 激活技能时只读SKILL.md只有执行到需要列定义或模板时才去读对应文件上下文不会被一次性塞满。4. 验证请求一次技能加载与调用验证的完整过程配置写完不代表能用必须验证 Agent 真的读到了技能、真的按流程执行了。我用一个最小可复现的脚本来模拟“技能加载 调用”的链路先通过 TaoToken 的接口发一条会触发技能描述的请求再把脚本单独跑一遍确认输出正确。先准备测试数据cat /tmp/input.json EOF {rows: [{name: Alice, amount: 120, date: 2025-01-01}, {name: Bob, amount: 80, date: 2025-01-02}]} EOF第一步单独验证脚本能跑通这一步和模型无关纯粹确认代码正确python .claude/skills/excel-export/scripts/export_excel.py /tmp/input.json /tmp/output.xlsx预期输出[OK] 已生成 /tmp/output.xlsx共 2 行第二步验证模型侧能否识别技能。用 curl 发一条请求把技能描述作为系统提示的一部分观察模型是否按列顺序组织输出curl -s https://taotoken.net/api/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: 你的模型ID, messages: [ {role: system, content: 可用技能: excel-export - Export structured JSON data to a fixed-format Excel file with predefined column order. Use when the user asks to export data to Excel.}, {role: user, content: 把 /tmp/input.json 导出成 Excel列顺序按 name, amount, date。} ] }如果技能描述写得够精确模型会在回复里体现出“先确认列顺序、再调用脚本”的意图而不是自由发挥。实测下来description里带上“when to use”的触发条件激活准确率明显更高。第三步把两步串起来写一个最小的验证脚本模拟 Agent 的“发现—激活—执行”# verify_skill.py import json import subprocess import os SKILL_DIR .claude/skills/excel-export def discover(): with open(os.path.join(SKILL_DIR, SKILL.md), encodingutf-8) as f: content f.read() meta content.split(---)[1] print([DISCOVER] 技能元数据:) print(meta.strip()) def execute(input_path, output_path): script os.path.join(SKILL_DIR, scripts, export_excel.py) result subprocess.run( [python, script, input_path, output_path], capture_outputTrue, textTrue ) print([EXECUTE], result.stdout.strip() or result.stderr.strip()) if __name__ __main__: discover() execute(/tmp/input.json, /tmp/output.xlsx)运行python verify_skill.py你会看到元数据被打印出来紧接着脚本执行成功。这一步跑通说明你的技能包在结构上是完整可用的。成功结果有两个标志[OK]输出出现且/tmp/output.xlsx能被打开、列顺序正确。5. 本篇常见错排查401、local proxy failed 与 reading choices技能调试阶段最容易卡在接入层而不是技能本身。下面这几个报错我基本都遇到过对照着排查能省不少时间。401 Unauthorized最常见的原因是 Key 没带上或带错了。检查Authorization头是不是Bearer sk-xxx格式中间有没有多余空格。如果你把 Key 放在环境变量里确认echo $TAOTOKEN_API_KEY有值。还有一种情况是 Key 被删除或额度耗尽去https://taotoken.net/api-keys重新生成一个。local proxy failed / connection refused这类报错通常出现在你本地配了转发但目标地址写错的时候。确认 Base URL 是https://taotoken.net/api不要多加/v1或结尾斜杠。如果你在代码里用了base_url参数检查它和实际请求路径拼接后是不是变成了/api/v1/chat/completions这种重复路径。reading choices 相关报错当你解析响应时访问choices[0]却报空或越界先打印完整响应体看看。常见原因是请求被拒返回的是 error 对象而不是 choices 数组或者模型 ID 填错导致返回结构异常。把model字段换成控制台里确认可用的 ID 再试。OAuth / 认证流程报错如果你用的是 Claude Code 这类带 OAuth 的客户端报错往往和本地凭证缓存有关。先确认客户端里配置的 Base URL 和 Key 与本文一致再清理本地凭证重新登录。注意不要把 OAuth 流程和 API Key 混用两者是不同通道。技能不激活如果模型完全无视你的技能先检查SKILL.md的 YAML 有没有语法错误name是否符合小写连字符规则description是否为空。YAML 对缩进敏感一个 tab 就能让整个元数据解析失败。排查顺序建议先确认 Key 和 Base URL 能单独调通用 curl 发一条最简请求再确认脚本能单独跑通最后才怀疑技能描述。把变量一个个隔离比一次性改一堆配置高效得多。6. 把技能包接进你的工作流从验证到长期使用技能跑通之后接下来就是把它用起来。如果你只是偶尔调试直接在项目里放.claude/skills/就够了但如果你打算长期维护多个技能、频繁迭代建议把模型接入和技能管理分开考虑。模型接入这块TaoToken 的 API Keys 页面https://taotoken.net/api-keys可以管理多个 Key方便你按项目隔离额度接入文档在https://taotoken.net/doc里面有各语言的调用示例照着改 Base URL 就行。如果你更偏向在对话里快速验证技能行为模型对话入口https://taotoken.net/chat可以直接试如果你要把技能接进编码 Agent 做长期自动化Coding Plan 页面https://taotoken.net/coding-plan有对应的方案说明。这三个入口按你的使用频率选就行不必都上。回到技能本身我自己的经验是先把一个技能写“窄”再考虑组合。比如excel-export就只干导出这一件事列顺序、格式、边界处理都写死在references/和scripts/里。等这个技能稳定了再写第二个技能去调用它的输出。技能之间通过文件系统解耦比在一个SKILL.md里塞十几个步骤要好维护得多。最后提醒一句安全边界scripts/里的代码是有执行权限的references/和assets/也可能被 Agent 读取后用于外部请求。引入第三方技能包之前先通读它的SKILL.md和脚本确认没有可疑的 URL 请求或文件操作。自己写的技能也一样别把生产库的连接串直接写进assets/。把技能当成代码来审这个习惯能帮你避开大部分坑。