Spring AI 初体验:配好 yml 就能聊,ChatClient 四步链式调用
Spring AI 初体验配好 yml 就能聊ChatClient 四步链式调用作者鱼宵 Spring AI 实战精通营 · 第 1 篇上周有个同事在群里发了张截图一个 Spring Boot 工程代码里从头到尾没出现一个模型类跑起来却能和人一问一答。我第一反应是又有什么黑魔法。后来把工程 clone 下来亲手跑了一遍才发现原来是 Spring 官方出了个叫Spring AI的框架——把大模型接入做成了配数据库一样的事改 yml、注入一个 ChatClient、写个接口完事。这篇文章就带你用最小工程跑通第一个 AI 接口。代码全在仓库的lesson-01/目录里clone 下来照着命令一步步重跑一遍十分钟后你也有一个能和人对话的 Spring Boot 项目——尤其是最后那两道挑战题不亲手跑一次你真以为 AI 接口很难。一、核心原理为什么配好 yml 就能用一句话Spring AI 把大模型客户端做成了 Spring 风格的 starter配置走 yml、使用走注入、组合走 Bean——你一行模型代码都不用写。1. 自动装配AI 也住进精装房以前自己接大模型得手写 HTTP 客户端、自己拼请求体、自己管重试就像租房后自己买家具、自己拉网线。**自动装配Auto-Configuration**是 Spring Boot 的老机制往 classpath 里丢一个 starter比如spring-ai-starter-model-openai启动时框架自动读 yml 里的spring.ai.*配置把ChatClient和底层模型客户端全部创建好你只管注入。类比一下starter 是家具套餐yml 是装修意见表注入 ChatClient 就是拎包入住。说白了这是 Spring Boot 干了几年的老本行只不过这次伺候的对象从数据库换成了大模型。2. ChatClient对话界的 JdbcTemplateChatClient 是 Spring AI 的统一对话入口所有 AI 交互都从它开始。它和 JdbcTemplate 的关系很像——你不用关心底层连的是谁、怎么连只调用统一接口。链式 API 四步面试必背步骤代码干什么1prompt()开始拼消息相当于打开对话框2可选.system(...)塞系统提示词——人设/规则3.user(msg)塞用户问题4.call()调用模型阻塞等回答回来5.content()取出回答文本类比点外卖prompt()打开外卖 Appsystem()备注不要辣user()下单call()等骑手送到阻塞等待content()拆开包装吃。注意call()是阻塞式等模型把整段回答生成完才返回简单但首字延迟高。打字机效果流式是第 5 课的主菜先记住这个对照。3. SystemPrompt给模型发一本入职手册SystemPrompt是发给模型的最高优先级人设/规则说明书。新员工模型上岗先读手册就知道自己是谁、该怎么说话。本课/interview接口就是给模型发了一本资深 Java 面试官手册——同一个问题有没有这本手册回答风格天差地别第四节有真实对比。二、动手十分钟跑通最小工程环境Windows JDK 17 Maven 3.9。会RestController、看得懂 yml 就行。第 1 步30 秒检查环境。java-version# 期望 TrueJDK17 在不在[bool][Environment]::GetEnvironmentVariable(DEEPSEEK_API_KEY)# 期望 TrueKey 配了没只看存在性别打印Get-NetTCPConnection-LocalPort 8093-State Listen-ErrorAction SilentlyContinue# 无输出端口空闲第 2 步编译 启动。cd 你的课程根目录\spring-ai-journey\lesson-01$env:JAVA_HOMEC:\Program Files\Java\jdk-17# Maven 必须跑在 JDK 17 上每个新窗口设一次mvn clean install-DskipTests# 结尾看到 BUILD SUCCESSmvn spring-boot:run# 看到 Tomcat started on port 8093 即启动成功第 3 步调两个接口中文参数要先 URL 编码。# 通用问答$q[uri]::EscapeDataString(用一句话介绍你自己)Invoke-RestMethodhttp://localhost:8093/chat?msg$q# 角色扮演Java 面试官$q2[uri]::EscapeDataString(什么是 final 关键字)Invoke-RestMethodhttp://localhost:8093/interview?msg$q2浏览器直接开http://localhost:8093/chat?msg你好也行浏览器会自动编码。三、关键代码三段文件逐行拆解工程是个标准 Spring Boot 项目真正要看的代码就三处yml模型配置、ChatController两个接口、主类启动。第一段application.yml——模型配置全课程统一套路。server:port:8093# 端口按课程分配表spring-ai 系列 lesson-01 8093spring:ai:openai:base-url:${LLM_BASE_URL:https://api.deepseek.com}# 环境变量优先默认 DeepSeek兼容 OpenAI 协议api-key:${DEEPSEEK_API_KEY}# Key 只从环境变量读文件里永远没有明文chat:options:model:${LLM_MODEL:deepseek-chat}# 模型名默认 deepseek-chatmax-tokens:200# 单次回答输出上限教学演示控成本temperature:0.7# 温度0严谨固定1天马行空聊天 0.7 自然这段 yml 有两个值得盯的写法${DEEPSEEK_API_KEY}Spring 占位符语法启动时从环境变量取值。这就是Key 不进文件的标准姿势——就算这份 yml 被传出去了里面也没有一个能用的 Key。${LLM_BASE_URL:https://api.deepseek.com}冒号后面是默认值。想切模型就$env:LLM_BASE_URL...再重启代码和文件都不用动第六节讲切模型三件套。第二段ChatController.java——两个接口总共没几行。packagecom.springai.lesson01;importorg.springframework.ai.chat.client.ChatClient;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RequestParam;importorg.springframework.web.bind.annotation.RestController;/** * 聊天控制器本课的 HTTP 入口。 * ChatClient 是 Spring AI 的核心门面就像 JdbcTemplate 之于数据库 * 由 starter 自动装配——只要 yml 配好模型注入就能用一个模型 Bean 都不用写。 */RestControllerpublicclassChatController{/** * ChatClient 实例通过 Builder 构建Spring AI 推荐用法。 * Builder 由 starter 自动装配背后是 yml 里 spring.ai.openai.* 配置。 */privatefinalChatClientchatClient;publicChatController(ChatClient.Builderbuilder){this.chatClientbuilder.build();}/** * 通用问答http://localhost:8093/chat?msg你好 * * prompt() 开始拼发给模型的消息user(msg) 塞用户问题 * call() 阻塞式调用等模型答完才返回流式是第 5 课的事 * content() 取出回答文本。 */GetMapping(/chat)publicStringchat(RequestParam(msg)Stringmsg){returnchatClient.prompt().user(msg).call().content();}/** * 角色扮演http://localhost:8093/interview?msg什么是final * * system(...) 在用户问题之前塞一段系统提示词人设说明书。 * 对比 /chat 的通用助手口吻体会 SystemPrompt 的作用。 */GetMapping(/interview)publicStringinterview(RequestParam(msg)Stringmsg){returnchatClient.prompt().system(你是资深 Java 技术面试官语气专业但友好。每次回答先用一句话点评候选人的回答再追问一个更深入的问题。).user(msg).call().content();}}第三段Lesson01Application.java——标准启动类三行搞定。packagecom.springai.lesson01;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;/** * Spring AI 实战精通营 · 第 1 课第一个 AI 接口。 * 启动后访问 * GET http://localhost:8093/chat?msg你好 —— 通用助手问答 * GET http://localhost:8093/interview?msg什么是final —— 角色扮演系统提示词 */SpringBootApplicationpublicclassLesson01Application{publicstaticvoidmain(String[]args){SpringApplication.run(Lesson01Application.class,args);}}注意一个细节整个工程没有任何new出来的模型对象。ChatClient.Builder是自动装配的你只管在构造函数里收——这就是配好 yml 就能用的魔法本体。四、实测输出同一份代码加一行 system() 判若两人以下是 2026-10-05 本机真实运行DeepSeek 实测HTTP 200。先调 /chatHTTP 200 我是DeepSeek一个由深度求索公司创造的AI助手随时准备用热情细腻的方式帮你解答问题、处理任务再调 /interview同一个大模型同一套代码只多了.system(...)一行HTTP 200 不错这是个基础但重要的概念。final 关键字在 Java 中表示最终的、不可改变的它可以用来修饰变量、方法和类。 既然你提到了 final那我想追问一下你能具体说说 final 修饰变量时对于基本类型和引用类型分别意味着什么吗看出差别了吗/chat 是热情细腻的助手/interview 变成先点评一句再追问一道的面试官——SystemPrompt 的约束力眼见为实。而且这个输出和 LangChain4j 课第 1 课的玩法二几乎同构同一业务两套实现两门课对照着学效率翻倍。排查提示如果没看到预期输出——404/端口连不上看启动日志有没有Tomcat started on port 8093401 是 Key 环境变量没生效检查设置后重启终端500 多半是编译时maven.compiler.parameters没开见第八节总结表。五、挑战题改参数看看会怎样⭐玩温度yml 里把temperature改成0.0再调/chat同一句用 10 个字介绍你自己改成1.5再调一次——对比三次回答的稳定性和发散性。答案在源码的application.yml里跑出来才知道差距有多大。⭐加一个诗人接口仿照/interview加GET /poet?msg你好系统提示词换成你是李白风格的诗人跑 3 个词看看诗风。答案就在源码ChatController.java——照抄一行.system(...)。⭐⭐切通义不改任何代码用环境变量把模型切到通义qwen-plus$env:LLM_BASE_URL$env:LLM_MODEL$env:QWEN_API_KEY验证切模型只改配置。答案在 README 第 4 步跑通了你就真的吃透了占位符。六、生产环境进阶三个加分项1. Key 不进文件防泄露红线。api-key 只从环境变量读实测后 grep 一遍日志和输出确保没有真实 Key 字样——只允许${DEEPSEEK_API_KEY}占位符出现。2. max-tokens 控成本。max-tokens: 200是输出上限长回答会被截断——这是它的教学现场。生产环境按业务调大同时它也是个天然的成本刹车。3. 切模型三件套。OpenAI https://api.openai.com/v1gpt-4o-mini通义 https://dashscope.aliyuncs.com/compatible-mode/v1qwen-plus。三个模型都走 OpenAI 兼容协议改三处配置就能换供应商代码零改动——这是 Spring AI 自动装配的隐藏福利。七、面试回答模板面试官Spring AI 的自动装配是什么为什么配好 yml 就能用 AI一句话把大模型客户端做成 Spring 风格的 starter配好 yml 自动装配成 Bean注入即用。展开说starter 进 classpath → 启动时读spring.ai.*配置 → 框架自动创建 ChatClient 和模型客户端类比精装房starter 是家具套餐、yml 是装修意见表。你一行模型代码都不用写。指向本课第一节 / lesson-01 的 application.yml追问ChatClient 链式 API 每一步在干什么prompt()开始拼消息 →.user(msg)塞问题 →.call()阻塞调用 →.content()取文本system()可插在最前面塞人设。背熟五步再说一句call 阻塞 vs stream 流式是加分项。指向本课第三节追问Spring AI 和 LangChain4j 最大的工程差异Spring AI 靠 yml 自动装配 官方生态VectorStore/Advisor 全家桶和 Spring 无缝LangChain4j 靠 Java Bean 手配模型更轻量、厂商覆盖更广。选型看团队栈纯 Spring 栈选前者要多模型灵活切换看后者。指向本课第一节 LangChain4j 课第 1 课追问Spring 6 下 RequestParam 为什么必须开 parameters 编译开关Spring 靠反射读方法参数名JDK 编译默认不保留参数名不开就 500。pom 里maven.compiler.parameterstrue是 Spring Boot 3 系列通用坑。指向本课踩坑表八、总结表坑现象解法JAVA_HOME 指向 JDK8mvn 跑在 Java 8 上构建前$env:JAVA_HOMEC:\Program Files\Java\jdk-17Spring 6 反射参数名RequestParam 省略名字时 500pom 开maven.compiler.parameterstrue中文 URL 参数乱码curl 直接带中文 400/乱码用[uri]::EscapeDataString()编码ChatClient.Builder 注入失败启动报 NoSuchBeanDefinition检查 yml 里 api-key 占位符是否配好版本不配套Spring AI 1.0.9 配 Boot 3.3.x 冲突冻结 Boot 3.5.x抄本课 pom端口占用Port 8093 was already in useGet-NetTCPConnection -LocalPort 8093查占用九、关于这个系列本文是「Java 后端实战精通营」系列第 1 篇原则实战驱动、由浅到深、面试向每篇文章的结论都可以亲手验证。Spring AI 实战精通营10 课https://gitee.com/j67mk2/spring-ai-journey本文对应源码位置lesson-01/最小 Spring Boot 工程内含ChatController双接口 application.yml模型配置系列文章一览按发布顺序篇主题1Spring AI 初体验配好 yml 就能聊ChatClient 四步链式调用2Spring AI 提示词模板{变量} 参数化 few-shot一条提示词反复用3Spring AI 结构化输出entity() 把模型回答解析成 JavaBean别再手撕 JSON4Spring AI 工具调用Tool 让大模型自己查订单查库存5Spring AI 流式输出Flux SSE 打字机回答不再干等三秒6Spring AI 多模态给大模型一双眼睛图片它也能看懂7Spring AI 向量检索本地 ONNX 嵌入文本秒变坐标知识库零成本起步8Spring AI RAG 问答助手回答带引用AI 不再睁眼说瞎话9Spring AI Advisor 编排记忆 工具 RAG 三合一一个接口全搞定10Spring AI 企业智能客服RAG 工具 记忆 流式 兜底十课收官下一篇预告《Spring AI 提示词模板{变量} 参数化 few-shot一条提示词反复用》——本课的人设提示词是写死在代码里的下一课把它做成带{变量}的可复用模板再塞几个示例few-shot你会发现链式 API 越来越Spring 味。跑完有任何报错把终端输出发评论区一起排查。标签建议SpringAI、大模型、ChatClient摘要建议≤256 字Spring AI 把大模型接入做成了配数据库一样的事改 yml、注入 ChatClient、写个接口就能对话。本文用最小工程跑通第一个 AI 接口逐行拆解自动装配与链式 API实测对比 system() 系统提示词的约束力附 3 道挑战题与面试回答模板源码在 gitee lesson-01 可 clone 直接跑。

