上一节我们使用SpringAI+Llama3.1构建了一个基础的Chat案例,本节将会从Prompt着手深度聊聊在SPringAI中如何更好的使用Prompt。
Prompt重要性
在生成式 AI 中,创建提示对于开发人员来说是一项至关重要的任务。 这些提示的质量和结构会显著影响人工智能输出的有效性。 投入时间和精力来设计深思熟虑的提示可以大大提高人工智能的结果。
在SpringAI框架下,处理提示的过程可以类比于Spring MVC中的“视图”管理,涉及使用占位符来构建包含动态内容的大量文本。这些占位符会根据用户请求或应用程序逻辑动态替换,这一过程类似于在SQL语句中使用带有占位符和动态值的表达式。
随着Spring AI框架的不断演进,它将逐步引入更为抽象的层来简化与AI模型的交互。本节所述的基础类,在功能上可与传统的JDBC API相类比。例如,这些基础类就像是JDK中提供的JDBC核心接口。在此基础上,Spring AI框架将提供类似于Spring Data JPA的高级抽象,例如ChatModelJdbcTemplate,以及更高级的组件如ChatEngines和Agents。这些高级组件能够集成模型的历史交互数据,以实现更智能的对话管理。
在AI领域,提示的构造已经经历了从简单字符串到复杂结构的演变。最初,提示仅限于基本的文本字符串。随着时间的推移,提示开始融入特定的标识符,如“USER:”,以指导AI模型如何处理输入。
SpringAI 中Prompt结构
Prompt
类用于封装一系列Message
对象,以便与AI模型进行交互。每个Message
在提示中扮演特定的角色,可以是用户查询、AI生成的响应或其他类型的内容。
以下是Prompt
类的更详细版本,包括一个假设的callChatModel
方法,该方法可能用于将提示发送到聊天模型并接收响应:
/**
* The Prompt class represents a prompt used in AI model requests. A prompt consists of
* one or more messages and additional chat options.
*
* @author Mark Pollack
* @author luocongqiu
*/
public class Prompt implements ModelRequest<List<Message>> {
// 对话消息
private final List<Message> messages;
// Chat 参数配置
private ChatOptions chatOptions;
// 其他代码省略
}
/****************************************************************************************
* Interface representing a request to an AI model. This interface encapsulates the
* necessary information required to interact with an AI model, including instructions or
* inputs (of generic type T) and additional model options. It provides a standardized way
* to send requests to AI models, ensuring that all necessary details are included and can
* be easily managed.
*
* @param <T> the type of instructions or input required by the AI model
* @author Mark Pollack
* @since 0.8.0
*/
public interface ModelRequest<T> {
/**
* Retrieves the instructions or input required by the AI model.
* @return the instructions or input required by the AI model
*/
T getInstructions(); // required input
/**
* Retrieves the customizable options for AI model interactions.
* @return the customizable options for AI model interactions
*/
ModelOptions getOptions();
}
ModelRequest的实现类分别为多模态提示词实现类。
详细Content体系设计
从上面的的Prompt类定义中可以看到,泛型为List,那么Message定义了完整的Prompt模板结构设计。
其中,着重关注一下Message
和Content
接口。
Message
接口的各种实现对应于 AI 模型可以处理的不同类别的消息。 这些模型根据对话角色区分消息类别。
MessageType包含 user、assistant、system、tool 四种角色类型的对话信息。
/**
* Data structure that contains content and metadata. Common parent for the
* {@link org.springframework.ai.document.Document} and the
* {@link org.springframework.ai.chat.messages.Message} classes.
*
* @author Mark Pollack
* @author Christian Tzolov
* @since 1.0.0
*/
public interface Content {
/**
* Get the content of the message.
*/
String getContent(); // TODO consider getText
/**
* return Get the metadata associated with the content.
*/
Map<String, Object> getMetadata();
}
/****************************************************************************************
* The Message interface represents a message that can be sent or received in a chat
* application. Messages can have content, media attachments, properties, and message
* types.
*
* @see Media
* @see MessageType
*/
public interface Message extends Content {
// 设置消息类型:user、assistant、system、tool
MessageType getMessageType();
}
Prompt中的角色
每条消息都被分配有特定的角色。 这些角色对消息进行分类,阐明 AI 模型的每个提示段的上下文和目的。 这种结构化的方法增强了与人工智能通信的细微差别和有效性,因为提示的每个部分在交互中都扮演着独特而明确的角色。
主要角色是:
- 系统角色(system):指导 AI 的行为和响应风格,为 AI 如何解释和回复输入设置参数或规则。这类似于在开始对话之前向 AI 提供指示。
- 用户角色(user):代表用户的输入 - 他们对 AI 的问题、命令或陈述。这个角色是基本的,因为它构成了人工智能反应的基础。
- 助理角色(assistant):AI 对用户输入的响应。 它不仅仅是一个答案或反应,对于维持对话的流畅性至关重要。 通过跟踪 AI 之前的响应(其“助理角色”消息),该系统确保了连贯且与上下文相关的交互。 助手消息可能还包含函数工具调用请求信息。 它就像 AI 中的一个特殊功能,在需要时用于执行特定功能,例如计算、获取数据或其他任务,而不仅仅是说话。
- 工具/函数角色(tool):Too/Function 角色侧重于返回其他信息以响应工具调用 Aisstnat 消息。
public enum MessageType {
USER("user"),
ASSISTANT("assistant"),
SYSTEM("system"),
TOOL("tool");
// ...
}
关于Prompt结构设计
在Spring AI中,用于提示模板化的一个关键组件是PromptTemplate
类。这个类使用了由Terence Parr开发的OSS StringTemplate引擎来构建和管理提示。PromptTemplate
类旨在简化结构化提示的创建,这些提示随后被发送到AI模型进行处理。
以下是PromptTemplate
类实现的相关接口以及它们的中文解释:
public class PromptTemplate implements PromptTemplateActions, PromptTemplateMessageActions {
// 其他方法将在稍后讨论
}
这个类实现的接口支持提示创建的不同方面:
PromptTemplateStringActions
:专注于创建和渲染提示字符串,代表最基本的提示生成形式。PromptTemplateMessageActions
:专为通过生成和操作Message
对象来创建提示而设计。PromptTemplateActions
:用于返回Prompt
对象,该对象可以传递给ChatModel
以生成响应。
虽然这些接口在许多项目中可能不会广泛使用,但它们展示了提示创建的不同方法。
以下是这些接口及其方法的中文解释:
public interface PromptTemplateStringActions {
// 渲染提示模板成一个最终的字符串格式,不包含外部输入,适用于没有占位符或动态内容的模板。
String render();
// 增强渲染功能以包含动态内容。它使用一个Map<String, Object>,
// 其中map的键是提示模板中的占位符名称,值是要插入的动态内容。
String render(Map<String, Object> model);
}
public interface PromptTemplateMessageActions {
// 创建一个没有额外数据Message对象,用于静态或预定义的消息内容。
Message createMessage();
// 扩展消息创建以整合动态内容,接受一个Map<String, Object>,
// 其中每个条目代表消息模板中的占位符及其对应的动态值。
Message createMessage(Map<String, Object> model);
}
public interface PromptTemplateActions extends PromptTemplateStringActions {
// 生成一个没有外部数据输入的Prompt对象,适用于静态或预定义的提示。
Prompt create();
// 扩展提示创建功能以包含动态内容,接收一个Map<String, Object>,
// 其中每个映射条目是提示模板中的占位符及其相关的动态值。
Prompt create(Map<String, Object> model);
}
这些接口和方法提供了创建和管理AI模型提示的不同方式,允许开发者根据需要构建静态或动态的提示内容。通过使用这些接口,可以灵活地处理从简单到复杂的提示场景。
Prompt使用Case
此处咱们还是拿之前在《易车实战学习Langchain开发》-02-模型I/O,关于Prompt、LLMs、Output Parsers不能说的秘密 使用到的一个案例。
@RestController
@RequestMapping("/prompt")
@AllArgsConstructor
public class PromptCaseController {
private final OllamaChatModel ollamaChatModel;
@GetMapping
String chatOptions(@RequestParam String carName, @RequestParam Integer price) {
PromptTemplate promptTemplate = new PromptTemplate("您是一位专业的汽车销售文案撰写员。" +
"对于售价为 {price} 元的 {car_name} 轿车,您能提供一个吸引人的50字简短销售口号吗?");
Prompt prompt = promptTemplate.create(Map.of("price", price, "car_name", carName));
return ollamaChatModel.call(prompt).getResult().toString();
}
}
下面继续使用一个多角色的案例:
- 给AI定义为角色为文案专家,能够输出不同品牌的多种产品销售文案;
- 用户在AI的角色定义之下,让AI输出宣传文案。
@GetMapping("/role")
String chatRolePrompt(@RequestParam("name") String name, @RequestParam("product") String product) {
String userText = """
帮我设计一个小米14Pro手机的宣传文案,要求20字以内,手机特点如下:
1. 手机屏幕分辨率高;
2. 照片支持AI能力;
等等
""";
Message userMessage = new UserMessage(userText);
String systemText = """
你的名字是 {name},是一个优秀的 {product} 宣传文案设计,能够从用户的痛点出发,结合产品的特点进行宣传文案设计。
""";
SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemText);
Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", name, "product", product));
Prompt prompt = new Prompt(List.of(userMessage, systemMessage));
return ollamaChatModel.call(prompt).toString();
}
这显示了如何使用SystemPromptTemplate传入占位符值来构建实例。 然后,将包含角色的消息与角色的消息组合在一起,形成提示。 然后,将提示传递给 ChatModel 以获取生成响应。
以上就是本节的内容,下节将会继续SpringAI技术讲解,如何加载本地文件,然后将文件进行切分。