本文介绍如何在 Spring AI 中使用提示词模板:将提示词外部化、参数化,便于维护和复用。

源代码

如果您想自己尝试,可以查看我的源代码。为此,您必须克隆我的示例 GitHub 仓库 。然后,您只需按照我的说明操作即可。

为什么使用提示词模板

  • 外部化:长提示词放在文件或配置中,避免硬编码在 Java 里。
  • 参数化:用占位符(如 {topic}{count}{tone})在运行时填入变量,同一模板可复用于不同请求。
  • 角色与风格:通过系统消息(SystemMessage)固定助手角色与风格,用户消息(UserMessage)只传具体内容。

本示例使用 chat-model 模块中的 ChatPromptController,以下 API 均返回 {"content":"..."}

1. 系统消息 + 用户消息(无模板)

/api/chat/prompt 演示「系统消息 + 用户消息」的组成方式:系统消息写死在代码中,用户消息来自请求体。

@PostMapping
Output chat(@RequestBody @Valid Input input) {
String systemPrompt = "You are a friendly, helpful assistant. You always respond professionally.";
SystemMessage systemMessage = new SystemMessage(systemPrompt);
UserMessage userMessage = new UserMessage(input.prompt());
Prompt prompt = new Prompt(List.of(systemMessage, userMessage));
String response = chatClient.prompt(prompt).call().content();
return new Output(response);
}

适合:简单对话、系统角色固定且无需参数化。

2. 内联模板:PromptTemplate + 占位符

/api/chat/prompt/suggest-titles 使用 PromptTemplate 在代码中写模板字符串,占位符为 {topic}{count},运行时通过 Map 传入变量;createMessage(vars) 得到一条消息后交给 ChatClient。

@PostMapping("/suggest-titles")
Output suggestTitles(@RequestBody @Valid TitleSuggestionsRequest req) {
PromptTemplate pt = new PromptTemplate("""
I would like to give a presentation about the following:
{topic}
Give me {count} title suggestions for this topic.
Make sure the title is relevant to the topic and it should be a single short sentence.
""");
Map<String, Object> vars = Map.of("topic", req.topic(), "count", req.count());
Message message = pt.createMessage(vars);
String response = chatClient.prompt().messages(message).call().content();
return new Output(response);
}

要点:

  • PromptTemplate 的字符串中使用 {name} 形式的占位符。
  • createMessage(Map.of(...)) 将占位符替换后生成一条 Message(默认相当于用户消息),再通过 chatClient.prompt().messages(message).call().content() 调用模型。

适合:模板较短、与业务强相关、不需要单独文件时。

3. 文件模板:外部文件 + 占位符

/api/chat/prompt/gen-tweet 将系统提示词放在 classpath 资源 prompts/tweet-system-message.st 中,模板内容里包含占位符 {tone},运行时从请求体传入并渲染。

模板文件 src/main/resources/prompts/tweet-system-message.st

You are an expert software developer and experienced content creator.
Your job is to generate interesting tweet based on the given input.
* Use a catchy first line to convey the essence of the input.
* Keep it concise and engaging.
* Maintain a {tone} tone.
* Use bullet points to list key features or benefits
* Use emojis where appropriate.
* Include relevant hashtags at the end.
Don't use Markdown syntax. Use plain text format.

Java 中加载并渲染

@Value("classpath:/prompts/tweet-system-message.st")
Resource tweetSystemMsgResource;
@PostMapping("/gen-tweet")
Output generateTweet(@RequestBody @Valid GenTweetRequest request) throws IOException {
String templateContent = tweetSystemMsgResource.getContentAsString(UTF_8);
String tone = request.tone() != null ? request.tone() : "professional";
String systemPrompt = new PromptTemplate(templateContent)
.createMessage(Map.of("tone", tone))
.getText();
SystemMessage systemMessage = new SystemMessage(systemPrompt);
UserMessage userMessage = new UserMessage(request.prompt());
Prompt prompt = new Prompt(List.of(systemMessage, userMessage));
String response = chatClient.prompt(prompt).call().content();
return new Output(response);
}
record GenTweetRequest(@NotBlank String prompt, String tone) {}

流程简述:

  1. @Value("classpath:/prompts/...") 注入 ResourcegetContentAsString(UTF_8) 得到模板字符串。
  2. new PromptTemplate(templateContent).createMessage(Map.of("tone", tone)) 得到填充后的 Message.getText() 取出文本。
  3. 将该文本作为 SystemMessage,用户输入作为 UserMessage,组成 Prompt 后调用 chatClient.prompt(prompt).call().content()

适合:长提示词、多语言/多风格、希望与代码分离时。

三种方式对比

方式示例接口模板位置占位符典型场景
系统+用户消息/api/chat/prompt代码内简单对话、固定角色
内联模板/api/chat/prompt/suggest-titles代码内字符串{topic}, {count}短模板、参数少、逻辑集中
文件模板/api/chat/prompt/gen-tweetclasspath 文件{tone}长提示、多风格、易维护

配置与运行

本示例默认使用 OpenAI,亦可通过 Maven Profile 切换 Anthropic 与 Ollama。请先设置对应的环境变量:

Terminal window
export OPENAI_API_KEY=<your-openai-api-key>
export ANTHROPIC_API_KEY=<your-anthropic-api-key>

运行命令示例:

  • OpenAI(默认):mvn spring-boot:run
  • Anthropic:mvn spring-boot:run -Panthropic
  • Ollama:mvn spring-boot:run -Pollama

我这里使用 DeepSeek 模型启动应用

Terminal window
export DEEPSEEK_API_KEY=<your-deepseek-api-key>
mvn spring-boot:run -Dspring-boot.run.profiles=deepseek

启动应用后,按上文 curl 示例依次测试 /api/chat/prompt/api/chat/prompt/suggest-titles/api/chat/prompt/gen-tweet 即可验证三种提示词用法。

Terminal window
# 1. 系统消息 + 用户消息
curl -s -X POST http://localhost:8080/api/chat/prompt \
-H "Content-Type: application/json" \
-d '{"prompt":"What is Spring Boot?"}'
# 2. 内联模板(标题建议)
curl -s -X POST http://localhost:8080/api/chat/prompt/suggest-titles \
-H "Content-Type: application/json" \
-d '{"topic":"Spring Boot Tips and Tricks","count":5}'
# 3. 文件模板(生成推文)
curl -s -X POST http://localhost:8080/api/chat/prompt/gen-tweet \
-H "Content-Type: application/json" \
-d '{"prompt":"IntelliJ IDEA 2025.2 发布,支持 Java 25 EA、Maven 4。","tone":"professional"}'

总结

  • 系统消息 + 用户消息:用 SystemMessageUserMessage 组成 Prompt,无需模板。
  • 内联模板new PromptTemplate("... {var} ...").createMessage(Map.of("var", value)),得到 Message 后交给 ChatClient
  • 文件模板:classpath 资源读成字符串 → new PromptTemplate(content).createMessage(vars).getText() 得到渲染后的系统提示 → 再包成 SystemMessage 与用户消息一起调用。

按需选择「无模板 / 内联 / 文件」即可在 Spring AI 中用好提示词模板。