本文介绍如何在 Spring AI 中使用提示词模板:将提示词外部化、参数化,便于维护和复用。
源代码
如果您想自己尝试,可以查看我的源代码。为此,您必须克隆我的示例 GitHub 仓库 。然后,您只需按照我的说明操作即可。
为什么使用提示词模板
- 外部化:长提示词放在文件或配置中,避免硬编码在 Java 里。
- 参数化:用占位符(如
{topic}、{count}、{tone})在运行时填入变量,同一模板可复用于不同请求。 - 角色与风格:通过系统消息(SystemMessage)固定助手角色与风格,用户消息(UserMessage)只传具体内容。
本示例使用 chat-model 模块中的 ChatPromptController,以下 API 均返回 {"content":"..."}。
1. 系统消息 + 用户消息(无模板)
/api/chat/prompt 演示「系统消息 + 用户消息」的组成方式:系统消息写死在代码中,用户消息来自请求体。
@PostMappingOutput 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) {}流程简述:
- 用
@Value("classpath:/prompts/...")注入Resource,getContentAsString(UTF_8)得到模板字符串。 new PromptTemplate(templateContent).createMessage(Map.of("tone", tone))得到填充后的 Message,.getText()取出文本。- 将该文本作为 SystemMessage,用户输入作为 UserMessage,组成
Prompt后调用chatClient.prompt(prompt).call().content()。
适合:长提示词、多语言/多风格、希望与代码分离时。
三种方式对比
| 方式 | 示例接口 | 模板位置 | 占位符 | 典型场景 |
|---|---|---|---|---|
| 系统+用户消息 | /api/chat/prompt | 代码内 | 无 | 简单对话、固定角色 |
| 内联模板 | /api/chat/prompt/suggest-titles | 代码内字符串 | {topic}, {count} | 短模板、参数少、逻辑集中 |
| 文件模板 | /api/chat/prompt/gen-tweet | classpath 文件 | {tone} | 长提示、多风格、易维护 |
配置与运行
本示例默认使用 OpenAI,亦可通过 Maven Profile 切换 Anthropic 与 Ollama。请先设置对应的环境变量:
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 模型启动应用
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 即可验证三种提示词用法。
# 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"}'总结
- 系统消息 + 用户消息:用
SystemMessage与UserMessage组成Prompt,无需模板。 - 内联模板:
new PromptTemplate("... {var} ...").createMessage(Map.of("var", value)),得到Message后交给ChatClient。 - 文件模板:classpath 资源读成字符串 →
new PromptTemplate(content).createMessage(vars).getText()得到渲染后的系统提示 → 再包成SystemMessage与用户消息一起调用。
按需选择「无模板 / 内联 / 文件」即可在 Spring AI 中用好提示词模板。