概念: 提示词是引导AI模型生成特定输出的输入
比如,把AI模型想象成一个厨师—— 这个厨师学过做各种菜,你给它食材和要求,它就能做出对应的菜品。AI 模型也是如此,它提前 “学” 了海量数据,你给它指令,它就能输出结果(比如写文案、算题、翻译)。提示:就是你给这个智能工具的具体指令。还是用厨师举例,你说 “我要一份番茄炒蛋,少盐”,这句话就是提示。
在 Spring AI 与 AI 模型的最低级交互时,处理提示在某种程度上类似于 Spring MVC 中管理“视图”。 这包括创建带有动态内容占位符的大量文本。 这些占位符随后根据用户请求或应用程序中的其他代码被替换。最初,提示词是简单的字符串。 随着时间推移,它们逐渐加入了特定输入的占位符,比如“USER:”,AI模型能识别的角色。 OpenAI 通过将多个消息字符串分类为不同角色,为提示引入了更多结构,然后再由 AI 模型处理。
提示
通常会使用call()方法聊天模型这需要一个提示实例并返回聊天回应.
这提示类作为有组织序列的容器消息对象和请求聊天选项. 每消息在提示中具有独特的角色,内容和意图各异。 这些角色涵盖多种环节,从用户提问到AI生成的相关背景信息回复。 这种安排使得与AI模型的复杂且细致的互动成为可能,提示由多条消息构成,每条信息在对话中被赋予特定角色。
以下是Prompt类的简短版本,为了简洁起见省略了构造函数和实用方法:
public class Prompt implements ModelRequest<List<Message>> {
private final List<Message> messages;//多条不同角色的消息
private ChatOptions chatOptions;//里面可以设置模型,温度值,最大tokens数等等
}
消息
这消息接口封装了提示文本内容、元数据属性集合,以及一种称为消息类型.
接口定义如下:
public interface Content {
/**
* Get the content of the message.
* @return the content of the message
*/
String getText();
/**
* Get the metadata associated with the content.
* @return the metadata associated with the content
*/
Map<String, Object> getMetadata();
}
多模态消息类型还实现了<font style="color:rgb(25, 30, 30);">媒体内容</font>接口提供列表<font style="color:rgb(25, 30, 30);">媒体</font>内容对象。
public interface MediaContent extends Content {
/**
* Get the media associated with the content.
*/
List<Media> getMedia();
}
各种实现<font style="color:rgb(25, 30, 30);">消息</font>界面对应于AI模型能够处理的不同类别消息。 模型根据对话角色区分消息类别。
此图还是旧,个别方法的有变动,依赖关系没有变,变动方法参考文档代码块
角色
每个消息都被分配了特定的角色。 这些角色负责对信息进行分类,明确提示中每个部分的上下文和目的,供AI模型使用。 这种结构化的方法增强了与AI沟通的细腻度和有效性,因为提示的每个部分在互动中都扮演着独特且明确的角色。
主要职责包括:
- 系统角色:指导AI的行为和响应风格,设定AI如何解释和响应输入的参数或规则。这就像在发起对话前先给AI提供指令。
- 用户角色:代表用户的输入——他们对AI的问题、命令或陈述。这一角色至关重要,因为它构成了人工智能应对的基础。
- 助理角色:AI对用户输入的回应。 这不仅仅是一个回答或反应,更对于保持对话的流畅性至关重要。 通过追踪AI之前的回复(其“助理角色”消息),系统确保互动连贯且符合上下文。 助手消息也可能包含功能工具调用请求信息。 它就像AI中的一个特殊功能,用于执行特定功能,比如计算、获取数据或其他不仅仅是说话的任务。
- 工具/功能角色:工具/功能角色专注于回复工具呼叫助手消息时返回更多信息。
Spring AI 中角色以枚举形式表示,如下所示
public enum MessageType {
/**
* A {@link Message} of type {@literal user}, having the user role and originating
* from an end-user or developer.
* @see UserMessage
*/
USER("user"),
/**
* A {@link Message} of type {@literal assistant} passed in subsequent input
* {@link Message Messages} as the {@link Message} generated in response to the user.
* @see AssistantMessage
*/
ASSISTANT("assistant"),
/**
* A {@link Message} of type {@literal system} passed as input {@link Message
* Messages} containing high-level instructions for the conversation, such as behave
* like a certain character or provide answers in a specific format.
* @see SystemMessage
*/
SYSTEM("system"),
/**
* A {@link Message} of type {@literal function} passed as input {@link Message
* Messages} with function content in a chat application.
* @see ToolResponseMessage
*/
TOOL("tool");
提示模板
Spring AI 中提示模板化的一个关键组件是<font style="color:rgb(25, 30, 30);">提示模板</font>类,旨在促进结构化提示的创建,然后发送给 AI 模型进行处理
public class PromptTemplate implements PromptTemplateActions, PromptTemplateMessageActions {
private static final Logger log = LoggerFactory.getLogger(PromptTemplate.class);
private static final TemplateRenderer DEFAULT_TEMPLATE_RENDERER = StTemplateRenderer.builder().build();
/**
* If you're subclassing this class, re-consider using the built-in implementation
* together with the new PromptTemplateRenderer interface, designed to give you more
* flexibility and control over the rendering process.
*/
private String template;
private final Map<String, Object> variables = new HashMap<>();
private final TemplateRenderer renderer;
public PromptTemplate(Resource resource) {
this(resource, new HashMap<>(), DEFAULT_TEMPLATE_RENDERER);
}
public PromptTemplate(String template) {
this(template, new HashMap<>(), DEFAULT_TEMPLATE_RENDERER);
}
该类使用<font style="color:rgb(25, 30, 30);">模板渲染器</font>API来渲染模板。默认情况下,Spring AI使用以下<font style="color:rgb(25, 30, 30);">StTemplateRenderer</font>该系统基于Terence Parr开发的开源StringTemplate引擎。模板变量通过语法标识,但你也可以配置分隔符使用其他语法。默认使用<font style="color:rgb(25, 30, 30);">{}</font>进行模版变量的替换
public class StTemplateRenderer implements TemplateRenderer {
private static final Logger logger = LoggerFactory.getLogger(StTemplateRenderer.class);
private static final String VALIDATION_MESSAGE = "Not all variables were replaced in the template. Missing variable names are: %s.";
private static final char DEFAULT_START_DELIMITER_TOKEN = '{';
private static final char DEFAULT_END_DELIMITER_TOKEN = '}';
private static final ValidationMode DEFAULT_VALIDATION_MODE = ValidationMode.THROW;
private static final boolean DEFAULT_VALIDATE_ST_FUNCTIONS = false;
private final char startDelimiterToken;
private final char endDelimiterToken;
private final ValidationMode validationMode;
private final boolean validateStFunctions;
}
public interface TemplateRenderer extends BiFunction<String, Map<String, Object>, String> {
@Override
String apply(String template, Map<String, Object> variables);
}
Spring AI使用了<font style="color:rgb(25, 30, 30);">模板渲染器</font>用于实际将变量替换到模板字符串中的接口。默认实现使用 [StringTemplate]。你可以提供你自己的实现<font style="color:rgb(25, 30, 30);">模板渲染器</font>如果你需要自定义逻辑。对于不需要模板渲染的场景(例如模板字符串已经完成),你可以使用提供的<font style="color:rgb(25, 30, 30);">NoOpTemplateRenderer</font>.
示例使用自定义StringTemplate渲染器,带有“<”和“>”分隔符
PromptTemplate promptTemplate = PromptTemplate.builder()
.renderer(StTemplateRenderer.builder().startDelimiterToken('<').endDelimiterToken('>').build())
.template("""
Tell me the names of 5 movies whose soundtrack was composed by <composer>.
""")
.build();
String prompt = promptTemplate.render(Map.of("composer", "John Williams"));
示例用法
- 简单模版示例
package spring.ai;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello")
public class ChatController03 {
private final ChatClient chatClient;
public ChatController03(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder.build();
}
@GetMapping("/prompt")
String generation() {
PromptTemplate promptTemplate = new PromptTemplate("请告诉我一个 {adjective} 关于 {topic}");
String messageContent = promptTemplate.create(java.util.Map.of("adjective", "电影", "topic", "张艺谋")).getContents();
return this.chatClient.prompt()
.user(messageContent)
.call()
.content();
}
}
访问验证
2.基于角色消息示例
@GetMapping("/rolePrompt")
String rolePrompt() {
String userText = """
请告诉我三位黄金时代海盗的著名人物及其行为动机,为每位海盗至少写一句话。
""";
Message userMessage = new UserMessage(userText);
String systemText = """
你是乐于助人的AI助手,能帮人找信息。你的名字是{name},请用{voice}的风格回复我。
""";
SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemText);
Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", "小智", "voice","严肃" ));
Prompt prompt = new Prompt(List.of(userMessage, systemMessage));
List<Generation> response = this.chatClient.prompt(prompt).call().chatResponse().getResults();
return response.get(0).getOutput().getText();
}
这展示了如何逐步建立<font style="color:rgb(25, 30, 30);">提示</font>,实例通过使用<font style="color:rgb(25, 30, 30);">系统提示模板</font>以创建<font style="color:rgb(25, 30, 30);">消息</font>系统角色传递占位符值。 角色传递的信息<font style="color:rgb(25, 30, 30);">用户</font>然后与角色的信息结合<font style="color:rgb(25, 30, 30);">系统提示</font>形成完整提示。 完整提示随后传递给ChatModel,以获得生成性回。
验证:
3.使用自定义模版渲染器
可以通过实现模板渲染器接口并将其传递给提示模板构造 函数。你也可以继续使用默认StTemplateRenderer但配置是自定义的。
默认情况下,模板变量通过语法标识。如果你打算在提示词中包含JSON,可能需要使用不同的语法以避免与JSON语法冲突。例如,你可以使用和分隔符。{}改为<``>
@GetMapping("/customPrompt")
String customPrompt() {
PromptTemplate promptTemplate = PromptTemplate.builder()
.renderer(StTemplateRenderer.builder().startDelimiterToken('<').endDelimiterToken('>').build())
.template("""
告诉我五部电影名称由某位导演<composer>导演的.
""")
.build();
String prompt = promptTemplate.render(Map.of("composer", "张艺谋"));
return this.chatClient.prompt(prompt)
.call()
.content();
}
验证: