我最早接触Claude Code的Skills系统是在一个代码库分析任务做到一半的时候。当时Claude Code已经能读文件、跑命令、改代码可每一次会话我都要反复交代背景哪些目录不用管、测试命令是什么、代码风格要注意什么、最终报告要按什么格式出。直到我把这些规则整理成一个Skill让Claude Code在需要时自己加载工作流才真正变得顺畅。这篇就来聊聊Claude Code Skills系统的技术机制包括技能包怎么组织、如何在项目中落地以及几个我在实际场景里用过的应用案例。不管你刚接触Agent类工具还是已经折腾过一段时间这套思路都能直接套用。1. 先从设计理念说起Skills到底解决什么问题1.1 没有Skills之前我们怎么用Claude Code干活最开始用Claude Code的时候我采用的是“一次性对话”模式。什么意思呢就是把所有背景信息都塞进首条消息里项目结构、技术栈、编码规范、常用命令、期望的输出格式。模型确实很聪明照着这些信息就能干活。但问题很快就暴露了——上下文窗口是有限的你塞进去的“背景说明书”越多模型真正用来思考当前任务的余量就越少。尤其当你每天面对着同样类型的重复任务时效率不升反降。举个例子我经常要给一批SQL慢查询做索引评估。在没有Skills的时候我每次都要把评估标准和步骤重新贴一遍先看执行计划、检查type是否为ALL、关注rows估算值、再判断是否需要联合索引。贴完这一大段Claude Code才开始分析。一次两次还能接受时间一长就是巨大的重复劳动而且每次贴的措辞还会稍有出入导致输出质量不稳定。后来我把这套评估流程做成了技能包情况就完全不同了。只需要用一句“帮我看一下这些慢查询的索引问题”Claude Code就会自动识别出应该加载“数据库索引体检”技能然后按技能里定义的步骤执行输出格式也统一了。这背后就是Claude Code Skills系统在做语义匹配模型先读技能的名称和描述再决定要不要把完整的操作手册加载进上下文。1.2 Skills的定位可复用的“能力包”Claude Code的Skills系统本质上是一种可复用的“能力包”。一个技能通常放在一个目录里里面可以包含操作说明、参考文档、脚本、模板等文件。核心文件是SKILL.md它用Markdown格式定义了两件事这个技能在什么情况下使用以及使用时应该怎么操作。可以把它理解成给Agent配的“岗位手册”。普通员工入职时会拿到一份工作流程说明里面有标准操作步骤、常见注意事项和可调用的工具。Skills做的事情完全一样把某个领域的操作经验沉淀成一个独立的、按需加载的模块。它和传统插件模式的区别在于加载策略。传统插件通常是在会话开始时就全部加载不管当前任务用不用得上而Skills是“按场景触发”的只有当用户请求涉及对应能力时系统才把完整的技能内容注入上下文。这种设计直接影响成本和质量。如果所有技能都常驻上下文中会充斥着大量无关指令既浪费Token又容易让模型产生混淆——不同技能之间可能还有互相矛盾的要求。按需加载则有效避免了这些问题也让技能本身可以写得更详细、更专业。1.3 为什么选择语义触发而不是硬编码最初我也想为什么不做一个命令前缀直接调用比如输入/db-check就执行固定的技能。硬编码确实简单直接但它有两个明显的短板。第一用户不会记得每个技能对应的命令。技能多了之后命令列表本身就成了负担。第二硬编码触发要求在会话里显式输入命令打断了自然对话的流畅性。用户直接说“这几个SQL看起来不太对劲帮我看看索引”这本身就是最自然的表达。语义触发能识别这种意图不需要用户学习额外的命令语法。Claude Code的做法是在会话开始时扫描可用的技能列表提取每个技能的name和description形成一个轻量的索引。当用户发出请求时模型根据这个索引判断当前意图和哪个技能匹配。一旦匹配成功系统再加载完整的SKILL.md内容和关联的辅助文件。整个过程看起来像是模型突然“想起了”自己还有这么一套专业流程——实际上这就是一次基于语义的上下文注入。这个设计有一个很精妙的地方索引阶段的描述文本要尽可能精炼而完整技能内容可以足够详细。因为索引内容是常驻上下文的一部分如果写得又臭又长同样会挤压思考空间。所以写技能的核心难点在于如何在description里用短短几句话把技能的适用场景说清楚让模型能准确命中又不至于误触发。2. 技能包长什么样目录结构、元信息与触发机制2.1 一个最简技能的完整目录先从我用得最多的一个技能目录说起。这个技能叫“code-review”用于系统化代码审查。完整的目录结构如下~/.claude/skills/ code-review/ SKILL.md scripts/ run_review.sh templates/ review_report.md在这个结构里SKILL.md是入口文件系统识别技能时首先读它。scripts目录存放辅助脚本用来处理那些不适合让语言模型直接“想”的确定性逻辑比如统计文件行数、提取代码块、调用静态分析命令等。templates目录则存放输出报告模板保证技能每次产出的文档格式一致。技能目录可以放在个人全局目录~/.claude/skills也可以放在项目目录下的.claude/skills或.agent/skills中。全局目录适合放那些跨项目通用的技能比如代码审查、日志分析、PR描述生成项目目录则适合放和当前代码库强相关的技能比如这个项目的特殊构建命令、部署流程、业务规则等。项目级技能还有一个好处如果你们团队用Git管理代码技能定义会跟随仓库分发新成员拉下代码后自己就拥有了同样的技能基础。2.2 SKILL.md里的frontmatter和正文SKILL.md主要由两部分组成开头的frontmatter和正文。frontmatter使用YAML格式关键字段是name和description。下面是一个实际参考--- name: code-review description: 用于对代码变更进行系统化审查。当用户提交一个PR、一个diff或一段修改代码并要求检查性能、安全、可维护性或测试覆盖时使用。日常问答不要使用。 ---name字段要简短通常用连字符连接的小写字母和目录名保持一致。description字段决定触发命中率这里有几个经验描述里要写清楚“什么时候用”最好加上“什么时候不要用”。比如上面加了“日常问答不要使用”就是为了减少误触发。正文部分才是真正的操作手册。这里写技能的具体执行步骤、规则和注意事项# 代码审查流程 ## 执行步骤 1. 先读取用户提供的diff或代码文件确认变更范围。 2. 使用 scripts/run_review.sh 对变更文件做基础统计输出变更行数、涉及函数列表。 3. 对照以下检查项逐条审查 - 性能循环内是否有重复查询、是否缺索引。 - 安全是否有SQL拼接、是否校验输入长度。 - 可维护性命名是否清晰、函数是否过长。 - 测试覆盖新增逻辑是否有对应测试。 4. 按 templates/review_report.md 输出报告问题按严重程度排序。 ## 重要约束 - 对于拿不准的问题只做提示不要自行修改代码。 - 如果涉及外部接口必须标明“需要人工确认”。正文不需要写得很长但要足够清晰。模型读到这段内容后会把它当作任务指令来执行。如果技能标题下有多条规则可以用列表和表格组织方便模型逐步遵循。2.3 技能如何被识别和加载很多人好奇技能放进去之后是不是马上生效我实际测试下来大部分版本支持热加载但为了稳妥通常重开会话更可靠。启动后Claude Code会在后台扫描技能目录为每个技能生成一条索引记录。这个索引只包含技能名和描述不会读取完整正文。假设你在对话里说“帮我审查一下这个变更”模型看到索引里有一条描述写着“用于对代码变更进行系统化审查……”语义匹配成功系统就把SKILL.md的完整内容注入进来同时被注入的还有它引用的辅助文件和模板。这一步完成后模型就像临时“入职”了审查岗位有了整套工作手册。这里有一个很关键的设计技能的正文不会被保留在下一次对话中。每次会话结尾这部分注入内容就会丢掉。所以技能必须写成自包含的文档不能依赖会话之前的临时记忆。换句话说在SKILL.md里如果写了“参照之前讨论的规则”那这个技能基本就废了——因为下次加载时模型压根不知道你之前讨论过什么。所有必要信息都应该写在这一个文件里。3. 手写一个“数据库索引体检”技能从零到可用的完整过程3.1 需求拆解与技能设计为了让这个过程更有代入感我来完整复盘一个我自己写过的技能“db-index-check”。这个技能解决的需求很具体我经常收到一堆慢查询日志需要分析哪些SQL语句存在索引问题。以前我手动看每一条explain效率很低而且标准不统一。现在我希望Claude Code能按固定流程替我完成初步分析我再复核最终结论。技能应该做到以下几点第一接收慢查询日志或SQL文本第二用程序化手段提取高频出现的表和SQL模式第三按统一的报告模板输出分析结果和建议。这里我理解的安全边界是不直接让Claude Code连接生产数据库而是只分析用户提供的文件或文本避免误执行危险操作。根据这个需求我创建一个目录db-index-check里面包含SKILL.md、一个统计脚本analyze_slow_query.py和一个报告模板report.md。3.2 编写SKILL.md与辅助脚本SKILL.md的frontmatter如下--- name: db-index-check description: 用于分析数据库慢查询日志检查索引缺失和性能瓶颈。当用户提到慢查询、SQL性能、索引优化、explain结果时使用。仅用于分析用户提供的日志或SQL文本不连接数据库执行任何操作。 ---正文部分我写得很具体# 数据库索引体检流程 ## 步骤 1. 读取用户提供的慢查询日志文件或SQL文本提取所有SQL语句。 2. 从SQL中识别主表名、关联表、WHERE条件字段、ORDER BY字段。 3. 对每条SQL如果用户提供EXPLAIN结果则重点检查以下信号 - type字段是否为 ALL全表扫描。 - key是否为 NULL未使用索引。 - rows估算值是否远大于实际表行数。 4. 调用 scripts/analyze_slow_query.py 日志文件 生成统计结果包括高频表名、高频模式、平均耗时。 5. 基于统计结果和EXPLAIN信号按 templates/report.md 格式输出报告。 ## 分析原则 - 推荐索引时优先考虑联合索引并说明字段顺序依据。 - 避免过度推荐同一个表最多建议3个新索引。 - 所有建议必须标注风险等级高、中、低。辅助脚本我用Python写因为做文本统计比Bash顺手。脚本接收一个文件参数输出一个JSON结果。#!/usr/bin/env python3 import sys, re, json, collections def main(path): with open(path, r, encodingutf-8, errorsignore) as f: content f.read() # 简单抽取SQL中的表名忽略复杂语法这里只做演示 tables re.findall(r(?:from|join)\s([a-zA-Z_][a-zA-Z0-9_]*), content, re.I) counter collections.Counter(t.lower() for t in tables if t.lower() not in (dual, system)) print(json.dumps(counter.most_common(10))) if __name__ __main__: main(sys.argv[1])实际上我的版本会处理更多的SQL模式但这里展示核心思路就够了。脚本的作用是给模型一个真实的统计数据避免它凭空猜测表名出现的频次。因为模型如果只靠读文本可能会把一些出现在注释里的表名也算进来脚本就能避免这个坑。3.3 本地测试与触发验证技能目录放好后我先在Claude Code会话里输入一个测试语句“我这里有个slow.log帮我看看哪些表最该加索引”第一版我并没有立即看到技能被触发。查看调试信息后发现是我的description里没有明确的“slow.log”相关词。修改之后我把description改成了现在这样再次测试技能就正常被加载了。验证生效的另一个技巧是看输出格式。如果模型输出的是report.md模板里的结构说明技能加载成功如果输出的是通用回答格式那很可能没触发。你也可以故意在模板里加一个标记比如“生成时间{date}”如果输出包含这个标记基本可以确认技能路径走对了。测试稳定后我还会做一次“排除测试”防止误触发。比如故意问一些无关的问题像“帮我分析这段代码的复杂度”这时候技能不应该被加载。如果被加载了说明description太宽泛需要继续缩小适用范围。3.4 为什么参数和阈值必须解释清楚写技能的时候还有一个容易忽略的点所有涉及判断的参数都要写明依据。比如我在正文里写了“rows估算值远大于实际表行数”这个“远大于”模型不知道是多少。所以我又补了一句“如果rows比实际行数高一个数量级以上标记为高风险。”这样模型的输出才可重复。同理如果你在技能里写了“优先使用左前缀索引”那最好顺带解释“因为索引在复合列上只能从左到右匹配”。技能正文不是给模型科普而是约束模型让它知道在什么情况下做什么决定。一段好的技能正文应该像一个半自动化的检查清单而不是一篇开放式的文章。4. 三个真实场景下的应用案例解析4.1 案例一遗留代码库的模块梳理有一次我需要接手一个别人维护了很久的后端项目。代码量不小文档缺失模块边界模糊。直接让Claude Code去读它也能回答但每问一次都要重新确认目录结构。后来我写了一个“codebase-mapper”技能让它按固定流程输出模块地图。技能的核心步骤是先扫描顶层目录和模块入口文件然后识别路由注册、服务注册等关键文件再用脚本统计每个模块的代码行数和相互依赖关系最后生成一份Markdown报告列出模块名称、核心入口、依赖项、以及建议阅读顺序。实际应用时我只说了一句“帮我梳理一下这个仓库的模块结构”Claude Code就自动加载技能先跑脚本、再读关键入口文件最后输出了一份很像样的模块地图。这份报告让我快速锁定了几个核心模块节省了一天多的排查时间。技能的description写的是“用于代码库结构梳理、模块边界分析、新项目快速上手。当用户要求了解项目整体架构或模块划分时使用。”这个描述不算窄但因为内容比较通用误触发的风险也低。算是一个典型的“低风险、高回报”技能。4.2 案例二接口变更影响面分析另一个让我觉得值回票价的技能是“impact-analysis”。它的目标是分析一次代码变更会影响哪些调用方。以往人工处理时要么用全局搜索逐个找引用要么是凭感觉判断容易漏掉间接调用。这个技能利用了git diff和ripgrep两个工具。流程是这样的先读取git diff获取变更文件列表再解析变更的函数名、类名、接口路径然后用ripgrep在整个仓库里搜索这些符号的所有引用位置最后根据引用位置所属的模块和测试文件生成影响面报告。脚本负责提取符号和统计引用模型负责判断调用链上的风险。实际案例中一次接口的请求体字段改名影响到了十几个下游服务。技能生成的报告准确列出了一处单元测试和两个外部对接模块都在没有看完整调用链的情况下找到了。这种技能的价值在于它把“全局搜索、符号提取、调用分析”这几个可程序化的步骤固定下来模型只需要做结果的解释和风险评级大大降低了主观跳步的概率。4.3 案例三自动化生成测试用例测试用例生成是我见过最常见的技能需求也是最容易翻车的。如果让模型“生成所有测试”它往往会拍脑袋乱来。我的“test-generator”技能定义了一套约束只针对用户指定的函数或模块先读取函数签名和类型注解再根据已有测试风格生成模板生成内容以“骨架”为主不追求一步到位。简单示例当我说“给这个calculate_discount函数生成测试用例”时技能会先找到该函数的定义提取参数price和level及其默认逻辑再根据项目现有测试框架比如pytest生成测试代码。技能中明确要求生成的用例必须包含边界值、正常分支、异常分支并且对不确定的业务规则用注释标记# TODO: 确认折扣规则而不是硬编一个预期值。实际测试中生成的骨架质量相当不错我只需要补几组真实业务数据就能覆盖主要分支。这个技能的关键在于正文里写了“不要生成超出函数可见范围的测试”否则模型很容易虚构依赖和mock对象。它告诉我们好的技能不是让模型彻底自动化而是让模型把重复的部分做完把需要判断的部分留给人。5. 踩坑记录与排查技巧5.1 技能总是不被触发如果你发现Claude Code完全无视技能先别急着怪系统。我遇到最多的原因是description写得太笼统。比如“分析数据库”这种描述语义匹配时可能不会被选中因为用户提问的措辞千变万化很难从“帮我看看索引怎么优化”匹配到“分析数据库”上。更好的写法是用几个常见的触发句式组织描述“当用户要求查慢查询、看索引、优化SQL性能、分析explain结果时使用”。其次检查目录结构。SKILL.md必须直接放在技能目录下不能嵌套一层子目录再放。另外不同版本的Claude Code可能识别优先级不同全局目录和项目目录同时存在同名技能时项目目录通常会覆盖全局目录。如果你修改了某个技能但没生效先确认你改的是不是真正被加载的那个。5.2 技能被错误触发误触发是另一个常见问题。有一段时间我的“code-review”技能description里写了“任何时候都可用”结果用户正常问代码问题也会触发它导致模型一上来就跑审查流程上下文被大量无关模板占据。后来我在description末尾加了一句“仅当用户明确提出审查要求时使用普通代码问答不要使用。”误触发率立刻下降。如果误触发已经发生你只需要在对话里说“不要使用该技能直接回答”模型通常就会绕过。但要根治还是要改description。一个辅助技巧是在技能正文的开头写“除非用户明确申请否则不要主动启动此技能”这能在语义层面进一步拦住模型。同时也要注意多个技能之间的边界。如果两个技能的description都包含“分析”这个关键词同一条请求可能会同时命中两者导致上下文被塞进两份内容。解决方法是把技能的适用范围写窄并在措辞上区分比如一个写“慢查询日志分析”一个写“代码复杂度分析”。5.3 脚本执行环境不一致技能里的脚本在测试时一切正常结果在实际会话中突然报错通常是因为路径假设错了。我踩过的一个坑是脚本里直接写了./analysis_result但Claude Code执行脚本时的工作目录是当前对话的项目根目录而不是技能目录。最终相对路径指向了错误位置。对策很简单在SKILL.md正文里明确标注“所有脚本的执行路径以会话当前工作目录为准”或者让脚本内部使用os.path.abspath(__file__)来定位自身目录。另外记得给脚本加执行权限。如果你用Python可以不用#!/usr/bin/env python3而是直接让技能正文写“运行python3 scripts/xxx.py 参数”避免权限和解释器路径的坑。5.4 上下文平衡与权限控制最后还有一个容易忽视的问题技能本身也会占用上下文。很多人会把几十条经验写进SKILL.md结果加载后挤占了大量空间反而影响后续推理。我的经验是技能正文尽量控制在1000字以内如果确实需要大量参考内容就把它拆成独立的参考文件在正文里只需一句“阅读references/constraints.md”。这样既保证了技能信息完整又让模型在不需要细读规则时不至于全文加载。权限控制更要注意。技能的自动化能力是一把双刃剑。如果你的技能里写了“自动执行rm -rf”那就不是技能是事故触发器。我在所有技能正文里都会固定加一段“安全约束只做分析和建议不做任何破坏性操作涉及修改文件时必须先展示变更内容等待用户确认。”这个习惯帮我避免了好几次误删和误改。Claude Code Skills系统本身提供的是框架能力具体边界还是由你在技能定义里画清楚。我之前还在项目级的agent/skills里放过一套只有3个技能的小集合分别是“会话开场简报”、“测试运行辅助”、“提交信息生成”。这三个技能每个都很轻但组合起来让团队新成员上手项目的成本降低了不少。后来我把常用的“PR描述生成”也做成了技能每次提交后说一句“帮我生成PR描述”它就能按项目模板输出规范的描述内容不再需要我反复复制粘贴格式。一路用下来我最大的体会是Skills系统的核心不是“写几个文件”而是“把你的工作方法论结构化”。如果你能把你反复做的那件事讲清楚拆明白它就是最适合做的第一个技能。第一次写可能不好用没关系多跑几遍从误触发和输出质量里改描述、补约束这个迭代过程本身就是对工作流的一次梳理。希望这篇拆解能给你的项目带来一些可直接落地的灵感。
阅读完成 · 觉得有帮助?