Agent Skills 是一种模块化、可复用的能力包,它不是一段配置文件,也不是一个类,而是一个文件夹。
每个 Skill 文件夹的内部结构长这样:
my-skill/
├── SKILL.md # 必需:YAML 元数据 + Markdown 指令正文
├── scripts/ # 可选:可执行脚本(Python/Bash/Node)
├── references/ # 可选:参考文档(按需加载到上下文)
└── assets/ # 可选:模板、图片等资源文件整个文件夹就是一个"技能"。Agent 调用这个技能时,会加载里面的 SKILL.md,按照其中指令行事,并可以读取 references/ 下的参考文档,或者执行 scripts/ 下的辅助脚本。
为什么要搞这玩意?
写过 AI Agent 的人都踩过两个坑:
坑一:工具爆炸。 给 Agent 挂载十几个 @Tool 方法,工具描述越来越长,token 被吃光不说,LLM 还经常选错工具。每个工具都是一个独立的 FunctionCallback,管理起来一坨乱麻。
坑二:上下文膨胀。 为了覆盖多种场景,把所有指令写进系统提示词(System Prompt)。结果每次对话,不管需不需要,几千行指令全塞进上下文。token 烧得肉疼。
Agent Skills 的解决思路很直接——按需加载,分三层递进。
核心机制:三层渐进式加载
这是整个设计中最重要的部分。下面用一张图说清楚:
三层设计带来的直接收益:即使你注册了 100 个 Skill,初始上下文也只有几千 token。Skill 的指令正文(L2)和辅助资源(L3)只有在真正用到时才会被加载。
SKILL.md 怎么写?
SKILL.md 是每个 Skill 的入口文件,由两部分组成:YAML frontmatter(元数据)+ Markdown 正文(指令)。
YAML frontmatter 字段
name | ||
description | ||
license | ||
metadata | ||
allowed-tools |
完整示例
---
name:code-reviewer
description:ReviewsJavacodeforbestpractices,securityissues,andSpringFrameworkconventions.Usewhenuseraskstoreview,analyze,orauditcode.
license:MIT
metadata:
version:"1.1"
author:backend-team
---
# Code Reviewer
## Instructions
Whenaskedtoreviewcode,follow this process:
1.**SecurityCheck**—Checkforvulnerabilities(SQLinjection,XSS,pathtraversal,insecuredeserialization)
2.**SpringBootBestPractices**—Verifydependencyinjectionpatterns,properuseofannotations,transactionboundaries
3.**NullSafety**—LookforpotentialNullPointerExceptionrisks
4.**Readability**—Suggestnamingimprovementsandrefactoringopportunities
5.**CodeExamples**—Providespecificbefore/aftercodesnippets
FordetailedSpringbestpractices,see`./references/spring-conventions.md`.
Toformattheoutput,run:
`pythonscripts/format_review.py--stylehtml`这里有几个关键点:
• description的质量直接决定 LLM 能否在正确的时机激活这个 Skill。写得太泛会误触发,写得太窄会漏触发。• Markdown 正文就是给 LLM 看的"操作手册",风格越具体越好,别写虚的。 • 引用外部资源时用相对路径(如 ./references/xxx.md),SkillsTool 会自动解析。
怎么集成到 Spring Boot 项目里?
第一步:加依赖
<dependency>
<groupId>org.springaicommunity</groupId>
<artifactId>spring-ai-agent-utils</artifactId>
<version>0.4.2</version>
</dependency>需要 Spring AI 2.0.0-M2 或更高版本。
第二步:配置 ChatClient
import org.springaicommunity.agent.utils.SkillsTool;
import org.springaicommunity.agent.utils.filesystem.FileSystemTools;
import org.springaicommunity.agent.utils.shell.ShellTools;
@SpringBootApplication
publicclassAgentApplication {
publicstaticvoidmain(String[] args) {
SpringApplication.run(AgentApplication.class, args);
}
@Bean
CommandLineRunner demo(ChatClient.Builder chatClientBuilder) {
return args -> {
ChatClientchatClient= chatClientBuilder
// 注册 SkillsTool:扫描 .claude/skills 目录
.defaultToolCallbacks(
SkillsTool.builder()
.addSkillsDirectory(".claude/skills")
.build()
)
// 可选:文件读取工具(让 Agent 能读 references)
.defaultTools(FileSystemTools.builder().build())
// 可选:Shell 执行工具(让 Agent 能跑 scripts)
.defaultTools(ShellTools.builder().build())
.build();
// 测试:让 Agent 审查代码
Stringresponse= chatClient.prompt()
.user("Review this controller: src/main/java/com/example/UserController.java")
.call()
.content();
System.out.println(response);
};
}
}第三步:创建 Skill 文件夹
在项目根目录的 .claude/skills/ 下创建你的 Skill:
.claude/skills/
├── code-reviewer/
│ ├── SKILL.md
│ ├── references/
│ │ └── spring-conventions.md
│ └── scripts/
│ └── format_review.py
└── sql-optimizer/
├── SKILL.md
└── references/
└── mysql-explain-guide.md搞定,启动应用即可。
生产环境配置
如果想把 Skill 打包进 JAR 发布,改用 classpath 路径:
@Value("classpath:.claude/skills")
private Resource skillsResource;
SkillsTool.builder()
.addSkillsResource(skillsResource)
.build()这样 Skill 文件夹会打进 JAR,部署时不会丢失。
工具组合说明
spring-ai-agent-utils 提供了三个核心工具:
| SkillsTool | Skill(name) | |
| FileSystemTools | Read(path) | |
| ShellTools | Bash(command) |
三者的协作流程如下:
注意:ShellTools 在本地机器直接执行脚本,没有沙箱隔离。如果你的 Agent 面向外部用户,建议在 Docker 容器或受控环境下运行。
运行时工作流详解
把整个过程拆解来看:
整个过程的核心在于:LLM 自己决定什么时机该用什么 Skill。不需要你在代码里写 if (message.contains("review")) { loadSkill("code-reviewer"); }。
实际踩坑经验
用了几个月 Agents Skills,总结几个实操中的坑:
1. description 写不好,Skill 形同虚设
LLM 是否激活一个 Skill,完全靠 description 做语义匹配。如果 description 写的是 "Helps with code",那几乎任何请求都可能误触发;如果写的是 "Reviews Spring Boot REST controllers for SQL injection vulnerabilities in JdbcTemplate queries",那大部分代码审查请求又触发不了。
建议:写完 description 后,用几个不相关的请求测试一下,看会不会被误激活。
2. references/ 也会吃 token
参考文档同样会进入 LLM 上下文。如果你放了几十页的 Spring 文档进 references/,Agent 调用 Read 后一次性能塞进去好几千 token。
建议:references 放"最小必要信息",比如检查清单(checklist)而非完整文档。
3. ShellTools 的安全边界
当前版本(0.4.2)的 ShellTools 没有内置命令白名单或权限控制。Agent 执行什么命令完全由 LLM 决定,而 LLM 可能被 prompt injection 诱导执行危险命令。
建议:不要给面向外部用户的 Agent 挂 ShellTools。内部使用也建议在容器里跑。
4. Skill 多了以后,LLM 选 Skill 也会出错
和工具选择一样,当 Skill 数量超过 20-30 个时,LLM 偶尔会选错 Skill。不是你的 description 写得不好,而是 LLM 的 attention 被稀释了。
建议:按业务域拆分 Agent,每个 Agent 只挂 5-10 个相关 Skill,而不是一个全能 Agent 挂 50 个 Skill。
夜雨聆风