news 2026/10/2 11:42:29

保姆级拆解 Agent Skills:从 SKILL.md 到 references/scripts/assets 的完整落地指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
保姆级拆解 Agent Skills:从 SKILL.md 到 references/scripts/assets 的完整落地指南

1. 为什么你的 Agent 总是“只会聊天”:从一次真实翻车说起

先说一个我踩过的坑。去年我给团队做了一个内部知识助手,提示词写了三千多字,把公司规范、接口文档、常见问题全塞进 system prompt。刚开始效果还行,直到有一次用户问“帮我按公司规范生成一份周报”,模型开始胡编字段名,把project_id写成projectId,把日期格式从YYYY-MM-DD改成2026年3月6日。我盯着输出看了半天才反应过来:不是模型笨,是我把“技能”和“知识”搅成了一锅粥。

这就是 Agent Skills 要解决的核心问题。Agent Skills 是一套让 AI 具备可复用技能包的工程化约定,它把一个技能拆成入口文件SKILL.md加三类资源目录references/、scripts/、assets/,让模型按需加载、按需执行,而不是一次性把所有上下文灌进去。适合谁?适合那些已经会用 Claude Code、Cline、Codex 这类工具,但发现“提示词越写越长、效果越来越飘”的开发者。

你可以把 Agent Skills 理解成给 AI 装“技能插件”。以前你教 AI 做事,是把整本说明书念给它听;现在你告诉它“说明书在书架上,第几章讲什么,需要的时候自己去翻”。这个差别在 token 消耗和输出稳定性上是数量级的。

我实测下来,一个组织良好的 Skill 能把同类任务的 token 消耗压到原来的三分之一左右,而且字段格式错误率明显下降——因为格式规范写在references/里,模型只在需要时读取,不会被无关内容干扰。

这篇会从目录结构讲到SKILL.md模板,再到scripts/里脚本怎么被调用、assets/里的模板怎么被引用,最后用 TaoToken 的统一 API 通道做一次完整的联调验证。全程可复制,你跟着建目录、填文件、发请求就能跑通。

2. TaoToken 前置准备:统一 Key 与 API 通道怎么配

在动手写 Skill 之前,得先把“调用通道”理顺。因为 Skill 里的scripts/脚本最终要发 HTTP 请求给模型,如果每个脚本各自维护一套 Key 和 Base URL,后面排查问题会非常痛苦。我的做法是统一走 TaoToken 的 API 通道,一个 Key 管所有模型调用。

TaoToken 在这里扮演的角色是统一的模型调用入口:你拿到一个 API Key,配一个 Base URL,就能在脚本里调用不同模型,不用为每个模型单独申请和切换。官网入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 地址是 https://taotoken.net/api ,注意 API 地址后面不加任何 UTM 参数,保持干净。

具体操作分三步。第一步,登录后在控制台创建 API Key,路径是 console 页面,建议给这个 Key 起个能识别的名字,比如agent-skills-dev,方便后面在脚本里区分环境。第二步,把 Key 写进环境变量,不要硬编码进scripts/里的代码,这是很多人后面 Key 泄露的根源。第三步,确认你要用的 Model ID,比如做代码类 Skill 常用claude-sonnet-4-5这类标识,具体以控制台模型列表为准。

环境变量这样配,Linux/macOS 写进~/.zshrc或~/.bashrc:

export TAOTOKEN_API_KEY="sk-你的key" export TAOTOKEN_BASE_URL="https://taotoken.net/api"

Windows PowerShell 用:

$env:TAOTOKEN_API_KEY="sk-你的key" $env:TAOTOKEN_BASE_URL="https://taotoken.net/api"

配完之后验证一下环境变量有没有生效:

echo $TAOTOKEN_BASE_URL # 期望输出:https://taotoken.net/api

这里有个细节要注意:Base URL 是https://taotoken.net/api,很多 OpenAI 兼容的 SDK 会自动在末尾拼/v1/chat/completions,所以你在代码里不要再手动加/v1,否则会变成/api/v1/v1/...这种重复路径,直接 404。这个坑我在第一次接入时踩过,报错信息是404 page not found,排查了半小时才发现是路径重复。

