ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Spring AI Alibaba 1.x入门:从版本配置到ChatClient、MCP与可观测性

2026/9/7 23:18:26 拓冰建站 浏览量
Spring AI Alibaba 1.x入门:从版本配置到ChatClient、MCP与可观测性 先说个我见过很多次的场景打开 Spring AI Alibaba 官方文档第一条命令还没跑人已经在版本号里迷失了。Spring AI 1.0、Spring AI Alibaba 1.0、Spring Boot 3.4、JDK 17这四个版本到底怎么对齐更别说翻阅社区时一堆人开始聊 Spring AI 2.0 的 ObservationHandler、RAG 实例让人怀疑自己学的到底是不是同一个框架。我写这篇入门案例就是想先把版本迷雾拨开用一套最小依赖把它跑起来再从 ChatClient 这个核心对象讲清楚最后把 MCP 服务接入、NL2SQL、可观测性这几个热搜概念串进来。不管你是刚接触 Spring AI Alibaba还是已经在项目里摸了两天这篇文章都值得按顺序读完。1. 动手之前先把Spring AI Alibaba 1.x的身份问题理清楚1.1 它和Spring AI的真实关系很多人会把 Spring AI 和 Spring AI Alibaba 当成两个并列的框架其实不是。Spring AI 是 Spring 官方做的大模型应用抽象层地位和 Spring Data、Spring Cloud 类似它把不同模型厂商、不同接入协议、不同调用方式统一成一套 API。你写业务代码的时候不用关心对面是通义千问还是别的模型背后都叫 ChatModel、ChatClient。Spring AI Alibaba 则是阿里云在 Spring AI 之上做的落地增强包它做的事情有两类一类是把 DashScope阿里云百炼模型的能力接入 Spring AI 的标准化接口另一类是补充 Spring AI 官方没做的工程化能力比如 MCP 组件、NL2SQL、异常诊断、可视化等。但它的核心 API 并没有另起炉灶你学的 ChatClient、ChatClient.Builder、Advisor、ToolCallback在 Spring 官方项目里同样成立。所以你在实验 Spring AI Alibaba 1.x 的时候遇到问题去查资料可以直接查 Spring AI 1.0 的官方文档绝大多数答案是通用的。这个认知能帮你少走很多弯路。1.2 入门案例真正需要的功能切片很多人看官方文档会被目录吓到Embedding、VectorStore、RAG、Function Calling、MCP、Structured Output、Advisors、Evaluation……好像每个都要学。但入门案例不需要覆盖全部你只需要一个能真正跑起来的最小闭环。我建议第一次动手时只关注四件事第一用 ChatClient 发起一次普通对话第二用流式方式拿到增量输出第三给这个对话案例接上外部技能MCP 服务第四通过可观测性看到一次对话的耗时和调用信息。NL2SQL 可以放到这四个能力之后顺手验证因为它本质上不是独立的魔法而是 Tool Calling 的一个具体场景。这个功能切片的好处是它覆盖了从调通模型到做工程化的最短路径但不会把你拖进 RAG、向量库、Embedding 这些偏后的模块里。1.3 本案例最终长什么样子我后面会带着你做一个完整的 Spring Boot 工程目录结构大概是这样spring-ai-alibaba-demo ├── pom.xml └── src/main/java/com/example/demo ├── DemoApplication.java ├── ChatController.java └── config ├── ChatConfig.java └── AiObservationConfig.java这个工程暴露几个 HTTP 接口/chat做普通对话/stream做流式输出接完 MCP 后可以用自然语言让模型调用外部工具最后通过 actuator 暴露指标。整个工程不依赖复杂中间件你只需要一个可以访问 DashScope 的 API Key加上本地 Java 环境就能复现。2. 第一个完整可跑的对话案例从空目录到一个HTTP接口2.1 工程初始化与pom里的版本管理我建议不要用 Spring Initializr 在线生成直接手工建一个 Maven 工程。原因是 Spring AI Alibaba 的 starter 依赖版本比较敏感手工搭能让你清楚知道每个版本是谁管理的。这是我的入门 pom.xml我加了必要的注释?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.4.5/version relativePath/ /parent groupIdcom.example/groupId artifactIdspring-ai-alibaba-demo/artifactId version0.0.1-SNAPSHOT/version namespring-ai-alibaba-demo/name properties java.version17/java.version spring-ai-alibaba.version1.0.0/spring-ai-alibaba.version /properties dependencyManagement dependencies dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-bom/artifactId version${spring-ai-alibaba.version}/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-starter/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-actuator/artifactId /dependency /dependencies /project这里最关键的是通过spring-ai-alibaba-bom统一管理 Spring AI 相关依赖的版本。不要自己再手动引入io.spring.ai:spring-ai-bom两个 BOM 同时在 dependencyManagement 里会出现版本覆盖后面第 6 部分我会专门说这个坑。2.2 application.yml的核心配置逐行拆解配置文件非常简单默认使用 DashScope 作为模型供应商spring: application: name: spring-ai-alibaba-demo ai: dashscope: api-key: ${DASHSCOPE_API_KEY:} chat: options: model: qwen-plus temperature: 0.7 management: endpoints: web: exposure: include: health,info,metrics,prometheus逐个说spring.ai.dashscope.api-key你在阿里云百炼控制台创建的 API Key。我强烈建议用环境变量注入而不是直接写在文件里。如果你还没申请去百炼控制台创建一个模型那边开通一下 DashScope 服务即可。spring.ai.dashscope.chat.options.model模型名默认qwen-plus足够覆盖入门场景。想更快更便宜可以用qwen-turbo想要更强效果可以换qwen-max。temperature采样温度0.7 是通用值。做代码生成、SQL 生成时建议压到 0.10.3做文案写作可以高一点。management.endpoints...暴露 actuator 端点第 5 部分的 ObservationHandler 会用到。这里有个容易忽略的点Spring AI Alibaba 1.x 的配置前缀是spring.ai.dashscope.*不是spring.ai.alibaba.dashscope.*。如果你在网上搜到特别老的教程里用spring.ai.alibaba.*前缀多半是 0.x 阶段的版本建议以当前 1.x 官方文档为准。2.3 写一个最简对话接口先写启动类package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }再写一个 ChatController。这个类只做一件事情接收用户消息调用 ChatClient返回模型回复。package com.example.demo; import org.springframework.ai.chat.client.ChatClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; RestController public class ChatController { private final ChatClient chatClient; public ChatController(ChatClient.Builder builder) { this.chatClient builder.build(); } GetMapping(/chat) public String chat(RequestParam(defaultValue 你好请用一句话介绍你自己) String message) { return chatClient.prompt() .user(message) .call() .content(); } }这段代码看起来简单但它背后已经把 Spring AI 的自动配置、DashScope 模型客户端、ChatClient 构建流程全部串联起来了。ChatClient.Builder是 Spring AI 自动注册的 Bean你只需要用构造器注入不需要手动 new。2.4 启动并用curl做最小验证直接启动DemoApplication然后打开终端curl --get \ --data-urlencode message你好用一句话介绍通义千问 \ http://localhost:8080/chat正常返回的是一段文本类似你好我是通义千问是阿里云研发的大语言模型可以回答问题、编写代码、提供建议等。看到这个返回你的第一个 Spring AI Alibaba 1.x 案例就算跑通了。整个过程只有三个文件没有 XML 配置没有自定义注解也没有写模型调用代码这就是 Spring AI 抽象层最大的价值。2.5 入门阶段最容易撞上的三个异常我根据自己踩过的坑整理了入门阶段最常见的三个异常给你直接排雷异常现象根本原因处理方式401 Unauthorized或InvalidApiKeyAPI Key 填错了或环境变量没生效检查spring.ai.dashscope.api-key值和百炼控制台是否一致connect timeout/UnknownHostExceptionDashScope 网络端点不通或自定义 base-url 填错不配置base-url使用默认地址如果改了确认协议和路径正确模型名相关报错如Model Not Existmodel 参数填成了不存在的模型标识确认qwen-plus、qwen-turbo、qwen-max是否已开通权限还有一个不太显眼的问题如果你本机有代理流量转发类工具有时候会捕获 443 连接导致超时而报错信息并不会直接说是代理问题。建议第一次跑通前先把系统代理关掉或者把 DashScope 域名加入放行列表否则排查起来会怀疑人生。3. 把ChatClient吃透入门才算没白做3.1 ChatModel、ChatClient、ChatClient.Builder三张脸怎么认很多新人看到这三个类第一反应是怎么这么多命名很像的类。用数据库来类比ChatModel就像DriverManager底层的数据库驱动负责真正处理协议和网络请求ChatClient就像JdbcTemplate是对你提供的业务 APIChatClient.Builder则是把各种装配细节封装起来的工厂。在 Spring AI Alibaba 1.x 里ChatModel的实体类是 DashScope 适配器你不需要直接碰它。你的业务代码只依赖ChatClient这个接口测试和替换都很方便。这也是为什么官方示例里都推荐通过ChatClient.Builder注入而不是直接注入ChatModel。3.2 prompt().user().call().content()这条链到底经历了什么这行链式调用是整个 Spring AI 编程模型的核心chatClient.prompt() .user(message) .call() .content();按顺序拆解prompt()创建了一个 Prompt 构建器.user(message)把用户消息加到消息列表里.call()将组装好的 Prompt 发给模型并等待完整响应返回一个ChatResponse.content()从响应中提取模型生成的文本。这不是什么魔法本质上就是构造请求、发送请求、解析响应。但 Spring AI 在中间塞入了大量扩展点比如 Advisor用来做记忆、日志、审核、ToolCallback用来让模型调外部工具、ChatOptions用来控制 temperature、maxTokens。理解这条链后面加任何能力都不慌。3.3 流式输出用Flux接住每一段token对话类应用里用户最反感的是长时间转圈等一大段结果。流式输出能解决这个问题。Spring AI 里的写法很自然import org.springframework.http.MediaType; import reactor.core.publisher.Flux; GetMapping(value /stream, produces MediaType.TEXT_EVENT_STREAM_VALUE) public FluxString stream(RequestParam(defaultValue 讲一个程序员冷笑话) String message) { return chatClient.prompt() .user(message) .stream() .content(); }调用之后接口会以 Server-Sent Events 风格不断返回文本片段。在命令行里可以直接用curl -N看效果curl -N --get \ --data-urlencode message讲一个程序员冷笑话 \ http://localhost:8080/stream流式接口对前端友好的同时也会带来两个工程问题第一需要在网关层加长超时时间第二统一日志里需要额外拼接才能得到完整上下文。所以很多生产项目里最终还是会同时保留流式和非流式两个接口内部走同一套 ChatClient。3.4 参数应该放哪里从defaultOptions到单次override模型参数有两层设置入口第一层是ChatClient.Builder.defaultOptions()对所有通过该 Client 发起的请求生效第二层是单次请求的prompt().options()只在这次调用生效。下面这个例子可以直观看出差别Bean ChatClient chatClient(ChatClient.Builder builder) { return builder .defaultOptions(DashScopeChatOptions.builder() .withModel(qwen-plus) .withTemperature(0.7) .build()) .build(); }如果你只是想某一次请求用更低的温度写chatClient.prompt() .user(生成一段sql) .options(DashScopeChatOptions.builder() .withTemperature(0.1) .build()) .call() .content();有一点要注意DashScopeChatOptions是 DashScope 特有的实现类。如果你不想绑定特定厂商可以用ChatOptions接口或者通过ChatClient的通用配置。入门阶段直接用DashScopeChatOptions没问题但如果你打算以后切换模型厂商建议代码里尽量依赖 Spring AI 的抽象。3.5 多轮对话为什么不能靠一句记住我们刚才说的我第一次做多轮对话时天真地以为给模型传一句记住我们刚才说的就行结果模型每次都在一本正经地瞎编历史。大模型没有记忆这个概念它只接收你这次请求里携带的消息列表不持有任何状态。Spring AI 提供了ChatMemory和MessageChatMemoryAdvisor来解决这个问题。最小配置如下import org.springframework.ai.chat.memory.ChatMemory; import org.springframework.ai.chat.memory.InMemoryChatMemory; import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor; Bean ChatMemory chatMemory() { return new InMemoryChatMemory(); }然后在构建 ChatClient 时挂上 AdvisorBean ChatClient chatClient(ChatClient.Builder builder, ChatMemory chatMemory) { return builder .defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory)) .build(); }请求时带上conversationId框架就会自动把之前的历史记录拼到消息列表里。InMemoryChatMemory 只适合单机和测试环境生产环境多实例部署时建议换成基于 Redis 的ChatMemory实现否则用户切到另一台机器就失忆了。4. 给入门案例接上外部技能使用别人提供的MCP服务4.1 MCP到底解决什么问题MCPModel Context Protocol可以理解成 AI 应用生态里的USB 接口。以前一个 AI 应用要接一个外部数据源或工具就得写一套私有集成代码。现在只要对方提供 MCP 服务你通过标准协议连接模型就能自动发现工具、按需调用。热搜词里有个很典型的场景如何让别人提供的 MCP 服务。这意味着你不需要自己实现那些工具只需要在 Spring AI Alibaba 1.x 里配置一个 MCP 客户端把远程服务暴露的工具当成本地工具注册给 ChatClient。4.2 接一个HTTP MCP Server的最小配置假设第三方已经部署了一个 HTTP 类型的 MCP 服务地址是http://localhost:3000/mcp它对外暴露了一个获取天气的工具。第一步是在 pom.xml 里加上 MCP 客户端依赖dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-client/artifactId /dependency然后在配置文件中声明连接spring: ai: mcp: client: http: connections: weather-server: url: http://localhost:3000/mcp headers: Authorization: Bearer ${MCP_ACCESS_TOKEN:}这里的weather-server名字可以自己取Spring AI 会用它来区分不同 MCP 连接。如果你的服务不需要认证headers 那行可以不要。4.3 把MCP工具注册进ChatClient的关键一步很多同学卡在配置完了但模型不调用工具。原因是光配置 MCP 连接还不够必须把 MCP 暴露出来的 ToolCallback 注册进 ChatClient 的 defaultTools。我见过不少项目用自动配置后以为万事大吉结果日志里根本没有工具注册信息。推荐做法是在配置类中注入ListToolCallback再构建 ChatClientimport org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.model.tool.ToolCallback; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.List; Configuration public class ChatConfig { Bean ChatClient chatClient(ChatClient.Builder builder, ListToolCallback toolCallbacks) { return builder .defaultTools(toolCallbacks.toArray(ToolCallback[]::new)) .build(); } }启动时如果一切正常你会在日志里看到类似 Registered tool: getWeather 的同步信息。之后写一个接口让用户直接问北京今天冷不冷ChatClient 会先让模型判断需要调用getWeather工具拿到结构化结果后再组织自然语言回复。4.4 对方用npx启动服务时怎么连很多开发者在本地用 npx 启动临时 MCP 服务比如模型上下文协议官方提供的测试服务。这种服务不暴露 HTTP 端口而是通过标准输入输出通信你需要用 stdio 模式连接spring: ai: mcp: client: stdio: connections: test-server: command: npx args: - -y - modelcontextprotocol/server-everything需要注意stdio 模式的服务生命周期由 Spring AI 客户端管理应用退出时服务也会被终止。远程生产环境基本不会用 stdio更多是 HTTP 或 SSE 方式。入门阶段用 npx 服务验证链路是够的但别直接搬到生产。4.5 MCP接入失败时优先检查的6个点我在这块折腾过不少时间总结排查顺序如下确认 MCP 服务本身能连通比如curl http://localhost:3000/mcp是否正常。确认依赖齐全spring-ai-starter-mcp-client没有被版本仲裁覆盖掉。确认启动日志里能看到工具注册信息没有的话重点看 4.3 节的配置。确认模型本身支持function calling像qwen-turbo和qwen-plus都支持但个别旧模型不一定。确认超时配置够长有些 MCP 工具执行耗时超过默认超时会在模型侧表现为工具无响应。确认授权认证HTTP 模式下很多服务要求请求头带 token如果配置了但没传进去工具会返回 401。还有一个很容易忽略的点MCP 工具的 description 质量决定了模型会不会在合适的场景调用它。如果你接的服务工具描述写得很含糊模型很可能忽略掉。这种情况不是代码问题是工具的元数据问题。5. 跑通后顺手验证两个热搜能力NL2SQL与ObservationHandler5.1 用自然语言查数据库的本质先拆成四步NL2SQL 是近期的热门场景核心目标是用一句自然语言直接查出数据库结果。官方有专门的 NL2SQL 封装模块但它经历过不同小版本的接口调整我不建议入门阶段一上来就去追那些配置。先理解它的本质它其实就是四条链路把数据库表结构建表 DDL注入到模型上下文里让模型根据用户问题生成一条只读 SQL程序拿到 SQL 后在受控的数据源里执行再把查询结果交给模型让它用自然语言整理成可读答案。这个流程在 Spring AI Alibaba 1.x 里完全可以用 Tool Calling 实现。这样做的好处是你对每一步都有掌控权不会出现官方模块自动执行了危险 SQL这种黑盒风险。5.2 不依赖魔法配置文件用Tool Calling实现一个可运行的NL2SQL最稳妥的方式是创建一个只读查询工具然后在 ChatClient 里注册给它。先写一个工具类这里我用 Spring 的 JdbcTemplate 做查询import org.springframework.ai.tool.annotation.Tool; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import java.util.List; import java.util.Map; Service public class DatabaseQueryTool { private final JdbcTemplate jdbcTemplate; public DatabaseQueryTool(JdbcTemplate jdbcTemplate) { this.jdbcTemplate jdbcTemplate; } Tool(description 执行只读SELECT SQL返回JSON格式的结果集) public String runReadOnlyQuery(String sql) { // 防止误操作强制只允许SELECT或者with开头的只读SQL String trimmed sql.trim().toLowerCase(); if (!trimmed.startsWith(select) !trimmed.startsWith(with)) { return 只允许执行SELECT或WITH开头的只读SQL; } ListMapString, Object rows jdbcTemplate.queryForList(sql); return rows.toString(); } }然后把工具方法注册成 ToolCallbackimport org.springframework.ai.tool.ToolCallbackProvider; import org.springframework.ai.tool.method.MethodToolCallbackProvider; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class ToolConfig { Bean ToolCallbackProvider databaseToolProvider(DatabaseQueryTool databaseQueryTool) { return MethodToolCallbackProvider.builder() .toolObjects(databaseQueryTool) .build(); } }这里最关键的是把建表 DDL 放在系统提示词里让模型先学习表结构再让它生成 SQL。例如在 Controller 里GetMapping(/nl2sql) public String nl2sql(RequestParam String question) { String ddl CREATE TABLE orders ( id BIGINT PRIMARY KEY, user_name VARCHAR(50), amount DECIMAL(10,2), created_at DATETIME ); ; String promptText 表结构如下 %s 根据用户问题%s 生成一条只读SQL并调用工具执行最后用自然语言回答。 .formatted(ddl, question); return chatClient.prompt() .system(你是数据库分析助手只执行只读SQL。) .user(promptText) .call() .content(); }这样你就有了一条完全可控、且能真正跑通的 NL2SQL 链路。如果要落到生产建议加上 SQL 白名单、行数上限、耗时上限等防护比如只允许查视图而不是物理表。5.3 ObservationHandler给每一次对话装上仪表盘Spring AI 1.0 开始模型调用统一通过 Micrometer Observation 埋点Spring AI Alibaba 1.x 同样继承了这个能力。只要引入了spring-boot-starter-actuator你其实已经能拿到很多 AI 调用指标了。但如果你想精确感知某一次对话什么时候开始、什么时候结束、耗时多久可以注册一个自定义 ObservationHandler。写起来并不复杂import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class AiObservationConfig { private static final Logger log LoggerFactory.getLogger(AiObservationConfig.class); Bean ObservationHandlerObservation.Context aiObservationHandler() { return new ObservationHandlerObservation.Context() { Override public boolean supportsContext(Observation.Context context) { return context.getName().startsWith(spring.ai); } Override public void onStart(Observation.Context context) { log.info([AI][开始] 名称{}, context.getName()); } Override public void onStop(Observation.Context context) { log.info([AI][结束] 名称{}, 耗时{}ms, context.getName(), context.getTimeSinceStart()); } }; } }启动后每调用一次对话接口控制台就会输出对应的开始、结束日志。这个 Handler 本身不会影响业务逻辑纯粹是在旁边看仪表盘的角色去掉它也不会改变程序行为。5.4 在Actuator和Prometheus里能看到什么如果你按前面的配置暴露了 actuator 端点启动后访问http://localhost:8080/actuator/prometheus可以搜到一系列spring.ai前缀的指标。比较典型的有对话调用次数和耗时分布不同类型操作prompt、stream、entity 转换的调用情况模型调用相关的 token 使用量具体依赖版本和模型是否返回 token usage。具体指标名会因为版本不同有所差异比如有的版本叫spring_ai_chat_client_turns有的版本把观察名称改得更细。先不要死记指标名你要理解背后的设计思想Spring AI 已经把可观测性做成了标准件你只要接上 actuator就能把模型调用的健康度纳入监控大盘。如果你用 Prometheus Grafana直接在抓取/actuator/prometheus后给 Spring AI 相关指标配一个面板就行。这比自己在业务代码里手工打点靠谱得多。6. 从入门到实战的坡道上我劝你先躲开这5个坑6.1 两个BOM混用的版本陷阱这是我最想强调的坑。很多人在 pom 里同时加了io.spring.ai:spring-ai-bom和com.alibaba.cloud.ai:spring-ai-alibaba-bom觉得多一个更保险。结果 Maven 的 dependencyManagement 是按声明顺序仲裁的后声明的 BOM 会把前面的版本覆盖掉。严重时会出现ChatClient.Builder在 Spring AI 1.0 编译、运行却加载了 Spring AI 2.0 类库的情况报错又多又难查。我建议以spring-ai-alibaba-bom为准不要额外引入 Spring AI 官方 BOM。Spring AI Alibaba starter 内部已经把对应版本的 Spring AI 依赖管理好了。6.2 DashScope和长得像OpenAI的配置不能互抄DashScope 提供了 OpenAI 兼容接口导致很多人以为配spring.ai.openai.base-url指向 DashScope 也行。这种方案偶尔能通但生产环境不要这么干。Spring AI Alibaba 对 DashScope 有很多针对性的适配包括模型名映射、返回格式处理、工具调用兼容等绕过去这些增强你的代码就退化成裸的 HTTP 调用出了问题两边都难排查。正确做法是认准spring.ai.dashscope.*配置前缀。如果项目中同时接多个模型也建议按厂商拆配置不要用同一个spring.ai.openai前缀去顶。6.3 API Key硬编码在配置里是迟早会爆的雷我第一次写入门案例时图省事把 API Key 直接写在 application.yml 里。结果不小心把项目推到了公开仓库几个小时内就收到了异常账单短信。虽然 DashScope 有额度控制但这种错误完全可以通过习惯避免。正确做法是配置成环境变量spring: ai: dashscope: api-key: ${DASHSCOPE_API_KEY}本地调试时可以在 IDE 的 Environment variables 里设置也可以在.env文件里管理但不要提交到 Git。如果你需要多环境配置建议接入配置中心或密钥管理服务而不是把密钥写进业务代码仓库。6.4 想要稳定JSON别指望prompt一遍遍强调我在做结构化输出时踩过很深的坑让模型返回 JSON前后写了十几条提示词什么只返回JSON不要写多余文字结果还是偶尔夹杂解释文本。后来改用 Spring AI 的entity()方法问题一下子解决了。public record Movie(String title, int year, String director) {} GetMapping(/movie) public Movie movie(RequestParam String name) { return chatClient.prompt() .user(推荐一部关于 name 的电影输出title、year、director字段) .call() .entity(Movie.class); }entity()会把模型输出解析成目标类型解析失败时会做重试或报错远比你自己手写ObjectMapper去解析稳定。Spring AI Alibaba 1.x 中这种类型转换能力是继承自 Spring AI 的可以放心用。6.5 热搜再热闹也要先弄清自己的版本基线最近社区里关于 Spring AI 2.0 的讨论越来越多什么 ObservationHandler、RAG 实例、新版 auto-configuration看起来都很酷。但你要记住Spring AI Alibaba 1.x 的基线是 Spring AI 1.0.xSpring AI 2.0 的很多类名、包名、配置行为都变了直接抄 2.0 的代码到 1.x 项目里编译期就会被一大堆不存在的类教做人。我的建议是先明确自己用的是哪个基线再决定参考哪些资料。Spring AI Alibaba 1.x 项目就参考 Spring AI 1.0 官方文档、Spring AI Alibaba 1.x 官方文档。2.0 的内容可以收藏但那是升级路线上的事不是入门阶段该操心的事。最后说点我个人的体会。Spring AI Alibaba 1.x 的入门案例核心不是让你把每个 API 都背下来而是建立一条最小依赖链路的心智模型。从 ChatClient 发起一次对话再到挂 Advisor、接 MCP、加观测都是一步一步往这条链路上挂东西。我见过太多人一上来就想搭一个包含 RAG、多模型、复杂 agent 的工程结果卡在环境版本上整整两周。先把这个最小闭环跑通再思考要往里面扩展什么这才是最稳的学习路径。