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 直接跑。
阅读完成 · 觉得有帮助?