1. 从零跑通 Spring AI Alibaba 对话 Demo 的真实场景
如果你是一个写 Java 后端的开发者,最近想在自己的项目里接一个大模型对话能力,大概率会搜到 Spring AI Alibaba 这个框架。它把 Spring 生态那套依赖注入、自动配置、Advisor 拦截的玩法搬到了大模型调用上,写起来确实顺手。但真正动手时,第一个卡点往往不是代码,而是配置:application.yml里那个spring.ai.dashscope到底该填什么,api-key从哪来,endpoint 能不能换,换完之后请求发出去返回的 JSON 长什么样。
这篇内容就是解决这个问题的。我会带你从零搭一个能跑起来的 Spring AI Alibaba 对话 Demo,重点放在application.yml里 DashScope endpoint 与 api-key 的可复制配置片段、Maven 依赖坐标、启动类代码,最后用一次 curl 验证调用是否返回预期 JSON。整个过程控制在十分钟左右,适合第一次接触 Spring AI Alibaba 的 Java 开发者。
先说清楚这个 Demo 能做什么:启动一个 Spring Boot 服务,暴露一个/chat接口,你传一句中文进去,它返回模型生成的回复。适合谁:有 Java 基础、用过 Spring Boot、想快速验证大模型接入链路的同学。不适合谁:完全没写过 Spring Boot 的人,建议先补一下@RestController和application.yml的基本用法。
我试过把 endpoint 指向 TaoToken 的兼容地址,整个链路是通的,返回结构和官方 DashScope 一致。下面按步骤来,每一步都给可复制的代码和配置。
2. TaoToken 前置准备:拿到 Base URL 和 API Key
在写代码之前,先把两样东西准备好:一个可用的 API Key,一个正确的 Base URL。Spring AI Alibaba 的 DashScope starter 默认会去请求官方的 DashScope 地址,但它的base-url是可配置的,所以我们可以在application.yml里把它改掉。
TaoToken 的 API 地址是https://taotoken.net/api,这个地址就是我们要填进base-url的值。注意这里不要带任何多余的路径后缀,Spring AI Alibaba 会自己在后面拼接/chat/completions之类的路径。如果你填成https://taotoken.net/api/v1,很可能会拼出双份路径导致 404。
API Key 的获取走控制台:打开https://taotoken.net/console,登录后在 API Keys 页面创建一个新的 Key。创建时建议给它起个能认出来的名字,比如spring-ai-demo,方便以后区分。Key 只在创建时完整显示一次,复制下来存好,后面要填进配置文件。
这里有个小细节:不要把 Key 硬编码进application.yml然后提交到 Git。正确做法是用环境变量。Windows 下可以这样设:
setx TAOTOKEN_API_KEY "sk-你的key"macOS 或 Linux 下:
export TAOTOKEN_API_KEY="sk-你的key"设完之后重启一下终端,用echo $TAOTOKEN_API_KEY(Windows 用echo %TAOTOKEN_API_KEY%)确认能打印出来。这样配置文件里写${TAOTOKEN_API_KEY}就能读到。
如果你还想在浏览器里先验证一下 Key 能不能用,可以打开模型对话页面https://taotoken.net/model-chat,选一个模型发一句话,能正常回复说明 Key 没问题。这一步能帮你排除掉后面一半的报错。
3. 可复制配置:pom.xml 依赖与 application.yml 片段
这一节是核心,所有配置都给完整片段,你直接复制改 Key 就能用。
先看 Maven 依赖。Spring AI Alibaba 的版本管理用 BOM,这样各个 starter 的版本不会打架。在pom.xml的properties和dependencyManagement里加上:
<properties> <java.version>17</java.version> <spring-boot.version>3.4.0</spring-boot.version> <spring-ai.version>1.0.0</spring-ai.version> <spring-ai-alibaba.version>1.0.0.3</spring-ai-alibaba.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-bom</artifactId> <version>${spring-ai.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-bom</artifactId> <version>${spring-ai-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>然后在dependencies里加核心 starter:
<dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-starter-dashscope</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>注意spring-ai-alibaba-starter-dashscope不需要写版本号,BOM 已经管了。Java 版本要求 17 以上,Spring Boot 3.4.0 对应的是 Spring Framework 6,别用 JDK 8 去跑。
接下来是application.yml,这是整篇最关键的一段:
server: port: 888 spring: ai: dashscope: api-key: ${TAOTOKEN_API_KEY} base-url: https://taotoken.net/api chat: options: model: qwen-plus temperature: 0.7逐行解释一下。api-key读环境变量,避免明文。base-url指向 TaoToken 的 API 地址,这是把请求从默认 DashScope 切过来的关键。chat.options.model指定模型 ID,这里用qwen-plus,你也可以换成别的可用模型。temperature控制随机性,0.7 是个比较平衡的值。
如果你用的是application.properties格式,等价写法是:
spring.ai.dashscope.api-key=${TAOTOKEN_API_KEY} spring.ai.dashscope.base-url=https://taotoken.net/api spring.ai.dashscope.chat.options.model=qwen-plus两种格式选一种就行,别混用。配置写完后,Spring Boot 启动时会自动装配DashScopeChatModel这个 Bean,你直接注入就能用。
4. 启动类与 Controller:写第一个可验证的对话接口
配置好了,现在写代码。先看启动类,标准的 Spring Boot 入口:
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); } }然后写一个 Controller,暴露两个接口:一个普通调用,一个流式调用。普通调用返回完整字符串,流式调用返回Flux<String>,适合做打字机效果。
package com.example.demo.controller; import lombok.RequiredArgsConstructor; import org.springframework.ai.chat.model.ChatModel; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Flux; @RequiredArgsConstructor @RestController public class ChatController { private final ChatModel chatModel; @GetMapping("/chat") public String chat(@RequestParam String msg) { return chatModel.call(msg); } @GetMapping("/stream/chat") public Flux<String> streamChat(@RequestParam String msg) { return chatModel.stream(msg); } }ChatModel是 Spring AI 的核心接口,call是同步阻塞,stream是响应式流。这里注入的是DashScopeChatModel,因为 starter 自动配置了它。@RequiredArgsConstructor是 Lombok 的注解,帮你生成构造器注入,没装 Lombok 的话手写构造器也行。
启动服务:
mvn spring-boot:run看到控制台打印Started DemoApplication就说明起来了。如果启动时报No qualifying bean of type 'org.springframework.ai.chat.model.ChatModel',八成是api-key没读到,检查环境变量是否生效。
服务起来后,用 curl 验证一下。这是整篇最关键的检查动作:
curl "http://localhost:888/chat?msg=用一句话介绍Spring%20AI%20Alibaba"预期返回是一段中文文本,类似:
Spring AI Alibaba 是阿里云推出的、基于 Spring AI 的 Java 框架,用于快速接入通义千问等大模型能力。如果你想要更结构化的验证,可以看流式接口:
curl -N "http://localhost:888/stream/chat?msg=你好"-N参数关闭 curl 的缓冲,你会看到文字一段段吐出来,每段是 SSE 格式的data:行。这说明流式链路也通了。
到这里,第一条链路就跑通了。整个过程的核心就是base-url那一行配置,把它指向 TaoToken 的 API 地址,其余代码和官方示例完全一致。
5. 常见报错排查:401、local proxy failed、reading choices 怎么解
跑通之后,我把踩过的坑整理一下,你遇到报错可以对照。
报错一:401 Unauthorized 或 invalid api key
返回体里带"code":"InvalidApiKey"或 HTTP 401。原因通常是api-key没读到或者 Key 本身失效。排查顺序:先在终端echo $TAOTOKEN_API_KEY确认环境变量有值;再确认application.yml里写的是${TAOTOKEN_API_KEY}而不是别的变量名;最后去控制台https://taotoken.net/api-keys看这个 Key 是否被删了或者过期。注意 Key 前后不要有空格,YAML 里冒号后面要有一个空格。
报错二:local proxy failed 或 connection refused
这个报错说明请求根本没发出去,卡在网络层。常见原因是base-url写错了,比如写成了https://taotoken.net/api/带尾斜杠,或者写成了http://而不是https://。还有一种情况是本地开了某些网络工具,导致请求被劫持。先确认base-url是https://taotoken.net/api,然后关掉本地不必要的网络软件再试。如果公司网络有出口限制,换一个网络环境验证。
报错三:Error reading choices 或 JSON parse error
请求发出去了,返回也回来了,但解析失败。这种多半是base-url指向了一个返回非标准结构的地址。Spring AI Alibaba 期望的响应结构里有choices数组,如果返回的是 HTML 错误页或者别的 JSON 结构,就会报这个。检查base-url是否精确等于https://taotoken.net/api,不要多加/v1或/chat。另外确认model字段填的模型 ID 是真实存在的,填错模型有时会返回非预期结构。
报错四:OAuth 或 token 相关错误
如果你看到OAuth字样,通常是把别的认证方式混进来了。Spring AI Alibaba 的 DashScope starter 用的是 API Key 认证,不需要 OAuth 流程。确认你没有额外引入别的认证 starter,也没有在配置里写spring.ai.dashscope.oauth之类的字段。
报错五:启动时 Bean 找不到
No qualifying bean of type 'DashScopeChatModel'说明 starter 没生效。检查pom.xml里spring-ai-alibaba-starter-dashscope是否真的加进去了,以及dependencyManagement里的 BOM 是否 import 成功。有时候 IDE 没刷新 Maven,执行一次mvn clean compile强制重新拉依赖。
排查的时候有个通用技巧:把日志级别调到 DEBUG,在application.yml里加:
logging: level: com.alibaba.cloud.ai: DEBUG org.springframework.ai: DEBUG这样能看到请求的完整 URL 和响应体,定位问题快很多。
6. 继续深入:从 Demo 到可用服务的下一步
Demo 跑通只是起点。如果你打算把它用到实际项目里,有几个方向可以继续。
第一是加对话记忆。默认的ChatModel.call是无状态的,每次请求都是独立的。要做多轮对话,需要引入ChatMemory和MessageChatMemoryAdvisor,把历史消息存起来。Spring AI Alibaba 提供了基于 JDBC 的记忆实现,可以存到 MySQL。
第二是加 Advisor 做统一处理。比如日志记录用SimpleLoggerAdvisor,敏感词拦截用SafeGuardAdvisor,这些都能在ChatClient.builder()时挂上去,不用改业务代码。
第三是流式接口的工程化。Flux<String>直接返回给前端时,记得设置Content-Type: text/event-stream,并且处理好客户端断开连接的情况,否则容易泄漏连接。
第四是模型切换。如果你需要在不同模型之间动态切换,可以维护一个Map<String, ChatModel>,根据请求参数选对应的模型,再构建ChatClient。这在做 A/B 测试或者成本优化时很有用。
如果你打算长期在编码场景里用这套能力,可以了解一下 Coding Plan,它针对代码补全、Agent 这类高频调用场景做了优化。地址是https://taotoken.net/coding-plan。
最后提醒一句:base-url和api-key这两项配置,建议放在环境变量或配置中心里,不要写死在代码仓库。Demo 阶段图方便可以写在application.yml,上线前一定要改掉。接入文档在https://taotoken.net/doc,遇到配置项不确定的时候去翻一下,比搜索引擎靠谱。