☰
Claude Skills实战:构建专业级AI Agent的完整指南
2026/10/3 20:54:18 网站建设 项目流程

去年年底到今年,AI Agent 开发几乎成了圈子里绕不开的话题。我自己的项目从简单的 Prompt 组合到接入各种工具链,踩了不少坑,也一直在找一个既灵活又不至于失控的落地方式。直到我把Claude Skills用进生产项目,才真正感觉到“Agent 开发”这件事从拼 Prompt 变成了拼工程化能力。这篇文章不聊概念,只讲我在实际项目中怎么用 Claude Skills 搭一个专业级 AI Agent:从核心设计、目录规范、脚本实现到排查实录,全部是我自己验证过的路径,你可以直接照着抄。

整篇内容适合两类人:一是已经用 Claude 写代码、做自动化,但觉得“对话式”开发不够稳定的开发者;二是想从零开始搭建 Agent,又不想一上来就被 LangGraph、多智能体框架绕晕的朋友。读完你会清楚:Skills 和 MCP 的分工边界在哪里,一个可复用的技能应该怎么拆,遇到“技能加载失败”“上下文刷爆”这类问题该怎么定位。

1. 站在 Agent 开发的分岔路口:为什么 Claude Skills 值得学

如果你和我一样从 AI 编程工具刚火的时候就开始折腾,大概会经历三个阶段:先是觉得“对话生成代码好神奇”,然后发现“改来改去还是得自己动手”,最后开始研究“怎么让模型自动执行多步骤任务”。Claude Skills 就是第三个阶段的产物,它把“一次性对话生成”升级成了“可复用、可组合、可审计的技能调用”。

我最初看到 Skills 这个概念时,第一反应是“这不就是高级版的 Prompt 模板吗”?结果动手搭了一个代码审查技能之后,发现完全不是一回事。核心区别在于:Skills 让 Claude 具备了一套完整的“感知-决策-执行”闭环。模型不再只是“读你写的提示词然后给建议”,而是能够在合适的时候主动调用你准备好的脚本、读取你指定的文件、按照你预设的检查清单执行任务,最终给出结构化结果。

1.1 从 Prompt 工程到技能装配:范式转变

先聊一个我自己的真实感受:以前做自动化,最痛苦的不是模型不会写代码,而是“它每次写的都不一样”。同一个需求,今天让它生成一个数据清洗脚本,它给你用 pandas;明天再问,又改成了纯 Python 文件读写。不是模型不好,而是它的行为边界太宽了。

Claude Skills 出现之后,这个问题被“技能装配”的思路解决了。每个技能本质上是一个带有 YAML 元信息的目录,里面有一个SKILL.md文件描述这个技能是干什么的、什么时候该调用、有哪些执行步骤,再加上可选的脚本目录。当 Claude 在执行任务时感觉到“当前场景和某个技能描述匹配”,它就会自动加载这个技能的指令和工具。

这样你就把“每次对话都要从零约束模型”变成了一次性定义、无限次复用。我项目里有一个“日志巡检”技能,定义好之后,每次让它检查服务器日志,它都会按照我写的检查顺序来:先过滤 ERROR 级别,再按时间窗口聚合,最后生成报告。输出风格、字段格式完全稳定,这一点在交付客户项目的时候非常加分。

1.2 与 MCP、Agent SDK、Function Calling 的分工与边界

很多人会把 Claude Skills 和 MCP 混在一起,其实它们是互补关系,不是替代关系。我打个比方:MCP 是“插头”,解决的是 Claude 怎么连接外部数据源和工具;Skills 是“作业指导书”,解决的是 Claude 拿到工具之后怎么做才规范。一个管连接,一个管流程。

在实际项目里,我的经验是:先看任务需不需要外部数据源。如果只是让 Agent 基于已有文件、代码库做分析和操作,Skills 就够了,不需要引入额外的服务。如果 Agent 要读数据库、调用第三方 API、操作内部运维平台,那就通过 MCP 把这些能力接进来,然后在 SKILL.md 里说明“执行这个任务时优先使用哪个 MCP 工具”。

