Spring AI 2.0.0 Prompt 入门教程:system、user、template 和流式输出 Demo
Spring AI 2.0.0 Prompt 入门教程system、user、template 和流式输出 Demo很多 Spring AI Demo 一开始都是这样写的chatClient.prompt().user(你是一个 Java 专家请帮我解释这段代码回答要简洁code).call().content();能跑。但项目一复杂Prompt 很快就会变成一团字符串Stringprompt你是一个 Java 专家。你的任务是解释代码。回答要简洁按步骤输出。如果代码有问题要指出来。不要输出无关内容。代码如下\ncode;角色、任务、变量、输出格式、约束条件全塞进user。短期能跑长期很难改。下一次你想改回答风格得去字符串里找。再下一次你想换输出格式还得继续拼接。Prompt 不是不能写长。真正麻烦的是不同层级的内容混在一起。这篇就解决一个问题Spring AI 2.0.0 里system、user、template到底怎么分工先记住一句话system 放长期规则 user 放本次问题 template 放可复用结构后面所有代码都围绕这句话展开。一、先准备 ChatClient这篇示例按Spring AI 2.0.0写。默认你已经有一个能正常调用模型的 Spring Boot 项目。如果你已经接好了ChatClient可以直接跳到第二部分。如果接着前面的 DeepSeek Demo 做关键版本是propertiesjava.version17/java.versionspring-ai.version2.0.0/spring-ai.version/properties依赖是dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-starter-model-deepseek/artifactId/dependency如果你的项目是手写pom.xml别忘了通过spring-ai-bom管理 Spring AI 版本dependencyManagementdependenciesdependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-bom/artifactIdversion${spring-ai.version}/versiontypepom/typescopeimport/scope/dependency/dependencies/dependencyManagement配置类似这样spring:ai:deepseek:api-key:${DEEPSEEK_API_KEY}chat:model:deepseek-v4-flashtemperature:0.3注意Spring AI 2.0.0 里DeepSeek 的模型和温度配置直接放在spring.ai.deepseek.chat下面。如果你从 1.x 示例迁移过来不要继续写成spring.ai.deepseek.chat.options.model。这个系列里的示例模型都统一用deepseek-v4-flash。如果用 IDEA 运行在 Run/Debug Configurations 里加环境变量DEEPSEEK_API_KEY你的 API Key这篇重点不是模型配置而是 Prompt 怎么组织。二、System放长期规则system适合放稳定规则。它不是随便写一句你是一个 Java 专家。这句话有用但太粗。更好的system通常会把长期规则说清楚你是谁 主要负责什么 什么能做什么不能做 回答风格是什么 信息不足时怎么处理 输出结构是什么我们做业务系统不用写得很夸张。但有一个原则很重要每次都应该生效的规则放到system。比如做一个 Java 代码助手chatClient.prompt().system( 你是一个资深 Java 工程师负责解释和审查 Java/Spring 代码。 请用简洁中文回答先给结论再解释原因。 如果代码存在风险请指出触发条件和建议改法。 如果信息不足请说明还需要补充什么不要编造项目背景。 不要输出与代码无关的泛泛建议。 ).user(这段代码有什么问题\ncode).call().content();这里的system不关心这次传进来的代码是什么。它只规定一件事无论用户问哪段代码都按这套规则回答。如果每次请求都要重复写这一段就应该提到ChatClient默认配置里ConfigurationpublicclassChatClientConfig{BeanpublicChatClientchatClient(ChatClient.Builderbuilder){returnbuilder.defaultSystem( 你是一个资深 Java 工程师负责解释和审查 Java/Spring 代码。 请用简洁中文回答先给结论再解释原因。 如果代码存在风险请指出触发条件和建议改法。 如果信息不足请说明还需要补充什么不要编造项目背景。 不要输出与代码无关的泛泛建议。 ).build();}}这样业务代码里就不用反复写固定规则。记住system管“长期怎么回答”不是管“这次问什么”。也别把system写成产品说明书。它应该稳定但不应该臃肿。和当前场景无关的公司介绍、技术栈罗列、口号都可以删掉。三、User放本次输入user放当前这一次请求。也就是用户这次问了什么 这次要处理什么数据 这次任务有什么特殊要求比如解释代码chatClient.prompt().user(请解释这段代码\n\ncode).call().content();如果下一次要生成单元测试user就换成chatClient.prompt().user(请为这段代码生成 JUnit 5 单元测试\n\ncode).call().content();长期角色和回答风格仍然由defaultSystem管。所以不推荐这样chatClient.prompt().user( 你是一个资深 Java 工程师。 回答要简洁、准确。 输出格式先给结论再解释原因。 请解释这段代码 code).call().content();更推荐这样chatClient.prompt().user(请解释这段代码\n\ncode).call().content();前提是ChatClient已经配置了defaultSystem。这样分工就很清楚system长期规则 user本次问题四、Template放可复用结构如果 Prompt 有固定格式并且要填多个变量就适合用 Template。比如“解释代码”这个任务每次结构都差不多请解释以下 {language} 代码 文件路径{filePath} 代码内容 {code} 重点关注{focus}如果用字符串拼接会变成这样Stringprompt请解释以下 language 代码\n文件路径filePath\n\n代码内容\ncode\n\n重点关注focus;变量一多就很难读。Spring AI 的ChatClient可以直接在user里写模板chatClient.prompt().user(u-u.text( 请解释以下 {language} 代码 文件路径{filePath} 代码内容 {code} 重点关注{focus} ).param(language,language).param(filePath,filePath).param(code,code).param(focus,focus)).call().content();这里的{language}、{filePath}、{code}、{focus}都是模板变量。Spring AI 会在调用前替换成真实值。在 Spring AI 2.0.0 里ChatClient默认使用StTemplateRenderer渲染user和system文本里的变量。默认变量语法就是{变量名}。所以 Template 适合这些场景固定格式 多个变量 多处复用 后续可能调整 Prompt 结构但不要为了模板而模板。如果只有一个变量直接写.user(请解释这段代码\n\ncode)就够了。五、完整例子下面写一个最小接口接收一段代码让模型解释它。packagecom.example.springaideepseekdemo.controller;importorg.springframework.ai.chat.client.ChatClient;importorg.springframework.http.MediaType;importorg.springframework.web.bind.annotation.PostMapping;importorg.springframework.web.bind.annotation.RequestBody;importorg.springframework.web.bind.annotation.RequestParam;importorg.springframework.web.bind.annotation.RestController;importreactor.core.publisher.Flux;RestControllerpublicclassCodeExplainController{privatefinalChatClientchatClient;publicCodeExplainController(ChatClient.Builderbuilder){this.chatClientbuilder.defaultSystem( 你是一个资深 Java 工程师负责解释和审查 Java/Spring 代码。 请用简洁中文回答先给结论再解释原因。 如果代码存在风险请指出触发条件和建议改法。 如果信息不足请说明还需要补充什么不要编造项目背景。 不要输出与代码无关的泛泛建议。 输出格式 1. 代码功能概述 2. 关键逻辑解释 3. 潜在问题或优化建议 ).build();}PostMapping(/code/explain)publicStringexplain(RequestParam(defaultValueJava)Stringlanguage,RequestParam(defaultValueunknown)StringfilePath,RequestParam(defaultValue可读性、性能、潜在 bug)Stringfocus,RequestBodyStringcode){returnchatClient.prompt().user(u-u.text( 请解释以下 {language} 代码。 文件路径{filePath} 代码内容 {code} 重点关注{focus} ).param(language,language).param(filePath,filePath).param(code,code).param(focus,focus)).call().content();}PostMapping(value/code/explain/stream,producesMediaType.TEXT_EVENT_STREAM_VALUE)publicFluxStringexplainStream(RequestParam(defaultValueJava)Stringlanguage,RequestParam(defaultValueunknown)StringfilePath,RequestParam(defaultValue可读性、性能、潜在 bug)Stringfocus,RequestBodyStringcode){returnchatClient.prompt().user(u-u.text( 请解释以下 {language} 代码。 文件路径{filePath} 代码内容 {code} 重点关注{focus} ).param(language,language).param(filePath,filePath).param(code,code).param(focus,focus)).stream().content();}}普通输出这样测curl-XPOSThttp://localhost:8080/code/explain?filePathUserService.java\-HContent-Type: text/plain\--data-binarypublic String getName(User user) { return user.getName(); }流式输出这样测curl-N-XPOSThttp://localhost:8080/code/explain/stream?filePathUserService.java\-HContent-Type: text/plain\--data-binarypublic String getName(User user) { return user.getName(); }-N的作用是关闭 curl 的缓冲方便你看到模型一段一段返回。这里没有在 URL 里直接写中文参数。如果你要在 query string 里传中文需要先做 URL 编码否则新版本 Tomcat 可能直接返回400 Bad Request。正常情况下模型会指出这段代码的核心风险如果 user 为 null调用 user.getName() 会触发 NullPointerException。这个例子里分工很清楚defaultSystem角色、风格、输出格式 user template本次任务结构 param本次变量以后要调整“回答风格”改defaultSystem。要调整“这类任务的结构”改user模板。要处理不同代码只改参数。六、几个常见坑1. 把所有东西都塞进 user这是最常见的问题。user里既有“你是专家”又有“回答要简洁”还有“请分析这段代码”。短期能跑长期一定难维护。先问自己一句这句话是不是每次请求都一样如果是就优先考虑放到system。2. system 写得太长system不是越长越好。很多人会写成你是 Java 专家精通 Spring、MyBatis、Redis、Kafka、微服务、DDD……看起来很专业但很多身份描述并不直接约束输出还会浪费 token。更好的写法是给清晰规则回答要简洁。 先给结论再解释原因。 不确定时说明不确定不要编造。3. 变量名太随意不推荐.user(u-u.text(分析 {a} 和 {b}关注 {c}).param(a,oldCode).param(b,newCode).param(c,focus))更推荐.user(u-u.text(分析 {oldCode} 和 {newCode}关注 {focus}).param(oldCode,oldCode).param(newCode,newCode).param(focus,focus))变量名就是文档。以后回头看代码不用猜a、b、c分别是什么。4. JSON 示例和模板变量冲突Spring AI 默认用{}识别模板变量。如果 Prompt 里要放 JSON 示例就可能被误识别成模板变量。比如请返回 { summary: ..., risk: ... }这时可以给这次调用配置TemplateRenderer把变量分隔符换成变量名这类写法。比如继续用默认的StTemplateRenderer但把分隔符从{}换成和。这个点不用一开始就展开但要知道模板里的{}不是普通字符它有变量含义。5. 忘了约束输出格式你想让模型按固定格式回答就要明确告诉它。比如.system( 你是 Java 代码审查助手。 输出格式只返回 JSON不要输出 Markdown。 字段包括 summary、risks、suggestions。 )不过真正要让模型稳定返回 Java 对象后面还要用结构化输出。这块更适合单独写一篇。写在最后Spring AI 里的 Prompt 管理不用想复杂。先记住三句话system 管长期规则 user 管本次问题 template 管可复用结构Prompt 不是越长越好。真正重要的是分工清楚、上下文干净、规则稳定。这一步做好了后面的结构化输出、RAG、Tool Calling都会更容易维护。配套代码按文章编号放在对应分支方便对照运行。后续会继续更新 Spring AI、RAG、Memory、Tool Calling、MCP 等实战内容。