相关新闻

为什么你的企业上系统总是失败?一个毛巾厂“1个月vs1周“的真实案例

为什么你的企业上系统总是失败?一个毛巾厂“1个月vs1周“的真实案例

很多企业主找我聊数字化转型,开口第一句话是:"有没有好用的进销存系统推荐?"我的回答往往是:先别急着选系统,看看你手上的数据准备好了没有。今天讲一个我经手的真实案例,也许能帮正在准备上系统…

2026/10/13 18:38:24 阅读更多 →
PhotoCraft:纯Rust开源重制Photoshop,免费可用的原生图像编辑器完整评测

PhotoCraft:纯Rust开源重制Photoshop,免费可用的原生图像编辑器完整评测

PhotoCraft:纯Rust开源重制Photoshop,免费可用的原生图像编辑器完整评测 【免费下载链接】photocraft An open-source, clean-room reimplementation of Adobe Photoshop in pure Rust 项目地址: https://gitcode.com/gh_mirrors/pho/photocraft …

2026/10/11 16:32:52 阅读更多 →
2026年方形摇摆筛行业现状与选择指南,海盐筛分用户力荐实力厂家

2026年方形摇摆筛行业现状与选择指南,海盐筛分用户力荐实力厂家

2026年方形摇摆筛行业现状与选择指南:海盐筛分用户力荐实力厂家新乡市先锋振动机械有限公司,是一家集研发、生产、销售、服务于一体的振动筛分设备制造企业,筛分领域十余年,主营圆形摇摆筛、方形摇摆筛、超声波振动筛、旋振筛、直…

