Files
oci-portal/docs/ai-gateway.md
T
wangdefa 0a86b5a291
CI / test (push) Successful in 32s
Release / release (push) Successful in 1m4s
AI网关新增TTS/重排/审核端点,xAI工具扩展,swagger修缺
- 新端点 /ai/v1/audio/speech(xai.grok-tts)、/rerank(cohere.rerank-v4)、/moderations(OCI Guardrails)
- Responses 放行 code_interpreter 与远程 mcp 工具,web_search/x_search 解除仅非流式限制
- 模型能力映射扩展:TEXT_RERANK→RERANK、TEXT_TO_AUDIO→TTS
- AI 网关文档独立 docs/ai-gateway.md,字段兼容矩阵只列支持项;README 精简引用
- swagger 修缺:135 处响应注解具体化,RawMessage/联合类型统一渲染 AnyJSON,overrides 迁至 docs/.swaggo
- CHANGELOG 0.4.0,版本段不再记日期;DASH_VERSION v0.4.0
2026-07-13 20:17:06 +08:00

21 KiB
Raw Permalink Blame History

AI 网关

本文是 OCI Portal AI 网关的完整使用与兼容性文档:端点定位、协议兼容边界、已知上游限制与字段兼容矩阵。 路由与鉴权的机器可读定义以 Swagger YAML 或运行时 Swagger UI 为准;无法由 OpenAPI 表达的兼容边界以本文为准。

AI 网关使用面板创建的独立密钥鉴权,支持 Authorization: Bearer sk-...x-api-key: sk-...。密钥可绑定渠道分组和模型白名单;全局模型黑名单会从模型列表、路由和探测候选中同时排除目标模型。

