Spring AI 入门:(4)提示词、提示词模板、提示词工程与模型参数
目录
本章导读:你向AI提问的方式,直接决定了它回答的质量。就像与人沟通一样,把需求表达得越清楚,对方理解得就越准确。在Spring AI中,提示词的设计和构造有着一套完整的体系——从基础的四种消息角色,到动态的提示模板,再到工程化的最佳实践。本章将带你系统掌握这些知识,让你从“随意提问”进阶到“专业引导”。
4.1 提示词的本质
4.1.1 什么是Prompt
Prompt(提示词)是我们与AI沟通的唯一方式。你可以把它理解为给AI下达的指令或提出的问题——就像和人沟通一样,你说得越清楚,对方理解得就越准确,Prompt写得好不好,直接决定了AI输出的质量。
一个有效的Prompt并非简单的提问,而是指令与上下文的巧妙融合。它告诉模型你期望它做什么(指令),并为其提供完成任务所需的背景信息(上下文)。模型接收到Prompt后,会基于其庞大的知识库和对语言的理解,生成符合你指令和上下文的输出。
从API层面来看,Spring AI中的Prompt并非简单的字符串,而是一个容器。Prompt类充当一系列有组织的Message对象和请求ChatOptions的容器。每条Message在提示中都包含一个独特的角色,其内容和意图不同。这些角色可以包含各种元素,从用户查询到AI生成的对相关背景信息的响应。这种安排支持与AI模型进行复杂而详细的交互。
4.1.2 Prompt的组成要素
一个完整的Prompt在Spring AI中由两个核心部分组成:
- 消息列表(
List<Message>):包含系统消息、用户消息、助手消息等,每条消息都有特定的角色。 - ChatOptions:控制模型行为的参数,如
temperature、maxTokens等。
4.1.3 四种Message角色详解
在Spring AI中,消息被抽象为几个类,每种类型对应对话中的一个特定角色,“同一句话,放在不同消息角色里,效果可能完全不同”——Prompt的本质不是提问,而是精确表达任务。
| 消息类型 | 说明 | 典型用途 |
|---|---|---|
SystemMessage |
系统提示词,设定AI角色和行为 | “你是一个专业的Java技术专家” |
UserMessage |
用户消息,实际的问题或指令 | “什么是Spring AI?” |
AssistantMessage |
AI的回复消息 | 记录对话历史 |
ToolResponseMessage |
工具调用返回的结果 | 天气查询结果 |
SystemMessage(系统消息) 是最重要也最容易被忽视的消息类型。它在对话开始前设定AI的身份、行为准则、输出风格或知识边界,通常用户不可见,但深刻影响AI的所有响应。简而言之,SystemMessage告诉模型“你是谁”和“你应该怎么做”。
UserMessage(用户消息) 承载用户的真实需求——问题、指令或陈述,这是AI生成响应的直接依据。
AssistantMessage(助理消息) 代表AI模型对之前消息的回复,主要用于构造多轮对话历史。
ToolResponseMessage(工具响应消息) 将工具执行的结果反馈给AI,供其生成最终回答。框架的@Tool注解已经封装了这一细节,开发者通常无需直接操作。
理解这些消息类型是构造高质量Prompt的基础。SystemMessage设定角色和边界,UserMessage提出具体任务,两者分工明确,切忌将所有内容混入UserMessage。
4.2 提示工程基础
提示工程(Prompt Engineering)是指通过精心设计提示词来优化AI模型输出效果的一套方法论。以下是三种核心的提示工程技术。
4.2.1 零样本提示(Zero-shot Prompting)
零样本提示是最基础的提示模式:直接向AI模型发出指令,不提供任何示例,让模型依靠其训练时获得的知识来理解和执行任务。第三章中的所有示例都属于零样本提示。
@GetMapping("/chat")
public String chat(@RequestParam(defaultValue = "你好") String msg) {
return chatClient.prompt()
.user(msg)
.call()
.content();
}
4.2.2 少样本提示(Few-shot Prompting)
与零样本相反,少样本提示在发出指令的同时提供一两个示例,让模型参考示例的格式和风格来生成输出。这种方式在需要模型模仿特定输出格式时特别有效。
以下示例展示了如何让AI输出固定格式的回答:
@GetMapping("/classification")
public String classifySentiment(@RequestParam String review) {
return chatClient.prompt()
.system("""
你是一个情感分析助手。将用户评论分类为「好评」「中评」或「差评」。
示例:
输入:"这个产品质量太差了,完全不符合预期"
输出:差评
输入:"物超所值,非常满意!"
输出:好评
输入:"还行吧,没有特别惊艳但也不差"
输出:中评
""")
.user(review)
.call()
.content();
}
4.2.3 思维链提示(Chain-of-Thought)
对于复杂推理问题,思维链提示通过引导模型“一步一步思考”来提升推理准确性。在提示中要求模型展示推理过程,而非直接给出结论。
@GetMapping("/reasoning")
public String solveProblem(@RequestParam String problem) {
return chatClient.prompt()
.system("""
你是一个逻辑推理专家。对于复杂问题,请按以下步骤分析:
1. 拆解问题的关键要素
2. 逐步推理每个要素的逻辑
3. 综合得出结论
请一步一步分析,不要直接给出最终答案。
""")
.user(problem)
.call()
.content();
}
4.2.4 系统提示词的设计原则
一个高质量的SystemMessage通常包含多个关键要素,常见的设计框架是“角色+任务+格式+示例”的四段式结构。
| 要素 | 说明 | 示例 |
|---|---|---|
| 角色 | 告诉模型“你是谁” | “你是一个专业的Java技术助手” |
| 任务 | 你要做什么 | “回答技术问题、帮助debug代码” |
| 约束 | 什么能做、什么不能做 | “不确定的内容要说明,不要编造” |
| 格式 | 用什么格式返回 | “使用Markdown格式,代码用代码块包裹” |
| 示例 | 给一两个示例让模型参考 | Few-shot Prompting |
在代码中,可以通过ChatClient.Builder的defaultSystem()来配置默认的系统消息。这样配置后,这段文本会作为基础角色设定,注入到每次对话的上下文中。
@RestController
public class SystemPromptController {
private final ChatClient chatClient;
public SystemPromptController(ChatClient.Builder builder) {
this.chatClient = builder
.defaultSystem("""
你是一个专业的Java技术助手。
职责:
- 回答Java、Spring Boot相关的技术问题
- 帮助用户理解代码原理
- 提供最佳实践建议
规则:
- 代码示例使用Java 17+语法
- 回答简洁,不要过度解释
- 不确定的内容要说明,不要编造
""")
.build();
}
@GetMapping("/ask")
public String ask(@RequestParam String question) {
return chatClient.prompt()
.user(question)
.call()
.content();
}
}
4.3 使用PromptTemplate动态构造提示
在实际开发中,我们经常需要根据不同的用户输入动态构造提示词。如果不用模板,每个问题都要写一个新的请求,代码会变得重复、难以维护。
PromptTemplate正是为解决这个问题而设计。使用模板,你可以定义一套包含占位符的提示结构,运行时动态替换占位符的值,实现“一套模板,复用多个场景”。
4.3.1 基本语法
PromptTemplate是Spring AI中用于创建带变量模板的Prompt的核心类,使用{}包裹占位符:
// 1. 创建模板,使用{}包裹占位符
PromptTemplate template = new PromptTemplate("你好,我叫{name},今年{age}岁");
// 2. 填充变量,Map的key对应模板中的占位符
Prompt prompt = template.create(Map.of("name", "张三", "age", "25"));
// 3. 调用AI
String result = chatClient.prompt(prompt).call().content();
// 输出:你好,我叫张三,今年25岁
4.3.2 在ChatClient中直接使用模板
ChatClient也支持在链式调用中直接使用模板,语法更加简洁:
@GetMapping("/introduce")
public String introduce(@RequestParam String name, @RequestParam int age) {
return chatClient.prompt()
.user(u -> u.text("你好,我叫{name},今年{age}岁")
.param("name", name)
.param("age", age))
.call()
.content();
}
4.3.3 SystemPromptTemplate:系统消息专用模板
SystemPromptTemplate是专门用于创建系统消息的模板,用法与PromptTemplate几乎一致:
// 创建系统消息模板
SystemPromptTemplate systemTemplate = new SystemPromptTemplate(
"你是一个{profession}专家,擅长{skill}"
);
// 填充变量,生成SystemMessage
Message systemMessage = systemTemplate.createMessage(Map.of(
"profession", "Java",
"skill", "后端开发"
));
// 输出:你是一个Java专家,擅长后端开发
4.3.4 从外部文件加载模板
将模板内容从代码中分离到外部文件,是一种良好的工程实践。模板与代码解耦,便于维护和版本控制。
步骤一:创建模板文件
在src/main/resources/prompts/目录下创建模板文件qa-template.txt:
请基于以下背景信息回答问题。
【背景信息】
{context}
【问题】
{question}
【要求】
- 如果背景信息中包含答案,请基于背景信息回答
- 如果背景信息中不包含答案,请明确告知用户"根据现有信息无法回答"
- 回答要简洁、准确
步骤二:在Java代码中加载
import org.springframework.core.io.ClassPathResource;
import org.springframework.ai.chat.prompt.PromptTemplate;
@GetMapping("/rag-answer")
public String answerWithTemplate(
@RequestParam String context,
@RequestParam String question) throws IOException {
// 从resources/prompts/qa-template.txt加载模板
Resource resource = new ClassPathResource("prompts/qa-template.txt");
String templateContent = resource.getContentAsString(StandardCharsets.UTF_8);
PromptTemplate promptTemplate = new PromptTemplate(templateContent);
Prompt prompt = promptTemplate.create(Map.of(
"context", context,
"question", question
));
return chatClient.prompt(prompt).call().content();
}
这种模板文件化管理方式将提示词与Java代码分离,对于提示词较长、格式复杂或需要频繁调整的场景,强烈推荐使用。
4.4 模型参数详解
在发起请求与大模型交互时,可以配置各类核心参数,以此控制模型的生成行为、回复长度、随机性等关键特性。
ChatOptions是Spring AI中管理这些配置的核心接口,它继承了ModelOptions根接口。ChatOptions除了一个默认实现类DefaultChatOptions外,还有两个子接口:ToolCallingChatOptions(工具调用配置)和StructuredOutputChatOptions(结构化输出配置)。
4.4.1 核心参数说明
| 参数 | 作用 | 取值范围 | 推荐场景 |
|---|---|---|---|
temperature |
控制输出随机性,越低越确定,越高越有创意 | 0~2(不同模型范围略有差异) | 代码生成用0.10.3,创意写作用0.81.0 |
maxTokens |
限制模型输出的最大Token数量 | 取决于模型上下文窗口 | 短问答用500,长内容生成用2000+ |
topP |
核采样,选择概率和质量达到P的token集 | 0~1 | 通常与temperature配合,推荐调整其中一个即可 |
frequencyPenalty |
惩罚重复token,抑制模型重复内容 | -2~2 | 需要多样化输出时可设为0.5~1.0 |
presencePenalty |
惩罚已出现过的主题,鼓励引入新话题 | -2~2 | 需要探索新话题时可设为0.5~1.0 |
temperature(温度)详解:温度参数可能是影响模型输出最直观的配置。低温度(0.1-0.3)使模型倾向于选择高概率的token,输出更确定、更稳定;高温度(0.8-1.0)增加低概率token被选中的机会,输出更多样、更有创意。
maxTokens(最大输出长度):限制模型单次回复的Token数量上限,同时直接影响API调用成本(按Token计费)。
4.4.2 在ChatClient中配置参数
ChatClient提供了链式的参数配置方式:
@GetMapping("/code")
public String generateCode(@RequestParam String requirement) {
return chatClient.prompt()
.user(requirement)
.options(ChatOptions.builder()
.temperature(0.2D) // 低温度保证代码准确
.maxTokens(1000) // 限制输出长度
.topP(0.95D) // 核采样
.build())
.call()
.content();
}
也可以通过ChatOptions.builder快速构建配置,兼容所有厂商:
ChatOptions options = ChatOptions.builder()
.model("qwen-plus") // 指定模型
.temperature(0.1D) // 低随机性,适合精准回答
.maxTokens(1024) // 最大输出1024 Token
.topP(0.9D) // 核采样参数
.stopSequences(List.of("###")) // 停止词
.build();
4.4.3 厂商专属配置
每个大模型厂商都有自己独有的API参数,Spring AI为特定厂商大模型提供了不同的ChatOptions实现类。例如,如果使用通义千问并通过DashScope OpenAI兼容端点接入,标准ChatOptions即可满足大部分需求;如果直接使用其他厂商的专有SDK,可以使用对应的专属配置类。
4.5 综合实战:可配置的智能问答助手
现在,让我们将本章所学内容整合起来,构建一个完整的可配置智能问答助手。这个助手支持:
- 动态系统提示词(用户可指定AI角色)
- 模型参数可调节
- 从外部模板文件加载提示词
- 支持多轮对话参数配置
4.5.1 完整代码实现
@RestController
@RequestMapping("/configurable")
public class ConfigurableChatController {
private final ChatClient chatClient;
public ConfigurableChatController(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
/**
* 核心问答接口
* @param question 用户问题
* @param systemPrompt 可选系统提示词,默认值为"你是一个乐于助人的AI助手"
* @param role AI角色,用于模板替换
* @param temperature 温度参数,控制输出随机性,默认0.7
* @param maxTokens 最大输出Token数,默认500
*/
@GetMapping("/ask")
public String ask(
@RequestParam String question,
@RequestParam(defaultValue = "你是一个乐于助人的AI助手") String systemPrompt,
@RequestParam(defaultValue = "普通助手") String role,
@RequestParam(defaultValue = "0.7") double temperature,
@RequestParam(defaultValue = "500") int maxTokens) {
// 方式1:直接使用传入的系统提示词
// 方式2:也可以从模板文件中加载系统提示词
String finalSystemPrompt = "你是一个" + role + "。" + systemPrompt;
return chatClient.prompt()
.system(finalSystemPrompt)
.user(question)
.options(ChatOptions.builder()
.temperature(temperature)
.maxTokens(maxTokens)
.build())
.call()
.content();
}
/**
* 使用模板文件的问答接口(演示外部模板加载)
*/
@GetMapping("/ask-with-template")
public String askWithTemplate(
@RequestParam String role,
@RequestParam String topic,
@RequestParam String question) throws IOException {
// 从外部文件加载系统消息模板
Resource resource = new ClassPathResource("prompts/system-template.txt");
String systemTemplateStr = resource.getContentAsString(StandardCharsets.UTF_8);
SystemPromptTemplate systemTemplate = new SystemPromptTemplate(systemTemplateStr);
// 创建系统消息
Message systemMessage = systemTemplate.createMessage(Map.of(
"role", role,
"topic", topic
));
// 构建完整的Prompt并调用
return chatClient.prompt()
.messages(systemMessage)
.user(question)
.options(ChatOptions.builder()
.temperature(0.7)
.maxTokens(800)
.build())
.call()
.content();
}
}
其中src/main/resources/prompts/system-template.txt代码如下:
你是一个{role},专注于{topic}领域。
你的回答风格:
- 专业、准确、简洁
- 使用中文回答
- 如果需要代码示例,请使用适当的代码块格式
请基于以上角色和领域知识,回答用户的问题。
4.5.2 测试示例
测试1:零样本问答
GET /configurable/ask?question=什么是Spring AI&role=Java专家&temperature=0.2
输出结果会更确定、更专业,适合技术问答场景。
测试2:带创意的回答
GET /configurable/ask-with-template?question=讲一下Java面向对象&role=Java专家&topic=编程
输出结果按照你的文件的风格展示。
4.6 常见误区与最佳实践
4.6.1 ❌ 误区一:把控制参数写进提示词
很多人写Prompt时喜欢加这些句子:
- “请保持稳定输出”
- “不要超过200字”
- “回答要随机一些”
这些说法不是完全没用,但Spring AI提供了更专业的控制方式——通过ChatOptions配置temperature、maxTokens等参数来控制生成行为。上面的示例已给出正确示范。
4.6.2 ❌ 误区二:提示词和代码不分家
当提示词内容较长时,散落在Java代码字符串中既不便于维护,也难以协作。正确的做法是将提示词模板抽取到外部文件(src/main/resources/prompts/目录下)或数据库中,实现提示词与代码的分离。
4.6.3 ✅ 良好提示词的标准
一个工程化良好的Prompt在代码中应具备以下特征:
┌─────────────────────────────────────────────────────┐
│ SystemMessage: 角色 + 任务 + 约束 + 格式 │
├─────────────────────────────────────────────────────┤
│ UserMessage: 具体问题(支持参数化) │
├─────────────────────────────────────────────────────┤
│ ChatOptions: temperature / maxTokens 等参数配置 │
└─────────────────────────────────────────────────────┘
将这些要素拆开、参数化,而不是揉成一团堆在一个字符串里,这才是工程化的方式。
4.7 本章小结
在本章中,我们系统学习了Spring AI的提示词体系:
- 四种消息类型:
SystemMessage设定AI角色,UserMessage承载用户任务,AssistantMessage记录AI回复,ToolResponseMessage反馈工具执行结果 - 提示工程基础:零样本提示、少样本提示(通过示例让模型模仿)、思维链提示(引导模型一步步思考)
PromptTemplate:使用模板实现提示词参数化和复用,支持从外部文件加载,将提示词与Java代码分离- 模型参数:
temperature控制输出随机性,maxTokens限制输出长度,ChatOptions统一管理 - 综合实战:构建了一个完整的可配置智能问答助手,演示了上述所有技术的整合使用
- 最佳实践:区分系统消息和用户消息、使用
ChatOptions控制参数、提示词与代码分离
提示词质量在很大程度上决定了AI应用的输出质量。从本章开始,你不再是“随意提问”的用户,而是能够“专业引导”AI的开发者。
下一章,我们将学习如何让AI输出结构化的数据——将模型返回的自然语言直接映射为Java对象,让AI的输出真正可以被业务代码直接消费。
参考来源
- Spring AI官方Prompt API文档
- Spring AI ChatClient源码分析
- 阿里云DashScope API参数参考
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)