在大语言模型(LLMs)和生成式人工智能(AGI)的领域中,提示(prompts)就像是我们和模型交流的“密码”,正确设置提示能引导模型给出我们想要的输出。今天咱们就学习Spring AI的提示模板(PromptTemplate),通过具体示例深入了解不同的消息角色,以及如何用它们创建提示并发送给AI模型。

一、前置准备

在运行本文的示例代码前,有两个关键的准备工作要做好。

首先,得正确设置OpenAI API密钥。把它配置到环境变量里,同时在application.properties文件中引用。要是不知道怎么操作,可以参考《Spring AI快速上手指南》,里面有详细的步骤说明。

其次,要在项目的依赖管理文件中添加必要的依赖。如果用的是Maven项目,就在pom.xml文件里添加下面的依赖:

<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> </dependency> 

要是Gradle项目,就在build.gradle文件里加上这行代码:

dependencies { implementation 'org.springframework.ai:spring-ai-openai-spring-boot-starter' } 

二、与AI对话中的不同角色类型

在与AI对话的提示场景里,角色能帮助我们明确不同参与者在对话中的视角和作用,确保在和大语言模型对话的每个环节都能“对号入座”,让对话顺利进行。

一般简单的对话,通常就涉及两个角色:用户(User)和助手(Assistant)。用户负责提出问题,助手则给出答案。但在更复杂、需要精细控制的对话中,还会有其他角色参与。具体的角色及相关信息如下:

  • 用户(USER):对应UserMessage类,在对话里,你就是用户,负责提出问题或者提供各种输入信息。
  • 助手(ASSISTANT):由AssistantMessage类表示,大语言模型就像这个助手,根据用户的问题给出回答和指导。
  • 系统(SYSTEM)SystemMessage类扮演这个角色,它主要处理对话的一些技术层面的事情,比如在对话开始前给大语言模型下达指令,控制模型如何理解用户的消息并做出回应。OpenAI有不少很棒的系统提示示例,感兴趣的话可以去看看。
  • 函数(FUNCTION)FunctionMessage类对应这个角色,主要用于让大语言模型完成一些特定的任务或操作。大语言模型有些事情做不了,像调用外部API获取实时数据,或者进行复杂的科学计算,这时候就可以用这个角色来搞定。

三、提示API详解

在Spring AI里,和大语言模型之间的请求与响应是通过ModelRequestModelResponse这两个接口来表示的。从名字就能猜到,ModelRequest代表发送给AI模型的请求,ModelResponse则是收到的模型响应。

这两个接口又有很多具体的实现类,这些实现类对应不同的对话风格,像文本聊天、音频处理或者图像相关的对话场景都有各自对应的实现类。具体如下:

  • ModelRequest接口的实现类AudioTranscriptionPrompt(用于音频转录提示)、EmbeddingRequest(用于嵌入请求)、ImagePrompt(用于图像提示)、Prompt(通用提示)。
  • ModelResponse接口的实现类AudioTranscriptionResponse(音频转录响应)、ChatResponse(聊天响应)、EmbeddingResponse(嵌入响应)、ImageResponse(图像响应) 。

 

在一个提示里,我们可以给不同的角色添加消息。比如,Prompt实例就可以接受一个消息列表。下面是Prompt类的简单定义:

