简单使用
新建工程
首先我们需要新建一个项目,直接去Spring官方文档下面的Initializer设置
- Spring 3.5.11
- JDK17
- Web Starter + Zhipu AI Starter
压缩包下下来之后解压IDE打开,获取智谱的api-key,放在配置文件
1 2 3 4 5 6 7 8 9
| spring: application: name: ai-demo ai: zhipuai: api-key: foo chat: options: model: GLM-4-Flash
|
调用接口
在启动类包下新建一个Controller(还是Spring的规范)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @RestController public class ChatController {
private final ZhiPuAiChatModel chatModel;
@Autowired public ChatController(ZhiPuAiChatModel chatModel) { this.chatModel = chatModel; }
@GetMapping("/ai/generate") public Map generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) { return Map.of("generation", chatModel.call(message)); }
@GetMapping("/ai/generateStream") public Flux<ChatResponse> generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) { var prompt = new Prompt(new UserMessage(message)); return chatModel.stream(prompt); } }
|
之后进入接口测试即可获取模型返回
Prompt
角色
在了解 Prompt 之前我们需要先知道角色
在 Spring AI 中,将大模型和用户之间的交互流程抽象成了四种角色:
- system: 系统角色,通常我们预设的提示词会和
system 角色关联
- user: 用户角色,用于表示用户输入的文本,通常输入的提问会和
user 角色关联
- assistant: 助手角色,用于表示模型生成的文本,通常大模型生成的答案会和
assistant 角色关联
- tool: 工具角色,用于表示模型调用的函数返回的内容,会和
tool 角色关联
因此,如果希望调用时给模型定义身份,可以修改Prompt实例的构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @GetMapping("/ai/generate") public Map generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
Prompt prompt = new Prompt( Arrays.asList(new SystemMessage("你现在是一个专注于解决编码问题的助手"), new UserMessage(message)), ZhiPuAiChatOptions.builder() .model(ZhiPuAiApi.ChatModel.GLM_4_Flash.getValue()) .temperature(0.7d) .user("trevorlink") .build() );
Generation generation = chatModel.call(prompt).getResult(); return Map.of("generation", generation == null ? "" : generation.getOutput().getText()); }
|
PromptTemplate
在提示词有复用的场景,可以考虑Spring AI提供的提示词模板功能:根据固定的模板,在程序运行时结合Map动态替换修改。
这个简单了解即可,只需要知道:
提示词模板实例可以生成系统提示词也可以生成用户提示词
提示词具体的内容除了字符串硬编码,还可以通过配置文件定义后注入的方式兼容Spring生态
一般通过提示词模板promptTemplate.create创建提示词,默认是创建UserMessage类型的消息;如果我们希望创建的是系统提示词可以使用SystemPromptTemplate
1 2 3
| SystemPromptTemplate promptTemplate = new SystemPromptTemplate("我们现在开始角色扮演的聊天,你来扮演{personality}的{aiRole}, 我来扮演{myRole}"); Message systemMsg = promptTemplate.createMessage(Map.of("personality", personality, "aiRole", aiRole, "myRole", myRole)); Prompt prompt = new Prompt(systemMsg, new UserMessage(msg));
|
具体可以参考
结构转换
正常来说大模型返回的结构都是没有结构的,我们需要显式进行将返回的数据指定转换为业务对象模型
ChatClient
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @RestController public class StructureChatController {
private final ZhiPuAiChatModel chatModel;
public StructureChatController(ZhiPuAiChatModel chatModel) { this.chatModel = chatModel; }
@GetMapping("/ai/queryFilms") public ActorsFilms queryFilms(@RequestParam(value = "actor") String actor) { PromptTemplate template = new PromptTemplate("帮我返回五个{actor}导演的电影名,要求中文返回"); Prompt prompt = template.create(Map.of("actor", actor)); return ChatClient.create(chatModel) .prompt(prompt) .call() .entity(ActorsFilms.class); }
}
record ActorsFilms(String actor, List<String> films) {}
|
BeanOutputConverter
也可以显式使用BeanOutputConverter基于ChatModel来实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| @RestController public class StructureChatController {
private final ZhiPuAiChatModel chatModel;
public StructureChatController(ZhiPuAiChatModel chatModel) { this.chatModel = chatModel; }
@GetMapping("/ai/queryFilms2") public ActorsFilms queryFilms2(@RequestParam(value = "actor") String actor) { BeanOutputConverter<ActorsFilms> converter = new BeanOutputConverter<>(ActorsFilms.class); String format = converter.getFormat();
PromptTemplate template = new PromptTemplate(""" 帮我返回五个{actor}导演的电影名 {format} """); Prompt prompt = template.create(Map.of("actor", actor, "format", format)); Generation generation = chatModel.call(prompt).getResult(); if (generation == null) { return null; } return converter.convert(generation.getOutput().getText()); }
}
record ActorsFilms(String actor, List<String> films) {}
|
这种方式虽然需要在 Prompt 模板中显式指定格式,但是准确性更可控
总结
使用 ChatClient 的方式本质上是通过Advisor从上下文获取信息注入到提示词,而 BenaOutputConverter 则是利用 Spring AI 的 Converter 具体实现.
上下文
和大模型的对话时,会将你们之前的对话内容也一并传给大模型,即:对于大模型而言,你的一次新的对话,它实际上把你们之前的所有对话都过了一遍;更专业一点的说法是你们的对话 是基于一个上下文,这个上下文会包含你之前和模型交互的所有内容。
若希望实现多轮对话,则每次和模型进行对话时,需要将之前和模型交互的所有内容都传递给模型,这样模型才能基于这些内容进行多轮的沟通。