
1. SpringAI 应用从零搭建时模型接入为什么总卡在第一步很多 Java 后端开发者第一次接触 SpringAI 大模型应用开发卡住的地方往往不是业务逻辑而是模型接入这一环。你可能会遇到这样的场景项目骨架搭好了pom 依赖也引入了结果一跑起来就报401 Unauthorized或者Connection refused又或者返回的 JSON 里choices字段是空的。这些问题背后通常不是代码写错了而是 base-url 和 api-key 这两个配置项没有对齐。SpringAI 的设计思路是屏蔽底层不同厂商大模型接口的差异给你一个统一的ChatClient调用入口。但统一的前提是你得先告诉它请求发往哪里、用什么身份认证。对于 Java 后端开发者来说最熟悉的配置方式就是application.yml或application.properties。SpringAI 通过spring.ai.openai前缀来读取这些配置其中base-url决定请求地址api-key决定身份凭证。这里有一个常见的认知误区很多人以为base-url必须填某个特定厂商的地址其实它填的是一个兼容 OpenAI 接口规范的端点。TaoToken 提供的统一 Key 接入方式就是让你用一个 Key 对接多个模型base-url 指向 TaoToken 的 API 地址api-key 填你在 TaoToken 申请的 Key。这样你的 SpringAI 应用不需要为每个模型单独改代码只需要在配置里切换模型 ID 即可。适合谁看这篇内容如果你是有 Spring Boot 基础、想快速跑通第一个 SpringAI 应用的 Java 后端开发者或者你已经在用 LangChain4j 但想试试 SpringAI 的接入方式这篇内容会给你一套可复制的配置片段和验证步骤。我试过从零搭一个最小可运行项目踩过的坑主要集中在配置项的命名和请求路径的拼接上下面会逐一说明。SpringAI 目前对 OpenAI 兼容接口的支持比较成熟spring-ai-starter-model-openai这个 starter 可以直接用。你不需要自己写 HTTP 客户端也不需要手动拼 JSON 请求体。框架会帮你把ChatClient.prompt().user(你好).call().content()这样的链式调用转换成标准的/v1/chat/completions请求。理解这一点之后配置就变成了唯一需要关注的事情。2. TaoToken 统一 Key 的前置准备与申请位置在写配置之前你需要先拿到一个可用的 API Key。TaoToken 的定位是统一 Key 接入层你可以在它的控制台里创建一个 Key然后这个 Key 就能用来调用它支持的多个模型。申请入口在官网的 console 页面具体路径是https://taotoken.net/console登录后找到 API Keys 管理区域点击创建即可。创建 Key 的时候建议你给它起一个能区分用途的名字比如springai-demo这样后面如果有多个项目排查问题时能快速定位是哪个 Key 在调用。Key 创建后会显示一次复制下来保存好页面上不会再完整展示第二次。如果你不小心弄丢了只能删掉重新建一个。拿到 Key 之后你还需要确认两件事一是 base-url 填什么二是模型 ID 填什么。TaoToken 的 API 地址是https://taotoken.net/api这个地址就是 SpringAI 配置里base-url的值。注意不要在后面多加/v1SpringAI 的 OpenAI starter 会自动拼接/v1/chat/completions路径。如果你手动加了/v1最终请求路径会变成/v1/v1/chat/completions直接 404。模型 ID 方面TaoToken 支持多个模型你可以在模型对话页面查看当前可用的模型列表。对于第一次跑通验证建议选一个响应速度快的模型比如gpt-4o-mini或claude-3-5-sonnet这类。模型 ID 要填完整不要自己简写。比如gpt-4o-mini不能写成gpt4o否则请求会返回模型不存在的错误。还有一个容易被忽略的点SpringAI 的配置项在application.yml里是嵌套结构base-url和api-key都在spring.ai.openai下面。如果你用的是application.properties写法是spring.ai.openai.base-url...和spring.ai.openai.api-key...。两种格式选一种就行不要混用。我建议用 YAML因为层级关系更直观后面加其他配置也不容易乱。3. application.yml 中 base-url 与 api-key 的可复制配置片段下面是一份可以直接复制到src/main/resources/application.yml的配置片段。这份配置假设你用的是 Spring Boot 3.x 和 SpringAI 1.0.x依赖里引入了spring-ai-starter-model-openai。server: port: 8080 spring: application: name: springai-demo ai: openai: base-url: https://taotoken.net/api api-key: sk-你的TaoTokenKey chat: options: model: gpt-4o-mini temperature: 0.7 embedding: options: model: text-embedding-3-small这份配置里base-url指向 TaoToken 的 API 地址api-key填你申请到的 Key。chat.options.model指定对话模型temperature控制随机性0.7 是一个比较通用的值。embedding.options.model是给向量化用的如果你暂时不做 RAG这一项可以先不配但留着也不影响启动。对应的 Maven 依赖需要加在pom.xml里。SpringAI 的 BOM 要放在dependencyManagement中starter 放在dependencies中。版本号建议用 1.0.1 或更高因为早期版本对 OpenAI 兼容接口的支持有一些边界问题。dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version1.0.1/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-openai/artifactId /dependency /dependencies如果你用的是 Gradle写法类似implementation platform(org.springframework.ai:spring-ai-bom:1.0.1)加上implementation org.springframework.ai:spring-ai-starter-model-openai。注意 Spring Boot 的版本要 3.2 以上因为 SpringAI 1.0.x 依赖 Spring Framework 6.x 和 Java 17。配置写完之后启动类不需要额外加注解Spring Boot 的自动配置会扫描到spring.ai.openai前缀并创建ChatClient.BuilderBean。你只需要在需要的地方注入ChatClient.Builder然后 build 出ChatClient实例即可。这里有一个细节如果你在多个地方注入ChatClient.Builder每次 build 出来的实例是独立的但底层共享同一个模型客户端不会重复创建连接池。注意api-key不要直接提交到 Git 仓库。建议用环境变量覆盖比如在application.yml里写api-key: ${TAOTOKEN_API_KEY}然后在启动时通过export TAOTOKEN_API_KEYsk-xxx注入。这样既安全也方便在不同环境切换 Key。4. 一次对话接口调用验证连通性与返回结果配置就绪后写一个最简单的 Controller 来验证连通性。这个 Controller 暴露一个 GET 接口接收用户输入调用ChatClient返回模型回复。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(/ai/chat) public String chat(RequestParam(message) String message) { return chatClient.prompt() .user(message) .call() .content(); } }启动项目后用 curl 发一个请求curl http://localhost:8080/ai/chat?message你好请用一句话介绍SpringAI如果配置正确你会看到类似这样的返回SpringAI 是 Spring 生态中用于简化大模型应用开发的框架提供统一的 ChatClient 接口来对接不同厂商的模型。返回内容的具体措辞取决于模型但关键是你能拿到非空的文本。如果返回的是空字符串或者抛出了异常说明请求没有成功到达模型端。这时候你需要看控制台的日志SpringAI 会把请求的 URL、状态码和响应体打印出来。一个更贴近实际开发的验证方式是写一个流式接口因为很多对话场景需要逐字输出。SpringAI 支持stream()方法返回FluxString配合produces MediaType.TEXT_EVENT_STREAM_VALUE就能实现 SSE 流式响应。import org.springframework.http.MediaType; 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; RestController public class StreamController { private final ChatClient chatClient; public StreamController(ChatClient.Builder builder) { this.chatClient builder.build(); } GetMapping(value /ai/stream, produces MediaType.TEXT_EVENT_STREAM_VALUE) public FluxString stream(RequestParam(message) String message) { return chatClient.prompt() .user(message) .stream() .content(); } }用 curl 测试流式接口时加-N参数禁用缓冲curl -N http://localhost:8080/ai/stream?message请分三点说明SpringAI的优势你会看到内容逐段返回每段之间有时间间隔。这说明流式通道打通了。如果流式接口卡住不返回但非流式接口正常通常是响应头或缓冲区的问题检查produces是否设置正确。验证成功后你可以把model换成另一个模型 ID比如claude-3-5-sonnet重启项目再调一次。如果也能正常返回说明 TaoToken 的统一 Key 接入确实做到了模型切换只改配置、不改代码。这个验证过程大概需要 5 分钟但能帮你排除掉后面开发中 80% 的接入类问题。5. 本篇常见错误排查401、local proxy failed、reading choices接入过程中最常见的报错有三个下面逐一对照排查。第一个是401 Unauthorized。这个错误说明请求到达了服务端但身份认证没通过。可能的原因有三个api-key 填错了、Key 被禁用或删除了、或者 base-url 指向了一个不需要认证的地址但请求里带了 Key。排查方法是先用 curl 直接调 TaoToken 的 API看返回什么。curl -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-你的Key \ -H Content-Type: application/json \ -d {model:gpt-4o-mini,messages:[{role:user,content:hi}]}如果这个 curl 返回 401说明 Key 本身有问题去 console 重新生成一个。如果 curl 正常但 SpringAI 报 401检查application.yml里api-key的值有没有多余空格或者是不是被环境变量覆盖成了空值。第二个是local proxy failed或Connection refused。这个错误通常出现在你本地配了代理但代理没有启动或者 SpringAI 的请求走了代理但代理不支持 HTTPS。排查方法是检查环境变量HTTP_PROXY和HTTPS_PROXY是否设置。如果设置了但代理不可用临时取消这两个环境变量再启动项目。另外如果你在application.yml里手动配了spring.ai.openai.base-url指向localhost或某个内网地址也会出现这个错误确认 base-url 是https://taotoken.net/api。第三个是reading choices相关的反序列化错误比如Cannot deserialize value of type ... from Array value或者choices字段为 null。这个错误说明请求成功了但返回的 JSON 结构不符合 SpringAI 预期的 OpenAI 格式。可能的原因是 base-url 指向了一个非 OpenAI 兼容的接口或者模型 ID 填错了导致服务端返回了错误结构。排查方法是看完整响应体SpringAI 的日志里会打印原始 JSON。如果响应体里是{error: model not found}那就是模型 ID 的问题去模型对话页面确认可用的模型名称。还有一个容易混淆的报错是OAuth相关的比如invalid_token或token expired。TaoToken 的 Key 是长期有效的不存在过期问题但如果你在代码里手动构造了 Authorization 头可能会覆盖 SpringAI 自动生成的 Bearer 头导致格式错误。检查你的代码里有没有手动设置Authorization的地方有的话删掉让 SpringAI 自己处理。提示排查问题时把 SpringAI 的日志级别调到 DEBUG在application.yml里加logging.level.org.springframework.ai: DEBUG这样能看到完整的请求 URL、请求头和响应体定位问题会快很多。6. 从验证到落地SpringAI 应用接入后的下一步跑通第一个对话接口之后你可以沿着几个方向继续深入。一个是把ChatClient的调用封装成 Service加上系统提示词和对话记忆。SpringAI 提供了MessageChatMemoryAdvisor配合MessageWindowChatMemory可以实现多轮对话。你只需要在 buildChatClient的时候加上.defaultAdvisors(...)然后在调用时传入conversationId参数框架会自动管理上下文窗口。另一个方向是结构化输出。SpringAI 的.entity()方法可以把模型返回的文本直接映射成 Java 对象或 List底层用的是ListOutputConverter或BeanOutputConverter。这对于需要把模型输出接入业务逻辑的场景很实用比如让模型返回一组候选名称你直接拿到ListString而不是自己解析字符串。如果你打算长期做编码类或 Agent 类应用可以关注 TaoToken 的 Coding Plan它针对高频调用场景做了额度优化。接入方式不变还是同一个 base-url 和 api-key只是在模型选择和调用频率上更适合持续开发。对于需要验证多个模型效果的场景模型对话页面可以快速切换模型对比输出不用改代码。接入文档里有更完整的参数说明和错误码对照遇到配置项不确定的时候可以查一下。API Keys 管理页面可以随时创建和删除 Key建议给不同项目分配不同的 Key方便追踪调用来源。这些入口都在同一个控制台里用起来比较顺手。最后说一个实际开发中的小技巧把base-url和model做成可配置项通过 Spring 的ConfigurationProperties绑定到一个配置类里这样切换模型时只需要改配置文件不用重新编译。如果你有多个环境开发、测试、生产可以用 Spring 的 profile 机制给每个环境配不同的 Key 和模型避免开发环境的调试请求影响到生产额度。