跳到主要内容

SpringAI初次尝试

阅读需 4 分钟

前言

最近在看SpringAI的文档,他可以让Spring应用更方便地集成AI能力,本人就想试试SpringAI来做些简单的事情。

正文

挑选AI模型

由于是测试使用,最好选一个免费的模型,这里我选择了阿里云百炼,然后创建一个API-KEY用于后续的调用。

程序调用AI大模型

参考SpringAI官方文档

项目初始化完成后,想要接入阿里云百炼,但是翻文档发现SpringAI并没有直接支持阿里云百炼的模型,需要引入SpringAIAlibaba

pom.xmlxml
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>

编写配置:

application.ymlyaml
spring:
ai:
dashscope:
api-key: your_api_key
chat:
options:
model: qwen-plus

测试下是否接入成功:

SpringAiAiInvoke.javajava
@Component
public class SpringAiAiInvoke implements CommandLineRunner {

@Resource
private ChatModel dashscopeChatModel;

@Override
public void run(String... args) throws Exception {
AssistantMessage assistantMessage = dashscopeChatModel.call(new Prompt("你好,我是李大骞"))
.getResult()
.getOutput();
System.out.println(assistantMessage.getText());
}
}

启动SpringBoot项目时,会自动跑上面的代码,如果接入成功则控制台会打印出AI的回复。

Advisors

SpringAI使用Advisors机制来增强AI的能力,可以理解为一系列可插拔的拦截器,在调用AI前和调用AI后可以执行一些额外的操作,比如日志记录、输入输出的修改等。

日志 Advisor:

MyLoggerAdvisor.javajava
@Slf4j
public class MyLoggerAdvisor implements CallAdvisor, StreamAdvisor {

@Override
public String getName() {
return this.getClass().getSimpleName();
}

@Override
public int getOrder() {
return 0;
}

private ChatClientRequest before(ChatClientRequest request) {
log.info("AI Request: {}", request.prompt());
return request;
}

private void observeAfter(ChatClientResponse chatClientResponse) {
log.info("AI Response: {}", chatClientResponse.chatResponse().getResult().getOutput().getText());
}

@Override
public ChatClientResponse adviseCall(ChatClientRequest chatClientRequest, CallAdvisorChain chain) {
chatClientRequest = before(chatClientRequest);
ChatClientResponse chatClientResponse = chain.nextCall(chatClientRequest);
observeAfter(chatClientResponse);
return chatClientResponse;
}

@Override
public Flux<ChatClientResponse> adviseStream(ChatClientRequest chatClientRequest, StreamAdvisorChain chain) {
chatClientRequest = before(chatClientRequest);
Flux<ChatClientResponse> chatClientResponseFlux = chain.nextStream(chatClientRequest);
return (new ChatClientMessageAggregator()).aggregateChatClientResponse(chatClientResponseFlux, this::observeAfter);
}
}

多轮对话

AgentApp.javajava
@Component
public class AgentApp {

private final ChatClient chatClient;

public AgentApp(ChatModel dashscopeChatModel) {
// 初始化基于内存的对话记忆
MessageWindowChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(new InMemoryChatMemoryRepository())
.maxMessages(20)
.build();
chatClient = ChatClient.builder(dashscopeChatModel)
.defaultAdvisors(
// 对话记忆 advisor
MessageChatMemoryAdvisor.builder(chatMemory).build(),
// 日志 advisor
new MyLoggerAdvisor()
)
.build();
}
}
AgentAppTest.javajava
@SpringBootTest
class AgentAppTest {

@Resource
private AgentApp agentApp;

@Test
void testChat() {
String chatId = UUID.randomUUID().toString();
// 第一轮
String message = "你好,我是程序员李大骞";
String answer = agentApp.doChat(message, chatId);
Assertions.assertNotNull(answer);
// 第二轮
message = "我有一只猫叫咪咪,我想买一个逗猫棒,你能帮我推荐一下吗?";
answer = agentApp.doChat(message, chatId);
Assertions.assertNotNull(answer);
// 第三轮
message = "我的猫叫上面名字来着?";
answer = agentApp.doChat(message, chatId);
Assertions.assertNotNull(answer);
}
}

通过日志我们可以看到,对话历史被放在了提示词中,从而实现了记忆功能。

工具调用

工具调用让AI模型可以调用外部工具来增强其能力,SpringAI的Tool Calling提供了相关的支持。

1.当我们想要为AI模型提供一个可用工具是,我们需要将他的定义信息放在Prompt中。 2.当AI模型决定调用工具时,它会返回一个特定格式的响应,告诉我们它想要调用哪个工具以及传递什么参数。 3.ChatModel将工具请求发送到ToolCallingManager。 4.ToolCallingManager根据请求调用相应的工具,并将结果返回给ChatModel。 5.ChatModel将工具的结果整合到Prompt中,继续与AI模型进行对话。

WeatherTool.javajava
public class WeatherTool {

@Tool(description = "Get current weather for a location")
public String getWeather(@ToolParam(description = "The city name") String city) {
return "Current weather in " + city + ": Sunny, 25°C";
}
}
AgentApp.javajava
@SpringBootTest
class AgentAppTest {

@Resource
private AgentApp agentApp;

@Test
void doChatWithTools() {
String chatId = UUID.randomUUID().toString();
String message = "你好,请帮我查询一下北京的天气怎么样?";
String answer = agentApp.doChatWithTools(message, chatId);
Assertions.assertNotNull(answer);
}
}

MCP

MCP(Model Context Protocol,模型上下文协议),规定了AI模型与外部系统交换信息的标准格式,有了标准就可以制造生态系统了,各个厂商可以提供自己的MCP sever。

MCP server其实就是一种官方提供的工具调用服务,具体使用文档见这里

Agent

Agent集成记忆知识库工具调用等能力为一体,为了实现特定目标而设计的一种智能体。

ReAct模式核心思想:

  1. 推理(Reason):将原始问题拆分为多步骤任务,明确当前要执行的步骤。
  2. 行动(Act):根据当前步骤选择合适的工具或知识库进行操作,获取所需信息。
  3. 观察(Observe):将工具或知识库返回的结果进行分析,判断是否达成目标或需要进一步操作。

手动通过写代码的方式实现ReAct模式的话,有个很不错的开源Agent可以参考:OpenManus,想通过工作流来编排Agent的话,可以使用Spring AI Alibaba Graph

A2A协议

多个Agent之间的相互合作可以通过A2A协议来实现,让Agent之间可以互相调用和协作,形成一个更强大的智能体网络。

总结

初步尝试了SpringAI的一些基本功能,理解了一个Agent的构建思路,可以参考OpenManus来实现更复杂的Agent应用,或者工作流编排的方式来实现Agent应用。AI还在继续发展,有点兴奋呢!

Loading Comments...