2026/10/11 8:35:19 阅读更多 →

最新新闻

多智能体电梯群控:基于目的楼层预约与PPO的深度强化学习实现

多智能体电梯群控:基于目的楼层预约与PPO的深度强化学习实现

简介:本资源是一套面向计算机、人工智能、自动化等专业学生的毕业设计与课程设计实践项目,聚焦于多智能体协同下的电梯群控优化问题,采用深度强化学习实现目的楼层预约调度算法,解决传统电梯响应延迟高、能耗大、乘客等待时间长等…

2026/10/13 19:14:30 阅读更多 →
语义分割环境搭建:PyTorch CPU与GPU版本安装及验证全攻略

语义分割环境搭建:PyTorch CPU与GPU版本安装及验证全攻略

1. 系列前情回顾与本期核心目标语义分割学习系列写到第四篇,前面几篇我分别梳理了语义分割的基本概念、常见数据集的组织方式、以及几个主流分割模型的结构差异。按照正常的学习路线,理论铺垫到这一步,接下来就该动手了。动手的第一步就是装环…

2026/10/13 19:14:30 阅读更多 →
Spring Boot配置绑定实战:@ConfigurationProperties原理与避坑

Spring Boot配置绑定实战:@ConfigurationProperties原理与避坑

接触Spring Boot这些年,我做得最多的一个动作就是替同事定位“配置不生效”的诡异问题。排查到最后,十有八九都落在同一个注解上——ConfigurationProperties。它看起来只是给配置类加个前缀声明,实际牵扯到数据绑定、松散命名、第三方注册、…

