Spring AI Alibaba - Skills 技能

Skills 技能

Skills 是可复用的指令与上下文包,智能体在相关任务时会自动发现并使用。通过 SkillRegistry 管理技能、SkillsAgentHook 注册 read_skill 工具并注入技能列表到系统提示,模型在需要时调用 read_skill(skill_name) 按需加载完整内容。

核心概念

渐进式披露

系统提示中先只注入技能列表(name、description、skillPath);模型判断需要某技能时调用 read_skill(skill_name) 加载完整 SKILL.md;再按需访问技能目录下的资源或使用与该技能绑定的工具。

Skill 目录结构

每个技能一个子目录,必须包含 SKILL.md

复制代码
skill-name/
├── SKILL.md          # 必需
├── references/       # 可选
├── examples/
└── scripts/

SKILL.md 格式规范

复制代码
---
name: skill-name
description: This skill should be used when...
---

# 技能名称
正文:功能说明、使用方法、可用资源列表等。

必需字段name(建议小写字母、数字、连字符,最长 64 字符)、description(超长会被截断)。


在 Agent 中使用 Skills

使用 FileSystemSkillRegistry

智能体支持从本地文件系统中加载 skills 技能,以下示例假设 skills 在进程工作目录,如:

复制代码
skills/
├── pdf-extractor/
	├── SKILL.md
	├── references/
	└── scripts/

FileSystemSkillRegistry + SkillsAgentHook

复制代码
SkillRegistry registry = FileSystemSkillRegistry.builder()
  .projectSkillsDirectory(System.getProperty("user.dir") + "/skills")
  .build();

SkillsAgentHook hook = SkillsAgentHook.builder()
  .skillRegistry(registry)
  .build();

ReactAgent agent = ReactAgent.builder()
  .name("skills-agent")
  .model(chatModel)
  .saver(new MemorySaver())
  .hooks(List.of(hook))
  .build();

agent.call("请介绍你有哪些技能");

目录配置:userSkillsDirectory(String|Resource)projectSkillsDirectory(String|Resource);不设置时用户级默认 ~/saa/skills,项目级默认 ./skills,同名技能"项目级别"覆盖"用户级别"。

使用 ClasspathSkillRegistry

技能放在 src/main/resources/skills 或随 JAR 打包。可选 .basePath("/tmp") 指定 JAR 内资源复制到的目录(默认 /tmp)。

ClasspathSkillRegistry

复制代码
SkillRegistry registry = ClasspathSkillRegistry.builder()
  .classpathPath("skills")
  .build();

SkillsAgentHook hook = SkillsAgentHook.builder()
  .skillRegistry(registry)
  .build();

ReactAgent agent = ReactAgent.builder()
  .name("skills-agent")
  .model(chatModel)
  .hooks(List.of(hook))
  .build();

完整集成示例(Skills + Python + Shell)

技能常需配合脚本执行(如技能目录下的 Python 脚本)和 Shell 命令。下面示例使用 ClasspathSkillRegistry 加载技能、SkillsAgentHook 提供 read_skillShellToolAgentHook 提供 Shell 工具、PythonTool 提供 Python 执行能力,Agent 可根据技能说明读取并处理技能目录下的文件。

Skills + Python + Shell 完整集成

复制代码
import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import com.alibaba.cloud.ai.graph.agent.hook.skills.SkillsAgentHook;
import com.alibaba.cloud.ai.graph.agent.hook.shelltool.ShellToolAgentHook;
import com.alibaba.cloud.ai.graph.agent.tools.PythonTool;
import com.alibaba.cloud.ai.graph.agent.tools.ShellTool2;
import com.alibaba.cloud.ai.graph.checkpoint.savers.MemorySaver;
import com.alibaba.cloud.ai.graph.skills.registry.classpath.ClasspathSkillRegistry;
import com.alibaba.cloud.ai.graph.skills.registry.SkillRegistry;

// 1. 技能注册表:从 classpath:skills 加载(如 src/main/resources/skills/)
SkillRegistry registry = ClasspathSkillRegistry.builder()
  .classpathPath("skills")
  .build();

// 2. Skills Hook:注册 read_skill 工具并注入技能列表到系统提示
SkillsAgentHook skillsHook = SkillsAgentHook.builder()
  .skillRegistry(registry)
  .build();

// 3. Shell Hook:提供 Shell 命令执行(工作目录可指定,如当前工程目录)
ShellToolAgentHook shellHook = ShellToolAgentHook.builder()
  .shellTool2(ShellTool2.builder(System.getProperty("user.dir")).build())
  .build();