如果你用的是 Claude Code 这类工具,配置方式略有不同,通常在settings.json里指定ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY,Base URL 同样填https://taotoken.net/api。Cline 这类 VS Code 插件则在设置面板里填 Base URL、API Key、Model ID 三件套。Codex 的auth.json里对应的是base_url和api_key字段。不管哪种工具,Base URL + Key + Model ID 这三件套必须齐全,缺一个就会报鉴权或模型不存在的错。

把通道理顺之后,Skill 里的脚本就只需要读环境变量,不用关心底层是哪个模型、哪个 Key。这样你换模型、换 Key 都只改一处,Skill 本身不用动。

3. 可复制配置:SKILL.md 模板与四类资源目录结构

现在进入正题。一个标准的 Skill 目录长这样,你可以直接复制这个结构:

weather-skill/ ├── SKILL.md ├── references/ │ ├── city-codes.md │ └── api-notes.md ├── scripts/ │ └── fetch_weather.py └── assets/ └── icons/ ├── sunny.png └── rainy.png

SKILL.md是唯一必填的文件,它是技能的入口。模型先读它,判断“这个技能是干什么的、什么时候触发、触发后按什么步骤走”。下面是一个可以直接用的模板,注意 frontmatter 里的name和description是给模型做技能路由用的,写得越准,触发越稳:

--- name: weather-skill description: 查询国内城市天气,用户问天气、气温、是否下雨时使用 version: 1.0.0 --- # 天气查询技能 ## 什么时候用 用户询问某个城市的天气、温度、是否下雨、穿衣建议时触发。 ## 怎么用 1. 从用户输入中提取城市名 2. 读取 references/city-codes.md,把城市名转成城市代码 3. 执行 scripts/fetch_weather.py,传入城市代码 4. 把脚本返回的 JSON 结果整理成自然语言回复 ## 输入格式 用户说:“北京天气怎么样”“上海明天会下雨吗” ## 输出格式 “北京今天晴,25℃,适合外出。” ## 注意事项 - 城市名无法识别时,引导用户补充 - 脚本执行失败时返回友好提示,不要暴露堆栈

references/放的是“大块知识”,比如城市代码对照表、API 字段说明、公司命名规范。它的价值在于渐进式加载:SKILL.md里只写“去读 references/city-codes.md”,模型在真正需要时才读,不需要时这部分内容不占上下文。city-codes.md可以长这样:

# 城市代码对照表 | 城市 | 代码 | | :--- | :--- | | 北京 | 101010100 | | 上海 | 101020100 | | 广州 | 101280101 | | 深圳 | 101280601 |

scripts/放真正能跑的代码。它的关键作用是把计算和外部调用从模型脑子里挪出来,脚本执行不消耗模型 token,跑完只把结果返回。下面这个fetch_weather.py演示了怎么读环境变量、怎么发请求,注意 Base URL 和 Key 都从环境变量取:

import os import sys import json import urllib.request API_KEY = os.environ.get("TAOTOKEN_API_KEY") BASE_URL = os.environ.get("TAOTOKEN_BASE_URL", "https://taotoken.net/api") def fetch_weather(city_code: str) -> dict: # 这里演示调用模型做结果整理,实际天气数据可换成任意数据源 payload = { "model": "claude-sonnet-4-5", "messages": [ {"role": "user", "content": f"城市代码 {city_code} 的天气,用一句话描述"} ] } req = urllib.request.Request( f"{BASE_URL}/v1/chat/completions", data=json.dumps(payload).encode("utf-8"), headers={ "Content-Type": "application/json", "Authorization": f"Bearer {API_KEY}" }, method="POST" ) with urllib.request.urlopen(req, timeout=30) as resp: return json.loads(resp.read().decode("utf-8")) if __name__ == "__main__": code = sys.argv[1] if len(sys.argv) > 1 else "101010100" result = fetch_weather(code) print(json.dumps(result, ensure_ascii=False, indent=2))