2026/10/13 19:14:30 阅读更多 →
语义分割必备:PyTorch CPU/GPU版本安装全攻略

语义分割必备:PyTorch CPU/GPU版本安装全攻略

废话不多说,直接进入正题。这一篇是这个系列的第四篇,主题是很多人在语义分割学习中绕不过去的第一道坎——CPU和GPU版本的PyTorch及其环境安装。前几篇我们聊了语义分割的数据标注、模型结构、评价指标,但真正动手跑代码的时候,你…

2026/10/13 19:14:29 阅读更多 →
Java核心知识点全解析:从JVM到并发编程的底层原理

Java核心知识点全解析:从JVM到并发编程的底层原理

做Java开发这些年,我有一个很深的感受:真正拉开水平差距的,不是谁背的框架更多、API记得更熟,而是对底层那批核心知识点有没有吃透。所谓“Java重要知识点”,不是让你背八股文,而是帮你在遇到线上问题时&am…

2026/10/13 19:14:29 阅读更多 →
Go监听MySQL binlog实战:轻量级数据变更捕获与生产避坑指南

Go监听MySQL binlog实战:轻量级数据变更捕获与生产避坑指南

1. 这不是“监听MySQL”,而是重建一套轻量级数据变更管道很多人第一次看到“用Go监听binlog”这个说法,第一反应是:“MySQL自己不就有mysqlbinlog命令吗?再不济写个Python脚本调用一下不就完了?”——我试过&#xff0…

2026/10/13 19:13:29 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →