跳到主要内容
版本:2.0.0-M6

Prompt Template

提示词模板是 Spring AI 的文本模板引擎,基于 StringTemplate 将带占位符的模板字符串渲染为最终提示词,支持变量替换、角色化消息和 ChatClient 链式集成。


1. 概述

Prompt Template 基于 StringTemplate 引擎,将带占位符的模板字符串渲染为最终提示词,支持变量替换和角色化消息。


2. 模板语法

Spring AI 默认使用 StringTemplate v4 语法,占位符由 {} 包裹。

2.1 基本变量

String template = "你好,我叫{name},是一名{role}";
PromptTemplate pt = new PromptTemplate(template);
pt.add("name", "张三");
pt.add("role", "Java 工程师");
String result = pt.render();
// 输出: 你好,我叫张三,是一名 Java 工程师

2.2 语法速览

语法示例说明
变量替换{name}替换为变量值
列表迭代{items; separator=", "}用分隔符拼接列表
条件判断{if(score > 60)}及格{else}不及格{endif}条件分支
字面量转义\{不是变量\}输出 {不是变量}
空值处理{name}变量为 null 时输出空字符串

3. PromptTemplate

PromptTemplate 是核心模板类,提供 render()create()createMessage() 三种输出方式。

3.1 渲染为字符串

完整示例:RenderStringDemo.java
RenderStringDemo.java
@Component
public class RenderStringDemo implements CommandLineRunner {

@Override
public void run(String... args) {
PromptTemplate pt = new PromptTemplate("用{language}语言写一个{pattern}模式的示例");

pt.add("language", "Java");
pt.add("pattern", "单例模式");

String rendered = pt.render();
System.out.println("渲染结果: " + rendered);
}
}

3.2 创建 Message

完整示例:CreateMessageDemo.java
CreateMessageDemo.java
@Component
public class CreateMessageDemo implements CommandLineRunner {

private final ChatModel chatModel;

public CreateMessageDemo(ChatModel chatModel) {
this.chatModel = chatModel;
}

@Override
public void run(String... args) {
PromptTemplate pt = new PromptTemplate("推荐{count}本关于{topic}的经典书籍");

pt.add("count", 3);
pt.add("topic", "系统设计");

Message message = pt.createMessage();
Prompt prompt = new Prompt(message);
ChatResponse response = chatModel.call(prompt);

System.out.println(response.getResult().getOutput().getText());
}
}

3.3 创建 Prompt

完整示例:CreatePromptDemo.java
CreatePromptDemo.java
@Component
public class CreatePromptDemo implements CommandLineRunner {

private final ChatModel chatModel;

public CreatePromptDemo(ChatModel chatModel) {
this.chatModel = chatModel;
}

@Override
public void run(String... args) {
PromptTemplate pt = new PromptTemplate("解释{concept}的核心原理,不超过{words}字");

pt.add("concept", "CAP 定理");
pt.add("words", 200);

Prompt prompt = pt.create(OllamaOptions.builder()
.temperature(0.3)
.build());

ChatResponse response = chatModel.call(prompt);
System.out.println(response.getResult().getOutput().getText());
}
}

3.4 Builder 方式

完整示例:BuilderDemo.java
BuilderDemo.java
@Component
public class BuilderDemo implements CommandLineRunner {

private final ChatClient chatClient;

public BuilderDemo(ChatClient.Builder builder) {
this.chatClient = builder.build();
}

@Override
public void run(String... args) {
PromptTemplate pt = PromptTemplate.builder()
.template("""
请对以下代码进行{action}:

{code}
""")
.variables(Map.of("action", "安全性审查"))
.build();

pt.add("code", """
public String getUserInput() {
Scanner scanner = new Scanner(System.in);
return scanner.nextLine();
}
""");

String response = chatClient.prompt()
.user(pt.render())
.call()
.content();

System.out.println(response);
}
}

3.5 render 传参

render(Map) 可以追加变量,会与已有变量合并(同名覆盖)。

完整示例:RenderWithMapDemo.java
RenderWithMapDemo.java
@Component
public class RenderWithMapDemo implements CommandLineRunner {

@Override
public void run(String... args) {
PromptTemplate pt = new PromptTemplate("请用{lang}解释{term}的含义");

pt.add("lang", "中文");
pt.add("term", "微服务");

String result = pt.render(Map.of("lang", "英文"));
// 同名变量被覆盖
System.out.println(result);
}
}

4. 角色化模板

Spring AI 提供了三个预设消息类型的模板子类,省去手动包装 Message 的步骤。

4.1 SystemPromptTemplate

完整示例:SystemPromptTemplateDemo.java
SystemPromptTemplateDemo.java
@Component
public class SystemPromptTemplateDemo implements CommandLineRunner {

private final ChatModel chatModel;

public SystemPromptTemplateDemo(ChatModel chatModel) {
this.chatModel = chatModel;
}

@Override
public void run(String... args) {
SystemPromptTemplate system = new SystemPromptTemplate("""
你是一个{role},擅长{skill}。
回答要求:专业准确,不超过{maxWords}字。
""");

system.add("role", "资深 Java 架构师");
system.add("skill", "JVM 调优");
system.add("maxWords", 300);

Message systemMsg = system.createMessage();
Message userMsg = new UserMessage("线上 Full GC 频繁怎么办?");

Prompt prompt = new Prompt(List.of(systemMsg, userMsg));
ChatResponse response = chatModel.call(prompt);

System.out.println(response.getResult().getOutput().getText());
}
}

4.2 AssistantPromptTemplate

完整示例:AssistantPromptTemplateDemo.java
AssistantPromptTemplateDemo.java
@Component
public class AssistantPromptTemplateDemo implements CommandLineRunner {

private final ChatClient chatClient;

public AssistantPromptTemplateDemo(ChatClient.Builder builder) {
this.chatClient = builder.build();
}

@Override
public void run(String... args) {
AssistantPromptTemplate assistant = new AssistantPromptTemplate("""
以下是{repoName}项目中发现的{issueCount}个问题:

1. {issue1}
2. {issue2}
""");

assistant.add("repoName", "order-service");
assistant.add("issueCount", 2);
assistant.add("issue1", "OrderController 缺少参数校验");
assistant.add("issue2", "OrderService 事务边界不合理");

String response = chatClient.prompt()
.messages(List.of(
new SystemMessage("你是一个代码审查助手,请确认以下审查结果"),
assistant.createMessage(),
new UserMessage("这些问题是否需要立即修复?")
))
.call()
.content();

System.out.println(response);
}
}

5. ChatPromptTemplate

组合多个 PromptTemplate,一次性生成完整的消息列表。

完整示例:ChatPromptTemplateDemo.java
ChatPromptTemplateDemo.java
@Component
public class ChatPromptTemplateDemo implements CommandLineRunner {

private final ChatModel chatModel;

public ChatPromptTemplateDemo(ChatModel chatModel) {
this.chatModel = chatModel;
}

@Override
public void run(String... args) {
SystemPromptTemplate systemPt = new SystemPromptTemplate("""
你是一个{role},用{style}风格回答问题。
""");

PromptTemplate userPt = new PromptTemplate("介绍一下{framework}的最新版本特性");

ChatPromptTemplate chatPt = new ChatPromptTemplate(List.of(systemPt, userPt));

chatPt.add("role", "前端技术专家");
chatPt.add("style", "通俗易懂");
chatPt.add("framework", "React 19");

List<Message> messages = chatPt.createMessages();
Prompt prompt = new Prompt(messages);
ChatResponse response = chatModel.call(prompt);

System.out.println(response.getResult().getOutput().getText());
}
}

6. ChatClient 集成

ChatClient 内置了模板渲染能力,通过 Consumer 风格的 .user() / .system() + .param() 使用,无需手动创建 PromptTemplate

6.1 带参数的用户消息

完整示例:ChatClientUserTemplateDemo.java
ChatClientUserTemplateDemo.java
@Component
public class ChatClientUserTemplateDemo implements CommandLineRunner {

private final ChatClient chatClient;

public ChatClientUserTemplateDemo(ChatClient.Builder builder) {
this.chatClient = builder.build();
}

@Override
public void run(String... args) {
String response = chatClient.prompt()
.user(userSpec -> userSpec
.text("请用{language}解释{concept}")
.param("language", "中文")
.param("concept", "依赖注入")
)
.call()
.content();

System.out.println(response);
}
}

6.2 带参数的系统消息

