Spring AI的聊天模型API为开发者提供了一条便捷通道,能够将强大的AI驱动的聊天完成功能无缝集成到各类应用中。借助预先训练的语言模型,如广为人知的GPT,它能够依据用户输入生成自然流畅、类人化的回复。这一API不仅工作机制高效,而且设计理念极为先进,旨在实现简单易用与高度可移植性,让开发者能以极少的代码改动在不同AI模型间自由切换,充分契合Spring框架一贯秉持的模块化与可互换性原则。
一、ChatClient接口
ChatClient 是一个接口,它定义了一个与聊天服务交互的客户端。这个接口主要用于创建聊天客户端对象,设置请求规范,以及发起聊天请求。
1.实现简单的对话
1 需求
用户输入设置用户消息的内容,通过SpringBoot AI封装的方法向 AI 模型发送请求,以字符串形式返回 AI 模型的响应。
2 编写Controller方法
package com.zhan.springai.controller;
import com.zhan.springai.common.Constants;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(Constants.API_PREFIX_V1 + "/ai")
public class ChatDeepSeekController {
private final ChatClient chatClient;
public ChatDeepSeekController(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder.build();
}
@Operation(summary = "聊天")
@GetMapping("/chat")
public String chat(@RequestParam(value = "msg", defaultValue = "给我讲个笑话") String message) {
//prompt:提示词
return this.chatClient.prompt()
//用户输入的信息
.user(message)
//请求大模型
.call()
//返回文本
.content();
}
}
3 测试结果
2.实现角色预设
1 配置默认角色
@Configuration
public class AIConfig {
@Bean
public ChatClient chatClient(ChatClient.Builder builder) {
return builder.defaultSystem("你是一名老师,你精通Java开发," +
"你的名字叫张三。").build();
}
}
2 编写controller
@RestController
@RequestMapping(Constants.API_PREFIX_V2 + "/ai")
public class AIController {
@Autowired
private ChatClient chatClient;
@GetMapping("/chat")
public String chat(@RequestParam(value = "msg") String message) {
return chatClient.prompt().user(message).call().content();
}
}
3 测试结果
3.实现流式响应
1 call和stream的区别
(1)非流式输出 call:等待大模型把回答结果全部生成后输出给用户;
(2)流式输出stream:逐个字符输出,一方面符合大模型生成方式的本质,另一方面当模型推理效率不是很高时,流式输出比起全部生成后再输出大大提高用户体验。
2 编写Controller
@GetMapping(value = "/chat/stream",produces="text/html;charset=UTF-8")
public Flux<String> chatStream(@RequestParam(value = "msg") String message) {
return chatClient.prompt().user(message).stream().content();
}
3 测试结果
二、ChatModel接口
1.概述
ChatModel接口作为核心,定义了与AI模型交互的基本方法。它继承自Model<Prompt, ChatResponse>,提供了两个重载的call方法:
public interface ChatModel extends Model<Prompt, ChatResponse> {
default String call(String message) {...}
@Override
ChatResponse call(Prompt prompt);
}
在ChatModel接口中,带有String参数的call()方法简化了实际的使用,避免了更复杂的Prompt和 ChatResponse类的复杂性。但是在实际应用程序中,更常见的是使用ChatResponse call()方法,该方法采用Prompt实例并返回ChatResponse。
我们使用的ChatClient底层是使用ChatModel作为属性的,在初始化ChatClient的时候可以指定ChatModel,这里我们直接看底层源码:
//ChatClient(部分构造器代码)
static ChatClient create(ChatModel chatModel) {
return create(chatModel, ObservationRegistry.NOOP);
}
2.实现简单的对话
@RestController
public class DeepSeekController {
@Autowired
3.提示词
-
提示词是引导大模型生成特定输出的输入,提示词的设计和措辞会极大地影响模型的响应结果
-
Prompt 提示词是与模型交互的一种输入数据组织方式,本质上是一种复合结构的输入,在 prompt 我们是可以包含多组不同角色(System、User、Aissistant等)的信息。如何管理好 Prompt 是简化 AI 应用开发的关键环节。
-
Spring AI 提供了 Prompt Template 提示词模板管理抽象,开发者可以预先定义好模板,并在运行时替换模板中的关键词。在 Spring AI 与大模型交互的过程中,处理提示词首先要创建包含动态内容占位符 {占位符} 的模板,然后,这些占位符会根据用户请求或应用程序中的其他代码进行替换。在提示词模板中,{占位符} 可以用 Map 中的变量动态替换。
@GetMapping("/prompt")
public String prompt(@RequestParam("name") String name, @RequestParam("voice") String voice) {
String userText = """
给我推荐湖北的至少三种景点
""";
UserMessage userMessage = new UserMessage(userText);
String systemText = """
你是一个旅游咨询助手,可以帮助人们查询旅游景点信息。
你的名字是{name},
你应该用你的名字和{voice}的旅游推荐回复用户的请求。
""";
SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemText);
//替换占位符
Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", name, "voice", voice));
Prompt prompt = new Prompt(List.of(userMessage, systemMessage));
List<Generation> results = chatModel.call(prompt).getResults();
return results.stream().map(x -> x.getOutput().getContent()).collect(Collectors.joining(""));
}
结果: