1. 为什么你的第一个 Spring AI 工程总是卡在配置这一步
很多 Java 开发者第一次接触 Spring AI,卡住的地方往往不是代码逻辑,而是配置。你打开官方文档,看到spring-ai-openai-spring-boot-starter这个依赖,兴冲冲加进pom.xml,然后在application.yml里填上api-key,启动,报错。再改,再报错。折腾半小时,连一句“Hello”都没让模型说出来。
这个场景太常见了。Spring AI 本身的设计是优雅的,它把 ChatClient 抽象成类似 RestTemplate 的调用方式,让你用几行代码就能完成一次对话。但它的配置项分散在 starter、autoconfigure、model 三个层次里,初学者很容易把base-url和api-key放错位置,或者漏掉spring.ai.openai.chat.options.model这个必填项。
我试过从零搭一个最小可运行工程,目标很明确:引入 starter,用 TaoToken 统一 Key 打通 API 通道,完成 ChatClient 注入,发一次对话请求,看到返回。整个过程不需要向量库、不需要 Function Calling、不需要流式响应,就是一个能跑通的最小骨架。这篇文章就把这个骨架完整拆给你,包括 pom 依赖、application.yml、Java Config 两种配置方式,以及启动后怎么用 curl 验证。
适合谁看?如果你会 Spring Boot,写过@RestController,但对 Spring AI 完全陌生,这篇就是你的第一块踏板。如果你已经用过 OpenAI 原生 HTTP 调用,想看看 Spring AI 的封装到底省了什么,也能从这里找到对照。
TaoToken 在这里的角色是一个统一的 API 通道。你不需要在代码里硬编码某个厂商的地址,也不需要为不同模型维护多套 Key。一个 Key,一个 base-url,Spring AI 的 OpenAI starter 就能直接对接。官网入口在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 地址是 https://taotoken.net/api ,注意这个地址后面不加 UTM 参数,直接用于配置。
下面从依赖开始,一步步把工程搭起来。
2. TaoToken 前置准备:拿到统一 Key 和 API 地址
在写任何 Java 代码之前,你需要先拿到两样东西:一个可用的 API Key,和一个正确的 base-url。TaoToken 的 API 地址是https://taotoken.net/api,这个地址在 Spring AI 的配置里会作为base-url使用。注意,Spring AI 的 OpenAI starter 默认会拼接/v1/chat/completions这样的路径,所以 base-url 只需要写到/api这一层,不要自己补/v1。
Key 的获取在控制台完成。打开 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,登录后进入 API Keys 页面,创建一个新的 Key。创建时建议给它起一个能识别用途的名字,比如spring-ai-demo,这样以后在多个项目里复用时不会搞混。创建完成后,Key 只会显示一次,复制下来存到安全的地方。
注意:不要把 Key 直接提交到 Git 仓库。本地开发可以用环境变量,或者在
application.yml里引用${TAOTOKEN_API_KEY},然后在 IDE 的运行配置里设置环境变量。后面我会给出两种配置方式的完整写法。
如果你还没有账号,先通过官网注册:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。注册流程不复杂,这里不展开,重点放在拿到 Key 之后怎么配到 Spring Boot 工程里。
拿到 Key 之后,建议先用 curl 验证一下通道是否通畅。这一步能帮你排除掉“Key 本身有问题”和“Spring 配置有问题”之间的混淆。命令如下:
curl -X POST https://taotoken.net/api/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -d '{ "model": "gpt-4o-mini", "messages": [{"role": "user", "content": "用一句话说明什么是Spring AI"}] }'如果返回的 JSON 里有choices[0].message.content,说明 Key 和通道都没问题。如果返回 401,检查 Key 是否复制完整;如果返回 404,检查 base-url 是否写成了https://taotoken.net/api而不是别的路径。这一步过了,再进 Spring 工程,排障范围就小很多。
3. 可复制配置:pom 依赖 + application.yml + Java Config 骨架
3.1 pom.xml 依赖
Spring AI 的版本迭代比较快,建议用 Spring Boot 3.2.x 搭配 Spring AI 1.0.0-M6 或更高版本。下面是最小依赖集,只引入 OpenAI starter 和 Web 模块,不需要额外引入 HTTP 客户端,starter 会自动带进来。
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.5</version> <relativePath/> </parent> <properties> <java.version>17</java.version> <spring-ai.version>1.0.0-M6</spring-ai.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> <version>${spring-ai.version}</version> </dependency> </dependencies> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>注意spring-ai-openai-spring-boot-starter在 M6 版本里是独立 starter,不需要再手动加spring-ai-core。如果你用的版本不同,依赖坐标可能有变化,以官方仓库为准。repositories里的 milestone 仓库必须加,因为 Spring AI 的正式版还没发布到 Maven Central。
3.2 application.yml 配置方式
这是最直接的方式,适合快速验证。把 Key 和 base-url 写在配置文件里,Spring AI 的 autoconfigure 会自动读取并创建 ChatClient.Builder。
spring: ai: openai: api-key: ${TAOTOKEN_API_KEY} base-url: https://taotoken.net/api chat: options: model: gpt-4o-mini temperature: 0.7这里有几个容易踩的坑。第一,base-url不要写成https://taotoken.net/api/v1,Spring AI 会自己拼/v1/chat/completions,多写一层会变成/api/v1/v1/chat/completions,直接 404。第二,api-key用${TAOTOKEN_API_KEY}引用环境变量,不要硬编码。第三,model是必填项,不填会报model must not be null。temperature可选,不写默认 0.7。
如果你在 IDE 里运行,需要在 Run Configuration 里加环境变量TAOTOKEN_API_KEY=你的Key。如果用命令行mvn spring-boot:run,可以这样:
export TAOTOKEN_API_KEY=你的Key mvn spring-boot:run3.3 Java Config 配置方式
有些团队不喜欢把 AI 配置散落在 yml 里,更倾向于用@Configuration类集中管理。Spring AI 提供了OpenAiApi和OpenAiChatModel两个核心类,你可以手动构造 Bean。
@Configuration public class ChatClientConfig { @Value("${taotoken.api-key}") private String apiKey; @Value("${taotoken.base-url}") private String baseUrl; @Bean public OpenAiApi openAiApi() { return OpenAiApi.builder() .baseUrl(baseUrl) .apiKey(apiKey) .build(); } @Bean public OpenAiChatModel openAiChatModel(OpenAiApi openAiApi) { return new OpenAiChatModel(openAiApi, OpenAiChatOptions.builder() .withModel("gpt-4o-mini") .withTemperature(0.7f) .build()); } @Bean public ChatClient chatClient(OpenAiChatModel chatModel) { return ChatClient.builder(chatModel).build(); } }对应的application.yml只需要保留自定义属性:
taotoken: api-key: ${TAOTOKEN_API_KEY} base-url: https://taotoken.net/api这种方式的优点是配置集中、可编程性强,比如你可以在openAiApi()里加拦截器、改超时时间。缺点是代码量比 yml 多,初学者容易在OpenAiChatOptions的 builder 方法名上写错。M6 版本用的是withModel而不是model,如果你升级到更高版本,方法名可能变成model,以实际依赖为准。
两种方式选一种就行,不要同时用。如果 yml 里配了spring.ai.openai,Java Config 里又手动建了OpenAiApiBean,可能会出现 Bean 冲突或者配置覆盖,排查起来很麻烦。
4. 验证请求:启动日志 + curl 调用 + 成功结果
配置写完之后,先写一个最简单的 Controller 来触发对话。不需要复杂的业务逻辑,就是一个 GET 接口,接收一个message参数,返回模型输出。
@RestController @RequestMapping("/ai") public class ChatController { private final ChatClient chatClient; public ChatController(ChatClient chatClient) { this.chatClient = chatClient; } @GetMapping("/chat") public String chat(@RequestParam String message) { return chatClient.prompt() .user(message) .call() .content(); } }启动应用,观察日志。如果配置正确,你会看到类似这样的输出:
o.s.a.o.a.OpenAiApi : OpenAI API base URL: https://taotoken.net/api o.s.a.o.a.OpenAiApi : OpenAI API key set: true o.s.a.o.c.OpenAiChatModel : OpenAI Chat Model initialized with model: gpt-4o-mini Tomcat started on port(s): 8080 (http)关键看两行:base URL是不是https://taotoken.net/api,API key set是不是true。如果 base URL 显示的是默认的https://api.openai.com,说明你的base-url配置没生效,检查 yml 缩进或者 Java Config 是否被扫描到。
启动成功后,用 curl 发一次请求:
curl "http://localhost:8080/ai/chat?message=用一句话说明Spring%20AI是什么"预期返回是一段中文文本,类似:
Spring AI 是一个面向 Java 开发者的 AI 应用框架,它把大模型调用抽象成 Spring 风格的 API,让你用 ChatClient 就能完成对话、嵌入、函数调用等操作。如果你看到的是 500 错误,先看控制台堆栈。最常见的两种:一是401 Unauthorized,Key 不对或没读到环境变量;二是404 Not Found,base-url 多写了/v1。还有一种情况是返回model not found,说明model参数填的模型名在 TaoToken 通道里不可用,换一个常见的模型名试试,比如gpt-4o-mini或gpt-3.5-turbo。
到这里,最小对话链路就通了。从 pom 到 yml 到 Controller 到 curl,整个流程没有多余步骤。你可以把这个工程作为模板,后面加流式、加 Function Calling、加向量库,都是在这个骨架上扩展。
5. 本篇常见错排查:从 401 到 Bean 冲突
5.1 启动报OpenAiApiBean 找不到
如果你用的是 Java Config 方式,但启动时报No qualifying bean of type 'org.springframework.ai.openai.api.OpenAiApi',大概率是@Configuration类没被扫描到。检查启动类上的@SpringBootApplication是否在配置类的父包路径上。如果配置类在com.example.config,启动类在com.example,那没问题;如果启动类在com.example.app,配置类在com.example.config,就需要手动加@ComponentScan。
5.2 401 错误:Key 没读到
application.yml里写${TAOTOKEN_API_KEY},但 IDE 运行配置里没设环境变量,Spring 启动时会把占位符原样注入,导致 Key 变成字符串${TAOTOKEN_API_KEY}。解决办法是在 Run Configuration 的 Environment variables 里加一行TAOTOKEN_API_KEY=你的Key。如果你用.env文件,需要额外引入spring-dotenv依赖,Spring Boot 本身不自动读.env。
5.3 404 错误:base-url 路径写错
Spring AI 的 OpenAI starter 默认拼接路径是/v1/chat/completions。所以 base-url 应该写到https://taotoken.net/api,最终请求地址是https://taotoken.net/api/v1/chat/completions。如果你写成https://taotoken.net/api/v1,最终会变成https://taotoken.net/api/v1/v1/chat/completions,直接 404。这个坑我踩过,日志里能看到完整的请求 URL,对着改就行。
5.4 返回内容为空或乱码
如果 curl 返回 200 但content是空字符串,检查ChatClient的调用链是否完整。.prompt().user(message).call().content()这四步缺一不可。如果返回乱码,检查请求头里的Content-Type和编码,Spring AI 默认用 UTF-8,一般不会有问题。TaoToken 通道返回的是标准 JSON,不会出现二进制乱码。
5.5 同时用 yml 和 Java Config 导致配置覆盖
前面提过,两种方式选一种。如果你在 yml 里配了spring.ai.openai.api-key,又在 Java Config 里手动建了OpenAiApiBean,Spring 会优先使用手动 Bean,yml 里的配置被忽略。这时候如果你改了 yml 里的 Key 但没改 Java Config 里的,就会一直 401。排查方法是看启动日志里OpenAI API key set后面的值,或者直接在openAiApi()方法里打一行日志输出 baseUrl 和 apiKey 的前几位。
5.6 模型名不可用
TaoToken 通道支持的模型列表以控制台或文档为准。如果你填了一个通道不支持的模型名,会返回model not found或类似的错误。解决办法是换一个通用模型名,比如gpt-4o-mini、gpt-3.5-turbo、claude-3-haiku等。具体支持哪些,可以在模型对话页面里试一下,或者查接入文档。
排障的核心思路是:先用 curl 验证通道,再用最小 Spring 工程验证配置,最后才加业务代码。每一步都确认通过,问题就不会堆在一起。
6. 下一步:从最小骨架到可复用的 AI 服务层
跑通这个最小工程之后,你手里就有了一个可运行的 Spring AI 骨架。接下来可以往几个方向扩展。如果你想让对话支持多轮上下文,可以把ChatClient的prompt()换成带messages列表的调用,把历史消息传进去。如果你想做流式输出,把.call()换成.stream(),返回Flux<String>,前端用 SSE 接收。如果你要接入多个模型,可以在 Java Config 里建多个ChatModelBean,用@Qualifier区分。
对于长期做编码和 Agent 开发的场景,建议了解一下 Coding Plan,它提供了更完整的工程化支持,包括 Prompt 管理、成本监控、单元测试等。入口在 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。如果你只是想先验证模型效果,可以直接在模型对话页面里试不同的模型和参数,地址是 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。
接入文档里有更详细的参数说明和示例代码,遇到配置问题时可以对照查阅:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。API Keys 的管理页面在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,需要新建或轮换 Key 的时候从这里进。
最后说一个实用技巧:把ChatClient的调用封装成一个AiService类,对外只暴露业务方法,内部处理异常、重试和日志。这样你的 Controller 不需要知道底层用的是哪个模型,换模型的时候只改配置,不改业务代码。这个封装思路在后面的企业级项目里会反复用到,现在先用最小骨架把路走通,后面加东西就是水到渠成的事。