完整示例:ChatClientSystemTemplateDemo.java
ChatClientSystemTemplateDemo.java
@Component
public class ChatClientSystemTemplateDemo implements CommandLineRunner {

private final ChatClient chatClient;

public ChatClientSystemTemplateDemo(ChatClient.Builder builder) {
this.chatClient = builder.build();
}

@Override
public void run(String... args) {
String response = chatClient.prompt()
.system(systemSpec -> systemSpec
.text("你是一个{role},只回答{subdomain}相关的问题,答案不超过{limit}字")
.param("role", "后端开发专家")
.param("subdomain", "数据库优化")
.param("limit", 200)
)
.user("MySQL 索引失效的常见原因有哪些?")
.call()
.content();

System.out.println(response);
}
}

6.3 Builder 默认模板

完整示例:DefaultTemplateDemo.java
DefaultTemplateDemo.java
@Component
public class DefaultTemplateDemo implements CommandLineRunner {

private final ChatClient chatClient;

public DefaultTemplateDemo(ChatClient.Builder builder) {
this.chatClient = builder
.defaultSystem(systemSpec -> systemSpec
.text("你是一个精通{language}的编程助手")
.param("language", "Java")
)
.build();
}

@Override
public void run(String... args) {
String r1 = chatClient.prompt()
.user("解释 Stream API 的 map 和 flatMap 区别")
.call()
.content();

System.out.println("结果1: " + r1);

String r2 = chatClient.prompt()
.system("你是一个精通 Python 的编程助手")
.user("解释列表推导式")
.call()
.content();

System.out.println("结果2: " + r2);
}
}

7. 自定义渲染器

7.1 自定义分隔符

默认分隔符 {} 可能与 JSON 等格式冲突,可替换为其他符号。

完整示例:CustomDelimiterDemo.java
CustomDelimiterDemo.java
@Component
public class CustomDelimiterDemo implements CommandLineRunner {

private final ChatClient chatClient;

public CustomDelimiterDemo(ChatClient.Builder builder) {
this.chatClient = builder.build();
}

@Override
public void run(String... args) {
TemplateRenderer renderer = StTemplateRenderer.builder()
.startDelimiterToken('[')
.endDelimiterToken(']')
.build();

String response = chatClient.prompt()
.templateRenderer(renderer)
.user(userSpec -> userSpec
.text("请用[language]解释[concept]")
.param("language", "中文")
.param("concept", "AOP 面向切面编程")
)
.call()
.content();

System.out.println(response);
}
}

7.2 变量校验模式

完整示例:ValidationModeDemo.java
ValidationModeDemo.java
@Component
public class ValidationModeDemo implements CommandLineRunner {

@Override
public void run(String... args) {
PromptTemplate pt = new PromptTemplate("姓名:{name},年龄:{age},职业:{job}");

pt.add("name", "李四");

TemplateRenderer strict = StTemplateRenderer.builder()
.validationMode(ValidationMode.THROW)
.build();

TemplateRenderer lenient = StTemplateRenderer.builder()
.validationMode(ValidationMode.WARN)
.build();

try {
strict.apply(pt.getTemplate(), Map.of("name", "李四"));
} catch (IllegalStateException e) {
System.out.println("严格模式报错: " + e.getMessage());
}

String result = lenient.apply(pt.getTemplate(), Map.of("name", "李四"));
System.out.println("宽松模式结果: " + result);
}
}

8. 完整综合示例

完整示例:PromptTemplateCompleteExample.java
PromptTemplateCompleteExample.java
@Component
public class PromptTemplateCompleteExample implements CommandLineRunner {

private final ChatClient chatClient;

public PromptTemplateCompleteExample(ChatClient.Builder builder) {
this.chatClient = builder.build();
}

@Override
public void run(String... args) {
record Analysis(String framework, String pros, String cons) {}

SystemPromptTemplate systemPt = new SystemPromptTemplate("""
你是一个{role}。分析给出的技术框架,
输出格式:{"framework": "框架名", "pros": "优势", "cons": "劣势"}
""");

systemPt.add("role", "技术选型顾问");

PromptTemplate userPt = PromptTemplate.builder()
.template("分析{framework}在{scenario}场景下的适用性,重点关注{aspect}")
.build();

userPt.add("framework", "Spring Cloud Gateway");
userPt.add("scenario", "高并发微服务网关");
userPt.add("aspect", "性能与可扩展性");

ChatPromptTemplate chatPt = new ChatPromptTemplate(List.of(systemPt, userPt));

Analysis result = chatClient.prompt()
.messages(chatPt.createMessages())
.call()
.entity(Analysis.class);

System.out.println("框架: " + result.framework());
System.out.println("优势: " + result.pros());
System.out.println("劣势: " + result.cons());
}
}