模板化 Prompt 的重要性
ChatClient内置 Prompt 模板功能,支持运行时替换变量,避免硬编码 Prompt 文本。这种设计体现了模板方法模式(Template Method Pattern),通过定义算法骨架,将具体实现延迟到子类或运行时。
Prompt 的组成结构
Prompt是发送给AI模型的输入,由以下部分组成:
-
用户消息 (User Messages)**:来自最终用户的直接输入。
-
系统消息 (System Messages)**:系统生成的指导性消息,用于引导AI行为。
-
Prompt选项:模型配置参数,如模型名称、温度等控制参数。
方式一、基础模板使用(默认分隔符 {})
java
import org.springframework.ai.chat.client.ChatClient;
/*
author: atg
*/
@Component
public class PromptTemplateDemo1 {
private final ChatClient chatClient;
public PromptTemplateDemo1(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder.build();
}
public String templateBasicDemo(String composer) {
// 使用{composer}作为变量占位符
return chatClient.prompt()
.user(u -> u
.text("推荐5部由{composer}作曲的电影原声带")
.param("composer", composer)) // 替换变量
.call()
.content();
}
}
模板参数的安全性
在使用模板参数时,需要注意:
-
参数验证:验证输入参数的有效性,防止注入攻击
-
转义处理:对特殊字符进行适当的转义
-
长度限制:限制参数长度,避免过长的输入
-
类型检查:确保参数类型符合预期
方式二、自定义模板分隔符(避免 JSON 冲突)
当 Prompt 包含 JSON 时,可自定义分隔符避免语法冲突:
java
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.template.StTemplateRenderer;
import org.springframework.stereotype.Component;
@Component
class CustomTemplateDemo {
private final ChatClient chatClient;
public CustomTemplateDemo(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder.build();
}
public String customDelimiterDemo(String genre) {
// 方法1:使用 PromptTemplate 单独处理
PromptTemplate promptTemplate = new PromptTemplate(
"推荐3部{genre}类型的经典电影,返回格式:{{\"title\":\"\",\"year\":\"\"}}",
Map.of("genre", genre)
);
// 自定义模板分隔符为<<和>>
return chatClient.prompt()
.user((Resource) promptTemplate)// 配置自定义分隔符
.call()
.content();
}
}
分隔符选择的考虑因素
选择自定义分隔符时,需要考虑:
-
冲突避免:分隔符不应在 Prompt 内容中出现
-
可读性:分隔符应该容易识别和理解
-
兼容性:确保分隔符不会引起解析问题
-
转义支持:支持分隔符的转义,以处理特殊情况
方式3、系统消息模板
系统消息模板允许为不同的应用场景定制 AI 行为:
java
import org.springframework.ai.chat.client.ChatClient;
@Component
public class SystemTemplateDemo {
private final ChatClient chatClient;
public SystemTemplateDemo(ChatClient.Builder chatClientBuilder) {
// 系统消息使用模板变量
this.chatClient = chatClientBuilder
.defaultSystem("你是一个{role}专家,专注于{domain}领域")
.build();
}
public String domainSpecificQuery(String role, String domain, String question) {
return chatClient.prompt()
.system(s -> s
.param("role", role)
.param("domain", domain))
.user(question)
.call()
.content();
}
}
动态系统消息的应用场景
动态系统消息适用于:
-
多租户系统:为不同租户定制不同的 AI 行为
-
领域专家:根据问题领域切换专业角色
-
语言本地化:根据用户语言偏好调整系统消息