相关新闻

UE 移动端场景性能热力图实践:如何定位地图低帧区域

UE 移动端场景性能热力图实践:如何定位地图低帧区域

用空间网格做 UE 场景性能热力图:定位“哪里卡”而不是“整体有点卡”摘要:复杂场景的性能通常具有明显空间差异。只沿一条跑图路线采样,容易漏掉转角、视野边缘、特效交汇区和资源密集区。本文介绍一种可自动化的空间网格采样方法&#xff1…

2026/6/27 21:27:07阅读更多 →
OmniStream SQL算子加速实战:从Calc到WindowAgg的完整指南

OmniStream SQL算子加速实战:从Calc到WindowAgg的完整指南

OmniStream SQL算子加速实战:从Calc到WindowAgg的完整指南 【免费下载链接】OmniStream OmniStream operator acceleration is implemented using native code (C/C) to optimize Flink SQL and DataStream operators. 项目地址: https://gitcode.com/openeuler/O…

2026/6/27 21:22:07阅读更多 →
如何利用witty-diagnosis-agent进行硬盘故障预测与诊断:完整教程

如何利用witty-diagnosis-agent进行硬盘故障预测与诊断:完整教程

如何利用witty-diagnosis-agent进行硬盘故障预测与诊断:完整教程 【免费下载链接】witty-diagnosis-agent The witty-diagnosis-agent is an intelligent diagnostic tool that provides automated analysis and troubleshooting for complex system issues. 项目…