这里顺带提一下 Agent SDK 和 Function Calling 的边界。Function Calling 是模型和函数之间的“一次性握手”,适合单轮工具调用;Agent SDK 偏重于构建完整的智能体运行时,适合复杂的状态流编排;而 Claude Skills 更像是一种轻量级的“能力模块”,你既可以在 Claude Code 里直接用,也可以配合 Agent SDK 把它们组织成更大的任务图。如果项目还处于验证阶段,我建议优先从 Skills 入手,成本最低,见效最快。

2. 构建你的第一个 Claude Skills Agent:整体设计与思路拆解

我真正把 Claude Skills 用到生产环境,是给团队搭了一个“代码变更影响分析 Agent”。这个 Agent 的输入是一段 git diff,输出是:受影响的模块、潜在风险点、建议补充的测试用例、需要人工确认的变更项。早期用纯 Prompt 做,每次输出格式都不一样,后来用 Skills 重写,输出稳定性和可维护性直接上了一个台阶。

这个项目从设计到落地大概花了三天,核心就一句话:把 Agent 的“经验”沉淀成“技能”,把“技能”变成可被模型自动触发的工程资产。下面我把整个设计思路和方案选型过程拆开来讲,包括每个选择背后的原因。

2.1 与“无脑堆 Prompt”相比,Skills 方案的三个核心优势

设计方案的时候,我其实纠结过:是继续在 CLAUDE.md 里写一堆长篇指令,还是迁移到 Skills。当时对比下来,Skills 压倒性胜出,核心优势有三个:

第一个优势是触发成本低。CLAUDE.md 里的指令不管当前任务需不需要,Claude 每次都要把所有内容读进上下文,既占 token 又会造成“指令疲劳”——写太多规则,模型反而不知道该优先遵守哪一条。Skills 是按需加载的,模型根据当前任务判断是否命中某个技能,然后再读取该技能的完整描述。也就是说,技能一多,上下文反而更干净。

第二个优势是可版本化。每个技能都是一个独立目录,天然适合用 Git 管理。我可以给产品版本创建一个技能分支,给测试环境创建另一个技能分支,哪个技能出现回归,单独回滚那一个目录就行。这在纯 Prompt 方案里是做不到的——CLAUDE.md 一改,整个 Agent 行为都受影响。

第三个优势是边界清晰。Skills 可以在 YAML 头里声明允许使用哪些工具,甚至指定模型。这种“技能内部声明”让权限控制变得很直观,我可以把一个技能配置成只能读文件不能执行命令,把另一个技能配置成可以调用 Bash 但不能联网。作为交付物,给客户演示的时候也特别容易讲清楚。相比之下,纯 Prompt 方案里的权限是靠“语气”约束的,模型偶尔会不听。

2.2 方案选型:Skills + 少量脚本 vs 完整 Agent 框架

在动手之前我还考虑过直接用 LangGraph 或者 Spring AI 那套多智能体框架来做。后来放弃了,原因很简单:对于单 Agent 多技能的场景,上框架是过度设计。LangGraph 适合需要复杂状态机、多 Agent 协作、精细控制循环时长的场景;但如果你核心诉求是“让 Claude 在正确的时候做正确的事”,Skills 天然就是那个“正确的事”的容器。

这不是说框架没用。实际上,当我需要同时跑“代码分析 Agent”和“文档生成 Agent”并且要共享结果时,我会用 Agent SDK 做编排,让两个 Agent 通过共享状态协作。但每个 Agent 内部的“专业能力”依然来自 Skills。所以更准确的说法是:Skills 是 Agent 的“肌肉”,框架是“骨骼”,两者并不冲突。

另一个差点让我走弯路的选择是“有没有必要每个步骤都写脚本”。我的答案是:不需要。Skills 的 SKILL.md 里可以直接写步骤指令,让 Claude 自己决定怎么执行。只有那些对确定性要求极高的环节(比如解析 git diff、过滤日志、解析 JSON),才值得写一个独立脚本,因为让模型用自然语言去解析复杂文本,偶尔会出低级错误,但脚本永远不会。我最终的方案是:约 30% 的环节写成 Python 脚本,70% 的环节用自然语言步骤描述。

3. 从零到一:专业级 Agent 的实操过程与核心实现

