侧边栏壁纸
博主头像
牧云

怀璧慎显,博识谨言。

  • 累计撰写 139 篇文章
  • 累计创建 13 个标签
  • 累计收到 8 条评论

目 录CONTENT

文章目录

Skills 技能

秋之牧云
2026-04-03 / 0 评论 / 0 点赞 / 0 阅读 / 0 字

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/
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)。

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 可根据技能说明读取并处理技能目录下的文件。

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 后,对应工具才会加入当次请求,实现按需暴露。激活后该技能的工具在会话后续轮次中仍可用。

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 支持)。

0

评论区