2026/6/27 21:22:07阅读更多 →
【中小学AI人工智能教育】多输出模型和不确定性加权技术

【中小学AI人工智能教育】多输出模型和不确定性加权技术

前面我们绍过使用AiEduLab.tech中“图像分类——手写数字识别”项目来完成图像分类模型的构建、训练、使用。实际上,AiEduLab.tech还支持多输出模型。有时我们不仅仅需要一组分类结果可能还希望同时得到另一组无法融合的结果。这可以通过训练另一个模型来实现&#…

2026/6/27 22:57:20阅读更多 →
怎么判断无人机装配线厂家的真实技术实力?5 步实测核验法

怎么判断无人机装配线厂家的真实技术实力?5 步实测核验法

最近好多做无人机制造的粉丝问我,怎么判断装配线厂家的真实技术实力?不少人被宣传册上的 “全自动化”“行业标杆” 话术忽悠,签完合同才发现是中间商转包,产线精度不达标、对接不了测试设备,返工损失动辄十几万。跑厂…

2026/6/27 22:57:20阅读更多 →
Windows配置DNS解析临时域名

Windows配置DNS解析临时域名

Windows Server 自带 DNS 服务(推荐,局域网统一域名,所有人不用改 hosts) 搭建内网 DNS,全局域网电脑 DNS 填192.168.1.66,直接访问 http://hub.local:5005,所有网段自动解析,一台服…

2026/6/27 22:57:20阅读更多 →
零碳园区管理系统的价值如在实际项目中体现

零碳园区管理系统的价值如在实际项目中体现

当前国内零碳园区建设已从概念试点、硬件堆砌阶段,全面迈入数字化落地、可量化收益、长效化运营的实战阶段。传统园区改造普遍存在新能源设备利用率低、用电成本居高不下、能耗管控粗放、碳效合规缺失、运维成本高昂、供电稳定性不足等实操痛点。零碳园区智能化管理…

2026/6/27 22:57:20阅读更多 →
量子力学核心:定义、公理与关键概念

量子力学核心:定义、公理与关键概念

在极小尺度下,宇宙的运行规律与我们日常所见的世界截然不同。量子力学作为物理学的一个重要分支,专门用来描述原子、电子、光子,以及分子、亚分子尺度下几乎所有物质的奇异特性。 量子力学诞生于20世纪上半叶,它推导得出的结论往往…

2026/6/27 22:57:20阅读更多 →
龙客文化GEO运营用了三个月,真的有效果吗?

龙客文化GEO运营用了三个月,真的有效果吗?

说实话,刚开始接触龙客文化GEO的时候,我心里也是打鼓的。我们做的是本地生活服务的,之前试过投竞价、搞地推,钱花了不少,但效果就跟打水漂一样,看得见摸不着。最头疼的就是客户搜不到我们,明明服…

2026/6/27 22:52:20阅读更多 →
【人工智能】一文搞定到底什么是智能体

【人工智能】一文搞定到底什么是智能体

【人工智能】一文搞定到底什么是智能体 一文搞定到底什么是智能体【人工智能】一文搞定到底什么是智能体一. LM,WorkFlow,Agent分别有什么么不同二. Agent的思考过程是怎样的三. Agent的五个核心部分1)LLM2)Prompt3)Me…

2026/6/27 11:20:40阅读更多 →
嵌入式GUI控件实战:ROTARY、SCROLLBAR、SLIDER原理与应用

嵌入式GUI控件实战:ROTARY、SCROLLBAR、SLIDER原理与应用

1. 嵌入式GUI控件:从原理到实战的深度解析在嵌入式系统开发中,图形用户界面(GUI)的设计与实现往往是项目从“能用”到“好用”的关键一跃。不同于资源充沛的PC或移动平台,嵌入式设备的GUI需要在有限的CPU性能、内存空间…

2026/6/27 5:46:02阅读更多 →
Google AI Studio 300美元额度的真相与实战指南

Google AI Studio 300美元额度的真相与实战指南

1. 这300美金不是“送钱”,而是Google埋下的第一道技术门槛 你看到标题里那个醒目的“$300美金”时,第一反应可能是:又一个免费额度?领完就完事?我亲手试过——这300美金根本不是红包,而是一张入场券&…

2026/6/27 11:20:39阅读更多 →
10分钟AI语音克隆与实时变声:Retrieval-based-Voice-Conversion-WebUI完整指南

10分钟AI语音克隆与实时变声:Retrieval-based-Voice-Conversion-WebUI完整指南

10分钟AI语音克隆与实时变声&#xff1a;Retrieval-based-Voice-Conversion-WebUI完整指南 【免费下载链接】Retrieval-based-Voice-Conversion-WebUI Easily train a good VC model with voice data < 10 mins! 项目地址: https://gitcode.com/GitHub_Trending/re/Retrie…

2026/6/27 0:04:03阅读更多 →
Layerdivider:3分钟AI智能分层,彻底告别手动抠图时代

Layerdivider:3分钟AI智能分层,彻底告别手动抠图时代

Layerdivider&#xff1a;3分钟AI智能分层&#xff0c;彻底告别手动抠图时代 【免费下载链接】layerdivider A tool to divide a single illustration into a layered structure. 项目地址: https://gitcode.com/gh_mirrors/la/layerdivider 还在为复杂的图像分层工作烦…

2026/6/27 0:04:03阅读更多 →
Tomcat中X-Frame-Options配置实战:防御点击劫持的四种方法与最佳实践

Tomcat中X-Frame-Options配置实战:防御点击劫持的四种方法与最佳实践

1. 项目概述&#xff1a;为什么X-Frame-Options是Web安全的“防盗门”&#xff1f;最近在排查一个老项目的安全审计报告时&#xff0c;又被提到了“点击劫持”风险&#xff0c;矛头直指缺失的X-Frame-Options响应头。这已经不是第一次了&#xff0c;很多开发团队&#xff0c;尤…

2026/6/27 0:04:03阅读更多 →