news 2026/4/20 20:15:36

Java开发者AI转型第四课!告别硬编码!Spring AI 提示词模板 (Prompt) 注入与多模态识图全攻略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java开发者AI转型第四课!告别硬编码!Spring AI 提示词模板 (Prompt) 注入与多模态识图全攻略

前言

大家好,我是直奔標杆!欢迎来到《Spring AI 零基础到实战》专栏的第四节,感谢各位小伙伴的持续关注与支持!

在上一节《Java开发者AI转型第三课!给大模型立“人设”!Spring AI 三大核心角色揭秘与高阶调参指南》中,我们通过System参数,成功给大模型赋予了各种贴合业务的灵魂与人设,相信大家已经感受到了Spring AI的便捷。但在真实的Java企业级开发中,用户的输入千变万化,我们总不能每次都用String的+号,去死磕长篇大论的提示词吧?

相信做过相关开发的小伙伴都有共鸣,传统开发中处理提示词,总有三大痛点:

  • 字符串拼接:代码又臭又长,可读性差,还极易漏掉空格或标点,排查起来费时费力;

  • String.format():满屏的%s,一旦变量变多,传参顺序极易出错,维护成本直接翻倍;

  • 强耦合:几百字的业务提示词和Java业务逻辑混写在一起,前端改个文案、调整个话术,都需要后端重新打包发版,效率极低!

为了解决这个困扰无数Java开发者的史诗级痛点,Spring AI特意引入了杀手锏——PromptTemplate (提示词模板)。它的核心思想,和我们平时常用的Freemarker、MyBatis动态SQL一模一样,就是要实现“静态文本”与“动态变量”的彻底解耦,让代码更简洁、维护更高效!

今天,咱们就一起彻底打通大模型输入端的任督二脉,不仅学会优雅处理提示词,还会教大家如何让AI“长出眼睛”,轻松看懂图片,解锁多模态交互新能力!

本节学习目标(建议收藏)

  • 底层解构:深入理解Prompt与Message的核心架构,看透Spring AI的参数封装哲学,知其然更知其所以然;

  • 模板魔法:熟练掌握PromptTemplate的使用,通过Java Map优雅完成占位符替换,告别硬编码;

  • 资源解耦:将超长提示词外置为.st文件,实现业务代码与AI文案的彻底分离,提升开发与维护效率;

  • 多模态识图:打破纯文本交互边界,使用Media接口实现图片上传,让AI完成视觉分析,解锁更多应用场景。

一、核心原理:Prompt渲染引擎

在动手敲代码之前,咱们先通过一个直观的逻辑,感受一下PromptTemplate的工作流程:一段包含占位符的静态文本模板,如何与Java的Map变量结合,最终生成大模型能听懂的终极指令?

其实原理很简单,就像我们平时用模板生成报表、邮件一样,把固定不变的文本抽成模板,动态变化的内容用占位符替代,最后通过变量注入,生成最终的内容——这就是Spring AI提示词渲染的核心逻辑。

Prompt到底是个啥?(源码视角解读)

在前面两节内容中,我们一直用ChatClient.user("...")进行无脑调用,快速实现与大模型的交互。今天咱们扒开Spring AI的源码,看看背后的核心逻辑:大模型通信的最基本单元,是一个叫做Prompt的对象。

// 源码路径:org.springframework.ai.chat.client.DefaultChatClientUtils static ChatClientRequest toChatClientRequest(DefaultChatClient.DefaultChatClientRequestSpec inputRequest) { // ..... return ChatClientRequest.builder().prompt(Prompt.builder().messages(processedMessages).chatOptions(processedChatOptions).build()).context(new ConcurrentHashMap(inputRequest.getAdvisorParams())).build(); }

简单来说,Prompt就像是一个“指令包裹”,里面装了两样最核心的东西,缺一不可:

  1. List<Message>:消息列表,包含我们上一节讲过的SystemMessage(大模型人设)、UserMessage(用户提问)、AssistantMessage(大模型回复)等;

  2. ChatOptions:模型请求参数,比如控制生成随机性的Temperature、控制回复长度的MaxTokens等。

这里给大家划个重点(新手必看):PromptTemplate的作用,就是帮我们优雅、高效地动态生成这个Prompt中的Message对象,避免手动拼接带来的各种问题。