// 4. 构建 Agent:同时挂载 Skills Hook、Shell Hook 和 Python 工具
ReactAgent agent = ReactAgent.builder()
  .name("skills-integration-agent")
  .model(chatModel)
  .saver(new MemorySaver())
  .tools(PythonTool.createPythonToolCallback(PythonTool.DESCRIPTION))
  .hooks(List.of(skillsHook, shellHook))
  .enableLogging(true)
  .build();

// 5. 调用示例:用户请求处理技能目录下的文件时,模型可先 read_skill 再按技能说明调用 Python/Shell
String skillFilePath = "/path/to/skills/pdf-extractor/saa-roadmap.pdf";  // 实际路径来自技能目录或 hook.listSkills()
AssistantMessage response = agent.call("请从 " + skillFilePath + " 文件中提取关键信息。");
  • SkillRegistryFileSystemSkillRegistryprojectSkillsDirectory(path)ClassPathResource("skills")ClasspathSkillRegistryclasspathPath("skills")
  • ShellTool2ShellTool2.builder(workDir).build()workDir 为 Shell 执行的工作目录(如 System.getProperty("user.dir"))。
  • PythonToolPythonTool.createPythonToolCallback(PythonTool.DESCRIPTION) 即够用,如需自定义描述可传第二个参数。
  • 技能列表中会包含每个技能的 skillPath,模型可用该路径拼出技能目录下文件的绝对路径并交给 Python/Shell 处理。

高级用法

渐进式工具 Tool 披露

通过将工具与 Skill 技能名绑定,可以做到工具跟随 Skill 实现渐进式披露:仅当模型对该技能调用了 read_skill 后,对应工具才会加入当次请求,实现按需暴露。激活后该技能的工具在会话后续轮次中仍可用。

groupedTools 绑定工具到技能

复制代码
Map<String, List<ToolCallback>> groupedTools = Map.of(
  "my-skill",   // 与 SKILL.md 的 name 一致,如 'pdf-extractor'
  List.of(myTool)
);

SkillsAgentHook hook = SkillsAgentHook.builder()
  .skillRegistry(registry)
  .groupedTools(groupedTools)
  .build();

生产环境配置

自动重载技能

启用技能自动重载

复制代码
SkillsAgentHook hook = SkillsAgentHook.builder()
  .skillRegistry(registry)
  .autoReload(true)
  .build();

每次 Agent 执行前会调用 registry.reload()(若实现支持;不支持则抛 UnsupportedOperationException,Hook 会捕获并打 debug 日志)。

注意,每次 Agent 执行可能包含多次模型推理,registry.reload() 仅会在第一次推理时执行并加载最新的 skills,这样能保证同一次 Agent 执行时行为的连续性。

用户级与项目级目录

用户级与项目级技能目录

复制代码
SkillRegistry registry = FileSystemSkillRegistry.builder()
  .userSkillsDirectory("/home/user/saa/skills")
  .projectSkillsDirectory("/app/project/skills")
  .build();

同名技能项目覆盖用户。

自定义系统提示模板

SAA 框架内置了 Skill Prompt 模板,用来引导实现 Skill 的渐进式披露。用户可结合自己系统的 Skill 组织方式定制 Prompt 模板。

自定义技能系统提示模板

复制代码
SystemPromptTemplate customTemplate = SystemPromptTemplate.builder()
  .template("## 可用技能\n{skills_list}\n\n## 加载说明\n{skills_load_instructions}")
  .build();

FileSystemSkillRegistry registry = FileSystemSkillRegistry.builder()
  .projectSkillsDirectory("./skills")
  .systemPromptTemplate(customTemplate)
  .build();

模板变量:{skills_list}{skills_load_instructions}

拓展 SkillRegistry 实现

实现 SkillRegistry 接口(getlistAllcontainssizereadSkillContentgetSkillLoadInstructionsgetRegistryTypegetSystemPromptTemplate,可选 reload())即可接入现有 Skills 体系。SkillMetadata 需包含 namedescriptionskillPath(及可选 source)。可参考 AbstractSkillRegistryFileSystemSkillRegistryClasspathSkillRegistry


在 Graph 中使用 Skills

除在 ReactAgent 上通过 SkillsAgentHook 使用 Skills 外,在基于 GraphChatClient 的链路中,可通过 ChatClient 配合 SkillPromptAugmentAdvisorspring-ai-alibaba-graph-core)将技能列表注入系统提示,实现渐进式披露的「技能发现」部分。

使用 ChatClient + SkillPromptAugmentAdvisor