有了设计思路,接下来就是动手。这一节我会完整展示我是怎么搭建一个“代码变更影响分析 Agent”的,从技能目录结构、SKILL.md 的 YAML 配置,到核心 Python 脚本、Agent 主配置,每一步都给出可直接复制的代码。这个项目目录规范我后来直接复用到其他 Agent 上,算是被验证过的模板。

需要提前说明的是,下面的实现基于 Claude Code + Claude Skills 的常见实践路径,Skill 目录结构、YAML 字段是当前版本验证可用的方案。如果未来 Claude 版本更新导致字段变化,核心思路依然成立,无非是配置字段名称有调整。

3.1 第一步:初始化技能目录与工程骨架

先约定一下技能存放位置。Claude Code 默认会扫描两个技能目录:用户级目录~/.claude/skills/和项目级目录.claude/skills/。我的习惯是:通用技能(比如代码审查、日志分析)放用户级,任何项目都能用;项目专属技能(比如针对某个系统的变更分析)放项目级,避免污染其他项目。

# 创建项目级技能目录 mkdir -p .claude/skills/impact-analysis/scripts # 查看目录结构 tree .claude/skills/ # .claude/skills/ # └── impact-analysis # ├── SKILL.md # └── scripts # ├── parse_diff.py # └── report_generator.py

这里有一个细节:技能目录名建议用英文短横线命名,比如impact-analysis,不要用空格或者中文。原因有两个,一是模型在自然语言描述中引用技能时,短横线命名更容易被准确识别;二是在文件路径中短横线不会引发转义问题。我最初建了一个叫代码分析工具的目录,后面在脚本里引用路径时踩了不少坑,统一改成英文后就好了。

3.2 第二步:编写 SKILL.md 并理解 YAML frontmatter

SKILL.md 是整个技能的“大脑”。它分为两部分:开头的 YAML frontmatter 和正文的 Markdown 指令。模型会先读取 frontmatter 里的 description 来决定“当前场景是否要用这个技能”,命中之后才会读取正文来执行具体步骤。

--- name: impact-analysis description: 分析代码变更影响范围,识别风险模块,生成测试建议。当用户提供 git diff、代码变更、commit 信息,或要求评估某个改动的影响范围时使用本技能。典型触发场景包括:代码审查、合并请求预检、变更风险评估、上线前影响面确认。 allowed-tools: - Bash - Read - Write model: claude-sonnet-4-5 ---

这几个字段的含义我逐个说明:

  • name:技能的唯一标识,建议和目录名保持一致。
  • description:这是整个 SKILL.md 里最重要的字段。模型就是靠它来判断“什么时候该用这个技能”。如果描述太窄,模型会漏用;太宽则会在不该用的时候强行触发。我这边测试下来,最有效的描述写法是“功能描述 + 触发条件 + 典型场景列举”三段式,命中率能从 60% 提到 90% 以上。
  • allowed-tools:技能可以使用的工具白名单。这里我只给了 Bash、Read、Write,意思是这个技能可以做文件读写和命令执行,但建议你根据场景收紧。比如一个纯分析技能,完全不需要 Write 权限。
  • model:可选字段,指定该技能使用哪个模型执行。像这种需要严谨分析的任务,我会指定 Sonnet,响应速度更快且成本适中。需要高难度推理时,再切到 Opus。

说完 frontmatter,再看 SKILL.md 正文部分。正文以 Markdown 编写,核心任务是告诉模型“拿到这个技能之后,按照什么步骤执行、中间要注意什么、输出什么格式”。我给这个技能写的正文指令如下:

# 代码变更影响分析技能 ## 执行步骤 1. 首先通过 `git diff --stat` 概览变更范围,再通过 `git diff <commit1> <commit2>` 获取完整变更内容。 2. 调用 `python3 scripts/parse_diff.py <diff文件路径>` 解析变更,提取变更文件列表、新增/删除行数、涉及的关键函数名。 3. 根据解析结果,逐一判断每个变更文件的风险等级: - 高风险:改动核心业务逻辑、公共工具函数、数据库迁移脚本。 - 中风险:改动模块内部实现但不涉及对外接口。 - 低风险:新增独立文件、注释修改、不影响逻辑的格式化调整。 4. 生成测试建议:针对高风险文件列出重点回归场景,针对中风险文件列出冒烟测试范围。 5. 将结果写入 markdown 文件 `impact_report_YYYYMMDD.md`,输出给用户。 ## 注意事项 - 如果 diff 中涉及依赖管理文件(如 requirements.txt、package.json),务必在报告中单独列出,并提示团队检查依赖冲突。 - 如果变更文件包含 TODO/FIXME 注释,在报告中单独标记。 - 分析结论必须基于 diff 内容,不要推测文件内容,必要时才读取目标文件。

