Spring AI 核心功能
一、对话模型
1、对话模型概念
Chat Completion API 帮助开发人员轻松将 AI 聊天完成功能融入应用程序。它利用预训练的语言模型,如 GPT(Generative pre-trained Transformer),以自然语言生成对用户输入的类人响应。
API 通常通过向人工智能模型发送提示或部分对话来工作,人工智能模型会依据其训练数据和自然语言模式理解,生成对话。然后将完成的响应返回给应用程序,应用程序可以将其呈现给用户或用于进一步处理。
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/837bf46333694b0cb0034e5fe15d1e65.png#pic_center)
2、call 和 stream 方法分表对应大模型的两种输出方式:
a、非流式输出 call:等待大模型把回答结果全部生成后输出给用户;
b、流式输出 stream:逐个字符输出,一方面符合大模型生成方式的本质,另一方面当模型推理效率不是很高时,流式输出比起全部生成后再输出大大提高用户体验。
package com.cesske.demo.controller;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import reactor.core.publisher.Flux;
import javax.annotation.Resource;
/**
* openAi 聊天的实现
*/
public class ChatController {
/**
* 自动注入的
*/
@Resource
private OpenAiChatModel openAiChatModel;
/**
* 聊天的方法。底层调用的openAi的方法
* RequestParam 接受参数
* msg 就是我们提的问题
*
* @return
*/
@RequestMapping("/ai/chat")
public String chat(@RequestParam("msg") String msg) {
String called = openAiChatModel.call(msg);
return called;
}
/**
* 聊天的方法。底层调用的openAi的方法
* RequestParam 接受参数
* msg 就是我们提的问题
* ChatResponse 返回的是一个josn串
* chatResponse.getResult().getOutput().getContent();只获取文本
* @return
*/
@RequestMapping("/ai/chat2")
public Object chat2(@RequestParam("msg") String msg){
ChatResponse chatResponse = openAiChatModel.call(new Prompt(msg));
return chatResponse.getResult().getOutput().getContent();
}
/**
*OpenAiChatOptions.builder() 传入的一个参数,可以控制大模型的设置
* @param msg
* @return
*/
@RequestMapping("/ai/chat3")
public Object chat3(@RequestParam("msg") String msg){
ChatResponse chatResponse = openAiChatModel.call(new Prompt(msg, OpenAiChatOptions.builder()
//.withModel("gpt-4-32k") //gpt的版本 ,32K是参数,参数越高,回答问题越准确
.withTemperature(0.4F) //温度值,温度越高,回答的准确率越低,温度越低,回答的准确率越高
.build()));
return chatResponse.getResult().getOutput().getContent();
}
/**
*OpenAiChatOptions.builder() gpt的可选参数
* @param msg
* @return
*/
@RequestMapping("/ai/chat4")
public Object chat4(@RequestParam("msg") String msg){
Flux<ChatResponse> flux = openAiChatModel.stream(new Prompt(msg, OpenAiChatOptions.builder()
//.withModel("gpt-4-32k") //gpt的版本 ,32K是参数,参数越高,回答问题越准确
.withTemperature(0.4F) //温度值,温度越高,回答的准确率越低,温度越低,回答的准确率越高
.build()));
return flux.collectList();
}
}
二、提示词模板
1、提示词是引导大模型生成特定输出的输入,提示词的设计和措辞会极大地影响模型的响应结果。
[推荐当前受欢迎的5中开发语言] 就是一个最简单的提示词。在 AI 领域,提示的结构随着时间的推移不断发展,最初的提示只是简单的字符串,随着时间的推移,提示词开始包含特定输入的占位符,例如 "USER:"、"ASSISTANT" 这些,大模型可以识别这些占位符,并给出更符合用户需求的内容输出。
OpenAI 后来引入了一种更具条理的方法。在他们的模型中,提示不再仅仅是简单的文本字符串,而是由一系列带有特定角色的消息构成。尽管每条消息依然是文本形式,但它们各自被赋予了明确的角色。这些角色不仅帮助分类消息,还进一步澄清了大模型提示词中每个部分的上下文和目的。这种结构化的方法极大地提升了与大模型沟通的准确性和效率,因为提示词中的每个元素在都承载着独特且清晰的功能。
下面是一个带有角色信息的 prompt 示例,可以看到 prompt 是包括对话的上下文,可以让模型更好的理解用户的意图。
{"role":"user","content":"你好"},
{"role":"assistant","content":"你好,请问有什么我可以帮助你的吗?无论你有什么问题或需要帮助,我都会尽力回答和协助你。请随时告诉我你的需求。"},
{"role":"user","content": "我在上海,周末可以去哪里玩?"},
{"role":"assistant","content": "上海是一个充满活力和文化氛围的城市,有很多适合周末游玩的地方。以下是几个值得推荐的地方:\n\n1. 上海科技馆:上海科技馆是中国大陆最大的科技馆之一,有许多互动展览和科学实验室,可以让您了解科技的发展历史和最新成果。\n2. 上海博物馆:上海博物馆是一座集艺术、历史和文化于一体的博物馆,有许多精美的艺术品和文物,可以让您深入了解中国和世界的文化历史。\n3. 外滩:外滩是上海的标志性景点之一,有许多高楼大厦和繁华的商业街区,是欣赏黄浦江美景和城市风貌的好去处。\n4. 上海迪士尼乐园:上海迪士尼乐园是世界上最大的迪士尼主题公园之一,有许多精彩的游乐项目和演出,可以让您尽情享受娱乐和欢乐。\n5. 上海野生动物园:上海野生动物园是一个以自然保护为主题的野生动物园,有许多珍稀动物和植物,可以让您近距离接触大自然。\n\n这些地方都是上海周末游玩的好去处,可以根据自己的兴趣和需求选择合适的行程。"},
{"role":"user","content": "上海有哪些美食"}
Spring AI 适配了主流大模型,有不同的角色供使用:
在 Spring AI 代码中对应不同的枚举值:
public enum MessageType {
USER("user"),
ASSISTANT("assistant"),
SYSTEM("system"),
FUNCTION("function");
}
2、提示词模板
在 Spring AI 与大模型交互的过程中,处理提示词的方式与 Spring MVC 中管理 “视图 View” 的方式有些相似。首先要创建包含动态内容占位符的模板,然后,这些占位符会根据用户请求或应用程序中的其他代码进行替换。另一个类比是 JdbcTemplate 中的语句,它包含可动态替换的占位符。
下面是一个使用提示词模板的简单例子,在提示词模板中,{占位符} 可以用 Map 中的变量动态替换。
PromptTemplate promptTemplate = new PromptTemplate(“Tell me a {adjective} joke about {topic}”);
Prompt prompt = promptTemplate.create(Map.of(“adjective”, adjective, “topic”, topic));
return chatClient.call(prompt).getResult();
3、示例
@RequestMapping("/ai/prompt")
public Response prompt(@RequestParam(value = "name") String name,
@RequestParam(value = "voice") String voice) {
String userText = "给我推荐上海的至少三个旅游景点";
UserMessage userMessage = new UserMessage(userText);
String systemText = "你是一个有用的人工智能助手,可以帮助人们查找信息,\n" +
" 你的名字是{name},\n" +
" 你应该用你的名字和{voice}的风格回复用户的请求。";
SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemText);
Map<String, Object> map = new HashMap<>();
map.put("name",name);
map.put("voice", voice);
Message systemMessage = systemPromptTemplate.createMessage(map);
List<Message> msg = new ArrayList<>();
msg.add(userMessage);
msg.add(systemMessage);
Prompt prompt = new Prompt(msg);
List<Generation> response = openAiChatModel.call(prompt).getResults();
StringBuilder result = new StringBuilder();
for (Generation generation : response) {
String content = generation.getOutput().getContent();
result.append(content);
}
return Response.ok(result);
}
调用示例:
localhost:8080/ai/prompt?name=小二&voice=幽默
{
"errno": 0,
"msg": "success",
"data": "嘿,我是小二!上海是一个充满魅力的城市,有很多值得一游的景点。我给你推荐三个:\n\n1. 东方明珠塔:作为上海的标志性建筑,东方明珠塔是上海的地标之一。你可以乘坐电梯到达塔顶,欣赏整个上海城市的美景。\n\n2. 外滩:外滩是上海最著名的观光区之一,这里有许多欧洲风格的建筑,可以欣赏到黄浦江两岸的美景,尤其在夜晚灯火辉煌。\n\n3. 田子坊:这里是上海的老街区,保留了许多传统的建筑和文化。你可以在这里漫步,感受上海的历史和文化氛围。\n\n希望你能在上海玩得开心!如果还有其他问题,随时问我哦~"
}