1. 从/skills命令说起Claude-Code 里 Skill 到底是什么如果你在 Claude Code 里敲过/skills会弹出一个 SkillsMenu把当前会话能用的 skill 全列出来——内置的、项目里的、用户目录下的、插件带的一目了然。但很多人只把它当成一个「命令列表」没意识到背后是一条完整的加载与执行链路从磁盘上的SKILL.md被扫描、解析 frontmatter、注册进注册表到模型侧通过 Skill 工具触发、再到实际执行工具调用。这条链路如果搞不清楚遇到「我写的 skill 为什么不生效」「模型为什么不调用我的 skill」这类问题就只能瞎猜。这篇就带你从源码层面把这条链路拆开。核心检索词先摆出来Claude-Code Skill 源码解读讲的是 Skill 从定义、注册、加载到执行触发的完整实现适合已经会用 Claude Code、想搞清楚内部机制、或者想自己写 skill 调试的开发者。读完之后你应该能独立完成一次 Skill 执行链路追踪知道入口在哪、断点打在哪、每一步的数据结构长什么样。先建立一个整体认知。一个 Skill 在 Claude Code 里本质上是「目录 SKILL.md」的组合SKILL.md的 frontmatter 描述元信息正文是给模型看的指令。比如--- name: my-skill description: 一句话描述何时使用 whenToUse: 更详细的使用场景 allowed-tools: Read, Grep, Bash --- 这里写具体的执行指令模型会按这段内容行动。name是唯一标识description和whenToUse决定模型在什么场景下会想到它allowed-tools限定它能用哪些工具。这个结构决定了后面所有环节加载时要解析它注册时要按 name 去重执行时要按 allowed-tools 做权限校验。Skill 的来源不止一种。内置的 bundled skills 由 CLI 自带在src/skills/bundled/index.ts的initBundledSkills()里注册动态的则来自项目级.claude/skills/name/SKILL.md、用户级~/.claude/skills/name/SKILL.md、托管策略目录、插件目录、遗留的.claude/commands/*.md以及 MCP 服务器暴露的命令。这些来源没有固定清单取决于你本机装了什么、项目里写了什么。理解这条链路的价值在于当 skill 行为不符合预期时你能快速定位是「没被扫描到」「解析失败」「注册被覆盖」还是「模型没触发」。下面按加载顺序逐层拆。2. 前置准备用 TaoToken 打通 Claude-Code 的模型调用链路在深入源码之前得先保证你的 Claude Code 能正常跑起来、能真实触发一次 skill 调用否则断点调试没有意义。这里涉及模型接入的问题。Claude Code 默认走 Anthropic 官方接口但很多开发者在本地调试时希望有一个稳定的、可观测的调用入口方便配合源码追踪看请求到底发了什么。我自己的做法是通过 TaoToken 来做模型接入层。它的 API 地址是https://taotoken.net/api兼容 Anthropic 的接口格式Claude Code 可以直接把 Base URL 指过去。这样做的实际好处是你在追踪 Skill 执行链路时模型侧的请求和响应都能在一个统一入口观察配合本地日志能更快定位「是 skill 没注册上」还是「注册了但模型没选它」。具体配置上Claude Code 读取的是环境变量或 settings 文件。你需要准备三件套Base URL、API Key、Model ID。Base URL 填https://taotoken.net/apiAPI Key 在控制台的 API Keys 页面生成Model ID 按你实际要用的模型填。这三者缺一不可尤其是 Model ID填错会直接导致请求 404 或模型不存在。如果你还没生成 Key可以先去控制台创建https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentskill_source_walkthroughutm_campaignrewrite。生成后复制保存Key 只显示一次。配置方式有两种选一种即可。第一种是环境变量适合临时调试export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_API_KEYsk-你的key export ANTHROPIC_MODEL你的模型ID第二种是写进 Claude Code 的 settings 文件适合长期使用。在项目根目录或用户目录下创建.claude/settings.json{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-你的key, ANTHROPIC_MODEL: 你的模型ID } }注意路径要和 Claude Code 实际读取的一致项目级是repo/.claude/settings.json用户级是~/.claude/settings.json。项目级优先级更高调试时建议用项目级避免污染全局配置。配好之后先别急着看源码跑一个最小验证启动 Claude Code敲/skills确认菜单能正常弹出、能列出内置 skill。如果这一步就失败说明模型接入没通先解决接入问题再往下走。验证模型是否正常响应可以直接在对话里发一句简单指令或者用模型对话页面单独测一下https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentskill_source_walkthroughutm_campaignrewrite。这一步的意义在于建立基线接入通了、/skills能列出内容后面源码追踪时任何异常都能排除掉「环境没配好」这个干扰项。很多人调试 skill 时卡半天最后发现是 Base URL 或 Key 的问题白白浪费时间。3. 可复制配置Skill 加载路径与注册表结构拆解现在进入源码层面。Skill 的加载分两个阶段扫描收集和注册。扫描阶段负责从各个来源路径找到SKILL.md文件注册阶段负责解析 frontmatter、去重、放进统一的注册表。先看内置 bundled skills。入口在src/skills/bundled/index.ts的initBundledSkills()。这个函数在 CLI 启动时被调用把内置 skill 逐个注册进去。内置 skill 分两类默认启用的和条件启用的。默认启用的包括/update-config配置 settings.json 的权限、hooks、环境变量、/keybindings-help自定义快捷键模型可调用但用户不能直接调、/debug开启或读取本会话 debug 日志、/skillify把当前会话的可复用流程沉淀成 Skill 文件、/remember整理 auto-memory 提升到 CLAUDE.md、/simplify审查已改代码的复用性与质量。这些在多数环境下都可见。条件启用的则依赖功能开关或环境变量。比如/verify需要USER_TYPE ant/lorem-ipsum和/stuck是 Ant 内部用/batch始终注册但需用户手动调/loop依赖AGENT_TRIGGERS/schedule依赖AGENT_TRIGGERS_REMOTE加策略允许/claude-api依赖BUILDING_CLAUDE_APPS/claude-in-chrome在 Chrome 扩展可用时启用。还有几个是 stub比如/dream、/hunter、/run-skill-generator在还原仓库里只有占位实现。动态 skill 的扫描路径是重点因为你自己写的 skill 走的就是这条路来源路径作用范围项目级.claude/skills/name/SKILL.md仅当前仓库用户级~/.claude/skills/name/SKILL.md所有项目托管策略管理目录下的.claude/skills/企业策略下发插件各 plugin 的 skills 目录安装插件后自动加载遗留.claude/commands/*.md旧版 commands 目录MCP连接的 MCP 服务器由 MCP 暴露的 skill 命令扫描逻辑会遍历这些路径对每个SKILL.md做解析。解析的核心是 frontmatter用 YAML 格式读出来映射到内部的数据结构。这里有个容易踩的坑frontmatter 格式错误比如缩进不对、冒号后没空格会导致解析失败但错误信息不一定明显skill 就静默消失了。注册表本身是一个以name为键的 map。同名 skill 的处理顺序决定了谁覆盖谁通常是后加载的覆盖先加载的或者按优先级排序。项目级一般优先于用户级这样你可以在具体项目里覆盖全局 skill。如果你想在本地验证扫描逻辑可以在initBundledSkills()调用之后、动态扫描开始之前打断点观察注册表在每一步之后的内容变化。具体做法是在源码里找到扫描函数在遍历路径的循环里加日志for (const skillPath of skillPaths) { console.log([skill-scan] found:, skillPath); const parsed parseSkillFile(skillPath); console.log([skill-scan] parsed:, parsed?.name, parsed?.description); registry.set(parsed.name, parsed); }跑一次启动流程看日志里有没有你写的 skill。如果没有说明路径不对或文件没被扫到如果有但parsed是 undefined说明 frontmatter 解析失败。这一步能快速区分「没找到」和「找到了但解析挂了」两类问题。4. 验证请求断点追踪一次 Skill 从触发到执行配置和注册都确认之后最关键的是验证执行链路。Skill 的执行触发分两侧用户侧通过/skill-name直接调用模型侧通过 Skill 工具调用。系统提示里会列出可用 skill 的名称和简介模型据此决定是否触发。先做用户侧验证。启动 Claude Code敲/skills确认你的 skill 在列表里。然后直接调用它比如/my-skill。这时候在源码里调用入口会先查注册表拿到 skill 定义再校验allowed-tools最后把 skill 正文作为指令注入当前上下文。断点建议打在这几个位置注册表查询处、allowed-tools 校验处、指令注入处。观察每一步的入参和出参。注册表查询返回 undefined 说明 name 对不上校验失败说明你调用了 allowed-tools 之外的工具注入后模型没反应说明指令内容或 description 不够明确。模型侧验证更接近真实使用场景。你不需要显式敲命令而是给一个符合 skilldescription描述的任务看模型会不会主动调用。比如你的 skill 描述是「审查代码质量」那就贴一段代码让模型审查观察它是否触发 Skill 工具。这里可以用一个请求验证的小技巧在模型调用层加日志打印每次请求的 system prompt 和 tools 列表。system prompt 里应该包含可用 skill 的名称和简介tools 列表里应该有 Skill 工具。如果 system prompt 里没有你的 skill说明注册了但没进提示词如果 tools 里没有 Skill 工具说明工具注册环节有问题。console.log([request] system prompt skills section:, extractSkillsSection(systemPrompt)); console.log([request] tools:, tools.map(t t.name));成功的结果应该是system prompt 里能看到你的 skill 名称和 description模型在合适场景下返回一个 Skill 工具调用参数里带上 skill name然后执行链路继续往下走按 skill 正文的指令调用 allowed-tools 里的工具。实测下来最常见的「模型不触发」原因是 description 写得太泛或太窄。太泛比如「帮助处理任务」模型不知道什么时候用太窄比如「处理 2024 年 3 月的 CSV 文件」又匹配不上。好的 description 应该是一句「何时使用」的清晰描述配合whenToUse补充细节。如果你在追踪过程中需要反复验证模型行为可以配合模型对话页面单独测 prompt把 skill 正文贴进去看模型反应这样能快速迭代 description 而不必每次重启 Claude Codehttps://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentskill_source_walkthroughutm_campaignrewrite。5. 常见报错排查401、local proxy failed 与 reading choices追踪链路时遇到的报错大部分能归到几类。下面按真实报错对照排查。401 Unauthorized。这是接入层最常见的。原因通常是 API Key 没配、配错、或者环境变量没生效。排查顺序先确认ANTHROPIC_API_KEY是否设置echo $ANTHROPIC_API_KEY看有没有值再确认 settings.json 里的 key 和实际生成的一致最后确认 Base URL 是https://taotoken.net/api而不是别的。注意 Key 只在生成时显示一次如果丢了就重新生成一个。三件套Base URL Key Model ID任何一个错都会导致 401 或 404。local proxy failed。这个报错通常出现在 Claude Code 尝试连接本地代理但失败时。如果你没有配代理检查是不是环境里残留了HTTP_PROXY或HTTPS_PROXY变量清掉再试。如果你用的是统一接入层确认 Base URL 指向正确不要同时配代理和自定义 Base URL两者会冲突。reading choices 相关报错。这类错误一般出现在解析模型响应时响应结构不符合预期。常见原因是 Model ID 填错返回的不是标准 chat completion 结构或者接入层返回了错误格式。排查方法在请求层打印原始响应看返回的 JSON 结构里有没有choices字段。如果没有说明请求根本没到模型或者模型 ID 无效。OAuth 相关报错。Claude Code 某些功能依赖 OAuth 登录态。如果你看到 OAuth 报错先确认是不是用了需要登录的功能。用 API Key 接入时一般不走 OAuth但如果配置里混了登录态和 Key可能冲突。清理掉冲突的配置统一用 Key 接入。Skill 不生效但无报错。这是最隐蔽的。分几种情况frontmatter 解析失败检查 YAML 格式冒号后要有空格缩进用空格不用 tabname 重复被覆盖检查是否有同名 skill路径不对项目级确认在.claude/skills/下用户级确认在~/.claude/skills/下allowed-tools 里写了不存在的工具导致校验失败。排查时建议按链路顺序来先确认文件被扫描到看扫描日志再确认解析成功看 parsed 结果再确认注册进表看 registry 内容再确认进了 system prompt看请求日志最后确认模型触发看响应里的工具调用。每一步都有对应的日志点按顺序查能快速定位。如果你在接入层反复遇到问题可以对照接入文档逐项检查配置https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentskill_source_walkthroughutm_campaignrewrite。文档里有完整的 Base URL、Key、Model ID 配置示例以及常见错误的处理方式。6. 长期调试与 Agent 场景把 Skill 链路追踪变成日常能力单次追踪解决的是「这一次为什么不生效」但如果你在持续开发 skill、或者在做 Agent 相关的项目需要的是把这条链路追踪变成日常能力。这意味着你要有一套稳定的调试环境能随时复现、随时观察。第一件事是把配置固化下来。项目级的.claude/settings.json提交到仓库团队里每个人拉下来就能用同一套接入配置。Key 不要提交用环境变量注入settings 里只放 Base URL 和 Model ID。这样既统一了环境又不会泄露凭证。第二件事是建立日志习惯。在扫描、解析、注册、请求四个环节各留一个日志点平时关掉调试时打开。这样遇到问题不用改代码改个开关就能看到全链路。日志格式统一方便 grep。第三件事是准备一组测试 skill。写几个覆盖不同场景的 skill一个只用 Read 的、一个用 Bash 的、一个 allowed-tools 故意写错的。用它们来验证链路各环节是否正常。每次改完加载逻辑跑一遍这组测试能快速发现回归。如果你在做的是长期编码或 Agent 类项目skill 的稳定性和可观测性会直接影响开发效率。这种情况下可以考虑用 Coding Plan 来获得更稳定的调用配额和更完整的调试支持https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentskill_source_walkthroughutm_campaignrewrite。它适合需要持续跑 Agent、频繁触发 skill 的场景配额和稳定性比按次调用更适合开发调试。最后说一个实际经验追踪 Skill 链路时最容易忽略的是「模型侧触发」这一环。很多人把精力全放在加载和注册上确认 skill 进了注册表就以为完事了结果模型根本不调用。记住注册成功只是「可用」模型触发才是「生效」。这两者之间隔着 system prompt 的呈现和 description 的质量。调试时两边都要看别只盯着一头。把这条链路走通一次之后你对 Claude Code 的 skill 机制就有了完整的认知从磁盘文件到注册表从注册表到 system prompt从 system prompt 到模型决策从决策到工具执行。以后再遇到 skill 相关问题按这条链路顺序排查基本都能定位到具体环节。
阅读完成 · 觉得有帮助?