跳到主要内容
Router One

把 Spring AI 的 OpenAI starter 接到 Router One

Spring AI 为 Spring Boot 应用提供统一的 ChatClient 模型 API。它的 OpenAI starter 发送的是 Chat Completions 请求,所以一把 Router One Key 就能调用目录里在 /v1/chat/completions 上提供服务的所有聊天模型,每次请求都有成本 Trace。不同版本线唯一的差别在 base-url:Spring AI 2.0.x 把这个值交给官方 openai-java SDK,由 SDK 自行拼接 /chat/completions;1.x 则自己拼接 /v1/chat/completions。本指南两条版本线都覆盖,最后用一次普通调用和一次流式输出做验证。

引入 Spring AI BOM 和 OpenAI starter

Spring AI 的正式版发布在 Maven Central,不需要额外配置仓库。导入 spring-ai-bom,再添加 spring-ai-starter-model-openai;这个 starter 会带上 OpenAI 聊天模型实现、自动配置,以及本指南要注入的 ChatClient.Builder。BOM 版本要和你的 Spring Boot 版本线匹配:Spring AI 2.0.x(写作时为 2.0.1)支持 Spring Boot 4.0.x 和 4.1.x,Spring AI 1.1.x(1.1.8)支持 Spring Boot 3.4.x 和 3.5.x。两条版本线的依赖坐标相同,只有版本号不同。

pom.xml
<!-- pom.xml: Spring AI 2.0.x on Spring Boot 4.x; use 1.1.8 with Spring Boot 3.4/3.5 -->
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-bom</artifactId>
      <version>2.0.1</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-openai</artifactId>
  </dependency>
</dependencies>

把 Spring AI 配置到 Router One base URL

Spring AI 2.0.x 只需在 src/main/resources/application.yml 里设置三个属性。base-url 填 https://api.router.one/v1,要带 /v1:2.0 会把这个值原样传给 openai-java SDK,由 SDK 自行在后面拼接 /chat/completions(SDK 自己的默认地址本来就以 /v1 结尾,虽然 2.0.1 文档的属性表仍写着旧的纯主机默认值)。api-key 通过 Spring 占位符读取 ROUTER_ONE_API_KEY,这个变量名是本指南定义的,刻意不用 OPENAI_API_KEY——因为属性留空时,2.0 会回退读取环境里的 OPENAI_API_KEY 和 OPENAI_BASE_URL。chat.model 填目录里的精确模型 ID,若 ID 自带 provider 前缀也要保留;2.0 去掉了原来 chat.options.* 里的 options 这一层,旧名字仍能绑定,但已标记为弃用:

application.yml
# src/main/resources/application.yml: Spring AI 2.0.x (Spring Boot 4.x)
spring:
  ai:
    openai:
      base-url: https://api.router.one/v1
      api-key: ${ROUTER_ONE_API_KEY}
      chat:
        model: <model-id-from-/models>

# Shell (macOS/Linux) before starting the app:
# export ROUTER_ONE_API_KEY=sk-your-router-one-key

Spring AI 1.x:主机根地址加 completions-path

Spring AI 1.0.x 和 1.1.x 自己拼接请求地址:base-url 加上 chat.completions-path 属性,后者默认值是 /v1/chat/completions。所以在 1.x 上,base-url 填不带 /v1 的主机根地址 https://api.router.one,模型 ID 写在 chat.options.model 下。如果这里仍然带着 /v1,请求会被发到 /v1/v1/chat/completions。下面的 completions-path 一行就是默认值,写出来只是为了让拼接方式一目了然。另外,1.x 会通过属性默认把 temperature 设为 0.7,而 2.0 只在你设置时才发送 temperature:

application.yml (Spring AI 1.x)
# application.yml: Spring AI 1.0.x / 1.1.x (Spring Boot 3.4 / 3.5)
spring:
  ai:
    openai:
      base-url: https://api.router.one
      api-key: ${ROUTER_ONE_API_KEY}
      chat:
        completions-path: /v1/chat/completions
        options:
          model: <model-id-from-/models>

各版本线该填什么

两条版本线都是 Maven Central 上的正式版(写作时为 2.0.1 和 1.1.8),依赖坐标相同;1.0 之前里程碑版本使用的 spring-ai-openai-spring-boot-starter 这个名字止步于 1.0.0-M6。按你运行的 Spring Boot 版本线对照下表:

Spring AISpring Bootspring.ai.openai.base-url模型属性路径由谁拼接
2.0.x(2.0.1)4.0.x / 4.1.xhttps://api.router.one/v1spring.ai.openai.chat.modelopenai-java SDK 拼接 /chat/completions
1.1.x(1.1.8)、1.0.x(1.0.9)3.4.x / 3.5.xhttps://api.router.onespring.ai.openai.chat.options.modelspring.ai.openai.chat.completions-path,默认 /v1/chat/completions

用 ChatClient 各做一次普通调用和流式调用

注入自动配置的 ChatClient.Builder,构建 ChatClient,先做一次普通 call()——模型和端点都来自上面的属性,代码里不用重复。然后调用 stream().content(),它返回 Reactor 的 Flux<String>;Spring AI 的 ChatClient 文档说明流式输出运行在响应式技术栈上。启动应用,确认两段输出都正常,再去加工具调用、对话记忆或结构化输出;这些都留在你的应用里,网关只记录每次模型请求:

RouterOneSmokeTest.java
package com.example.demo;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
class RouterOneSmokeTest {