这段正文的目标是让模型“有章法地干活”,而不是漫无目的地看代码。你可以把它理解成给实习生写了一份带流程、带标准、带交付物要求的任务书,模型按着这份任务书执行,产出的稳定度就会非常高。

3.3 第三步:编写核心解析脚本并理解“为什么需要脚本”

SKILL.md 解决的是“怎么干活”,但有些环节我还是坚持用脚本。拿 diff 解析来说,直接让模型读一段几百行的 git diff 并总结变更点,它勉强能用;但一旦 diff 达到几千行,模型会开始丢细节、漏文件。脚本不会。

下面这个是parse_diff.py的简化版本,核心功能是解析 diff 并统计变更文件与函数级变更点。

#!/usr/bin/env python3 import re import sys from collections import defaultdict def parse_diff(diff_text): """解析 git diff 文本,返回文件级变更统计和函数变更点。""" file_changes = [] current_file = None hunk_info = None func_changes = [] for line in diff_text.splitlines(): if line.startswith("diff --git"): # 新文件开始 match = re.match(r"diff --git a/(.*) b/(.*)", line) if match: current_file = match.group(2) file_changes.append({ "file": current_file, "additions": 0, "deletions": 0, "funcs": [] }) elif line.startswith("@@") and current_file: hunk_info = line # 提取 hunk 中提及的函数名,常见于 Java/Python 等语言 func_match = re.search(r"@@.*@@\s*(?:-\s*)?(?:class|def|func|function)\s+([a-zA-Z_][a-zA-Z0-9_]*)", line) if func_match: func_changes.append({"file": current_file, "func": func_match.group(1)}) elif current_file and (line.startswith("+") and not line.startswith("+++")): file_changes[-1]["additions"] += 1 elif current_file and (line.startswith("-") and not line.startswith("---")): file_changes[-1]["deletions"] += 1 elif current_file and line.startswith("+") and "(" in line and ")" in line: # 粗略识别新增函数调用 call_match = re.search(r"([a-zA-Z_][a-zA-Z0-9_]*)\s*\(", line[1:]) if call_match: file_changes[-1]["funcs"].append({"type": "call", "name": call_match.group(1)}) # 合并函数变更信息到文件变更 for fc in func_changes: for fc_item in file_changes: if fc_item["file"] == fc["file"]: fc_item["funcs"].append({"type": "def", "name": fc["func"]}) return file_changes if __name__ == "__main__": if len(sys.argv) < 2: print("Usage: python3 parse_diff.py <diff_file>") sys.exit(1) with open(sys.argv[1], "r", encoding="utf-8") as f: content = f.read() result = parse_diff(content) for item in result: print(f"文件: {item['file']} (+{item['additions']}/-{item['deletions']})") for func in item["funcs"]: print(f" 变更点: {func['type']} -> {func['name']}")

这个脚本不复杂,但它把“提取变更文件、统计增删行数、定位函数级别变更点”这三个最耗 token 的操作从模型手里拿走了。模型只需要读取脚本输出的一小段结构化文本,就能基于它做分析和判断,上下文占用大幅下降。

写脚本时有一个比较容易忽略的点:不要试图让脚本一步到位生成最终报告。脚本只负责“数据提取”,把报告交给模型去写,因为报告需要结合业务语境做表达,这是模型的强项;而数据提取是确定性的,交给脚本才可靠。不要反着来。

3.4 第四步:配置 Agent 主入口并在 Claude Code 中验证

技能目录和脚本准备好之后,还需要有一个“Agent 主入口”,让 Claude 知道当前项目的背景、任务目标和如何使用这些技能。这个入口就是项目根目录下的CLAUDE.md,在 Claude Code 中扮演“团队负责人”的角色,统领所有技能调用。