SkillPromptAugmentAdvisor 是 Spring AI 的 Advisor,在每次请求的 before 阶段将技能元数据(name、description、skillPath)注入系统提示,使模型知晓可用技能及加载说明;模型需要完整 SKILL.md 时,需配合 read_skill 工具(可由 SkillsAgentHook 提供或自行注册)。

ChatClient + SkillPromptAugmentAdvisor

复制代码
import org.springframework.ai.chat.client.ChatClient;
import com.alibaba.cloud.ai.graph.advisors.SkillPromptAugmentAdvisor;

// 方式一:指定技能目录(字符串路径),Advisor 内部创建 FileSystemSkillRegistry
SkillPromptAugmentAdvisor skillAdvisor = SkillPromptAugmentAdvisor.builder()
  .projectSkillsDirectory("./skills")       // 或绝对路径 /path/to/skills
  // .userSkillsDirectory("~/saa/skills")  // 可选,默认 ~/saa/skills
  .lazyLoad(false)                          // 可选,true 则首次请求时再加载技能
  .build();

ChatClient chatClient = ChatClient.builder(chatModel)
  .defaultAdvisors(skillAdvisor)
  .build();

// 调用时系统提示中会包含可用技能列表
String response = chatClient.prompt()
  .user("请介绍你有哪些技能")
  .call()
  .content();

使用已有 SkillRegistry 构建 SkillPromptAugmentAdvisor

复制代码
import com.alibaba.cloud.ai.graph.skills.registry.SkillRegistry;
import com.alibaba.cloud.ai.graph.skills.registry.filesystem.FileSystemSkillRegistry;

SkillRegistry registry = FileSystemSkillRegistry.builder()
  .projectSkillsDirectory("./skills")
  .build();

SkillPromptAugmentAdvisor skillAdvisor = SkillPromptAugmentAdvisor.builder()
  .skillRegistry(registry)
  .build();

ChatClient chatClient = ChatClient.builder(chatModel)
  .defaultAdvisors(skillAdvisor)
  .build();

说明

  • SkillPromptAugmentAdvisor 仅负责在系统提示中注入技能列表与加载说明,不注册 read_skill 工具。若需模型按需读取完整 SKILL.md,请在 ChatClient/Graph 中额外注册 read_skill(例如使用带 SkillsAgentHook 的 Agent 节点,或单独将 ReadSkillTool 注册为工具)。
  • Graph 中的 Agent 节点 :若节点内部使用 ChatClient,可在构建该 ChatClient 时加入 SkillPromptAugmentAdvisor;若节点使用 ReactAgent,则直接使用 SkillsAgentHook (会同时注入技能列表并注册 read_skill)。
  • 技能通常需配合脚本执行(如技能目录下的 Python 脚本)和 Shell 命令才能在生产环境中正常使用。

最佳实践与性能建议

  • 控制 SKILL.md 大小 :单文件建议约 1.5k--2k tokens,长内容放 references/ 并在正文中列路径。
  • 技能名称一致nameread_skill 参数、groupedTools 的 key 保持一致。
  • 按需使用 groupedTools :仅需「随技能激活」的工具用 groupedTools,其余用 Agent 的 .tools() 即可。
  • 常用 APIhook.listSkills()hook.hasSkill(name)hook.getSkillCount()registry.reload()(ClasspathSkillRegistry 支持)。
相关推荐
冰西瓜6001 小时前
深度学习的数学原理(四十)—— Transformer 推理全过程
人工智能·深度学习·transformer
Bingorl1 小时前
机器学习之集成学习
人工智能·机器学习·集成学习
weixin_468466851 小时前
SURF 图像特征提取算法新手实战指南
图像处理·人工智能·算法·机器视觉·surf·sift
盛夏光年爱学习1 小时前
Agentic RAG 深度解析:让 Agent 自己决定要不要检索、检索几次,这才是 RAG 的正确打开方式
人工智能
weiwin1231 小时前
MAF入门(3 下):多轮对话进阶——清除历史、注入 System、截断策略
人工智能·agent
带派擂总1 小时前
Python全栈开发 Day08_控制文件指针移动 异常捕获 推导式
python
Coder小相2 小时前
LangChain 1.0 第五篇 - Tool与MCP让Agent拥有行动力
人工智能·langchain·ai编程
太华2 小时前
学习AI Agent编程-第五天-LlamaIndex - 将Nodes生成索引并存储
人工智能
XLYcmy2 小时前
面向Agent权限系统的快速审计工具
python·网络安全·ai·llm·飞书·agent·字节跳动