SpringAI - Prompt(二)
Prompt
Prompt
什么是Prompt
- 在上一篇已经记录了提示词主要是通过
Message
来实现结构化,且Message
会存在多个。 - 如果需要执行过程中操作这些
Message
,一个一个来就会变得繁琐。 - 所以SpringAI将
Message
按顺序聚合在Prompt
内,再提供处操作Message
的能力。 Prompt
除了Message
还组合了ChatOptions
,这个在后续模型中再学习记录。- 还有自身复制和异变等。
Prompt的能力
使用构造者模式创建
Prompt
增强/修改
SystemMessage
和UserMessage
,每次操作会都会复制一个新的Prompt
获取所有的
Message
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38private final ChatClient promptClient;
public void promptExample() {
// 构造者模式创建Prompt
Prompt prompt = Prompt.builder()
.messages(
// 用英文作为系统提示词
SystemMessage.builder().text("你是一位Java专家。").build(),
// 用户输入了Deque类,默认也是英文
UserMessage.builder().text("SpringAI有哪些优势").build()
).build();
log.info("\nprompt text -> {}", prompt.getContents());
// 增强/修改 SystemMessage
Prompt augmentSystemPrompt = prompt.augmentSystemMessage(systemMessage -> {
return SystemMessage.builder()
.text(systemMessage.getText() + "回答问题要精简,不需要做过多介绍跟解释。")
.build();
});
log.info("\naugmentSystemPrompt text -> {}", augmentSystemPrompt.getContents());
// 增强/修改 UserMessage
Prompt augmentUserPrompt = augmentSystemPrompt.augmentUserMessage(userMessage ->
UserMessage.builder()
.text("帮我解释一下:" + userMessage.getText())
.build()
);
log.info("\naugmentUserPrompt text -> {}", augmentUserPrompt.getContents());
// 获取所有的 Message
SystemMessage systemMessage = augmentUserPrompt.getSystemMessage();
List<UserMessage> userMessages = augmentUserPrompt.getUserMessages();
List<Message> instructions = augmentUserPrompt.getInstructions();
log.info("\nsystemMessage -> {}\nuserMessages -> {}\ninstructions -> {}", systemMessage, userMessages, instructions);
}创建&修改
Message
的输出。可以看到通过augmentXxxPrompt
每次都有变更掉Message
内容1
2
3
4
5
6
72025-07-02T15:20:01.646+08:00 INFO 21138 --- [spring-ai-example] [ main] c.s.ai.example.prompt.two.PromptExample :
prompt text -> 你是一位Java专家。SpringAI有哪些优势
2025-07-02T15:20:01.648+08:00 INFO 21138 --- [spring-ai-example] [ main] c.s.ai.example.prompt.two.PromptExample :
augmentSystemPrompt text -> 你是一位Java专家。回答问题要精简,不需要做过多介绍跟解释。SpringAI有哪些优势
2025-07-02T15:20:01.649+08:00 INFO 21138 --- [spring-ai-example] [ main] c.s.ai.example.prompt.two.PromptExample :
augmentUserPrompt text -> 你是一位Java专家。回答问题要精简,不需要做过多介绍跟解释。帮我解释一下:SpringAI有哪些优势获取所有的
Message
输出。可以获取到systemMessage\userMessages
或者所有的。1
2
3
4
5
62025-07-02T15:20:01.649+08:00 INFO 21138 --- [spring-ai-example] [ main] c.s.ai.example.prompt.two.PromptExample :
systemMessage -> SystemMessage{textContent='你是一位Java专家。回答问题要精简,不需要做过多介绍跟解释。', messageType=SYSTEM, metadata={messageType=SYSTEM}}
userMessages -> [UserMessage{content='帮我解释一下:SpringAI有哪些优势', properties={messageType=USER}, messageType=USER}]
instructions -> [SystemMessage{textContent='你是一位Java专家。回答问题要精简,不需要做过多介绍跟解释。', messageType=SYSTEM, metadata={messageType=SYSTEM}}, UserMessage{content='帮我解释一下:SpringAI有哪些优势', properties={messageType=USER}, messageType=USER}]
PromptTemplate
PromptTemplate族谱
PromptTemplate
是提示词模版化技术,可以有效简化结构化提示词。下面IDEA生成是类图
最顶端三个
Actions
的能力分别可以生成字符串、创建Prompt
、创建Message
。PromptTemplate
具备构造者模式,这里如果创建Prompt
或者Message
角色都是user
PromptTemplate
的子类子类其实有三个,分别就是另外三个角色类型的
PromptTemplate
。子类创建出来的
Message
都是对应的角色的。类图中只体现了SystemPromptTemplate
对应就是system
角色的。这里其实有点问题,子类中都没有重写
PromptTemplate
的构造者模式,如果使用构造者则默认创建了PromptTemplate
,然后创建的Message
又成了user
的。所以子类不能使用构造者模式来创建。
使用PromptTemplate
使用
PromptTemplate
来创建Message
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public void promptTemplateExample(String userMsg, UserInfo userInfo) {
// 通过模版来创建 UserMessage
Message user = PromptTemplate.builder()
.template("亲爱的小助手,{msg}")
.variables(Map.of("msg", userMsg))
.build()
.createMessage();
log.info("\nPromptTemplate createMessage -> {}", user);
String systemTemplate = "你是一位万能小助手。\n回答用户问题时必须要以“尊敬的用户:XXX,你好!”开头。\n用户信息:{info}";
// 通过模版来创建 SystemMessage,子类只能通过new
Message system = new SystemPromptTemplate(systemTemplate)
.createMessage(Map.of("info", userInfo));
log.info("\nSystemPromptTemplate createMessage -> {}", system);
promptClient.prompt()
.messages(system, user)
.call()
.content();
}调用案例
1
2
3
4
public void promptTemplateExample() {
promptExample.promptTemplateExample("你认识我吗?", new UserInfo("重案组之虎曹达华"));
}Message
的输出。可以看到时按照模版来生成的Message
1
2
3
4
5
62025-07-02T16:04:08.356+08:00 INFO 22082 --- [spring-ai-example] [ main] c.s.ai.example.prompt.two.PromptExample :
PromptTemplate createMessage -> UserMessage{content='亲爱的小助手,你认识我吗?', properties={messageType=USER}, messageType=USER}
2025-07-02T16:04:08.360+08:00 INFO 22082 --- [spring-ai-example] [ main] c.s.ai.example.prompt.two.PromptExample :
SystemPromptTemplate createMessage -> SystemMessage{textContent='你是一位万能小助手。
回答用户问题时必须要以“尊敬的用户:XXX,你好!”开头。
用户信息:UserInfo[name=重案组之虎曹达华]', messageType=SYSTEM, metadata={messageType=SYSTEM}}AI的输出
1
2
3
4
5
6
7025-07-02T16:04:18.082+08:00 INFO 22082 --- [spring-ai-example] [ main] c.s.a.e.advisor.three.LogExampleAdvisor :
Chat client response from AI
output text -> 尊敬的用户:重案组之虎曹达华,你好!
我当然认识您!您可是香港电影《逃学威龙》系列中赫赫有名的重案组之虎曹达华,周星驰电影里的经典角色。您以"软饭硬吃"的独特风格和"我系重案组总督察黄启发"的经典台词闻名,是无数影迷心中的喜剧警探形象代表。
请问有什么可以为您效劳的吗?是要讨论案情还是需要生活上的帮助?
使用模版文件
在项目的
resources
下创建./prompts/promptTemplateResourceExample.st
文件promptTemplateResourceExample.st
模版内容1
你是一位万能小助手。回答用户问题时必须要以“尊敬的用户:XXX,你好!”开头。用户信息:{ }
Code。需要用到
org.springframework.core.io.Resource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private Resource promptTemplateResource;
public void promptTemplateResourceExample(String userMsg, UserInfo userInfo) {
Prompt prompt = new SystemPromptTemplate(promptTemplateResource)
.create(Map.of("info", userInfo));
log.info("\nSystemPromptTemplate resource createMessage -> {}", prompt.getSystemMessage());
Message user = PromptTemplate.builder()
.template("亲爱的小助手,{msg}")
.variables(Map.of("msg", userMsg))
.build()
.createMessage();
promptClient.prompt(prompt)
.messages(user)
.call()
.content();
}调用案例
1
2
3
4
public void promptTemplateResourceExample() {
promptExample.promptTemplateResourceExample("你也听说过我的故事?", new UserInfo("重案组之虎曹达华"));
}输出。完全按照模版来生成提示词的。
1
2
3
4
5
6
7
8
9
10
112025-07-02T16:13:45.836+08:00 INFO 22313 --- [spring-ai-example] [ main] c.s.ai.example.prompt.two.PromptExample :
SystemPromptTemplate resource createMessage -> SystemMessage{textContent='你是一位万能小助手。回答用户问题时必须要以“尊敬的用户:XXX,你好!”开头。用户信息:UserInfo[name=重案组之虎曹达华]', messageType=SYSTEM, metadata={messageType=SYSTEM}}
2025-07-02T16:13:45.872+08:00 INFO 22313 --- [spring-ai-example] [ main] c.s.a.e.advisor.three.LogExampleAdvisor :
Chat client request to AI
prompt text -> 你是一位万能小助手。回答用户问题时必须要以“尊敬的用户:XXX,你好!”开头。用户信息:UserInfo[name=重案组之虎曹达华]亲爱的小助手,你也听说过我的故事?
context -> {
"ClientName" : "promptClient"
}
2025-07-02T16:13:53.874+08:00 INFO 22313 --- [spring-ai-example] [ main] c.s.a.e.advisor.three.LogExampleAdvisor :
Chat client response from AI
output text -> 尊敬的用户:重案组之虎曹达华,你好!当然听说过您的传奇故事啦!您可是警界赫赫有名的"重案组之虎",破获过无数大案要案。不知道今天有什么可以为您效劳的?是遇到了棘手的案件需要分析,还是想聊聊您的光辉事迹?
修改模版的引用占位符
从前面的案例可以看到模版默认是使用
{}
作为引用占位符的。比如{msg}
和{info}
如果有特殊要求是可以通过
TemplateRenderer
修改成自定义的,比如修改成<>
。1
2
3
4
5
6
7
8
9
10
11
12
13public void promptTemplateRendererExample() {
Message user = PromptTemplate.builder()
// 自定义模版占位符规则
.renderer(StTemplateRenderer.builder()
.startDelimiterToken('<')
.endDelimiterToken('>')
.build())
.template("亲爱的小助手,<msg>")
.variables(Map.of("msg", "你在教我做事啊?"))
.build()
.createMessage();
log.info("\nPromptTemplateRenderer createMessage -> {}", user);
}输出结果。可以看到是一样的效果。
1
22025-07-02T16:21:15.398+08:00 INFO 22467 --- [spring-ai-example] [ main] c.s.ai.example.prompt.two.PromptExample :
PromptTemplateRenderer createMessage -> UserMessage{content='亲爱的小助手,你在教我做事啊?', properties={messageType=USER}, messageType=USER}这里好像也只能
PromptTemplate
可以通过TemplateRenderer
修改,子类不行。也是因为子类没有重写构造者的原因,然后也没有提供set方法,导致无该能力。等后续SpringAI版本升级吧。
总结
- 可以通过
Prompt
来操作Message
。这个在Advisor
的案例中就已经使用过的。 - 可以通过
PromptTemplate
来创建Prompt
或者Message
,达到简化结构化提示词。- 可以通过模版文本。
- 也可以通过模版文件。
PromptTemplate
的子类没有重写构造者模式,等于是被阉割了。
- 可以通过
TemplateRenderer
自定义模版的引用占位符。PromptTemplate
的子类也无法使用。
最后
提示词是使用AI非常重要的工程,提示词的质量和结构显著影响 AI 输出的有效性。
如何创建高效的提示词SpringAI官方也有一些推荐
- 指令:向 AI 提供清晰直接的指示,类似于与人沟通的方式。这种明确性对帮助AI “理解” 预期目标至关重要。
- 外部上下文:必要时包含相关背景信息或对 AI 响应的具体指导。这种 “外部上下文” 构建了提示框架,帮助 AI 理解整体场景。
- 用户输入:这是直接部分 — 用户构成提示核心的明确请求或问题。
- 输出指示器:这部分可能很棘手。它需要指定 AI 响应的期望格式(如 JSON),但需注意 AI 可能不会严格遵循该格式。例如,它可能在实际 JSON 数据前添加 “这是您的JSON” 等短语,或有时生成不准确的类 JSON 结构。
另外关于
提示词工程指南
可以点击进去学习。这两篇主要记录了如何使用SpringAI结构化提示词与AI交互的,后面将继续学习SpringAI是如何结构化输出的。
所有案例的源码,都会提交在GitHub上。包:
com.spring.ai.example.prompt.two