# 项目背景 这是一个电商后端仓库,技术栈为 Python FastAPI + PostgreSQL。 本项目使用 Claude Skills 构建“代码变更影响分析 Agent”。 # Agent 工作目标 当收到 git diff 后,自动调用 impact-analysis 技能,输出变更影响报告。 # 工作规范 - 所有影响分析必须调用 impact-analysis 技能,不得脱离技能自行分析。 - 生成报告使用统一模板:变更概览、风险模块、测试建议、待确认事项。 - 报告输出到 docs/impact-reports/ 目录,文件名格式 impact_report_YYYYMMDD.md。 # 常用命令 - 查看当前分支变更:git diff main...HEAD - 运行技能脚本:python3 .claude/skills/impact-analysis/scripts/parse_diff.py <diff文件>

配置好之后,我在 Claude Code 里直接开始验证:

# 进入项目目录 cd ~/work/ecommerce-backend # 启动 Claude Code claude

然后在对话中输入:

帮我分析一下 main...HEAD 的变更影响范围

Claude 的表现是:先读取 CLAUDE.md,了解项目背景,然后识别到“变更影响范围”这个任务命中了impact-analysis技能,自动加载 SKILL.md,按步骤执行git diff生成 diff 文件,调用parse_diff.py解析,最后基于解析结果生成一份结构完整的impact_report_20250601.md。

整个过程中我唯一做的事情就是输入了一句需求。模型自主完成了:任务识别、技能加载、命令执行、脚本调用、报告生成。这就是 Claude Skills 构建 Agent 的完整闭环。

4. 常见问题与排查技巧实录

搭好第一版之后,我开始在不同项目里复用这套方案,期间踩过的坑不少。这里挑几个出现频率最高的问题,整理成速查表,每一条都是我自己定位和解决的,不是理论推测。

4.1 问题一:技能明明存在,Agent 却不调用

这个是我见过最多的问题,多半出在 SKILL.md 的description字段上。Claude 判断是否使用技能,几乎完全依赖这个字段的语义匹配度。如果你的 description 写的是“用于分析代码变更”,模型在面对“帮我看看这个改动有没有问题”时,大概率会漏选这个技能,为什么?因为“看看有没有问题”和“分析变更影响范围”在语义上不是强关联。

我测试出来的有效做法是:在 description 里把常见的口语化触发词都列出来。比如:“审查代码改动、评估 merge request 风险、说明这次改动的后果、列出需要重点测试的地方”。这些同义表达越多,模型精准命中的概率越高。写完 description 之后,建议用不同问法各试五次,出现两次以上漏触发就需要补充触发词。

4.2 问题二:技能脚本权限不足或路径找不到

如果你的技能脚本是 Python 或 shell,Claude Code 调用时偶尔会遇到两种报错:permission denied 和 file not found。前者是脚本没有执行权限,后者是相对路径出了问题。

处理权限问题,给脚本加执行权限即可。路径问题则需要注意一个坑:SKILL.md 里引用脚本时,建议用相对于技能目录的路径,并且在执行前先让模型确认当前工作目录。如果你的技能位于项目级目录,而 Claude 的执行目录在项目根目录,那么scripts/parse_diff.py是有效的。但如果技能位于用户级目录,而你在别的项目里调用,就要在 SKILL.md 里明确写明绝对路径或调用方式,否则模型会懵。

我现在的习惯是:在 SKILL.md 正文开头加一行“脚本执行路径说明”,比如:

本技能脚本位于:<技能目录>/scripts/parse_diff.py 执行方式:python3 <技能目录>/scripts/parse_diff.py <参数>

让模型先根据SKILL.md文件位置推导技能目录,再拼接脚本路径,实测下来路径错误率基本归零。

4.3 问题三:上下文被技能内容刷爆

技能本身的内容会占用上下文,如果你的 SKILL.md 写了几千字,再加上外部读取的文件,上下文很容易告急。尤其是多个技能依次触发时,上下文膨胀非常快。

我的解决思路是把 SKILL.md 精简到“流程控制”级别,详细的规则、规则表、检查清单不要写在 SKILL.md 里,而是放到技能目录下的另一个文件(比如rules.md或prompts.md),并在 SKILL.md 里指示模型“执行到某一步时再去读取这个文件”。这样上下文里永远只有当前需要的详细规则,不需要一次性加载全部内容。