public class Prompt { // 用于存储消息列表 private final List<Message> messages; // 其他代码... } 

Message是一个接口,它把对话过程中各种类型消息的必要信息都封装起来了。针对前面提到的每种角色,都能创建特定的消息实例,像AssistantMessageChatMessageFunctionMessageSystemMessageUserMessage 。具体使用方式如下:

// 通过依赖注入获取OpenAiChatModel实例 OpenAiChatModel chatModel; // 省略其他代码... // 创建用户消息 Message userMessage = new UserMessage("USER: ..."); // 创建系统消息 Message systemMessage = new SystemMessage("SYSTEM: ..."); // 创建包含用户消息和系统消息的提示 Prompt prompt = new Prompt(List.of(userMessage, systemMessage)); // 调用模型并获取生成结果 Generation generation = chatModel.call(prompt).getResult(); // 输出模型生成内容 System.out.println(generation.getOutput().getContent()); 

四、提示模板API

提示或者消息可不总是简单的字符串,很多时候,它们是在模板字符串里插入了好几个参数后形成的复杂格式化字符串。在Spring AI里,org.springframework.ai.chat.prompt.PromptTemplate类就是处理提示模板的核心。Spring AI借助了第三方库StringTemplate引擎(由Terence Parr开发)来构建和插值提示。

PromptTemplate类还有一些子类,像AssistantPromptTemplateFunctionPromptTemplateSystemPromptTemplate ,不过它们的使用方式和父类基本一样。下面来看一个PromptTemplate类的简单示例:

// 创建提示模板对象,模板中包含需要替换的参数 PromptTemplate promptTemplate = new PromptTemplate("Tell me about {subject}. Explain if I am {age} years old."); // 从用户处获取相关值 String subject = "USA Elections"; int age = 14; // 根据参数创建提示对象 Prompt prompt = promptTemplate.create(Map.of("subject", subject, "age", age)); // 调用模型并获取生成结果 Generation generation = chatModel .call(prompt) .getResult(); // 输出提示内容 System.out.println(prompt.getContents()); // 输出模型生成内容 System.out.println(generation.getOutput().getContent()); 

上述代码运行后,输出结果类似这样:

AI Conversation Tell me about USA Elections. Explain if I am 14 years old. USA Elections are the process where people in the United States choose who will be their leaders, such as the President, Senators, and Representatives..... 

五、组合多个提示

当对话涉及多个角色时,我们可以根据需求为每个角色创建对应的消息,然后把这些消息组成一个列表,放到Prompt对象里,最后将Prompt对象发送给聊天模型。具体代码示例如下:

// 1. 定义用户消息模板 String userText = """ Tell me about five most famous tourist spots in {location}. Write at least a sentence for each spot. """; // 从用户处获取地点信息 String location = "Dubai(UAE)"; // 创建用户提示模板对象 PromptTemplate userPromptTemplate = new PromptTemplate(userText); // 根据模板和参数创建用户消息 Message userMessage = userPromptTemplate.createMessage(Map.of("location", location)); // 2. 定义系统消息模板 String systemText = """ You are a helpful AI assistant that helps people find information. Your name is {name} In your first response, greet the user, give a quick summary of the answer and then do not repeat it. Next, you should reply to the user's request. Finish with thanking the user for asking the question in the end. """; // 创建系统提示模板对象 SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemText); // 根据模板和参数创建系统消息 Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", "Alexa")); // 3. 创建包含用户消息和系统消息的提示 Prompt prompt = new Prompt(List.of(userMessage, systemMessage)); // 4. 调用API并提取结果 Generation generation = chatModel.call(prompt).getResult(); // 输出模型生成内容 System.out.println(generation.getOutput().getContent()); 

六、将模板字符串作为资源注入

到目前为止,我们都是在Java源文件里定义模板字符串。其实Spring还支持把提示数据放在资源文件里,然后直接注入到PromptTemplate里。

比如,我们可以在/resources/prompts/system-message.st文件里定义系统提示,内容如下:

You are a helpful AI assistant that helps people find information. Your name is {name} In your first response, greet the user, give a quick summary of the answer and then do not repeat it. Next, you should reply to the user's request. Finish with thanking the user for asking the question in the end. 

然后在代码里像下面这样引用这个文件来创建提示:

// 通过@Value注解注入资源文件 @Value("classpath:/prompts/system-message.st") private Resource promptSystemMessage; // 创建系统提示模板对象 SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemText); // 根据模板和参数创建系统消息 Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", "Alexa")); // 创建包含其他消息和系统消息的提示 Prompt prompt = new Prompt(List.of(..., systemMessage)); // 省略后续代码... 

七、总结

这篇关于Spring AI的教程详细介绍了Spring AI模块中用于创建提示模板功能的各类类和接口。强烈建议大家多去尝试不同类的用法,观察它们的输出,这样才能更熟练、更高效地运用这些知识。

要是想知道实际的请求和响应是什么样的,可以参考LangChain4J结构化输出示例,在这个示例里,记录了和OpenAI API之间实际的请求和响应信息,能帮助大家更好地理解。希望大家在学习过程中有所收获,要是遇到问题,欢迎一起交流探讨!