  @Bean
  CommandLineRunner routerOneSmokeTest(ChatClient.Builder builder) {
    ChatClient chatClient = builder.build();
    return args -> {
      // One plain call first; the model comes from spring.ai.openai.chat.model
      String reply = chatClient.prompt()
          .user("Reply with one short greeting.")
          .call()
          .content();
      System.out.println(reply);

      // Then streaming: a Flux<String> from the same ChatClient
      chatClient.prompt()
          .user("Count from 1 to 5, one number per line.")
          .stream()
          .content()
          .doOnNext(System.out::print)
          .blockLast();
    };
  }
}

Spring AI 该填哪个模型 ID?

从 /models 页复制精确的模型 ID,保留大小写、连字符和版本后缀,不要用展示名称代替。打开该模型的详情页,核对支持的 API 端点、上下文窗口和工具调用等能力,再与 Spring AI 当前选择的 provider 和功能对应。模型出现在目录里,不等于当前客户端能调用它的所有功能。建议为每个工具单独建 API Key,并设置 maxSpend 消费上限。

Spring AI 用的是哪种 API 协议?

OpenAI 兼容描述的是接口格式,不能据此推断 Chat Completions(/v1/chat/completions)、Responses(/v1/responses)和 Anthropic Messages(/v1/messages)可以互换。先核对工具当前版本、provider 配置和实际请求路径,再查模型详情与 API 兼容性事实页。一次普通对话成功,也不能证明服务端工具、历史状态或文件编辑功能都受支持。

在 trace 里验证 Spring AI 的调用

先在 Spring AI 发出一次简单文本请求,再到 Dashboard → Logs 按时间、模型和 request_id 核对 trace:tokens、花费、延迟和状态码。成功后再分别验证流式输出、工具调用和多轮历史。失败时保留实际请求路径、完整错误消息及 request_id;没有对应日志时,先查客户端配置和网络,不能仅凭客户端报错认定是网关或上游故障。

常见问题

Spring AI 的 OpenAI starter 用的是 Responses API 吗?

不是。这个 starter 把 Chat Completions 请求发到 /v1/chat/completions;Spring AI 2.0.1 文档明确写着 Responses API 是另一个端点,当前客户端不支持。因此只存在于 /v1/responses 上的功能(托管工具、previous_response_id、对话状态)在这个 starter 里用不到,模型是否支持 Responses 在这里也不重要——要看的是模型详情页是否列出 POST /v1/chat/completions。

从 Spring AI 1.x 升到 2.0 之后请求变成 404,哪里变了?

变了两处。一是 base-url 现在必须带 /v1:2.0 把它直接交给 openai-java SDK,也不再有 completions-path 属性;沿用旧的主机根地址时,请求会发到 /chat/completions,网关返回 404 的 not_found 错误,消息里会直接说明 OpenAI 兼容客户端需要以 /v1 结尾的 base URL。二是 chat.options.* 属性改成了 chat.*,旧名字仍能绑定,但已标记为弃用并将移除。两处都改完后,重新跑一次普通调用。

为什么一次 ChatClient 调用在 Logs 里出现好几条请求?

客户端重试。2.0 里 openai-java SDK 会对 408、409、429、5xx 响应和连接错误重试,次数上限是 spring.ai.openai.max-retries(文档默认 3);1.x 则由 spring.ai.retry 重试模板处理,上限是 spring.ai.retry.max-attempts(文档默认 10),默认不重试 4xx,除非打开 on-client-errors。每一次到达网关的尝试都是独立请求,有各自的 Trace 和费用;而网关在同一次请求内做的同系列故障转移只算一条 Trace。批处理任务建议调低重试次数,并给应用单独配一把设了 maxSpend 的 Key。

调用 Claude 系列模型需要换 Anthropic starter 吗?

本指南的配置不需要。网关的 /v1/chat/completions 服务目录里的所有聊天模型,从 /models 复制的 Claude 系列 ID 和其他模型一样填进 chat.model 即可。Spring AI 的 Anthropic starter 走 /v1/messages 的 Anthropic Messages 格式,用的是自己的 spring.ai.anthropic.* 属性,不在本指南范围内,需要单独验证。

1.x 上第一次调用就报 400,错误里提到 temperature,是网关的问题吗?

通常不是。1.x 默认通过属性发送 temperature 0.7,而 Spring AI 文档说明部分 GPT-5 系列模型不接受 temperature 参数。到 Logs 里看完整错误和 request_id:点名该参数的 400 是模型拒绝了它。2.0 只在你设置时才发送 temperature。针对该模型调整 temperature 设置即可,不要去改 base-url 或模型 ID。

Spring AI 能通过网关用哪些模型?

选用当前目录中同时支持 Spring AI 所用端点和所需功能的模型。精确 ID、当前单价与能力以 /models 及模型详情为准;不要仅按 GPT、Claude 等系列名判断兼容性。客户端能列出模型,只证明模型发现成功,仍需验证实际调用。

能列出模型,但调用报 400 或 404,怎么办?

先记录实际请求路径和错误消息,再核对精确模型 ID。400 可能是参数、工具类型或模型与端点不匹配;404 可能是请求路径或资源不存在,不能直接判定模型下线。若错误提示 must be called via,按它指明的端点调整客户端 provider,或换用支持当前端点的模型。不要在所有工具里统一增删 /v1 或 /chat/completions。

中国大陆能直连吗?

能。网关在大陆可直连、无需 VPN,配置与全球环境完全一致。

报 401/402/403/429 怎么排查?

先到 Dashboard → Logs 核对请求及错误消息。401 查 Key 是否传入和有效;402 查钱包余额与 maxSpend;403 查 Key 权限和访问限制;429 查请求频率、token 限额及上游限流,按错误来源处理。保留 request_id,再按错误码速查页逐项排查。