例如,我把“测试建议生成规则”单独放到scripts/test_rule.md,SKILL.md 里只写:

生成测试建议时,先读取 scripts/test_rule.md 中的规则,再按规则输出。

这样技能加载时的 token 成本降到最低,模型执行到这一步才会按需读取详细规则。

4.4 问题四:模型不按 SKILL.md 的步骤执行

有时候模型加载了技能,但没有严格按 SKILL.md 里的步骤走,而是自己另起炉灶。这个问题通常出在 SKILL.md 的描述语气上。如果你写的是“建议按以下步骤”,模型就会觉得这是可选建议;如果你写的是“必须按顺序执行以下步骤,不得跳过”,模型的服从度会高很多。

另外还可以在前面提到的 frontmatter 里加一个参数disable-model-invocation: false(默认就是 false),这个字段的作用是允许模型自主触发技能。如果你希望某个技能只能被显式调用、不能被模型自主触发,就设为 true。对于关键的生产流程技能,我有时会刻意设为 true,并在 CLAUDE.md 里要求“只有明确调用技能时才执行对应工作流”,这是一种防止模型乱来的控制手段。

5. 实战建议:从“能用”到“好用”的经验沉淀

这套基于 Claude Skills 的 Agent 方案我已经跑了三个生产项目,从最初只能做代码影响分析,扩展到了自动化运维巡检、数据库变更评审、文档一致性校验等多个场景。最后分享几条从实战里沉淀下来的建议,帮助你少走弯路。

5.1 技能边界划分:一个技能只做一件事

技能设计的核心原则我总结成一句话:一个技能只做一件事,但把这一件事做到极致。我最初犯过的错误是试图做一个“全栈开发助手技能”,结果模型经常不知道是该先写后端还是先写前端,加载技能后也不知道该执行哪一步。拆成“后端代码审查”“前端组件分析”“接口文档生成”三个独立技能后,每次触发都非常精准,输出质量也明显提升。

拆分的粒度参考标准是:看这个技能的执行步骤是否能在一屏之内读完。如果 SKILL.md 正文超过 80 行,大概率是塞了太多职责,建议继续拆分。小的技能块还有一个优势,就是可以自由组合。比如我做自动化运维巡检时,会把“日志分析”和“资源监控”拆成两个技能,当需要排查性能问题时让它们依次触发,两段分析结果拼在一起就是一份完整诊断报告。

5.2 技能脚本的可靠性与可测试性

只要技能里包含脚本,就要把脚本当作正式的代码来对待。我的要求有三条:必须能独立运行、必须有输入校验、必须有清晰的输出格式。

独立运行意味着不依赖 Claude Code 环境。我会先在终端里手动执行一遍:

python3 scripts/parse_diff.py /tmp/test.diff

确认输出符合预期,然后再放进技能里。输入校验主要是防止模型传了错误参数导致脚本崩溃。比如 parse_diff.py 里就判断了文件是否存在,参数是否传全。输出格式上,脚本输出的每一行都要设计成容易解析的形态,我用的是“前缀 + 内容”的结构,比如文件:、变更点:,这样模型读取后能够准确提取信息,不会在解析输出上浪费 token。

5.3 用版本管理来管理技能本身

最后一个小建议:把技能目录当作一个独立项目来做版本管理。我现在会把所有自研技能放在一个claude-skills仓库里,每次修改都会记录变更原因。收益是什么呢?我给你讲一个真实场景:某天我发现代码审查技能突然变得“特别严格”,每个 PR 都给出大量警告,仔细对比才发现是上周往 SKILL.md 里加了一条“发现潜在性能问题必须警告”的规则,结果模型把所有循环遍历都当成了性能风险。因为技能有 Git 历史,我一行git revert就恢复了正常,整个过程不到一分钟。

仓库共享也给团队协作带来很大便利。我建了一个内部的技能索引文档,列清楚每个技能的名称、用途、适用场景、维护人。新同事接手时不再需要翻聊天记录找“当时是怎么配置的”,直接拉仓库、看 README、试用技能就能上手。把 Agent 开发从“个人魔法”变成“团队工程能力”,这才是 Claude Skills 真正让我兴奋的地方。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询