assets/放成品模板和素材,比如周报 PPT 模板、公司 Logo、天气图标。它的加载时机是“生成产物时引用”,不是“推理时读取”。比如用户说“生成一份带图标的天气卡片”,模型才会去assets/icons/里取sunny.png。

四类资源的加载时机可以这样对照:

资源加载时机是否必填典型内容
SKILL.md技能路由时必读是触发条件、步骤、格式
references/需要背景知识时读否文档、对照表、规范
scripts/需要执行动作时跑否Python/Shell 脚本
assets/需要生成产物时取否模板、图片、字体

把目录建好、文件填好之后,Skill 的“静态部分”就完成了。接下来要验证它能不能真的被调用起来。

4. 验证请求:从本地脚本到模型对话的完整联调

验证分两层:先验证scripts/里的脚本能独立跑通,再验证模型能按SKILL.md的流程调用脚本。第一层是基础,脚本跑不通,后面全是空谈。

先跑脚本,确认 API 通道没问题:

cd weather-skill python scripts/fetch_weather.py 101010100

如果环境变量配对了,你会看到类似这样的返回:

{ "id": "chatcmpl-xxx", "object": "chat.completion", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "北京今天晴,气温 25℃,适合外出。" } } ] }

看到choices[0].message.content里有内容,说明 Base URL、Key、Model ID 三件套都对了。如果这里就报错,先别往下走,去第 5 节对照报错排查。

第二层验证,把 Skill 挂到支持 Agent Skills 的工具里,比如 Claude Code。在项目根目录建.claude/skills/目录,把weather-skill/整个放进去,然后在对话里问“北京天气怎么样”。模型应该会先读SKILL.md,再读references/city-codes.md,然后执行scripts/fetch_weather.py,最后返回自然语言结果。

如果你想在纯 API 层面验证模型是否理解了这个 Skill,可以把SKILL.md的内容作为 system prompt 的一部分发过去,观察模型是否按步骤走。用 curl 这样测:

curl -s https://taotoken.net/api/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -d '{ "model": "claude-sonnet-4-5", "messages": [ {"role": "system", "content": "你有一个技能 weather-skill,触发条件是用户问天气。步骤:1 提取城市名 2 读 references/city-codes.md 3 执行 scripts/fetch_weather.py 4 整理结果。"}, {"role": "user", "content": "北京天气怎么样"} ] }'

观察返回内容里有没有出现“提取城市名”“城市代码”这类步骤痕迹。如果模型直接开始编天气数据,说明SKILL.md的步骤描述不够明确,回去把“怎么用”那节写得更具体。

验证通过后,你可以把 Skill 分享给团队。这里有个实用技巧:把SKILL.md的description写得像搜索关键词,比如“查询国内城市天气、气温、降雨、穿衣建议”,这样模型在技能路由时更容易命中。我试过把 description 写成“天气相关”,结果模型经常不触发,改成具体场景词之后触发率明显提升。

5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth

这一节按真实报错来。你在接入过程中大概率会遇到下面几个,我按出现频率排。

401 Unauthorized。最常见的原因是 Key 没读到。先确认环境变量在当前 shell 里生效:

echo $TAOTOKEN_API_KEY

如果输出为空,说明~/.zshrc改了但没source,或者你用的是另一个终端会话。另一个原因是 Key 前后带了空格或引号,比如export TAOTOKEN_API_KEY=" sk-xxx ",脚本读到的就是带空格的字符串。检查方法是echo "$TAOTOKEN_API_KEY" | cat -A,看有没有多余的$或空格。

local proxy failed / connection refused。这个报错通常出现在你本地配了某个代理端口,但代理没启动。检查环境变量里有没有HTTP_PROXY、HTTPS_PROXY、ALL_PROXY:

env | grep -i proxy

如果有,临时清掉再试:

unset HTTP_PROXY HTTPS_PROXY ALL_PROXY

注意,这里说的是清理本地环境变量,不是让你去配什么网络工具,纯粹是排除干扰项。

