昊梵体育网

Spring AI 中智能体技能Agent Skill 入门开发示例-1

当前业务应用越来越多地与大型语言模型相结合,从而创造出超越简单问答功能的解决方案。为了打造能够处理复杂用户请求的 AI

当前业务应用越来越多地与大型语言模型相结合,从而创造出超越简单问答功能的解决方案。为了打造能够处理复杂用户请求的 AI 智能体,我们通常会将它们与多个模型上下文协议服务器(MCP Servers)相连,这些服务器通过各种工具为 AI 智能体提供所需的各项功能。

不过,对于那些只需要向单个智能体提供简单功能的轻量级、本地自动化任务来说,创建和运行 MCP 服务器未免有些大材小用。

Agent Skills 是一种规范,它提供了一种结构化的方式,用于在本地定义、封装这些功能,并将其呈现给 AI 智能体使用。

在本文中,我们将探讨 Spring AI 中的 Agent Skills 功能。我们会配置一个自定义技能,并将其与一个简单的聊天机器人相结合,用来对文章进行总结。

一、什么是Agent Skill?

Agent Skills 是一种开放式的规范,用于定义智能体具备的各种功能。所谓“技能”,本质上就是一个包含 SKILL.md 文件的目录。该文件相当于该技能的“清单”;此外,该技能还可能包含相关的代码,比如 Python 或 Bash 脚本,以及该技能所依赖的其他资源。

SKILL.md 文件包含一个用于描述该技能的标题和说明,随后是一系列用自然语言写成的指令,这些指令告诉智能体该如何使用该技能。

当智能体接收到用户请求后,它会读取所有可用技能的描述,判断其中是否有适合该请求的技能。如果有合适的技能,它会将相关文件加载到系统中,并按照该技能的指示来处理请求。如果没有任何技能适合该请求,智能体则直接利用自身的通用功能来回应用户,而无需调用任何特定技能。

在接下来的内容中,我们将看到智能体如何实际运用我们的自定义技能来完成任务。

二、设置项目

在开始具体实现之前,我们需要先安装所有必要的依赖项,并正确配置应用程序。

1. 依赖关系

首先,让我们把项目所需的依赖项添加到项目的 pom.xml 文件中吧:

<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.springaicommunity</groupId>
<artifactId>spring-ai-agent-utils</artifactId>
<version>0.10.0</version>
</dependency>

首先,我们需要导入 Spring AI 的 OpenAI 相关依赖包,这些依赖包将用于与我们希望与之交互的聊天模型进行交互。从 Spring AI 2 开始,该框架已经支持与各种智能体进行交互的功能,因此我们必须确保使用的是正确版本的 Spring AI。

接下来,我们从 Spring AI 社区导入 agent-utils 依赖项。这一操作使我们能够将智能体功能添加到我们的聊天模型中。

2. 配置聊天模型

接下来,让我们在 application.properties 文件中配置阿里千问 qwen 的 API 密钥和聊天模型相关设置:

# 阿里千问 Qwen(通过 DashScope 阿里云百炼 OpenAI 兼容模式接入)
# 申请 API Key: https://bailian.console.aliyun.com/ -> 模型广场/ApiKey
spring.ai.openai.api-key=${DASHSCOPE_API_KEY}
spring.ai.openai.chat.model=${MODEL_NAME:qwen3.7-plus}
spring.ai.openai.chat.base-url=${DASHSCOPE_BASE_URL:https://dashscope.aliyuncs.com/compatible-mode/v1}

我们使用${}属性占位符,从环境变量中读取 API 密钥的值。

此外,我们使用 qwen3.7-plus 这个模型 ID 来指定阿里千问的模型。当然,我们也可以使用其他支持相应功能的聊天模型。因为对于本次演示来说,具体使用哪种 AI 模型或服务提供商并不重要。

一旦设置了这两个属性,Spring AI 就会自动创建一个类型为 ChatModel 的 bean,从而让我们能够与该模型进行交互。

三、定义自定义技能

现在,让我们来定义一个自定义的智能体技能:该技能能够从给定的 URL 地址获取文章内容,并对其进行总结。

Agent 技能遵循特定的目录结构,那么我们现在就来设置这个结构吧。首先,我们在项目的 resources 目录下创建一个名为 skills 的目录。在这个目录下,我们可以再创建多个子目录,每个子目录对应一种不同的 Agent 技能。

接下来,我们将在 skills 目录下创建一个名为“article-summarizer”的子目录,用于存放我们的自定义技能。同时,我们还会在该子目录中定义名为 SKILL.md 的配置文件。

---
name: article-summarizer
description: 将文章总结为简明摘要。适用于用户要求总结文章或提取要点的场景。
---
# 文章摘要助手
## 使用说明
在总结文章时:
1. 如果提供了 URL:执行 `uv run scripts/fetch_article.py <url>` 获取文章内容。
2. 获取内容后,提取文章主旨、几个关键要点和结论。
3. 按 TL;DR、关键要点和最终结论的结构组织输出。

在前置信息部分,我们需定义该技能的名称和描述。描述非常重要,因为智能体会依据这些信息来判断该技能是否与用户的请求相关。接下来,我们需要给出详细的操作指南,告诉智能体在调用该技能时应该执行哪些步骤,包括要运行哪个脚本以及如何呈现最终结果。

接下来,让我们在名为“scripts”的新子目录中创建 fetch_article.py 脚本。我们将在后面的说明中引用这个子目录。

ARTICLE = """
... hardcoding sample article for demonstration
"""

print(ARTICLE)

在本次演示中,我们只是简单地打印出了关于 MCP 功能的固定内容,而并没有真正发送网络请求。无论请求中的 URL 是什么,AI 模型都会执行该脚本,并读取其标准输出内容,从而获取到这篇文章的内容。

另外,需要指出的是,我们可以用自己选择的任何语言来编写脚本。我们只需确保预先安装了智能体程序执行所需命令所必需的运行环境即可。

四、创建一个简单的聊天机器人

在完成各项配置之后,我们现在来构建一个简单的聊天机器人吧。

在 Spring AI 中,ChatClient 类是与我们所配置的聊天模型进行交互的主要入口。我们可以利用自动配置的 ChatModel bean 来定义 ChatClient bean。

@Configuration
public ChatbotConfiguration {
@Bean
ChatClient chatClient(ChatModel chatModel) {
String skillsRootDirectory;
try {
skillsRootDirectory = new ClassPathResource("skills").getFile().getAbsolutePath();
} catch (IOException ex) {
throw new IllegalStateException("Failed to resolvepath skills directory", ex);
}

return ChatClient
.builder(chatModel)
.defaultAdvisors(SimpleLoggerAdvisor.builder().build())
.defaultTools(
SkillsTool.builder()
.addSkillsDirectory(skillsRootDirectory)
.build(),
FileSystemTools.builder()
.allowedDirectory(skillsRootDirectory)
.build(),
ShellTools.builder()
.build())
.build();

}
}

在 Bean 定义中,我们首先使用 SkillsTool 来注册自定义技能目录,将其指向 skills 目录。

其次,我们注册了 FileSystemTools 这个工具。这样一来,智能体应用就能够读取和写入本地文件系统中的任何文件。为了确保该工具的操作仅限于预先指定的目录范围内,我们使用了 allowedDirectory()方法来限制其操作范围。

最后,我们需要注册 ShellTools。这样一来,智能体应用就能够执行 shell 命令,从而能够运行我们编写的 Python 脚本了。

不过需要指出的是,ShellTools 会在本地机器上直接执行我们的脚本,而不进行任何隔离处理。因此,我们必须仔细审查那些要传递给智能体的脚本,并考虑将应用程序置于容器中运行,以降低潜在的安全风险。

接下来,让我们将 ChatClient bean 注入到控制器类中,并暴露一个 REST API:

@RestController
public ChatbotController {
private final ChatClient chatClient;

public ChatbotController(ChatClient chatClient) {
this.chatClient = chatClient;
}

@PostMapping("/chat")
public ResponseEntity<ChatbotResponse> chat(@RequestBody ChatbotRequest chatbotRequest) {
String answer = chatClient
.prompt()
.user(chatbotRequest.question())
.call()
.content();
return ResponseEntity.ok(new ChatbotResponse(answer));
}

record ChatbotRequest(String question) {}

record ChatbotResponse(String answer) {}
}

在这里,我们只需将用户的问题传递给 chatClient 实例,然后返回大语言模型的响应即可。在接下来的部分中,我们将利用这个 API 接口来与聊天机器人进行交互。