端点 定位 流式
POST /ai/v1/responses OpenAI Responses,无状态主接口 SSE
POST /ai/v1/chat/completions OpenAI Chat Completions,存量客户端兼容层 SSE
POST /ai/v1/messages Anthropic Messages 转换层 SSE
POST /ai/v1/embeddings OpenAI Embeddings
POST /ai/v1/audio/speech OpenAI Audio Speech,文本转语音(xAI Voice
POST /ai/v1/rerank 文档重排(Cohere RerankJina 风格协议)
POST /ai/v1/moderations 内容审核(OCI Guardrails:内容审核 / PII / 提示注入)
GET /ai/v1/models 当前密钥可见的模型列表

兼容边界:

  • 对话请求统一转发 OCI OpenAI 兼容面,当前供给以 xai.meta.openai. 前缀模型为主;Cohere Embeddings 不受该对话模型范围影响
  • 网关不保存会话历史,客户端需要携带完整上下文;Responses 拒绝非空 previous_response_id、非 null conversationbackground:true
  • Responses 支持 Oracle 文档化的 xAI 服务端工具 web_search / x_search / code_interpreter 与远程 mcp 工具(非流式与流式均可),工具参数与限制遵循 xAI 规格code_interpreter 的命名容器管理(containers API)与 File Search 不提供
  • Responses 的 reasoning.effort、Messages 的 output_config.effort 和 Chat Completions 的 reasoning_effort 会传给上游,实际档位和效果由模型决定
  • Chat Completions 只承担协议转换与兼容修复;新能力优先在 Responses 和 Messages 提供
  • 单次请求最多尝试三个渠道;可重试错误会切换渠道,流式响应建立后不会换渠道重试
  • Audio Speech 直通 OCI 兼容面(模型 xai.grok-ttsvoice 取 xAI Grok Voice 列表:ara/eve/leo/rex/sal);上游把 language 当必填,缺省时网关自动注入 "auto"xAI 专属参数(output_format 等)可平铺在请求体透传;仅单请求返回音频,不提供 WebSocket 流式
  • Rerank 走 OCI typed 面(cohere.rerank-v4.0-pro / -fast),请求 {model, query, documents[], top_n?, return_documents?},响应 results[].index 指向入参下标;无 token 用量口径,调用日志只记时延
  • Moderations 是 OpenAI moderations 外壳映射 OCI Guardrailsinput 为字符串或字符串数组(至多 8 条),categories 用 OCI 原生维度 overall / blocklist / prompt_injection(阈值 0.5 判定 flagged),PII 命中放扩展字段 results[].pii(不参与 flagged);model 字段接受但忽略,无模型白名单维度;实测中文人名/手机号识别较弱,英文 PII 识别正常
  • Responses 的 input_file 内容块(file_url / file_data)实测被上游拒绝:File content is currently unsupported for ZDR customers——网关强制 store:false 属 ZDR 形态,该能力在上游侧不可用

已知上游限制:大 system 区流式断流

实测(2026-07-13OCI 兼容面对 instructionstools 合计超约 64.5KB 的流式请求会在发出少量事件后静默断开连接(无任何错误事件;同请求非流式正常),与模型、字符集、消息正文大小均无关——消息正文(input)不计入该限制。Chat Completions 与 Messages 的 system/developer 提示会转换为 instructions,因此 Claude Code 等自带大体量系统提示与工具定义的客户端极易触发。

网关侧应对:

  • Messages 与 Chat Completions 的流式请求在客户端尚未收到任何输出时遭遇上游断流,会自动降级为非流式重做,并按标准事件/chunk 序列一次推送;调用日志记 retries=1 与降级标记
  • Responses 直通因初始事件已转发、协议上无法透明降级,调用日志记「上游流提前终止」,客户端需自行回退非流式
  • 应急规避:将超长 system 内容移入首条 user 消息正文可绕过该限制(正文不计入),但语义有别,根治有待上游修复

这里提供的是兼容接口而非 OpenAI / Anthropic 协议的完整实现。OCI OpenAI 兼容面的部分行为来自实测,未见 Oracle 文档承诺,可能随上游调整。路由与鉴权定义以 Swagger YAML 或运行时 Swagger UI 为准;无法由 OpenAPI 完整表达的兼容边界列于上方。

字段兼容矩阵

以下矩阵以 2026-07-13 的 OpenAI ResponsesChat CompletionsEmbeddingsAudio SpeechModerationsAnthropic Messages 为标准基线,并与当前实现逐项核对;Rerank 无 OpenAI 对应端点,基线取 Cohere Rerank 协议。

这是一份兼容性快照,不替代 Swagger。标准接口和 OCI 上游都可能变化,最终行为以当前版本代码与实测为准。

矩阵只列网关支持的字段;不支持(本地拒绝)与被忽略的字段不入表,在各端点段落末尾以文字简述。

标记 含义
网关直接支持
➡️ 网关原样透传;是否生效由 OCI 上游决定
🔄 网关进行字段或协议转换后支持
部分支持、存在前置条件或语义降级
POST /ai/v1/responses 对比 OpenAI Responses

Responses 是“原始 JSON 直通 + 本地门禁”。除 store 外,网关不会重建请求体;未知顶层字段也会保留并送往 OCI。

标准字段 状态 网关行为
model 必须非空,还要通过密钥模型白名单并匹配可用渠道;随后原样透传
input ➡️ 支持标准的字符串或 item 数组,原始内容透传;网关不逐项保证 OCI 能处理所有 item 类型
instructionsmax_output_tokens ➡️ 类型可解析后原样透传,不做范围或模型能力校验
temperaturetop_pparallel_tool_calls ➡️ 原样透传,不做取值范围校验
text / text.format / text.verbosity ➡️ 整个原始对象透传;结构化输出是否可用由 OCI 模型决定
reasoning ➡️ 整个原始对象透传;effort 不校验档位,summary 等字段不会被网关删除
tool_choice ➡️ 任意 JSON 原样透传,本地不校验枚举或结构
store 🔄 无论客户端传什么,上游请求都强制改写为 false
stream 普通请求、function 与服务端工具均支持 SSE
tools[].type=function ➡️ 非流式和流式均可,工具对象原样透传
tools[].type=web_search / x_search / code_interpreter Oracle 文档化的 xAI 服务端工具,参数与限制遵循 xAI 规格(如 allowed_domains 上限 10、container 支持 {"type":"auto"}),非流式与流式均实测可用;x_search 不是 OpenAI 标准工具
tools[].type=mcp ➡️ 远程 MCP 服务由上游直连调用(server_url / require_approval / authorization 等原样透传),非流式与流式均实测可用
其余标准与未知顶层字段 ➡️ context_managementincludemetadatapromptprompt_cache_keyservice_tiertruncationuser 等未建模字段一律保留在原始请求中,由 OCI 决定是否接受

不支持(请求到达上游前返回 400):非空 previous_response_id、非 nullconversationbackground:true——网关无状态,不保存历史响应;以及 function / xAI 服务端工具 / mcp 之外的工具类型(web_search_previewfile_searchcomputerimage_generationshellcustom 等)。

响应边界:

  • 非流式成功响应不做转换,OCI JSON 原样返回;usage 解析只用于面板调用日志
  • SSE 事件逐行原样转发,不补 data: [DONE],推理增量也不会被网关过滤
  • 流建立前最多切换三个渠道;流建立后中断不重试,客户端可能只收到部分事件
  • 未知模型返回 404、无渠道返回 503;上游错误会套入 OpenAI 风格错误体,不保证与标准 OpenAI 错误字段完全相同

实现依据:airesponses.go · responses.go · aigateway.go

POST /ai/v1/chat/completions 对比 OpenAI Chat Completions

Chat Completions 会先转换为 Responses 请求,再把 OCI Responses 响应桥接回 Chat Completions 形态。转换器只搬运下表字段,其余字段不进入上游请求。

标准字段 状态 网关行为
model 必填,受密钥白名单和可用渠道限制;模型名保留到上游请求
messages 🔄 必填并转换为 Responses input / instructions
system / developer 消息 文本按出现顺序合并为 instructions;块数组中的非文本内容被忽略
user / assistant 文本内容 🔄 字符串及 text 块分别转为 input_text / output_text
image_url 内容块 URL 或 data URI 转为 input_imageimage_url.detail 被忽略
assistant tool_calls / role=tool 🔄 转为 function_call / function_call_output,保留调用 ID、函数名和参数
max_completion_tokens 🔄 转为 max_output_tokens,优先于 max_tokens
max_tokens 🔄 未提供 max_completion_tokens 时转为 max_output_tokens
temperaturetop_pparallel_tool_calls 原值写入 Responses 请求,但不校验范围或模型能力
stream 🔄 OCI Responses SSE 桥接为 chat.completion.chunk,末尾补 data: [DONE];上游断流且尚无输出时自动降级非流式重做,结果按 chunk 序列一次推送
stream_options.include_usage 🔄 控制网关在终块后追加 choices: [] 的 usage 块
tools[].type=function namedescriptionparameters 支持;function.strict 被忽略
tool_choice 支持 auto / none / required 和具名 function;非法或未知值被静默忽略
response_format json_objectjson_schema 转为 Responses text.format;未知类型交给 OCI 处理
reasoning_effort 转小写后映射为 reasoning.effort,不校验模型或档位
store 🔄 客户端取值被忽略,转换后的上游请求始终使用 store:false

不支持(返回 400):input_audiofilerefusal 等消息内容块;function 以外的工具类型(含 custom)。

静默忽略(转换后的上游请求不包含):消息级 name / refusal / audio / 旧式 function_call;采样与输出控制类 stopseedn(恒返回单个 choice)、frequency_penaltypresence_penaltylogprobstop_logprobslogit_bias;平台类 useraudiomodalitiespredictionmetadatamoderationprompt_cache_keysafety_identifierservice_tierverbosityweb_search_optionsstream_options.include_obfuscation 及其他未知字段。

响应边界:

  • 非流式固定生成一个 choices[0];文本会合并,函数调用转为 tool_calls
  • finish_reason 只生成 stoptool_callslength;其他上游终止原因不保留
  • reasoning 输出、logprobs、refusal、annotations、audio、service tier 和 system fingerprint 不返回
  • usage 保留 prompt_tokenscompletion_tokenstotal_tokensprompt_tokens_details.cached_tokens
  • 已建立的流中断或上游 response.failed 不会转换成标准 SSE 错误事件

实现依据:chatresponses.go · openai.go · aigateway.go

POST /ai/v1/embeddings 对比 OpenAI Embeddings
标准字段 状态 网关行为
model 必填,受密钥白名单限制,并且必须存在具有 EMBEDDING 能力的渠道
input 为字符串 包装为单个输入后调用 OCI
input 为字符串数组 按原顺序调用 OCI;空字符串不在本地拒绝,由 OCI 决定
dimensions 映射为 OCI 输出维度,不做范围或模型能力校验
encoding_format=float 返回 float 数组;省略时行为相同

不支持(返回 400):token ID 数组(一维或二维)形态的 input、空数组、null,以及 encoding_format=base64。静默忽略:user 及其他未知字段。

响应使用标准的 object:"list"data[].object:"embedding"indexmodel 和可选 usage 外壳;向量为 float32 数组,不支持流式。

实现依据:embeddings.go · aigateway_chat.go · aigateway.go

POST /ai/v1/messages 对比 Anthropic Messages

网关接受 Authorization: Bearerx-api-key,但不会校验或使用标准 Anthropic anthropic-versionanthropic-beta 请求头。

标准字段 状态 网关行为
model 用于模型与渠道选择,但空字符串不会在 handler 中按参数错误拒绝,通常最终返回模型不存在
max_tokens 🔄 可缺省(缺省或 ≤0 时按默认值 8192),转换为 max_output_tokens
messages 必须非空;角色、交替顺序和空内容不做完整校验
system 支持字符串或 text 块数组;多个文本块直接拼接,cache_control 等附加字段被忽略
temperaturetop_p 写入 Responses 请求,不做取值范围或模型能力校验
stream 🔄 Responses SSE 桥接为 Anthropic 事件序列;上游断流且尚无输出时自动降级非流式重做,结果按事件序列一次推送
tools 每个工具都转换成 Responses function;自定义客户端工具可用,Anthropic 服务端工具类型不保留原语义
tool_choice 支持 autoanynone、具名 tooldisable_parallel_tool_use 等附加字段被忽略
output_config.effort 🔄 转小写后映射为 Responses reasoning.effort

顶层静默忽略(能解析但不传上游):top_kstop_sequences(响应 stop_sequence 恒为 null)、metadatathinking(不控制上游思考预算)、output_config 其余子字段、cache_controlcontainerinference_geoservice_tier 及其他未知顶层字段。

messages[].content

标准内容块 状态 网关行为
字符串 / text 🔄 user 转 input_textassistant 历史转 output_text
image 仅支持 base64url source;缺字段或其他 source 类型返回 400
tool_use 🔄 转为 function_call,保留 ID、名称和输入
tool_result 转为 function_call_output;块数组只拼接 textis_error 和非文本结果丢失
null / 空块数组 该消息可能从上游 input 中消失,不返回参数错误

不支持的内容块(返回 400):document、服务端工具结果及其他未知块。历史 thinking / redacted_thinking 块会被删除,不进入上游上下文。

响应边界:

  • 非流式只把 Responses output_text 转成 textfunction_call 转成 tool_use
  • stop_reason 只生成 end_turntool_usemax_tokensstop_sequence 恒为 null
  • reasoning 不会生成 Anthropic thinking / redacted_thinking 块,也没有 signature
  • usage 只保留 input_tokensoutput_tokenscache_read_input_tokens,不提供 cache_creation_input_tokens
  • 流式输出标准事件骨架,但不生成 thinking_deltasignature_delta;上游错误事件与无终态断流会转成 Anthropic error 事件

实现依据:anthresponses.go · anthropic.go · aigateway.go

POST /ai/v1/audio/speech 对比 OpenAI Audio Speech

Audio Speech 与 Responses 同为“原始 JSON 直通 + 本地门禁”:除缺省注入 language 外不重建请求体,未知字段原样透传。

标准字段 状态 网关行为
model 必填,受密钥白名单限制,并且必须存在具有 TTS 能力的渠道(当前上游仅 xai.grok-tts
input 必填非空,随后原样透传
voice ➡️ 原样透传;取 xAI Grok Voice 音色(ara / eve / leo / rex / sal),OpenAI 标准音色名不可用
response_format ➡️ 原样透传;实测 mp3 可用,其余格式由上游决定
language(扩展字段) 🔄 上游必填;客户端缺省时网关自动注入 "auto"
speedinstructions 及其他未知字段 ➡️ 原样透传(含 xAI 专属参数如 output_format),是否生效由上游决定

不支持:流式音频(stream_format 等流式选项无效,响应恒为一次性完整音频)与 WebSocket 语音会话。

响应边界:

  • 成功响应为音频字节,Content-Type 透传上游(缺省 audio/mpeg
  • 无 token 用量口径,调用日志只记时延与渠道

实现依据:genai_speech.go · service/aigateway_extras.go · api/aigateway_extras.go

POST /ai/v1/rerank 对比 Cohere Rerank

Rerank 无 OpenAI 对应端点,协议取 Jina / Cohere 通行风格,上游走 OCI typed 面(cohere.rerank-v4.0-pro / -fast)。

字段 状态 网关行为
model 必填,受密钥白名单限制,并且必须存在具有 RERANK 能力的渠道
query 必填非空
documents 必填,仅接受字符串数组;Cohere 旧版 {"text": ...} 对象数组形态返回 400
top_n 可选,传给上游限制返回条数;缺省返回全部文档的重排结果
return_documents 可选,trueresults[].document.text 回带原文

静默忽略:max_tokens_per_doc 等 Cohere 专属参数及其他未知字段。

响应边界:

  • results[] 按相关度降序,index 指向入参 documents 下标,relevance_score 为 01 浮点;响应 model 回显请求值
  • 无 token 用量口径,调用日志只记时延与渠道

实现依据:genai_guard.go · rerank.go · service/aigateway_extras.go

POST /ai/v1/moderations 对比 OpenAI Moderations

Moderations 是 OpenAI moderations 外壳映射 OCI Guardrails(内容审核 / PII / 提示注入)。上游是服务级 API,没有模型与白名单维度;渠道按分组直接挑选。

标准字段 状态 网关行为
input 为字符串 单条审核
input 为字符串数组 逐条审核,单次 1~8 条

不支持(返回 400):多模态 input(图片等对象数组形态)、空字符串条目、空数组或超过 8 条的数组。静默忽略:model(接受任意值,不校验白名单)及其他未知字段。

响应边界:

  • categories / category_scores 用 OCI 原生维度 overall / blocklist / prompt_injection,而非 OpenAI 标准类目(hate / violence 等);任一维度得分 ≥ 0.5 判定 flagged
  • PII 命中放扩展字段 results[].piitext / label / score / offset / length),不参与 flagged 判定;实测中文人名 / 手机号识别较弱,英文 PII 识别正常
  • 响应 model 恒为 oci-guardrails

实现依据:genai_guard.go · moderations.go · service/aigateway_extras.go

GET /ai/v1/models 使用 OpenAI Models 列表外壳(objectdata[].id/object/created/owned_by),但只返回当前渠道目录中通过分组、全局黑名单和密钥白名单筛选后的模型;网关不提供标准的单模型检索端点。