reading 'choices' of undefined。这个报错说明代码在解析返回时,choices字段不存在。原因通常是返回体是一个错误对象,比如{"error": {"message": "..."}},但你的代码直接去读data["choices"][0]。修复方法是先判断:

if "choices" not in result: print("接口返回异常:", json.dumps(result, ensure_ascii=False)) sys.exit(1)

打印出完整返回体,你就能看到真实错误信息,通常是模型名写错或路径重复。

OAuth / authentication_error。如果你用的是 Claude Code 或 Codex 这类工具,报 OAuth 相关错误,说明工具在走它自己的登录流程,而不是用你配的 API Key。以 Claude Code 为例,需要在settings.json里显式指定:

{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的key" } }

Codex 的auth.json对应字段是:

{ "base_url": "https://taotoken.net/api", "api_key": "sk-你的key" }

Cline 在 VS Code 设置里填 API Provider 为 OpenAI Compatible,Base URL 填https://taotoken.net/api,API Key 填你的 Key,Model ID 填控制台里看到的模型标识。三件套缺一不可,只填 Key 不填 Base URL 会走默认端点,直接鉴权失败。

还有一个隐蔽的坑:scripts/里的脚本用了相对路径读references/,但执行时工作目录不对。比如脚本里写open("references/city-codes.md"),而你在项目根目录执行python weather-skill/scripts/fetch_weather.py,工作目录是根目录,就会FileNotFoundError。修复方法是用__file__定位:

import os BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) ref_path = os.path.join(BASE_DIR, "references", "city-codes.md")

这样不管从哪个目录执行,路径都对。

6. 把 Skill 用起来:从单技能到技能库的落地建议

跑通一个 Skill 之后,下一步是把它变成可维护的技能库。我的做法是在项目里建一个skills/目录,每个技能一个子目录,共享同一套环境变量和 API 通道。这样新增技能只需要复制目录结构、改SKILL.md和脚本,不用重新配 Key。

关于references/的拆分粒度,有个经验:单个 reference 文件控制在 200 行以内,超过就再拆。因为模型读取时是按文件读的,文件太大反而浪费上下文。比如城市代码表如果超过 500 个城市,就按省份拆成多个文件,SKILL.md里写“根据城市名首字母选择对应文件”。

scripts/里的脚本建议统一加一个--dry-run参数,只打印将要执行的请求而不真正发送。这样调试 Skill 流程时不会产生真实调用,排查路径问题特别方便。实现很简单:

import argparse parser = argparse.ArgumentParser() parser.add_argument("--dry-run", action="store_true") args = parser.parse_args() if args.dry_run: print("将请求:", BASE_URL, payload) sys.exit(0)

assets/里的模板文件建议加版本号,比如weekly-report-v2.pptx,避免模型引用到旧模板。SKILL.md里写清楚“使用 assets/weekly-report-v2.pptx”,模型就不会拿错。

最后说一个团队协作的细节:SKILL.md的description字段是技能路由的唯一依据,多人维护时容易写重。建议在技能库里加一个INDEX.md,列出所有技能的 name 和 description,新增技能前先查一遍有没有语义重叠。这个习惯能避免模型在多个相似技能之间反复横跳。

如果你还没配好 API 通道,先去 https://taotoken.net/api-keys 创建 Key,再对照 https://taotoken.net/doc 的接入文档确认 Base URL 和模型标识。想先验证模型对话效果,可以直接在 https://taotoken.net/chat 里试;长期做编码类 Agent 的,可以看 https://taotoken.net/coding-plan 的套餐说明。通道理顺了,Skill 的工程化落地就是水到渠成的事。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 11:41:00

OpenClaw 的本质突破:把本地自托管 AI 智能体的 endpoint 改到 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/2 11:40:55

上游悄悄变了:模型行为漂移的排查与兜底

说明:本文讨论的是线上模型行为漂移的排查与兜底,属于 AI 运维话题,不涉及具体模型版本与价格。AI 领域版本迭代极快,凡涉及版本号、价格、可用性,请以你阅读时的官方页面为准。文中代码为结构示意,未在某个…

作者头像 李华