1. 为什么你的 AI Agent 总是“答非所问”
用 Claude Code 写 TypeScript 项目时,你可能遇到过这种场景:让它加一个formatDate工具函数,它给你返回一段带moment.js的代码,而你的项目早就统一用date-fns了;让它补个测试,它写出来的断言跟你的vitest配置对不上;让它提交,commit message 又是“update code”这种没法看的东西。问题不在模型智商,而在于它每次都在“重新猜”你的工程约定。
Skills 就是来解决这件事的。你可以把它理解成给 AI Agent 配的一套“岗位操作手册”:每个 skill 是一个独立的小目录,里面写清楚什么时候触发、按什么步骤执行、产出什么格式。Agent 不再靠临场发挥,而是按你定义好的工作流走。这篇就以 TypeScript 技能包为例,从目录结构、触发条件、调用链路一路写到 Claude Code 里的验证步骤,并说明怎么通过 TaoToken 统一 Key 和 API 通道,让代码生成、测试、提交这些动作稳定跑起来。
适合谁看:每天用 Claude Code / Cursor 写 TS 的人、被 Agent 输出不稳定折磨过的人、想在团队里推一套可复用 AI 工作流的人。下面所有配置都可以直接复制改。
2. TaoToken 前置:把 Key 和 API 通道先统一
Skills 本身是“行为规范”,它不负责模型调用。真正发请求的那一层,需要一个稳定的 API 入口。我试过把 Key 散落在各个工具的环境变量里,换台机器就要重新配一遍,后来统一走 TaoToken 的通道,Claude Code、脚本、CI 都读同一份配置,省事很多。
TaoToken 在这里的角色是统一接入层:你拿到一个 Key,配好 base URL,Claude Code 和后续的 skill 调用都走这条通道。官网入口在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 地址是 https://taotoken.net/api (这个不加 UTM)。
操作顺序建议这样:先注册并创建 API Key,再在 Claude Code 里配置环境变量,最后才去装 skills。顺序反了的话,skill 装好了但请求发不出去,排查起来会绕。
创建 Key 的入口在控制台的 API Keys 页面:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite 。建议给不同用途建不同的 Key,比如claude-code-dev、ci-test,方便后面按 Key 看用量、出问题也能单独吊销。
注意:Key 只显示一次,创建后立刻复制到密码管理器或本地
.env,不要提交进 git。
3. 可复制配置:TypeScript 技能包目录骨架
Skills 的核心是“约定大于配置”。一个 skill 目录里通常有两类文件:一份描述元信息(叫什么、什么时候用),一份是真正的执行指令(步骤、约束、输出格式)。下面这套骨架是我在 TS 项目里实际用的,你可以直接建目录。
3.1 目录结构
.claude/ └── skills/ ├── ts-gen/ │ ├── SKILL.md │ └── templates/ │ └── function.ts.tpl ├── ts-test/ │ ├── SKILL.md │ └── templates/ │ └── spec.ts.tpl └── ts-commit/ └── SKILL.md三个 skill 各管一件事:ts-gen负责按项目规范生成函数,ts-test负责补 vitest 用例,ts-commit负责生成符合 Conventional Commits 的提交信息。拆小是有意的——skill 越小,触发条件越清晰,Agent 越不容易误用。
3.2 SKILL.md 的写法
以ts-gen为例,SKILL.md用 frontmatter 声明元信息,正文写执行约束:
--- name: ts-gen description: 当用户要求新增 TypeScript 工具函数或模块时使用。生成前必须先读取 CONTEXT.md 确认命名与依赖约定。 --- # TypeScript 函数生成 ## 触发条件 - 用户说“加一个函数/工具/模块” - 目标文件在 src/utils 或 src/lib 下 ## 执行步骤 1. 读取项目根目录 CONTEXT.md,提取命名规范与允许的依赖 2. 检查是否已存在同名导出,避免重复 3. 按 templates/function.ts.tpl 生成,替换占位符 4. 输出时附上文件路径与新增导出名 ## 约束 - 禁止引入 CONTEXT.md 未列出的第三方依赖 - 日期处理统一用 date-fns - 每个导出函数必须有 JSDocdescription这一行很关键,Agent 就是靠它判断“当前请求该不该触发这个 skill”。写得太宽(比如“处理代码”)会导致乱触发,写得太窄又永远不触发。经验是把用户可能说的原话关键词塞进去。
3.3 模板文件
templates/function.ts.tpl里放占位符,skill 执行时替换:
/** * {{DESCRIPTION}} */ export function {{NAME}}({{PARAMS}}): {{RETURN_TYPE}} { // TODO: implement }ts-test的模板同理,固定用vitest的describe/it/expect结构,避免 Agent 一会儿写 jest 一会儿写 vitest。
3.4 在 Claude Code 里配置 API 通道
Skill 装好后,请求还是要发出去。在项目根目录建.env(记得加进.gitignore):
TAOTOKEN_API_KEY=sk-你的key TAOTOKEN_BASE_URL=https://taotoken.net/api然后在 Claude Code 的配置里指向这个 base URL。如果你用的是命令行启动,可以这样导出:
export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_API_KEY="$TAOTOKEN_API_KEY"这样 Claude Code 的请求就走 TaoToken 通道,skill 里定义的步骤照常执行,模型调用这一层不用每个 skill 单独配。
4. 验证请求:在 Claude Code 里跑通一次完整链路
配置写完不算完,得实际验证 skill 有没有被正确触发、请求有没有正常返回。下面是我常用的三步验证法。
4.1 第一步:确认 skill 被加载
在 Claude Code 里输入:
列出当前可用的 skills正常应该看到ts-gen、ts-test、ts-commit三个。如果没出现,先检查目录是不是在.claude/skills/下、SKILL.md的 frontmatter 有没有写错(比如name和目录名不一致)。
4.2 第二步:触发一次生成
帮我在 src/utils 下加一个 formatCurrency 函数,输入 number,输出带 ¥ 的字符串预期行为:Agent 先读CONTEXT.md,确认没有重复导出,然后按模板生成,最后告诉你文件路径和导出名。如果它直接甩代码、没读 CONTEXT,说明description的触发条件没写清楚,回去补关键词。
4.3 第三步:验证 API 通道
如果 skill 触发了但请求报错,多半是 Key 或 base URL 的问题。用一个最小请求单独测通道:
curl https://taotoken.net/api/v1/messages \ -H "x-api-key: $TAOTOKEN_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" \ -d '{ "model": "claude-sonnet-4-20250514", "max_tokens": 64, "messages": [{"role": "user", "content": "只回复 ok"}] }'返回里带content字段且内容是ok,说明通道正常。这一步能把“skill 问题”和“网络/Key 问题”彻底分开,省很多排查时间。
4.4 成功结果长什么样
跑通后,一次完整的工程动作应该是这样:你说“加个 formatCurrency 并补测试”,ts-gen先生成函数,ts-test接着按 vitest 模板补用例,最后ts-commit给出feat(utils): add formatCurrency这样的提交信息。三个 skill 串起来,就是一条可复用的工程工作流。
5. 本篇常见错排查
skill 不触发:九成是description写得太泛或太窄。把用户可能说的原话(“加函数”“补测试”“提交”)直接写进去,比抽象描述有效。
触发了但读不到 CONTEXT.md:检查文件路径。skill 里的相对路径是相对项目根目录的,不是相对 skill 目录。写成./CONTEXT.md而不是../CONTEXT.md。
请求 401:Key 没生效。确认环境变量名和 Claude Code 读的名字一致,ANTHROPIC_API_KEY和TAOTOKEN_API_KEY别混用。用 4.3 的 curl 单独测一次最快。
请求 404:base URL 写错了。注意是https://taotoken.net/api,不要多加/v1后缀,路径拼接由客户端处理。
生成代码引入了禁用依赖:skill 的约束段没写死。在SKILL.md里明确列出允许的依赖白名单,比写“不要引入不必要依赖”这种模糊表述管用。
多个 skill 抢触发:比如ts-gen和ts-test的 description 都包含“代码”。把触发条件收窄到具体动作词,生成归生成、测试归测试。
commit 信息格式不对:ts-commit里把 Conventional Commits 的 type 列表写全(feat/fix/docs/refactor/test/chore),并给一个正例一个反例,Agent 照着套就行。
6. 把通道和技能包一起固化下来
Skills 解决的是“Agent 怎么干活”,TaoToken 解决的是“请求从哪走”。两件事分开配、一起用,工程工作流才算闭环。日常开发里,我建议把 Key 按用途拆开:本地开发一个、CI 一个,出问题能快速定位是哪条链路。
如果你还在调 skill 的触发条件,可以先用模型对话页面快速试 prompt 效果,确认描述词能命中再写进SKILL.md:https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite 。长期跑编码和 Agent 任务的话,Coding Plan 更适合按量用:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。接入细节和参数说明都在文档里:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。Claude Code 相关的配置参考这个页面:https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claude_code&utm_campaign=rewrite 。
最后留一个实用习惯:每次改完SKILL.md,用第 4 节的 curl 先确认通道没断,再跑一次真实生成。两步都过,再提交技能包。这样你的 Agent 工作流会越用越稳,而不是越改越乱。