ARTICLE · 1055242
[AI工程] Spring AI第四篇:提示词使用与设置技巧(2.0)
💡 很多人把大模型效果不好归因于“模型不够强”,但实际项目里,更常见的问题是:任务描述模糊、上下文缺失、输出格式不可控。
同一个模型,提示词从“帮我写篇文章”改成“面向什么读者、写多长、按什么结构、禁止输出什么”,结果往往会有明显差异。
Spring AI 2.0 把提示词、消息角色、模板渲染和 ChatClient 做成了统一的工程能力。这篇文章从基础 Message、PromptTemplate 到可复用 Prompt 文件,讲清楚提示词该怎么写。

1. Prompt 不只是一个字符串
在 Spring AI 中,一次模型调用由多个 Message 组成。不同消息角色承担不同责任:
SystemMessage | ||
UserMessage | ||
AssistantMessage | ||
ToolResponseMessage |
可以简单理解成:
SystemMessage --> 规定 AI 应该怎样做UserMessage --> 告诉 AI 这次要做什么ToolResponse --> 给 AI 提供外部事实Assistant --> 保留此前的对话结果
系统提示词不是万能指令。它的职责是定义长期稳定的规则;当前任务、用户材料和动态参数,应该放在用户消息或工具结果中。
String content = chatClient.prompt().system("""你是程序员GC的技术助手。回答使用中文,结论优先。不确定的信息必须明确说明。""").user("解释 Spring AI 中 Advisor 的作用。").call().content();
2. PromptTemplate:把动态内容从字符串拼接中解放出来
提示词通常不能写死。例如生成影评、产品介绍、知识库问答时,角色、风格、主题和上下文都需要动态传入。
Spring AI 2.0 默认使用 StTemplateRenderer,基于 StringTemplate。默认变量分隔符是 {}。
String systemText = """你是一个友好的 AI 助手。你的名字是 {name}。请使用 {voice} 的风格回答用户问题。""";PromptTemplate template = PromptTemplate.builder().template(systemText).build();String systemPrompt = template.render(Map.of("name", "程序员GC","voice", "专业但易懂"));Prompt prompt = new Prompt(List.of(new SystemMessage(systemPrompt),new UserMessage("请解释什么是 RAG")));ChatResponse response = chatModel.call(prompt);System.out.println(response.getResult().getOutput().getText());
如果使用 ChatClient,代码会更自然:
String answer = ChatClient.create(chatModel).prompt().user(user -> user.text("列出 5 部由 {director} 执导的代表电影。").param("director", "周星驰")).call().content();
模板变量解决“动态内容”;System Prompt 解决“长期规则”;User Prompt 解决“当前任务”。
官方说明:Spring AI Prompt 文档。
3. JSON 与模板冲突时:自定义分隔符
默认 {} 很方便,但当 Prompt 中包含 JSON Schema、JSON 示例或代码片段时,容易和变量占位符混淆。
这时可以改用 <变量名>:
PromptTemplate template = PromptTemplate.builder().renderer(StTemplateRenderer.builder().startDelimiterToken('<').endDelimiterToken('>').build()).template("""请介绍 5 部 <director> 的代表电影。输出 JSON:{"movies": [{"name": "", "year": 0}]}""").build();String prompt = template.render(Map.of("director", "周星驰"));System.out.println(prompt);
ChatClient 也可以在单次请求中指定渲染器:
String answer = ChatClient.create(chatModel).prompt().user(user -> user.text("列出 5 部 <director> 的电影。").param("director", "周星驰")).templateRenderer(StTemplateRenderer.builder().startDelimiterToken('<').endDelimiterToken('>').build()).call().content();
如果 Prompt 完全没有变量,或内容本身包含大量 {},也可以考虑 NoOpTemplateRenderer,避免无意义的模板解析。
4. Prompt 文件化:别把长提示词塞进 Java 代码
系统提示词一旦超过几十行,继续放在 Java 字符串里会越来越难维护。更实用的方式是将它们放到资源目录。
目录结构:
src/main/resources/prompts/tech-blog-system.st
tech-blog-system.st:
你是程序员GC的技术博客助手。任务:- 用中文回答;- 优先给出结论;- 使用 Markdown;- 涉及不确定事实时明确标注;- 避免营销语气。当前文章主题:{topic}目标读者:{audience}
在 ChatClient 中加载:
@SpringBootTestclass PromptFileTest {@Testvoid testPrompt(@Autowired DeepSeekChatModel chatModel,@Value("classpath:/prompts/tech-blog-system.st")Resource systemResource) {ChatClient chatClient = ChatClient.builder(chatModel).defaultSystem(systemResource).build();String content = chatClient.prompt().system(system -> system.param("topic", "Spring AI Advisor").param("audience", "Java 后端开发者")).user("请写一个 300 字左右的入门介绍。").call().content();System.out.println(content);}}
这样做有三个好处:
Prompt 可以独立 Review、测试和版本管理; 产品、运营与开发可以协作修改; 避免系统提示词散落在 Controller、Service 和测试类中。
5. 提示词设计:从“让模型猜”变成“给模型明确任务”
5.1 指令要明确
❌ 模糊写法:
写一篇文章。✅ 清晰写法:
写一篇约 800 字的中文技术文章。主题:Spring AI 中的 ChatClient。读者:有 Spring Boot 基础的 Java 开发者。结构:引言、三个核心能力、一个代码示例、总结。风格:专业直接,避免营销用语。输出:Markdown。
提示词可以套用这个公式:
角色设定+ 具体任务+ 必要上下文+ 输出格式+ 限制条件+ 示例参考
例如旅游助手:
# 角色你是一位专业、耐心的旅行规划师。# 任务根据用户预算、天数、出发城市和偏好设计旅行路线。# 输出格式1. 每日行程2. 交通建议3. 住宿区域建议4. 预算估算5. 注意事项# 限制- 只讨论旅行相关内容;- 不提供违法或高风险活动建议;- 信息不确定时明确提示用户核实。
5.2 用结构降低歧义
Markdown 标题、列表、表格和 XML 标签都可以帮助模型理解任务层次。
<背景>用户是 Java 后端开发者,刚接触 Spring AI。</背景><任务>解释 ChatClient 与 ChatModel 的区别。</任务><输出要求>- 使用表格;- 给出一个最小代码示例;- 控制在 500 字以内。</输出要求>
比起“你懂我的意思吧”“写详细一点”“差不多就行”,这种表达更可测试、更稳定。
5.3 常见任务的 Prompt 方向
6. 高级技巧:Few-shot、ReAct 与工程边界
提示词不是越长越好,而是要让模型得到完成任务所需的最小充分信息。
Few-shot:给模型一个正确示例
将用户问题分类为:订单、退款、物流、其他。示例:输入:我的快递什么时候到?输出:物流输入:我想取消订单。输出:订单现在开始分类:输入:退款多久到账?输出:
Few-shot 特别适合分类、格式转换、固定文风和结构化输出。
CoT 与 ReAct:不要把“思考过程”当成用户内容
CoT 更适合拆解复杂问题;ReAct 是“推理 + 工具调用”的模式。
用户问题--> 分析需要什么信息--> 调用工具查询--> 根据工具结果回答
在工程实践中,更重要的是让模型调用受控工具、返回可验证结果,而不是要求它输出冗长的思维过程。涉及订单、支付、数据库等业务时,工具权限、参数校验、审计与幂等性必须由应用负责。
Prompt 可以影响模型行为,但不能替代权限控制、数据校验和业务规则。
最后总结
提示词工程不是“写几句更有魔力的话”,而是把模型任务描述成可执行、可验证、可维护的规则。
如果只是简单问答: 明确任务、上下文和输出格式。
如果是企业级应用: 将 System Prompt 文件化、模板化,并通过 ChatClient 统一管理。
如果涉及工具、RAG 与 Agent: 用户输入、检索内容和工具结果都应视为不可信数据;权限与关键决策必须留在应用侧。
对于 Java 开发者,Spring AI 2.0 的价值在于:把 PromptTemplate、Message、ChatClient、Advisor 和 Tool Calling 组织成一套工程化能力,而不是散落的字符串拼接。
参考资料 & 致谢
[1] Spring AI Prompt 官方文档 [2] Spring AI ChatClient 文档 [3] Spring AI Prompt Engineering Patterns [4] Spring AI 官方项目 [5] 提示词使用与设置技巧参考资料(语雀)