AI 模型
受众:开发者 摘要:
spring-open-starter-ai-model提供统一 AI 模型调用抽象,负责把模型请求、配置解析和 Provider SPI 收敛到 starter 边界内。
定位
spring-open-starter-ai-model 是 AI 模型调用底座,不承载平台运营、用户 API Key、Token 计量、扣费、套餐和后台管理逻辑。这些业务能力由独立的 spring-open-module-ai 负责。
第一版包名统一为:
com.springopen.starter.ai.model这个命名表示 ai 能力域下的 model 子能力,后续可以自然扩展 com.springopen.starter.ai.gateway、com.springopen.starter.ai.embedding 等独立边界。
设计结构
AI 模型 starter 遵循项目统一 Provider 模型:
Facade -> Manager -> ConfigResolver -> Provider SPI| 组件 | 说明 |
|---|---|
AiModel | 静态 Facade,提供简洁调用入口 |
AiModelManager | 能力主入口,负责选择 Provider 并执行调用 |
AiModelConfigResolver | 解析请求级配置、默认模型和 Provider 配置 |
AiModelProvider | 可替换实现 SPI,隐藏第三方模型服务差异 |
AiModelProviderConfig | Provider 执行配置快照 |
AiModelMetadata | 模型元数据,承载展示名、能力、上下文窗口和输出上限 |
AiModelCapabilities | 模型能力常量,如 chat、stream、vision |
AiModelUsage | 模型用量统计,统一承载输入、输出和总 token 数 |
AiModelTokenEstimator | Token 预估入口,进入 Provider 前用于预检、预占和成本估算 |
AiModelStreamChunk | 流式响应片段,承载增量内容、结束标记和 token 统计 |
AiModelEmbeddingRequest / AiModelEmbeddingResponse | 向量生成 contract,承载 OpenAI Compatible input、encoding_format、dimensions、user 和 embedding 数据列表 |
AiModelError | 统一错误信息,承载错误类型、Provider、模型、上游状态和是否可重试 |
AiModelProviderNames | Provider 名称常量 |
当前已内置 mock、log、simulated、openai-compatible、newapi、account-pool、openai-official、anthropic-official 和 spring-ai Provider:
mock:用于本地验证普通响应、流式响应和 embeddings 调用链。log:用于网关 contract、计量、审计和联调链路冒烟验证;默认只记录调用元信息,不记录 prompt 内容,并提供确定性 embeddings。simulated:用于低成本模拟模型服务机制,支持普通响应、流式响应、embeddings、usage、延迟、限流、超时、上游错误和空响应,不访问外部模型服务。openai-compatible:适配 OpenAI Chat Completions、Embeddings 和 Models 兼容协议,适合 OpenAI、DeepSeek、通义千问兼容模式、Ollama OpenAI endpoint 和企业自建兼容网关等服务。newapi:面向 NewAPI 聚合网关的快速接入 Provider,内置默认关闭的本地预设,默认地址为http://127.0.0.1:3000/v1,协议处理复用 OpenAI Compatible HTTP / SSE //models实现。account-pool:面向本地或私有 OpenAI Compatible HTTP 服务入口,Provider 自身只接收base-url/api-key并转发请求;凭证健康、调度和冷却由 AI 模块运行时治理层完成。openai-official/anthropic-official:官方 SDK 可选桥接 Provider;默认不引入官方 SDK 依赖,只有应用或可选 starter 提供AiModelOfficialSdkClient时参与路由。spring-ai:基于 Spring AI2.0.0的 OpenAI ChatModel 做最小接入,适合验证 Spring AI 生态能力;默认关闭,需要显式启用。
DeepSeek 第一阶段作为正式供应商优先支持,但不单独新增 Java Provider 类。推荐把 deepseek 作为 provider 配置实例名,内部通过 provider: openai-compatible 复用公共底座。
anthropic-compatible、codex-compatible 等协议适配仍在 AI Gateway 模块承接;真实官方 SDK adapter 和外部工具联调放 P2 外部验收。
源码机制骨架
AI Model starter 的核心调用链如下:
AiModel / AiModelManager
-> AiModelConfigResolver
-> AiModelRouteSelector
-> AiModelResilienceExecutor
-> AiModelProvider| 入口 | 源码 | 机制边界 |
|---|---|---|
| Facade | AiModel | 静态入口,委托当前 Spring 容器内的 AiModelManager |
| Manager | DefaultAiModelManager | 校验请求、选择 Provider、展开 fallback、调用韧性执行器并写回路由元数据 |
| 配置解析 | DefaultAiModelConfigResolver | 合并默认 Provider、请求 Provider、请求模型和 Provider 实例配置,生成调用快照 |
| 路由选择 | AiModelRouteSelector | 未显式指定 Provider 时按健康状态、priority、weight 和 preferred Provider 选路 |
| 韧性执行 | AiModelResilienceExecutor | 按 Provider + model 维护 retry、circuit breaker、bulkhead 和 timeout |
| Provider SPI | AiModelProvider | 只负责上游协议转换、模型列表、流式片段和错误映射,不处理平台业务数据 |
| HTTP 兼容实现 | OpenAiCompatibleAiModelProvider | 使用标准 HTTP / Jackson 访问 Chat Completions、SSE 和 /models |
| Spring AI 实现 | SpringAiModelProvider | 通过 Spring AI OpenAI ChatModel 接入兼容上游,仍隐藏在统一 SPI 后 |
路由元数据会写入普通响应和流式片段的 metadata,包含 primaryProvider、actualProvider、fallbackUsed、routeStrategy、routeReason 和候选 Provider 顺序。AI 模块控制面和 AI Gateway 可以用这些字段做审计、计量、排障和运维展示。
DefaultAiModelManager 会先按本次操作需要的能力过滤候选 Provider,再进入 priority、weight、health 和 fallback 选择。chat / stream / embeddings 分别要求 chat、stream、embedding 能力;通用 relay 会通过 AiModelOperationCapabilities 把 endpoint 映射到 completion、response、realtime、image、audio、rerank、file、batch、fine-tuning、assistant、vector-store、eval 等能力。历史轻量 Provider 如果没有声明 capabilities,只保留 chat / stream 兼容,不会被 embeddings 或非对话 relay 误选。
fallback 只处理可恢复的调用失败。认证失败、Provider 禁用、请求参数错误等不可重试错误不会被 fallback 掩盖;模型不存在或模型不可用只有在 model-unavailable-fallback-enabled=true 时才允许切到后备 Provider。
OpenAI Compatible(含 NewAPI、Account Pool)和 Anthropic Compatible Provider 收到上游非 2xx HTTP 响应时,会在映射为 AiModelException 前输出 warn 日志。日志包含协议、operation、Provider 配置名、实现名、凭证名称、模型、HTTP 状态、请求方法、去除 query 和 user-info 的上游 URI,以及最多 4KB 的上游错误体;错误体中的常见密钥字段、Bearer token 和 sk-* 片段会脱敏,正常 2xx 响应不输出该告警。
Spring AI 接入状态
Spring AI 是项目优先复用的上游模型调用生态。当前主线已按开发决策接入 Spring AI 2.0.0,并提供 spring-ai Provider。该 Provider 仍隐藏在 AiModelProvider SPI 后面,业务模块和 Open Platform 网关只调用 AiModelManager,不直接依赖 Spring AI API。
当前 spring-ai Provider 属于最小接入:
- 底层使用 Spring AI OpenAI ChatModel。
- 支持普通响应、流式响应和 usage 转换。
- 支持
base-url、api-key、model、timeout、organization、project、max-retries和stream-usage。 - 模型列表仍返回本地配置的
AiModelMetadata,因为 Spring AI ChatModel 不提供统一/models抽象;需要动态同步官网模型列表时,继续使用openai-compatibleProvider。
后续升级 Spring AI 2.x 小版本时,只需要升级 spring-ai.version 并复跑 AI Model starter 与 Open Platform Gateway 测试,不改变业务调用 contract。
官方 SDK Provider 接入状态
OpenAI 和 Anthropic / Claude 都已有官方 Java SDK。当前默认 starter 暂不引入这些 SDK 依赖,原因是第一阶段 openai-compatible Provider 已覆盖 DeepSeek、OpenAI Compatible、自建兼容网关和开发者工具常用调用路径。
AI Model starter 已提供 openai-official / anthropic-official 桥接 Provider 和 AiModelOfficialSdkClient SPI。应用或后续可选 provider starter 可以自行引入官方 SDK,并把 SDK 调用适配为统一的 AiModelResponse、AiModelStreamChunk 和 AiModelMetadata。没有匹配客户端时,桥接 Provider 会保持 supports=false,Manager 会在 fallback 链中自动跳过它并继续尝试后续 Provider。
官方 SDK adapter 只建议用于这些场景:
- 官方新 API 或特殊字段无法通过兼容 HTTP Provider 稳定表达。
- 需要官方 SDK 特有认证、分页、流式事件或错误类型。
- 开发者显式引入可选 Provider 依赖。
即使接入官方 SDK,业务模块也只调用 AiModelManager / AiModelProvider,不直接依赖官方 SDK API。
快速开始
默认启用:
spring:
open:
ai:
enabled: true
platform:
enabled: true
gateway:
enabled: true
model:
enabled: true
default-provider: ${SPRING_OPEN_AI_MODEL_DEFAULT_PROVIDER:openai-compatible}应用默认配置已经内置 simulated、mock、log、deepseek、openai、openai-compatible、newapi、gemini 和 local-account-pool 这几类 Provider 实例模板。AI Model starter 还会默认注册一批关闭状态的 OpenAI Compatible 渠道预设,用于后台快速启用常见聚合网关、官方兼容接口和本地自托管端点。默认 Provider 名称是 openai-compatible,面向生产时优先接入真实兼容入口;该 Provider 的地址、模型和密钥默认留空,必须由管理员通过后台配置或环境变量显式启用后才会访问真实上游。simulated 默认启用,只用于 Knowledge 等内部能力的低成本降级兜底和本地联调,不作为生产主路由。
兼容渠道预设矩阵
AI Model starter 默认注册的渠道预设都处于 enabled=false,只作为后台 Provider 列表和快速配置模板,不会在启动时访问真实上游。
| 配置实例名 | 实际 Provider | 默认地址 | 类型 | 能力画像 | Relay 画像 |
|---|---|---|---|---|---|
newapi | newapi | http://127.0.0.1:3000/v1 | 聚合网关 | aggregated-openai-compatible | full-relay |
openai | openai-compatible | https://api.openai.com/v1 | 官方兼容接口 | full-openai-compatible | full-relay |
azure-openai | openai-compatible | https://example.openai.azure.com | 官方兼容接口 | deployment-openai-compatible | deployment-relay |
deepseek | openai-compatible | https://api.deepseek.com | 官方兼容接口 | official-openai-compatible | core-relay |
openrouter | openai-compatible | https://openrouter.ai/api/v1 | 聚合网关 | aggregated-openai-compatible | full-relay |
groq | openai-compatible | https://api.groq.com/openai/v1 | 官方兼容接口 | official-openai-compatible | core-relay |
mistral | openai-compatible | https://api.mistral.ai/v1 | 官方兼容接口 | official-openai-compatible | core-relay |
together | openai-compatible | https://api.together.xyz/v1 | 官方兼容接口 | official-openai-compatible | core-relay |
xai | openai-compatible | https://api.x.ai/v1 | 官方兼容接口 | official-openai-compatible | core-relay |
perplexity | openai-compatible | https://api.perplexity.ai | 官方兼容接口 | official-openai-compatible | core-relay |
gemini | openai-compatible | https://generativelanguage.googleapis.com/v1beta/openai | 官方兼容接口 | official-openai-compatible | core-relay |
cerebras | openai-compatible | https://api.cerebras.ai/v1 | 官方兼容接口 | official-openai-compatible | core-relay |
fireworks | openai-compatible | https://api.fireworks.ai/inference/v1 | 官方兼容接口 | official-openai-compatible | core-relay |
sambanova | openai-compatible | https://api.sambanova.ai/v1 | 官方兼容接口 | official-openai-compatible | core-relay |
ollama | openai-compatible | http://127.0.0.1:11434/v1 | 本地自托管 | self-hosted-openai-compatible | full-relay |
lm-studio | openai-compatible | http://127.0.0.1:1234/v1 | 本地自托管 | self-hosted-openai-compatible | full-relay |
vllm | openai-compatible | http://127.0.0.1:8000/v1 | 本地自托管 | self-hosted-openai-compatible | full-relay |
local-account-pool | account-pool | http://127.0.0.1:8000/v1 | 本地凭证池入口 | self-hosted-openai-compatible | full-relay |
这些预设统一声明 chat、completion、response、conversation、eval、realtime、stream、embedding、moderation、image、audio、rerank、file、batch、fine-tuning、vector-store 和 assistant 能力,并默认配置 /chat/completions、/embeddings、/models、/models/{model_id}、/responses、/responses/input_tokens、/responses/compact、/conversations、/conversations/{conversation_id}/items、/evals、/evals/{eval_id}/runs 和 /evals/{eval_id}/runs/{run_id}/output_items 等 OpenAI Compatible 路径。azure-openai 预设按 Azure OpenAI 传统 data plane 入口使用 /openai/deployments/{deployment}/... 路径模板、api-version query 参数和 api-key Header。capability-profile 和 relay-profile 是运营展示和路由治理画像,后台 Provider 列表、路由清单和候选排序都会透出这些字段;运行时真正进入候选集前还会按 operation 能力过滤,避免只支持 chat 的 Provider 承接 embeddings、rerank、file、assistant 等 endpoint。实际是否启用某个 endpoint 仍由管理员的 Provider 配置、模型目录和上游能力共同决定。管理员可以在后台启用任意预设,也可以在 YAML 中覆盖 base-url、api-key、model、capabilities、options.* 和 metadata。
NewAPI 快速接入
NewAPI 对外提供 OpenAI Compatible API。框架内置 newapi Provider 和后台 Provider 预设,管理员只需要在后台启用 newapi、填写 NewAPI 实例的 baseUrl 和 apiKey,再配置模型目录即可作为上游 Provider 使用;也可以通过 YAML 固化配置:
spring:
open:
ai:
model:
default-provider: ${SPRING_OPEN_AI_MODEL_DEFAULT_PROVIDER:newapi}
providers:
newapi:
provider: newapi
enabled: ${SPRING_OPEN_AI_MODEL_PROVIDERS_NEWAPI_ENABLED:true}
model: ${SPRING_OPEN_AI_MODEL_PROVIDERS_NEWAPI_MODEL:gpt-4.1}
display-name: NewAPI
base-url: ${SPRING_OPEN_AI_MODEL_PROVIDERS_NEWAPI_BASE_URL:${NEWAPI_BASE_URL:http://127.0.0.1:3000/v1}}
api-key: ${SPRING_OPEN_AI_MODEL_PROVIDERS_NEWAPI_API_KEY:${NEWAPI_API_KEY:}}
timeout: 30s
capabilities:
- chat
- stream
- embedding
- eval
options:
chat-completions-path: ${SPRING_OPEN_AI_MODEL_PROVIDERS_NEWAPI_CHAT_COMPLETIONS_PATH:/chat/completions}
embeddings-path: ${SPRING_OPEN_AI_MODEL_PROVIDERS_NEWAPI_EMBEDDINGS_PATH:/embeddings}
models-path: ${SPRING_OPEN_AI_MODEL_PROVIDERS_NEWAPI_MODELS_PATH:/models}
model-path: ${SPRING_OPEN_AI_MODEL_PROVIDERS_NEWAPI_MODEL_PATH:/models/{model_id}}
response-input-tokens-path: ${SPRING_OPEN_AI_MODEL_PROVIDERS_NEWAPI_RESPONSE_INPUT_TOKENS_PATH:/responses/input_tokens}
responses-compact-path: ${SPRING_OPEN_AI_MODEL_PROVIDERS_NEWAPI_RESPONSES_COMPACT_PATH:/responses/compact}
conversations-path: ${SPRING_OPEN_AI_MODEL_PROVIDERS_NEWAPI_CONVERSATIONS_PATH:/conversations}
conversation-path: ${SPRING_OPEN_AI_MODEL_PROVIDERS_NEWAPI_CONVERSATION_PATH:/conversations/{conversation_id}}
conversation-items-path: ${SPRING_OPEN_AI_MODEL_PROVIDERS_NEWAPI_CONVERSATION_ITEMS_PATH:/conversations/{conversation_id}/items}
conversation-item-path: ${SPRING_OPEN_AI_MODEL_PROVIDERS_NEWAPI_CONVERSATION_ITEM_PATH:/conversations/{conversation_id}/items/{item_id}}
evals-path: ${SPRING_OPEN_AI_MODEL_PROVIDERS_NEWAPI_EVALS_PATH:/evals}
eval-path: ${SPRING_OPEN_AI_MODEL_PROVIDERS_NEWAPI_EVAL_PATH:/evals/{eval_id}}
eval-runs-path: ${SPRING_OPEN_AI_MODEL_PROVIDERS_NEWAPI_EVAL_RUNS_PATH:/evals/{eval_id}/runs}
eval-run-path: ${SPRING_OPEN_AI_MODEL_PROVIDERS_NEWAPI_EVAL_RUN_PATH:/evals/{eval_id}/runs/{run_id}}
eval-run-output-items-path: ${SPRING_OPEN_AI_MODEL_PROVIDERS_NEWAPI_EVAL_RUN_OUTPUT_ITEMS_PATH:/evals/{eval_id}/runs/{run_id}/output_items}
metadata:
vendor: newapi配置要点:
base-url使用 NewAPI 实例地址,通常以/v1结尾。api-key使用 NewAPI 控制台颁发的令牌。model填 NewAPI 中可用的模型 ID;也可以先调用AiModel.models()从/v1/models读取列表。models-path用于模型列表,model-path用于models.retrieve/models.deleterelay,默认/models/{model_id}。- Responses 辅助子资源默认使用
/responses/input_tokens和/responses/compact;Conversation 生命周期默认使用/conversations、/conversations/{conversation_id}、/conversations/{conversation_id}/items和/conversations/{conversation_id}/items/{item_id};Eval 生命周期默认使用/evals、/evals/{eval_id}、/evals/{eval_id}/runs、/evals/{eval_id}/runs/{run_id}和/evals/{eval_id}/runs/{run_id}/output_items。 - 流式调用使用 OpenAI Compatible SSE 实时 relay,Provider 会边读取上游
data:事件边输出AiModelStreamChunk,不会等待上游整段响应结束后再返回。 - embeddings 调用默认走
/embeddings,可用options.embeddings-path覆盖;input、encoding_format、dimensions和user会按 OpenAI Compatible 结构发送。 - 需要保留低成本默认行为时,不要把
default-provider改成newapi,只在后台 Provider 配置中启用newapi,按业务场景显式指定 Provider。
OpenAI Compatible 参数模板与覆盖
openai-compatible、newapi 和 account-pool 都复用 OpenAI Compatible HTTP 实现,支持通过 Provider 或凭证 options.parameter-template / options.parameter-override 在发送上游请求前调整 JSON payload。该能力只用于合法授权上游之间的接口兼容、企业网络适配和请求归一化,不处理计费、凭证调度或后台运营逻辑。
模板模式用于声明渠道默认参数,会先于覆盖规则执行,只补齐缺失或 null 字段,不替换调用方已经传入的值;嵌套对象会递归补齐。兼容别名为 request-template:
spring:
open:
ai:
model:
providers:
newapi:
options:
parameter-template: >
{
"top_p": 0.9,
"extra_body": {
"reasoning_effort": "medium"
}
}覆盖模式用于强制归一化,会在模板之后执行。简单覆盖会把 JSON 对象直接合并到原始请求;兼容别名为 request-override:
spring:
open:
ai:
model:
providers:
newapi:
options:
parameter-override: >
{
"temperature": 0.3,
"max_tokens": 2000
}模板和覆盖都支持 operations 高级模式,按顺序执行 set、delete、move、copy、append、prepend、trim_prefix、trim_suffix、ensure_prefix、ensure_suffix、trim_space、to_lower、to_upper、replace 和 regex_replace。模板中的 set 默认等价于 keep_origin: true,只在目标字段缺失时写入;确需覆盖可显式设置 keep_origin: false:
spring:
open:
ai:
model:
providers:
newapi:
options:
parameter-template: >
{
"operations": [
{"path": "top_p", "mode": "set", "value": 0.9}
]
}
parameter-override: >
{
"operations": [
{
"path": "messages",
"mode": "prepend",
"value": [
{"role": "system", "content": "请保持专业、简洁。"}
]
},
{
"path": "temperature",
"mode": "set",
"value": 0.2,
"conditions": [
{"path": "messages.-1.content", "mode": "contains", "value": "代码"}
]
},
{"path": "model", "mode": "trim_prefix", "value": "openai/"}
]
}路径使用点号语法,例如 temperature、messages.0.content、messages.-1.content。条件支持 full、prefix、suffix、contains、gt、gte、lt、lte,并可使用 logic: "AND"、invert: true 和 pass_missing_key: true。数据库态凭证池也可以在单个凭证的 options 中配置同名规则,运行时选中凭证后会覆盖 Provider 级同名 option。
代码调用:
List<AiModelMetadata> models = AiModel.models();
AiModelResponse response = AiModel.chat("你好");
String content = response.getContent();也可以注入 AiModelManager:
AiModelRequest request = AiModelRequest.ofUserMessage("请总结这段内容");
AiModelResponse response = aiModelManager.chat(request);
long totalTokens = response.getUsage().getTotalTokens();流式调用:
AiModelRequest request = AiModelRequest.ofUserMessage("请流式回答");
try (Stream<AiModelStreamChunk> stream = aiModelManager.stream(request)) {
stream.forEach(chunk -> {
if (!chunk.isDone()) {
String delta = chunk.getDelta();
// 将 delta 写入 SSE / WebSocket / HTTP chunk。
}
});
}stream(...) 会自动把请求标记为流式请求。Provider 可以直接实现 stream(...),也可以复用默认实现,把普通响应包装为一个增量片段和一个结束片段。
结束片段会携带 AiModelUsage,调用方可以在普通响应和流式响应中使用同一个 usage contract 读取 token 用量:
if (chunk.isDone()) {
long totalTokens = chunk.getUsage().getTotalTokens();
}向量生成调用:
AiModelEmbeddingRequest request = AiModelEmbeddingRequest.of(List.of("hello", "world"));
request.setModel("text-embedding-3-small");
AiModelEmbeddingResponse response = aiModelManager.embeddings(request);
Object firstVector = response.getData().get(0).getEmbedding();input 保持 OpenAI Compatible 语义,可传字符串、字符串列表或 token 数组;encodingFormat、dimensions 和 user 会在兼容 Provider 中映射为 encoding_format、dimensions 和 user。默认 mock / log / simulated Provider 会返回本地确定性向量,便于本地测试和 Knowledge 向量化链路联调;真实 Provider 的向量维度和格式以对应上游模型能力为准。
配置项
| 配置 | 默认值 | 说明 |
|---|---|---|
spring.open.ai.model.enabled | true | 是否启用 AI 模型 starter |
spring.open.ai.model.default-provider | openai-compatible | 默认 Provider 名称;真实调用前需要启用并配置对应 Provider,simulated 默认启用用于内部降级兜底 |
spring.open.ai.model.fallback-providers | [] | 全局 fallback Provider 顺序 |
spring.open.ai.model.timeout | 30s | 默认调用超时时间 |
spring.open.ai.model.model-discovery-timeout | 5s | 默认模型发现超时时间,仅用于上游 /models 控制面探测 |
spring.open.ai.model.resilience.enabled | true | 是否启用 Provider 调用韧性封装 |
spring.open.ai.model.resilience.retry.enabled | true | 是否启用重试 |
spring.open.ai.model.resilience.retry.max-attempts | 2 | 最大尝试次数,包含首次调用 |
spring.open.ai.model.resilience.retry.wait-duration | 200ms | 重试间隔 |
spring.open.ai.model.resilience.circuit-breaker.enabled | true | 是否启用熔断 |
spring.open.ai.model.resilience.circuit-breaker.sliding-window-size | 20 | 熔断滑动窗口大小 |
spring.open.ai.model.resilience.circuit-breaker.minimum-number-of-calls | 10 | 计算失败率前的最小调用次数 |
spring.open.ai.model.resilience.circuit-breaker.failure-rate-threshold | 50 | 熔断失败率阈值 |
spring.open.ai.model.resilience.circuit-breaker.wait-duration-in-open-state | 30s | 熔断打开后的等待时间 |
spring.open.ai.model.resilience.bulkhead.enabled | true | 是否启用并发隔离 |
spring.open.ai.model.resilience.bulkhead.max-concurrent-calls | 50 | 单个 Provider / model 的最大并发调用数 |
spring.open.ai.model.resilience.bulkhead.max-wait-duration | 0s | 等待并发槽位的最长时间 |
spring.open.ai.model.resilience.time-limiter.enabled | true | 是否启用调用超时保护 |
spring.open.ai.model.resilience.time-limiter.cancel-running-future | true | 超时后是否取消底层调用 |
spring.open.ai.model.tokenizer.enabled | true | 是否启用 jtokkit Token 预估 |
spring.open.ai.model.tokenizer.fallback-encoding | cl100k_base | 模型无法匹配时使用的 tokenizer encoding |
spring.open.ai.model.tokenizer.fallback-chars-per-token | 4 | tokenizer 不可用时的字符数兜底估算比例 |
spring.open.ai.model.tokenizer.tokens-per-message | 3 | Chat 消息结构额外 token 预估 |
spring.open.ai.model.tokenizer.tokens-per-name | 1 | 消息 name 字段额外 token 预估 |
spring.open.ai.model.tokenizer.assistant-primer-tokens | 3 | Assistant 回复起始额外 token 预估 |
spring.open.ai.model.providers.<name>.provider | - | 实际 Provider 名称 |
spring.open.ai.model.providers.<name>.enabled | true | 是否启用该 Provider |
spring.open.ai.model.providers.<name>.model | - | Provider 默认模型 |
spring.open.ai.model.providers.<name>.display-name | - | 模型展示名称 |
spring.open.ai.model.providers.<name>.capabilities | [] | 模型能力,未配置时 Provider 可给出默认能力 |
spring.open.ai.model.providers.<name>.context-window | - | 上下文窗口 token 数 |
spring.open.ai.model.providers.<name>.max-output-tokens | - | 最大输出 token 数 |
spring.open.ai.model.providers.<name>.metadata | - | 模型扩展元数据 |
spring.open.ai.model.providers.<name>.fallback-providers | [] | 当前 Provider 失败后的 fallback Provider 顺序;优先级高于全局配置 |
spring.open.ai.model.providers.<name>.model-unavailable-fallback-enabled | true | 当前模型不存在或不可用时是否允许切换到 fallback Provider |
spring.open.ai.model.providers.<name>.upstream-error-passthrough-enabled | true | 是否允许向调用方透传上游错误码和错误摘要 |
spring.open.ai.model.providers.<name>.base-url | - | Provider 服务地址 |
spring.open.ai.model.providers.<name>.api-key | - | Provider API Key |
spring.open.ai.model.providers.<name>.timeout | - | Provider 调用超时时间 |
spring.open.ai.model.providers.<name>.model-discovery-timeout | - | Provider 模型发现超时时间;未配置时使用全局 model-discovery-timeout |
spring.open.ai.model.providers.<name>.options | - | Provider 扩展选项 |
spring.open.ai.model.providers.<name>.credential-pool.enabled | false | 是否启用 Provider 内上游凭证池;关闭时继续使用 Provider 级 base-url / api-key |
spring.open.ai.model.providers.<name>.credential-pool.strategy | priority | 凭证池选择策略,当前支持 priority、weighted 和平台侧 health-weighted |
spring.open.ai.model.providers.<name>.credential-pool.credentials[].name | - | 凭证名称,只用于路由观测和审计,不返回密钥明文 |
spring.open.ai.model.providers.<name>.credential-pool.credentials[].source-type | api-key | 凭证来源类型,当前面向 api-key、byok 和 compatible-endpoint 等可授权来源 |
spring.open.ai.model.providers.<name>.credential-pool.credentials[].base-url | - | 凭证级服务地址;为空时沿用 Provider 级 base-url |
spring.open.ai.model.providers.<name>.credential-pool.credentials[].api-key | - | 凭证级 API Key;为空时沿用 Provider 级 api-key |
spring.open.ai.model.providers.<name>.credential-pool.credentials[].priority | 0 | 凭证优先级,数值越大越优先 |
spring.open.ai.model.providers.<name>.credential-pool.credentials[].weight | 1 | 凭证权重,weighted 策略下使用 |
spring.open.ai.model.providers.<name>.credential-pool.credentials[].options | - | 凭证级 Provider 扩展选项,会覆盖同名 Provider 级选项 |
spring.open.ai.model.providers.<name>.credential-pool.credentials[].metadata | - | 凭证级公开元数据,只放可审计的非敏感字段 |
Spring AI Provider
spring-ai Provider 用于通过 Spring AI 调用 OpenAI Compatible 上游。它不替代 openai-compatible Provider 的动态模型列表能力,也不改变 AI Gateway 对外协议。
spring:
open:
ai:
model:
default-provider: spring-ai
providers:
spring-ai:
provider: spring-ai
enabled: true
model: ${SPRING_OPEN_AI_MODEL_PROVIDERS_SPRING_AI_MODEL:${OPENAI_MODEL:}}
base-url: ${SPRING_OPEN_AI_MODEL_PROVIDERS_SPRING_AI_BASE_URL:https://api.openai.com/v1}
api-key: ${SPRING_OPEN_AI_MODEL_PROVIDERS_SPRING_AI_API_KEY:${OPENAI_API_KEY:}}
timeout: 30s
capabilities:
- chat
- stream
options:
max-retries: 0
stream-usage: true
organization: ${OPENAI_ORGANIZATION:}
project: ${OPENAI_PROJECT:}常用扩展选项:
| 配置 | 默认值 | 说明 |
|---|---|---|
options.max-retries | 0 | Spring AI / OpenAI Java client 层重试次数;框架自身已在 Manager 层使用 Resilience4j,默认避免双层重试放大请求 |
options.stream-usage | true | 流式响应是否请求 usage,便于网关计量扣费 |
options.organization | - | OpenAI Organization |
options.project | - | OpenAI Project |
如果目标是“官网支持什么模型,平台就默认开放什么模型”,仍建议使用 openai-compatible Provider 的 /models 同步能力;spring-ai Provider 更适合作为 Spring AI 生态兼容验证和后续高级能力接入口。
调用韧性
AI Model starter 在 Provider 调用层接入 Resilience4j,默认提供:
- retry:只重试结构化错误中
retryable=true的异常,例如上游限流、超时和临时不可用。 - circuit breaker:按 Provider + model 维度维护熔断状态,避免持续打爆异常上游。
- bulkhead:按 Provider + model 维度限制并发,保护应用线程资源。
- time limiter:正式模型调用使用 Provider 自身
timeout,未配置时使用全局spring.open.ai.model.timeout;模型发现/models使用model-discovery-timeout,避免控制面状态页被慢上游长时间拖住。
fallback 顺序仍由 fallback-providers 决定。某个 Provider 经过重试后仍失败,Manager 才会尝试下一个 fallback Provider;认证失败、Provider 禁用、请求参数错误等不可重试错误不会被 retry 放大,也不会被 fallback 掩盖。模型不存在或模型不可用属于单独策略,只有 model-unavailable-fallback-enabled=true 时才会切换到 fallback Provider。
upstream-error-passthrough-enabled 控制错误响应是否透传上游错误码和错误摘要。关闭后,网关仍会保留结构化错误类型和状态码,但对外返回框架统一错误摘要,适合隐藏供应商原始错误内容或密钥类提示。
OpenAI Compatible Provider 会解析常见上游错误体,包括 error、error_response 和根级错误对象中的 code、type、message、detail 等字段。错误映射会优先参考上游错误码和摘要,再回退 HTTP 状态码,因此 model_not_found、rate_limit_error、invalid_api_key、service_unavailable 等错误可以稳定归一为框架内部结构化错误类型。
AiModelManager.resilienceSnapshots() 和 AiModel.resilienceSnapshots() 可读取当前进程内的 Provider + model 韧性快照,包含熔断器状态、失败率、慢调用率、成功 / 失败调用数和熔断拒绝调用数。该接口不暴露 Resilience4j 原生类型,方便 Open Platform、Admin 运维页或后续观测模块复用。
工具网关(受治理工具执行)
模型协议层的 tool_calls / function_call 是透传:Provider 把模型的函数调用在调用方与上游模型之间中转,不做服务端治理。tool 包在其之上补一层受治理工具执行,让模型只能调用显式授权、安全可审计的业务工具。
核心类型(com.springopen.starter.ai.model.tool):
ToolDefinition:工具定义,含工具名、参数 JSON Schema、所需scope、风险等级(LOW/MEDIUM/HIGH)、是否幂等、超时、是否要求二次确认和审计元数据。ToolRegistry(默认DefaultToolRegistry):显式注册工具,重复名 fail-fast;toModelToolSpecs()把已注册工具渲染成 OpenAItools规格,供AiModelRequest携带。ToolGateway(默认DefaultToolGateway):受治理执行入口。parseToolCalls(AiModelResponse):解析模型响应中的tool_calls(协议透传层 → 执行层的接缝),输出ToolCall。execute(ToolExecutionRequest):治理顺序为「定位定义 → 解析参数 →scope校验 → 高风险二次确认 → 幂等复用 → 限时执行 → 审计」,返回带ToolExecutionStatus(SUCCESS/NOT_FOUND/INVALID_ARGUMENTS/DENIED/CONFIRMATION_REQUIRED/TIMEOUT/ERROR)的结果。toToolMessage(ToolExecutionResult):把结果回灌为tool角色消息,喂回下一轮模型对话。
ToolAuditSink(默认LoggingToolAuditSink):执行审计 SPI,可替换为落库 / 上报实现。
安全边界:
- 只执行显式注册的工具,不把任意 Spring Bean 自动暴露成工具。
HIGH风险工具默认要求二次确认:未确认时返回CONFIRMATION_REQUIRED和ToolConfirmationRequest,调用方确认后必须携confirmed=true和本次返回的confirmationToken重试;确认令牌会绑定工具名、toolCallId、风险等级和参数快照,过期或参数变化都会被拒绝。- 不经工具网关执行真实支付、退款、钱包、Web3 出款、删除数据等不可逆高风险动作。
- 幂等复用为单实例尽力而为的有界缓存;跨实例持久幂等由
ToolHandler基于idempotencyKey自行落库实现。
注册与执行示例:
toolRegistry.register(
ToolDefinition.builder()
.name("get_order_status")
.description("查询订单状态")
.scope("tool:order:read")
.riskLevel(ToolRiskLevel.LOW)
.idempotent(true)
.build(),
context -> orderQueryService.status((String) context.getArguments().get("orderNo")));
// 模型返回 tool_calls 后:
for (ToolCall call : toolGateway.parseToolCalls(response)) {
ToolExecutionResult result = toolGateway.execute(ToolExecutionRequest.builder()
.toolName(call.toolName())
.toolCallId(call.toolCallId())
.rawArguments(call.rawArguments())
.grantedScope("tool:order:read")
.build());
AiModelMessage toolMessage = toolGateway.toToolMessage(result);
// 把 toolMessage 追加进下一轮请求 messages
}Token 预估
AI Model starter 默认通过 AiModelTokenEstimator 提供输入 token 预估能力。内置实现基于 jtokkit,会优先根据请求中的 model 选择匹配 encoding;无法匹配时使用 spring.open.ai.model.tokenizer.fallback-encoding,仍失败时再按 fallback-chars-per-token 做保守兜底。
预估只用于进入 Provider 前的配额预检、账务预占和成本估算。真正的用量仍以 Provider 返回的 AiModelUsage 为准;成功实扣和用量报表不依赖预估值。
开发者可以通过覆盖 AiModelTokenEstimator Bean 接入自定义 tokenizer,例如面向特定国产模型、私有模型或企业网关的专用估算规则:
@Bean
AiModelTokenEstimator aiModelTokenEstimator() {
return request -> 1L;
}DeepSeek 配置实例
DeepSeek 是 AI 模型供应商平台第一阶段优先支持的正式供应商。DeepSeek 采用 OpenAI Compatible 协议,第一版不单独实现 DeepSeekAiModelProvider,而是通过 openai-compatible 公共 Provider 接入:
spring:
open:
ai:
model:
default-provider: deepseek
providers:
deepseek:
provider: openai-compatible
enabled: ${SPRING_OPEN_AI_MODEL_PROVIDERS_DEEPSEEK_ENABLED:true}
model: ${SPRING_OPEN_AI_MODEL_PROVIDERS_DEEPSEEK_MODEL:${DEEPSEEK_MODEL:}}
base-url: ${SPRING_OPEN_AI_MODEL_PROVIDERS_DEEPSEEK_BASE_URL:${DEEPSEEK_BASE_URL:https://api.deepseek.com}}
api-key: ${SPRING_OPEN_AI_MODEL_PROVIDERS_DEEPSEEK_API_KEY:${DEEPSEEK_API_KEY:}}
capabilities:
- chat
- stream
- embedding
context-window: 128000
max-output-tokens: 8192deepseek 是配置实例名,provider: openai-compatible 才是实际 Provider 实现。默认调用 /chat/completions,模型列表调用 /models。如果使用企业网关、代理或私有转发入口,可以通过 base-url 覆盖。
第一阶段不在文档里虚构或改写 DeepSeek 模型名称。平台会优先通过上游 /models 同步官方模型列表,用户在 CC Switch、Claude Code 或 OpenAI Compatible 请求里填写官网返回的 id。如果希望服务端有兜底默认模型,可以通过 DEEPSEEK_MODEL 配置一个官方模型名;没有配置默认模型时,请求侧必须显式传 model。
OpenAI Compatible Provider
OpenAI Compatible Provider 不要求业务模块直接依赖 OpenAI SDK,而是用标准 HTTP 调用 Chat Completions 兼容接口:
spring:
open:
ai:
model:
default-provider: deepseek
providers:
deepseek:
provider: openai-compatible
enabled: ${SPRING_OPEN_AI_MODEL_PROVIDERS_DEEPSEEK_ENABLED:true}
model: ${SPRING_OPEN_AI_MODEL_PROVIDERS_DEEPSEEK_MODEL:${DEEPSEEK_MODEL:}}
base-url: ${SPRING_OPEN_AI_MODEL_PROVIDERS_DEEPSEEK_BASE_URL:${DEEPSEEK_BASE_URL:https://api.deepseek.com}}
api-key: ${SPRING_OPEN_AI_MODEL_PROVIDERS_DEEPSEEK_API_KEY:${DEEPSEEK_API_KEY:}}
capabilities:
- chat
- stream
- embedding
context-window: 64000
max-output-tokens: 8192如果需要通过通用兼容 Provider 接入其他 OpenAI Compatible 服务商,可以直接启用应用配置中的 openai-compatible 实例,并显式配置 base-url、api-key 和可选路径。
OpenAI 官方接口可以启用应用配置中的 openai 实例:
spring:
open:
ai:
model:
default-provider: openai
providers:
openai:
provider: openai-compatible
enabled: ${SPRING_OPEN_AI_MODEL_PROVIDERS_OPENAI_ENABLED:true}
model: ${SPRING_OPEN_AI_MODEL_PROVIDERS_OPENAI_MODEL:${OPENAI_MODEL:}}
base-url: ${SPRING_OPEN_AI_MODEL_PROVIDERS_OPENAI_BASE_URL:https://api.openai.com/v1}
api-key: ${SPRING_OPEN_AI_MODEL_PROVIDERS_OPENAI_API_KEY:${OPENAI_API_KEY:}}常用扩展选项:
| 配置 | 默认值 | 说明 |
|---|---|---|
options.chat-completions-path | /chat/completions | Chat Completions 兼容接口路径 |
options.embeddings-path | /embeddings | Embeddings 兼容接口路径 |
options.models-path | /models | 模型列表接口路径 |
options.model-path | /models/{model_id} | 单模型查询 / 删除接口路径 |
options.responses-path | /responses | Responses 创建接口路径 |
options.response-path | /responses/{response_id} | Response 详情 / 删除接口路径 |
options.response-input-tokens-path | /responses/input_tokens | Responses 输入 token 统计接口路径 |
options.responses-compact-path | /responses/compact | Responses 上下文压缩接口路径 |
options.conversations-path | /conversations | Conversation 创建接口路径 |
options.conversation-path | /conversations/{conversation_id} | Conversation 详情 / 更新 / 删除接口路径 |
options.conversation-items-path | /conversations/{conversation_id}/items | Conversation Item 创建 / 列表接口路径 |
options.conversation-item-path | /conversations/{conversation_id}/items/{item_id} | Conversation Item 详情 / 删除接口路径 |
options.evals-path | /evals | Eval 创建 / 列表接口路径 |
options.eval-path | /evals/{eval_id} | Eval 详情 / 更新 / 删除接口路径 |
options.eval-runs-path | /evals/{eval_id}/runs | Eval Run 创建 / 列表接口路径 |
options.eval-run-path | /evals/{eval_id}/runs/{run_id} | Eval Run 详情 / 删除接口路径 |
options.eval-run-output-items-path | /evals/{eval_id}/runs/{run_id}/output_items | Eval Run 输出项列表接口路径 |
options.organization | - | OpenAI Organization Header |
options.project | - | OpenAI Project Header |
options.extra-headers | - | 额外 HTTP Header,可用 JSON 对象或 Header=value,Header2=value;不会覆盖 Authorization、Content-Type、Accept |
options.auth-type | bearer | 鉴权方式,支持 bearer、api-key-header、none |
options.api-key-header | api-key | auth-type=api-key-header 时 API Key 使用的 Header 名称 |
options.api-version | - | 追加到 URL query 的 api-version,适合 Azure OpenAI |
options.query-parameters | - | 额外 query 参数,可用 JSON 对象或 a=b,c=d |
options.deployment / options.deployment-id | - | 路径模板 {deployment} / {deployment-id} 的值;未配置时使用当前模型名 |
options.parameter-template / options.request-template | - | 上游请求 payload 默认模板,只补齐缺失字段,支持简单 JSON 和 operations 高级操作 |
options.parameter-override / options.request-override | - | 上游请求 payload 覆盖规则,支持简单 JSON 合并和 operations 高级操作 |
兼容路径支持 {model}、{deployment} 和 {deployment-id} 变量。变量会按 URL path segment 编码后替换,避免模型名或部署名里的特殊字符破坏路径结构。
需要为 OpenRouter 等上游追加公开请求头时,可以使用 extra-headers:
spring:
open:
ai:
model:
providers:
openrouter:
provider: openai-compatible
enabled: true
base-url: https://openrouter.ai/api/v1
api-key: ${OPENROUTER_API_KEY:}
options:
extra-headers: >
{
"HTTP-Referer": "https://example.com",
"X-Title": "AI Gateway"
}Azure OpenAI 传统部署路径可以直接启用 azure-openai 预设,或按下面的 YAML 固化:
spring:
open:
ai:
model:
providers:
azure-openai:
provider: openai-compatible
enabled: true
model: ${AZURE_OPENAI_DEPLOYMENT:gpt-4o-prod}
display-name: Azure OpenAI
base-url: ${AZURE_OPENAI_ENDPOINT:https://example.openai.azure.com}
api-key: ${AZURE_OPENAI_API_KEY:}
capabilities:
- chat
- stream
- embedding
options:
auth-type: api-key-header
api-key-header: api-key
api-version: ${AZURE_OPENAI_API_VERSION:2024-10-21}
deployment: ${AZURE_OPENAI_DEPLOYMENT:gpt-4o-prod}
chat-completions-path: /openai/deployments/{deployment}/chat/completions
embeddings-path: /openai/deployments/{deployment}/embeddings
models-path: /openai/deploymentsProvider 会把框架的 AiModelRequest 转成 OpenAI 兼容 JSON:
modelmessagesstreamtemperaturemax_tokensmax_completion_tokenstop_ptoolstool_choice
messages[].content 支持文本和 OpenAI Compatible 复杂 content 数组;tool_call_id、tool_calls 和旧版 function_call 会被原样转发到上游。AI 网关入口未显式建模的 OpenAI Compatible 扩展字段会放入 request_parameters,Provider 会在不覆盖显式核心字段的前提下合并到最终 payload,例如 response_format、seed、logprobs、top_logprobs、parallel_tool_calls、stream_options 和 metadata。普通响应会解析 choices[0].message.content、tool_calls、function_call、finish_reason 和 usage;流式响应会实时解析 data: {...} SSE 片段,输出文本 delta、delta.tool_calls / delta.function_call 和结束片段。
Provider 也会把 AiModelEmbeddingRequest 转成 OpenAI Compatible /embeddings 请求:
modelinputencoding_formatdimensionsuser
响应会解析 object、model、data[].object、data[].index、data[].embedding 和 usage。embedding 可以是浮点数组,也可以是上游按 base64 返回的字符串;starter 会保留原始结构,由调用方或向量库适配层决定后续转换方式。
模型列表会在配置了 base-url 或 api-key 时请求兼容服务的 /models 接口,并把返回的 data[].id 转成 AiModelMetadata。未配置远程地址和密钥时,Provider 会回退到本地配置中的模型元数据,避免默认启动时误访问外部服务。
AI 模型供应商平台的模型目录默认开放上游 /models 可同步到的全部模型:官网支持什么,平台默认就允许进入可用模型目录。默认模型名称必须保持上游官网原名,用户配置 model 时优先填写官网模型名,避免平台自行改名造成疑惑。AI 模块的数据库模型目录可给这些模型补充展示描述、价格、能力标签、上下文窗口、限流、fallback、下架状态和可选平台别名;平台别名只在 AI 网关入口解析,starter 和上游 Provider 调用仍使用官网模型名。
Account Pool Provider
account-pool Provider 是一个协议中立的 OpenAI Compatible HTTP Provider,适合把框架接到本地或私有模型服务入口。它不读取数据库、不计算健康分、不做冷却和调度,只负责把 AiModelRequest 转成兼容 Chat Completions 请求,再把普通响应或 SSE 片段转回 starter 统一响应对象。
应用默认提供 local-account-pool 配置实例,默认关闭。启用时只需要指向本地兼容服务地址:
spring:
open:
ai:
model:
default-provider: local-account-pool
providers:
local-account-pool:
provider: account-pool
enabled: true
model: private-chat
base-url: http://127.0.0.1:8000/v1
api-key: ${LOCAL_ACCOUNT_POOL_API_KEY:}
options:
chat-completions-path: /chat/completions
embeddings-path: /embeddings
models-path: /models
evals-path: /evals
eval-path: /evals/{eval_id}
eval-runs-path: /evals/{eval_id}/runs
eval-run-path: /evals/{eval_id}/runs/{run_id}
eval-run-output-items-path: /evals/{eval_id}/runs/{run_id}/output_items如果需要在多个已授权凭证或多个兼容端点之间治理流量,把凭证放到 AI 模块的数据库态凭证池,并把 Provider 配置实例的 credential-pool.strategy 设置为 health-weighted。运行时 AiModelConfigResolverAdapter 会在调用前选出本次凭证并注入 baseUrl / apiKey / options,AccountPoolAiModelProvider 仍保持纯 HTTP 转发边界。
上游凭证池
Provider 可以启用上游凭证池,在同一个 Provider 配置实例下维护多组已授权 API Key、BYOK 或自建兼容端点。凭证池用于快速实现多 Key 容量分摊、供应商额度隔离、企业专属入口和后续后台运营接入;它只面向可授权、可审计的服务端 API 凭证与兼容端点。
spring:
open:
ai:
model:
providers:
deepseek:
provider: openai-compatible
model: deepseek-chat
credential-pool:
enabled: true
strategy: priority
credentials:
- name: deepseek-main
source-type: api-key
base-url: https://api.deepseek.com
api-key: ${DEEPSEEK_API_KEY_MAIN:}
priority: 10
weight: 5
- name: deepseek-backup
source-type: api-key
base-url: https://api.deepseek.com
api-key: ${DEEPSEEK_API_KEY_BACKUP:}
priority: 20
weight: 1选择策略:
priority:优先选择priority最大的启用凭证;优先级相同时权重更大的排前,再按名称稳定排序。weighted:先锁定最高priority分层,再按该分层内启用凭证的正权重做稳定哈希分配,避免每次调用随机跳动,便于审计和复现;权重为 0 的凭证不会被分配流量。health-weighted:Open Platform 运行时治理策略,按凭证健康分计算有效权重并做加权随机调度;冷却中或低于最低健康分的凭证不会进入候选集合。
选中的凭证会覆盖本次调用的 baseUrl、apiKey 和同名 options,并把 credentialName、credentialSourceType 和 credentialSelectionStrategy 写入 Provider metadata,供 Open Platform / AI Gateway 后续用量事件、成本分析和故障排查复用。
AI 模块也提供数据库态凭证池,适合在 Admin 运营台动态管理上游 API Key、BYOK 或自建兼容端点。后台接口位于 /api/v1/admin/ai/platform/providers/{providerName}/credentials,支持查询、保存和删除 Provider 下的多组凭证;API Key 使用 spring.open.ai.secret.encryption-key 加密落库到 ai_provider_credential,列表响应只返回 apiKeyConfigured、凭证名称、来源类型、baseURL、优先级、权重、配置 key 和公开 metadata,不返回密钥明文。
运行时 AiModelConfigResolverAdapter 会在本地 Provider 配置和 ai_provider_config 覆盖之上叠加已启用的数据库凭证。Provider 配置中的 credentialSelectionStrategy 决定数据库凭证池使用 priority、weighted 还是 health-weighted 策略;选中的凭证会覆盖本次调用的 baseURL / API Key / options,并把 upstreamCredentialName、upstreamCredentialSourceType 和 credentialSelectionStrategy 固化到 AI Gateway usage event。启用 health-weighted 时,响应 metadata 还会携带 credentialHealthScore、credentialScheduleReason 和候选摘要,方便后续审计和排障。
Log Provider
Log Provider 面向本地联调、网关 contract、计量和审计链路冒烟验证,不依赖任何外部模型服务:
spring:
open:
ai:
model:
default-provider: log
providers:
log:
provider: log
model: log-chat
options:
response-content: "[log] request accepted"
include-prompt-in-response: false
log-prompt: false常用扩展选项:
| 配置 | 默认值 | 说明 |
|---|---|---|
options.response-content | [log] request accepted | 固定响应内容 |
options.include-prompt-in-response | false | 是否把最后一条用户消息拼到响应里,仅建议测试时开启 |
options.log-prompt | false | 是否记录 prompt 内容,默认关闭,避免日志泄露敏感输入 |
Simulated Provider
Simulated Provider 面向低成本联调和故障演练。它不访问外部模型服务,不消耗真实 token,也不读取 Knowledge 或业务数据;调用方仍然通过标准 AiModelManager.chat(...) / stream(...) 消费它,因此可以用于 Knowledge Chat、AI Gateway、前端流式展示、usage 记录、fallback 和审计链路的完整联调。
spring:
open:
ai:
model:
default-provider: simulated
providers:
simulated:
provider: simulated
enabled: true
model: simulated-chat
options:
mode: echo
response-content: "[simulated] request accepted"
include-prompt-in-response: false
latency-ms: 0
failure-type:
stream-chunk-size: 12常用扩展选项:
| 配置 | 默认值 | 说明 |
|---|---|---|
options.mode | echo | 响应模式:echo 回显最后一条用户消息,template 使用固定模板并拼接用户消息,empty 返回空内容 |
options.response-content | [simulated] request accepted | template 模式或显式拼接时使用的固定响应内容 |
options.include-prompt-in-response | false | 非 echo 模式下是否把最后一条用户消息拼到响应中 |
options.latency-ms | 0 | 模拟调用延迟,适合验证前端 loading、超时和并发隔离 |
options.failure-type | 空 | 模拟失败类型:rate-limit、timeout、provider-unavailable、upstream-error |
options.stream-chunk-size | 12 | 流式响应每个 delta 的最大字符数 |
Fallback
Provider fallback 用于上游模型服务短时失败、限流或不可用时切换到备用 Provider:
spring:
open:
ai:
model:
default-provider: primary
fallback-providers:
- mock
providers:
primary:
provider: openai-compatible
model: chat-fast
display-name: Chat Fast
capabilities:
- chat
- stream
context-window: 128000
max-output-tokens: 8192
fallback-providers:
- mock
mock:
provider: mock
model: mock-chat执行顺序:
- 优先使用请求指定 Provider 或
default-provider。 - 如果当前 Provider 配置了
fallback-providers,优先使用当前 Provider 的 fallback 顺序。 - 如果当前 Provider 没有配置 fallback,则使用全局
fallback-providers。 - fallback 只切换 Provider 配置,不复用主 Provider 的密钥、地址和扩展选项。
错误映射
AI Model starter 会把 Provider 运行时异常映射为统一的 AiModelError,并通过 AiModelException#getError() 暴露给上层网关。
AiModelError 主要字段:
| 字段 | 说明 |
|---|---|
type | 错误类型,如 rate_limit、timeout、authentication、provider_unavailable |
provider | 发生错误的 Provider |
model | 发生错误的模型 |
status | 上游 HTTP 状态码,适合 HTTP Provider 填充 |
upstreamCode | 上游错误码 |
upstreamMessage | 上游错误摘要 |
retryable | 是否适合 fallback 或稍后重试 |
常见 HTTP 状态会被归一为稳定错误类型:
| HTTP 状态 | 错误类型 |
|---|---|
400 / 422 | invalid_request |
401 | authentication |
403 | authorization |
404 | model_not_found |
408 | timeout |
429 | rate_limit |
5xx | provider_unavailable |
后续 OpenAI Compatible、Claude / Anthropic Messages、Codex / Responses API 网关应基于这个错误 contract 转换各自协议的错误响应,不在 Controller 中重复判断第三方异常。
和 AI 模型平台的关系
spring-open-starter-ai-model 只负责“怎么调用模型”。spring-open-module-ai 负责“怎么运营平台”:
- 供应商管理
- 模型目录和模型别名
- 用户 API Key
- OpenAI Compatible 网关
- Claude Code / Anthropic Messages 网关
- Codex / Responses API 网关
- Token 计量
- 余额 / 套餐扣费
- 成本、售价和毛利
- Admin / App / PC 控制台
业务模块通过 starter 的 Manager / Provider contract 调用模型,不直接依赖第三方 SDK。
Translate starter 的 ai-model Provider 也是这个边界的一个消费方:Translate 负责文本、语言、格式提示和占位符保护,AI Model starter 负责模型路由、Provider 调用和 token usage 返回。翻译结果会把实际 Provider、模型、结束原因和 token 用量写入 TranslateResult.metadata(),方便后台预览、审计和后续计量归集。
验证
./mvnw -pl spring-open-starters/spring-open-starter-ai-model -am test -DskipITs