二、PromptTemplate实战演练(附完整代码,可直接复制使用)

理论讲再多,不如动手敲一遍。下面咱们结合3个实际开发场景,手把手教大家使用PromptTemplate,所有代码均经过实测,小伙伴们可以直接复制到项目中调试。

场景一:基础模板注入(两种常用写法)

在日常开发中,我们通常直接利用ChatClient提供的Fluent API,无缝集成模板渲染。默认情况下,PromptTemplate的占位符使用{变量名},下面给大家展示两种常用写法,按需选择即可。

/** * 写法1:常规方法,指定模板并通过param绑定变量(推荐日常开发使用) * @param subject 学科(动态变量) * @param message 用户提问 * @return AI生成的回复 */ @GetMapping("/api/teacher") public String teacher(@RequestParam String subject, @RequestParam String message) { // 1. 定义包含{占位符}的纯文本模板(静态文本) String systemTemplate = "现在你是一名{subject}老师。"; return this.chatClient.prompt() // 2. 注入System模板,并通过.param()绑定Map变量 .system(sp -> sp.text(systemTemplate) .param("subject", subject)) // 3. User消息同理,也可以使用模板(此处直接传入用户输入,简化演示) .user(message) .call() .content(); }
/** * 写法2:直接构建Prompt对象,更灵活(适合复杂场景) * @param subject 学科(动态变量) * @param message 用户提问 * @return AI生成的回复 */ @GetMapping("/api/teacher2") public String teacher2(@RequestParam String subject, @RequestParam String message) { // 1、构建用户消息(UserMessage) UserMessage userMessage = UserMessage.builder().text(message).build(); // 2、使用模板创建系统消息(SystemMessage) String systemTemplate = "现在你是一名{subject}老师。"; SystemPromptTemplate systemPromptTemplate = SystemPromptTemplate.builder() .template(systemTemplate) .variables(Map.of("subject", subject)) // 绑定变量 .build(); Message systemMessage = systemPromptTemplate.createMessage(); // 3、构建消息列表,封装成Prompt对象 Prompt prompt = Prompt.builder() .messages(Arrays.asList(userMessage, systemMessage)) .build(); // 调用大模型并返回结果 return chatClient .prompt(prompt) .call() .content(); }

🔧 测试请求(直接复制到浏览器即可调用):

http://localhost:8080/api/teacher?subject=数学&message=你是谁

http://localhost:8080/api/teacher2?subject=数学&message=你是谁

✅ 预期AI回复(供参考):

我是你的数学老师,专门帮你解决数学问题、讲解概念、辅导作业,或者一起探讨有趣的数学话题。如果你有题目不会做、公式不理解,或者想挑战一些数学难题,随时告诉我,我们一起搞定! 😊

场景二:自定义占位符符号 <>(避坑必备)

小伙伴们注意了,实际开发中,我们的提示词里可能本身就包含大量的{}(比如要求AI输出JSON格式、代码块等),这时候如果占位符还是{},Spring AI的解析器就会混淆,导致模板渲染失败。

别慌!Spring AI支持自定义占位符分隔符,下面以<变量名>为例,给大家演示如何自定义:

/** * 自定义占位符(解决占位符与提示词中{}冲突的问题) * @param subject 学科 * @return 渲染后的消息文本 */ @GetMapping("/api/placeholder") public String writePoem(@RequestParam String subject) { PromptTemplate promptTemplate = PromptTemplate.builder() // 自定义占位符:起始符<,结束符> .renderer(StTemplateRenderer.builder().startDelimiterToken('<').endDelimiterToken('>').build()) .template(""" 你是一个<subject>老师 """) .build(); // 绑定变量并生成消息 Message message = promptTemplate.createMessage(Map.of("subject", "美术")); return message.getText(); }

场景三:将提示词外置为.st文件(企业级开发推荐)

当提示词达到几百字甚至上千字时(比如构建RAG知识库、复杂Agent场景),把提示词硬编码在Java代码里,会导致代码臃肿、可读性差,还不利于维护。

Spring AI原生支持读取.st(StringTemplate)资源文件,我们可以将超长提示词外置,实现业务代码与AI文案的彻底分离,下面一步步教大家操作:

1. 新建.st文件:在src/main/resources目录下,新建prompts文件夹,然后在该文件夹下新建expert.st文件,写入以下内容(可根据自己的业务修改):

你是一个专业的 {role}。 你的核心任务是:{task}。 绝对遵守以下约束: 1. 不要捏造事实。 2. 必须以 {format} 的格式输出。

2. Java代码中通过@Value注入并使用(优雅又简洁):

// 注入.st文件资源 @Value("classpath:prompts/expert.st") private Resource expertPromptResource; /** * 读取外置.st文件,实现提示词与代码解耦 * @return AI生成的分析结果 */ @GetMapping("/api/expert") public String useResourceTemplate() { return this.chatClient.prompt() // 直接传入Resource对象,自动解析.st模板 .system(sp -> sp.text(expertPromptResource) .param("role", "Java 性能调优专家") .param("task", "分析长 GC 暂停的原因") .param("format", "Markdown 列表")) .user("我的系统经常出现 5 秒以上的 STW,请问怎么排查?") .call() .content(); }

💡 小贴士:这样一来,后续需要修改提示词文案,只需要修改.st文件,无需改动Java代码,也不用重新发版,架构瞬间清爽,维护效率直接拉满!

三、多模态识图 (Vision) 实战(解锁AI视觉能力)

现在的大模型早已不局限于处理文本,像GPT-4o、通义千问-VL、本地Ollama部署的Qwen3.5等,都具备多模态(Multi-modal)能力,能够识别图片、音频等。

在Spring AI中,让AI识别图片简直易如反掌,核心就在于Media对象——我们只需要将图片与UserMessage组合在一起,发送给大模型,就能实现图片识别。

下面结合实际案例,教大家实现本地图片识别(附完整代码):

前提:在src/main/resources/目录下,放入一张名为tupian.jpg的图片(可替换为自己的图片,注意修改文件名)。

/** * 多模态识图实战:使用GPT-4o(也可使用本地Ollama部署的Qwen3.5) * @return AI对图片的分析结果 */ @GetMapping("/api/image-vision") public String testImageVision() { // 1. 从classpath读取本地图片资源 Resource imageResource = new ClassPathResource("tupian.jpg"); // 2. 构建多模态UserMessage(文本+图片) UserMessage userMessage = UserMessage.builder() .text("查看这张图的内容,详细描述图片中的元素") // 提示词,引导AI分析图片 .media(Media.builder() .mimeType(MimeTypeUtils.IMAGE_JPEG) // 指定媒体类型(JPG格式) .data(imageResource) // 塞入图片数据 .build()) .build(); // 3. 封装进Prompt,发送给大模型 Prompt prompt = new Prompt(userMessage); // 调用大模型,返回图片分析结果 return chatClient .prompt(prompt) .call() .content(); }

⚠️ 重要注意事项:请确保你配置的底层大模型支持视觉能力,比如GPT-4o、通义千问-VL,或者本地Ollama部署的开源多模态模型(如Qwen3.5-VL),否则会识别失败。

拓展思考:有了这个能力,我们可以轻松开发出很多实用应用,比如“发票识别报销系统”“花草识别小程序”“图片内容审核工具”等,大大拓展Java应用的边界!

四、必备技巧:写好System Prompt的CRISPE原则

很多小伙伴会陷入一个误区:觉得PromptTemplate好用,就忽略了提示词本身的质量。要知道,Prompt模板再好用,里面填的内容如果是“垃圾”,AI产出的也会是“垃圾”(这就是行业内常说的Garbage In, Garbage Out)。

在企业级开发中,建议大家遵循CRISPE原则(核心4要素),来编写你的.st模板或提示词,确保AI输出符合预期、准确可靠:

  • Role (角色设定):明确AI的身份,比如“你是一个严谨的法务顾问”“你是一个资深的Java架构师”,让AI知道自己该以什么身份回应;

  • Task (任务目标):明确AI要完成的任务,比如“审查以下合同文本中的霸王条款”“分析这段Java代码的性能瓶颈”,避免AI偏离方向;

  • Constraints (约束条件):这是防AI幻觉的核心!比如“如果遇到不确定的内容,必须回答‘无法确定,请补充信息’,严禁自行捏造”“只能使用提供的知识库内容进行回复”;

  • Format (输出格式):明确AI的输出样式,比如“请输出JSON格式,包含{条款内容, 风险等级, 修改建议}”“请以Markdown列表形式输出,分点清晰”。

五、本节总结(重点回顾)

本节课,我们彻底告别了丑陋又繁琐的字符串拼接,核心收获有3点,大家可以对照自查,看看是否掌握:

  1. 掌握PromptTemplate的使用,通过Java Map优雅完成占位符替换,解决硬编码痛点;

  2. 学会将超长提示词外置为.st文件,实现业务代码与AI文案的彻底解耦,提升开发与维护效率;

  3. 解锁多模态识图能力,通过Media接口实现图片上传与AI视觉分析,拓展Java应用场景。

这些知识点,都为我们后续构建企业级复杂的RAG(检索增强生成)知识库,打下了极其坚实的基础,大家一定要多动手调试,加深理解。

但是,新的问题又来了:

在当前的演示中,AI无论多聪明,返回给我们的始终是一大长串String字符串。而在前后端分离的现代化开发中,前端需要的是规规矩矩的JSON对象(比如{"name": "张三", "age": 18}),难道我们要用正则表达式,去从AI的回答里苦哈哈地抠取数据吗?

答案当然是:不!千万不要用正则去解析AI的回答,既麻烦又容易出错!

下节预告(值得期待)

在第5节《Java开发者AI转型第五课!让AI懂规矩!Spring AI 结构化输出 (DTO) 映射与 Flux 流式打字机极速响应》中,你将见证Spring AI最惊艳的功能之一!

我们将一起学习:如何让AI直接返回一个完美的Java DTO / List对象,彻底打通AI与传统业务系统(如存入数据库)的最后一公里;以及如何通过Flux流式输出,缓解用户等待焦虑,提升交互体验。

精彩继续,咱们下节见!

专栏往期内容(循序渐进,建议按顺序学习)

  • Java开发者AI转型第一课!Spring AI+MCP实战,手把手打造企业级RAG知识库

  • Java开发者AI转型第二课!5行代码速通GPT5.4!Spring AI环境搭建+ChatClient入门指南

  • Java开发者AI转型第三课!Spring AI三大核心角色揭秘+大模型人设打造与高阶调参指南

💬 互动交流:大家在使用PromptTemplate或多模态识图时,遇到了哪些问题?欢迎在评论区留言讨论,一起学习、一起进步!我会及时回复每一条留言~

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/20 20:12:44

终极指南:如何5分钟掌握CAN数据库转换工具canmatrix

终极指南&#xff1a;如何5分钟掌握CAN数据库转换工具canmatrix 【免费下载链接】canmatrix Converting Can (Controller Area Network) Database Formats .arxml .dbc .dbf .kcd ... 项目地址: https://gitcode.com/gh_mirrors/ca/canmatrix canmatrix是一个功能强大的…

作者头像 李华
网站建设 2026/4/20 20:10:00

嵌入式开发必备:DTS、DTSO、DTBO文件实战指南(附完整编译命令)

嵌入式开发必备&#xff1a;DTS、DTSO、DTBO文件实战指南&#xff08;附完整编译命令&#xff09; 在嵌入式Linux开发中&#xff0c;设备树&#xff08;Device Tree&#xff09;已经成为描述硬件配置的标准方式。对于驱动开发工程师和嵌入式系统开发者来说&#xff0c;熟练掌握…

作者头像 李华
网站建设 2026/4/20 20:05:27

SQL注入攻击与防御实战:手把手教你挖漏洞

三、防御方案。1.参数化查询&#xff1a;用Prepared Statements&#xff0c;用户输入当数据处理。PHP用PDO&#xff0c;Java用PreparedStatement。2.输入验证&#xff1a;白名单过滤危险字符单引号、分号等。3.使用ORM框架&#xff1a;Laravel、Hibernate等内置防注入。4.最小权…

作者头像 李华
网站建设 2026/4/20 20:03:12

百度网盘秒传链接网页工具:3步搞定全平台文件极速分享

百度网盘秒传链接网页工具&#xff1a;3步搞定全平台文件极速分享 【免费下载链接】baidupan-rapidupload 百度网盘秒传链接转存/生成/转换 网页工具 (全平台可用) 项目地址: https://gitcode.com/gh_mirrors/bai/baidupan-rapidupload 还在为百度网盘大文件上传下载的漫…

作者头像 李华