欢迎来到《Spring AI 零基础到实战》的第 4 节!

在上一节中,我们通过 System 参数成功给大模型赋予了各种有趣的灵魂与人设。但在真实的 Java 企业级开发中,用户的输入是千变万化的,我们总不能每次都用 String+ 号去死磕长篇大论的提示词吧?

在传统的开发中:

  • 字符串拼接:代码又臭又长,极易漏掉空格或标点。
  • String.format():满屏的 %s,变量一旦变多,传参简直是灾难。
  • 强耦合:几百字的业务提示词和 Java 逻辑混写在一起,前端改个文案都需要后端重新发版!

为了解决这个史诗级痛点,Spring AI 引入了杀手锏——PromptTemplate (提示词模板)**。它的核心思想和我们熟悉的 Freemarker、MyBatis 动态 SQL 一模一样:**将“静态文本”与“动态变量”彻底解耦!

今天,我们就来彻底打通大模型输入端的任督二脉,甚至教你如何让 AI “长出眼睛”来看懂图片!

本节章节目标

  1. 底层解构:深入理解 PromptMessage 的核心架构,看透 Spring AI 的参数封装哲学。
  2. 模板魔法:掌握 PromptTemplate,使用 Java Map 优雅地进行占位符替换。
  3. 资源解耦:将超长提示词外置为 .st 文件,实现业务代码与 AI 文案的彻底分离。
  4. 多模态识图:打破纯文本边界,使用 Media 接口实现上传图片并让 AI 进行视觉分析。

核心原理:Prompt 渲染引擎

在动手敲代码前,我们可以通过下方的图直观地感受一下:一段包含占位符的文本,是如何与 Java 的 Map 变量结合,最终变成大模型能听懂的终极指令的?


Prompt 到底是个啥?

在前面两节中,我们一直用 ChatClient.user("...") 进行无脑调用。扒开 Spring AI 的源码,我们会发现大模型通信的最基本单元是一个叫做 Prompt 的对象。

//见:org.springframework.ai.chat.client.DefaultChatClientUtilsstatic 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(提问)等。
  2. ChatOptions:模型请求参数。比如 TemperatureMaxTokens

注:PromptTemplate 的作用,就是帮我们优雅地动态生成这个 Prompt 中的 Message 对象。


PromptTemplate 实战演练

让我们来看看在 Spring AI 中,如何优雅地进行变量绑定。

场景一:直接对话

在日常开发中,我们通常直接利用 ChatClient 提供的 Fluent API 来无缝集成模板渲染。默认情况下,占位符使用 {变量名}。如下我们通过两种方式来进行展示:

/** * 使用常规方法指定 * @param subject * @param message * @return */@GetMapping("/api/teacher")public String teacher(@RequestParam String subject, @RequestParam String message) {     // 1. 定义包含 {占位符} 的纯文本模板    String systemTemplate = "现在你是一名{subject}老师。";    returnthis.chatClient.prompt()            // 2. 注入 System 模板,并通过 .param() 绑定 Map 变量            .system(sp -> sp.text(systemTemplate)                    .param("subject", subject))            // 3. User 消息同理也可以用模板            .user(message)            .call()            .content();}/** * 使用Prompt直接定义 * @param subject * @param message * @return */@GetMapping("/api/teacher2")public String teacher2(@RequestParam String subject, @RequestParam String message) {    // 1、构建用户信息    UserMessage userMessage = UserMessage.builder().text(message).build();    // 2、使用模版创建系统信息    String systemTemplate = "现在你是一名{subject}老师。";    SystemPromptTemplate systemPromptTemplate = SystemPromptTemplate.builder()            .template(systemTemplate)            .variables(Map.of("subject", subject))            .build();    Message systemMessage = systemPromptTemplate.createMessage();    // 3、构建messageList    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 的解析器就会彻底懵圈。 别慌,我们可以自定义分隔符!

/** * 自定义占位符 * @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) 资源文件。

1. 在 src/main/resources/prompts/ 目录下新建 expert.st

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

2. 在 Java 中通过 @Value 优雅注入并使用:

@Value("classpath:prompts/expert.st")    private Resource expertPromptResource;    @GetMapping("/api/expert")    public String useResourceTemplate() {        returnthis.chatClient.prompt()                // 直接传入 Resource 对象!                .system(sp -> sp.text(expertPromptResource)                        .param("role", "Java 性能调优专家")                        .param("task", "分析长 GC 暂停的原因")                        .param("format", "Markdown 列表"))                .user("我的系统经常出现 5 秒以上的 STW,请问怎么排查?")                .call()                .content();    }

至此,你的 Java 代码中再也没有冗长的脏文本,架构彻底清爽!


多模态识图 (Vision) 实战

大模型不仅能处理文本,现代大模型(如 GPT-4o, 通义千问-VL)早就具备了**多模态(Multi-modal)**能力。在 Spring AI 中,让 AI 识别图片简直易如反掌。

核心在于 Media 对象。我们可以将图片与 UserMessage 组合在一起,发送给大模型。

假设你在 src/main/resources/ 下有一张图片叫 tupian.jpg

/**     * 图片识别:使用的是gpt-4o,也可以使用本地的ollama 部署的qwen3.5     * @return     */    @GetMapping("/api/image-vision")    public String testImageVision() {        // 1. 从 classpath 读取本地图片资源        Resource imageResource = new ClassPathResource("tupian.jpg");        // 2. 构建多模态 UserMessage        UserMessage userMessage = UserMessage.builder()                .text("查看这张图的内容")                .media(Media.builder()                        .mimeType(MimeTypeUtils.IMAGE_JPEG) // 指定媒体类型                        .data(imageResource)               // 塞入图片数据                        .build())                .build();        // 3. 封装进 Prompt 并发送给大模型        Prompt prompt = new Prompt(userMessage);        return chatClient                .prompt(prompt)                .call()                .content();    }

注意:请确保你配置的底层大模型支持视觉能力,如 gpt-4oqwen-vl或 本地ollama部署的开源模型

有了这个能力,你可以轻松开发出“发票识别报销系统”、“花草识别小程序”等炫酷应用!


写好 System Prompt 的 CRISPE 原则

Prompt 模板再好用,里面填的内容如果是垃圾,AI 产出的也是垃圾(Garbage In, Garbage Out)。在企业级开发中,请务必遵循以下 CRISPE 原则(或核心 4 要素) 来编写你的 .st 模板:

  1. Role (角色设定):你是谁?(例如:你是一个严谨的法务顾问。
  2. Task (任务目标):你要做什么?(例如:审查以下合同文本中的霸王条款。
  3. Constraints (约束条件)防幻觉的核心!例如:如果遇到不确定的法律条款,必须回答“建议咨询专业律师”,严禁自行捏造法条。
  4. Format (输出格式):期望结果长什么样?(例如:请输出 JSON 格式,包含 {条款内容, 风险等级}。

总结

本节课,我们彻底告别了丑陋的字符串拼接。通过学习 Spring AI 的 PromptTemplate.st 资源文件机制,我们实现了提示词文案与业务逻辑的完美解耦。同时,我们还突破了文本的界限,利用 Media 接口赋予了 AI“看图说话”的视觉能力。

这一切,都为我们后续构建企业级复杂的 RAG(检索增强生成)知识库打下了极其坚实的基础。

但是,问题又来了

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


下节预告

千万不要用正则去解析 AI 的回答!

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

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

这里给大家精心整理了一份全面的AI大模型学习资源包括:AI大模型全套学习路线图(从入门到实战)、精品AI大模型学习书籍手册、视频教程、实战学习、面试题等,资料免费分享

👇👇扫码免费领取全部内容👇👇
在这里插入图片描述

1. 成长路线图&学习规划

要学习一门新的技术,作为新手一定要先学习成长路线图方向不对,努力白费

这里,我们为新手和想要进一步提升的专业人士准备了一份详细的学习成长路线图和规划。可以说是最科学最系统的学习成长路线。
在这里插入图片描述

2. 大模型经典PDF书籍

书籍和学习文档资料是学习大模型过程中必不可少的,我们精选了一系列深入探讨大模型技术的书籍和学习文档,它们由领域内的顶尖专家撰写,内容全面、深入、详尽,为你学习大模型提供坚实的理论基础(书籍含电子版PDF)

在这里插入图片描述

3. 大模型视频教程

对于很多自学或者没有基础的同学来说,书籍这些纯文字类的学习教材会觉得比较晦涩难以理解,因此,我们提供了丰富的大模型视频教程,以动态、形象的方式展示技术概念,帮助你更快、更轻松地掌握核心知识

在这里插入图片描述

4. 2026行业报告

行业分析主要包括对不同行业的现状、趋势、问题、机会等进行系统地调研和评估,以了解哪些行业更适合引入大模型的技术和应用,以及在哪些方面可以发挥大模型的优势。

5. 大模型项目实战

学以致用 ,当你的理论知识积累到一定程度,就需要通过项目实战,在实际操作中检验和巩固你所学到的知识,同时为你找工作和职业发展打下坚实的基础。

在这里插入图片描述

6. 大模型面试题

面试不仅是技术的较量,更需要充分的准备。

在你已经掌握了大模型技术之后,就需要开始准备面试,我们将提供精心整理的大模型面试题库,涵盖当前面试中可能遇到的各种技术问题,让你在面试中游刃有余。

在这里插入图片描述

7. 资料领取:全套内容免费抱走,学 AI 不用再找第二份

不管你是 0 基础想入门 AI 大模型,还是有基础想冲刺大厂、了解行业趋势,这份资料都能满足你!
现在只需按照提示操作,就能免费领取:

👇👇扫码免费领取全部内容👇👇
在这里插入图片描述

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