API 参考¶
文档版本: 1.0.3
最后更新: 2026-09-15
Git 提交: 61384b4a
作者: Lincoln
JAiRouter 为各种 AI 服务提供 OpenAI 兼容的 API,以及用于配置和监控的管理 API。
API 分类¶
1. 统一 API (/api/v1/*)¶
AI 服务的统一入口(含 OpenAI 兼容端点与多模态端点):
- 统一 API - 聊天、嵌入、重排、TTS、STT、图像生成与编辑
- 与 OpenAI SDK 和工具兼容(路径前缀为
/api/v1) - 一致的请求/响应格式
另有一组 OpenAI 原生路径
/v1/*,只覆盖models、chat/completions、embeddings、rerank四个端点;音频与图像端点只在/api/v1/*下提供。
2. 管理 API (/api/*)¶
JAiRouter 特定的管理端点:
3. Actuator API (/actuator/*)¶
用于监控的 Spring Boot actuator 端点:
- 健康检查
- 指标
- 应用信息
基础 URL¶
所有 API 都从您的 JAiRouter 实例提供服务:
认证¶
认证默认是开启的:jairouter.security.enabled 默认 true(config/auth/jwt.yml),因此 /v1/** 需要凭据、/api/** 走权限校验,只有豁免清单允许匿名访问(/actuator/health 及其子路径、/actuator/info、/actuator/prometheus、登录接口 POST /api/auth/jwt/login 与 POST /api/auth/jwt/validate、/admin/** 与 /favicon.ico 静态资源 —— 见 SecurityConfiguration.java 与 AnonymousEndpointPaths.java)。Swagger / OpenAPI 文档不在豁免清单里,只有 jairouter.security.docs-public=true 时才匿名(ApiDocsAccessPolicy.java)。
网关自身的凭据有两种:
X-API-Key: <控制台创建的 API Key>Jairouter_Token: <JWT>
Authorization 头不参与网关认证,它被透传给下游 AI 服务(实例级 headers 优先)。
确实要关闭认证时,请显式设置 jairouter.security.enabled: false(不建议用于生产),不要依赖「默认不需要认证」。
限流¶
限流不是对所有 API 生效,主要在这几处:AI 调用链路(ServiceRequestHandler 里的服务级限流)、/api/auth/api-keys 前缀(AdminApiRateLimiter)与 API Key 校验链(ApiKeyValidator.validateRateLimit,见 错误码对照表)。
429 的响应体形状按入口面不同,code 取该路径实际发出的码:/api/auth/api-keys 的管理面限流是扁平体 RATE_LIMIT_EXCEEDED,API Key 校验链是 RATE_LIMITED_API_KEY(两者状态都是 429)。
/v1/**(OpenAI 面,经 V1ErrorBodyMapper;下面以校验链的码为例):
/api/auth/api-keys(扁平体,没有 error 包裹,见 AdminApiRateLimiter 的 writeRateLimited):
错误处理¶
错误响应的形状按入口面不同,并不存在「所有 API 统一」的错误体。
/v1/**(OpenAI 面)¶
没有 param、也没有 details(V1ErrorBodyMapper#toErrorBody 只写 message/type/code)。
/api/**(控制台面)¶
沿用 RouterResponse(success / message / data / errorCode / timestamp):
这个面上有三种响应不使用上面的形状 —— 它们破坏的不是「按面选形状」,而是「按谁写的选形状」:
| 场景 | 写入方 | 实际响应体 |
|---|---|---|
| 缺少 / 非法凭据(401) | 认证过滤器 | {"error":{"message":…,"type":"authentication_error","code":"AUTH_MISSING"}} |
| 凭据被限流(429) | 认证过滤器 | {"error":{"message":…,"type":"rate_limit_error","code":"RATE_LIMITED_API_KEY"}} |
| 被授权层拦下(403) | Spring Security 默认处理器 | text/plain,正文 Access Denied |
而 controller 自己抛的 403(例如 BUILTIN_READONLY)是 RouterResponse。因此客户端的判据应是 「顶层有没有 error 字段」:有就按协议形状解析,没有就按 RouterResponse 解析。
/v1/** 的 type 取值¶
| HTTP 状态 | type | 描述 |
|---|---|---|
| 400 / 422 / 其他 4xx | invalid_request_error | 请求格式错误 |
| 401 | authentication_error | 认证失败 |
| 403 | permission_error | 权限不足 |
| 404 | not_found_error | 资源未找到 |
| 429 | rate_limit_error | 超出限流 / 配额 |
| 所有 5xx(含 503) | api_error | 网关或下游内部错误 |
来源:V1ErrorBodyMapper#errorTypeOf。不存在 service_unavailable、circuit_breaker_open 这类 type。
内容类型¶
请求内容类型¶
application/json- JSON 请求(绝大多数 API,含图像生成与图像编辑)multipart/form-data- 只有/api/v1/audio/transcriptions(STT)声明了该消费类型
响应内容类型¶
application/json- JSON 响应(绝大多数 API,含图像生成与图像编辑)
图像 API 的响应是 JSON(
data[].url或data[].b64_json),不输出image/*。TTS 接口(POST /api/v1/audio/speech)返回音频二进制,其 Content-Type 由所选输出格式决定。
请求/响应示例¶
聊天对话¶
请求:
POST /v1/chat/completions
Content-Type: application/json
{
"model": "qwen2.5:7b",
"messages": [
{
"role": "user",
"content": "你好!"
}
],
"max_tokens": 100,
"temperature": 0.7
}
响应:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "chatcmpl-123",
"object": "chat.completion",
"created": 1677652288,
"model": "qwen2.5:7b",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "你好!今天我能为您做些什么吗?"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 9,
"completion_tokens": 12,
"total_tokens": 21
}
}
流式响应¶
JAiRouter 支持聊天对话的流式响应:
请求:
POST /v1/chat/completions
Content-Type: application/json
{
"model": "qwen2.5:7b",
"messages": [{"role": "user", "content": "你好!"}],
"stream": true
}
响应:
HTTP/1.1 200 OK
Content-Type: text/event-stream
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1677652288,"model":"qwen2.5:7b","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1677652288,"model":"qwen2.5:7b","choices":[{"index":0,"delta":{"content":"你好"},"finish_reason":null}]}
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1677652288,"model":"qwen2.5:7b","choices":[{"index":0,"delta":{"content":"!"},"finish_reason":"stop"}]}
data: [DONE]
SDK 兼容性¶
JAiRouter 与 OpenAI SDK 兼容。只需更改基础 URL:
Python (openai)¶
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:8080/v1",
api_key="not-needed"
)
Node.js (openai)¶
import OpenAI from 'openai';
const openai = new OpenAI({
baseURL: 'http://localhost:8080/v1',
apiKey: 'not-needed'
});
curl¶
curl -X POST http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "qwen2.5:7b", "messages": [{"role": "user", "content": "你好!"}]}'
健康检查¶
检查 API 健康状态:
响应:
下一步¶
- 统一 API - OpenAI 兼容端点
- 管理 API - 配置管理
- 监控 API - 健康和指标
- OpenAPI 规范 - 交互式 API 文档