<a id="top"></a>

<div align="center">

<img src="assets/logo.svg" width="88" alt="OCI Portal logo">

# AI 网关

**将多路 OCI Generative AI 统一为 OpenAI、Anthropic 与 xAI 兼容接口**

![OpenAI](https://img.shields.io/badge/OpenAI-Responses%20%7C%20Chat-412991?logo=openai&logoColor=white)
![Anthropic](https://img.shields.io/badge/Anthropic-Messages-D97757?logo=anthropic&logoColor=white)
![xAI](https://img.shields.io/badge/xAI-TTS%20%7C%20Tools-111111?logo=x&logoColor=white)
![Streaming](https://img.shields.io/badge/Streaming-SSE-0F9D58)

[快速接入](#quick-start) · [端点一览](#endpoints) · [路由机制](#routing) · [Codex 接入](#codex) · [已知限制](#limitations) · [兼容矩阵](#compatibility)

</div>

> [!NOTE]
> 网关集中处理密钥鉴权、模型访问控制、渠道调度与协议适配。路径、参数和
> 响应结构以 [Swagger YAML](swagger.yaml) 或运行时 Swagger UI 为准；协议差异、
> 兼容改写和实测边界以本文为准。

| 文档属性 | 当前值 |
| --- | --- |
| 兼容快照 | **2026-07-16** |
| API 基址 | `/ai/v1` |
| 首选对话协议 | OpenAI Responses |
| 会话模式 | 无状态，客户端携带完整上下文 |

<a id="quick-start"></a>

## 快速接入

### 基础地址与鉴权

网关密钥在管理面板中创建。连接信息如下：

| 项目 | 配置 |
| --- | --- |
| Base URL | `https://<网关地址>/ai/v1` |
| Bearer 鉴权 | `Authorization: Bearer sk-...` |
| API Key 鉴权 | `x-api-key: sk-...` |

密钥可绑定渠道分组和模型白名单。全局模型黑名单会同时作用于模型列表、
请求路由和探测候选；开启「过滤弃用模型」后，OCI 已宣布弃用的模型也会从
列表与路由中移除。

可先用模型列表验证地址与密钥：

```bash
curl "https://<网关地址>/ai/v1/models" \
  -H "Authorization: Bearer $OCI_PORTAL_KEY"
```

再发起一条最小 Responses 请求；请将示例模型替换为模型列表中的可见模型：

```bash
curl "https://<网关地址>/ai/v1/responses" \
  -H "Authorization: Bearer $OCI_PORTAL_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"xai.grok-4.3","input":"你好，请用一句话介绍自己。"}'
```

<a id="endpoints"></a>

## 端点一览

| 协议域 | 端点 | 角色 | 流式 |
| --- | --- | --- | :---: |
| 对话 | `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 外壳 | — |
| 语音 | `POST /ai/v1/tts` | xAI TTS 格式转换层 | — |
| 检索 | `POST /ai/v1/rerank` | Cohere / Jina 风格文档重排 | — |
| 安全 | `POST /ai/v1/moderations` | OpenAI 外壳映射 OCI Guardrails | — |
| 发现 | `GET /ai/v1/models` | 当前密钥可见模型列表 | — |

### 如何选择协议

| 使用场景 | 推荐接口 |
| --- | --- |
| 新客户端、推理模型、服务端工具 | **Responses** |
| Anthropic SDK、Claude 生态客户端 | **Messages** |
| 仅支持旧 OpenAI 对话协议的客户端 | **Chat Completions** |
| 向量、语音、重排与安全审核 | 对应专用端点 |

<a id="routing"></a>

## 路由与全局行为

### 请求链路

```mermaid
flowchart LR
    A[客户端] --> B[网关密钥鉴权]
    B --> C[分组、白名单与全局过滤]
    C --> D[模型与能力匹配]
    D --> E[选择最小 Priority]
    E --> F[同优先级按 Weight 加权]
    F --> G[OCI GenAI]
    G -. 可重试且流未建立 .-> D
```

单次请求最多尝试三个渠道。模型不可用、限流、上游服务错误或网络错误可触发
换渠道；流式连接建立后不会切换渠道重试。

### 全局兼容边界

| 主题 | 当前行为 |
| --- | --- |
| 会话状态 | 网关不保存会话历史，客户端必须在每次请求中携带完整上下文 |
| 上游存储 | Responses 请求始终强制 `store:false` |
| 有状态字段 | Responses 拒绝非空 `previous_response_id`、非 `null` 的 `conversation` 和 `background:true` |
| 对话上游 | 对话请求统一进入 OCI OpenAI 兼容面，当前供给以 `xai.`、`meta.`、`openai.` 前缀模型为主 |
| 推理强度 | Responses `reasoning.effort`、Messages `output_config.effort`、Chat `reasoning_effort` 会传给上游；可用档位由模型决定 |
| 服务端工具 | Responses 支持 `web_search`、`x_search`、`code_interpreter` 和远程 `mcp`；命名容器管理与 File Search 不提供 |
| 文件输入 | `input_file` 会被 OCI ZDR 形态拒绝，详见[已知限制](#limitations) |
| Chat 定位 | Chat Completions 只承担协议转换与兼容修复；新能力优先落在 Responses 与 Messages |

### 可配置运行策略

| 策略 | 默认行为 | 配置入口 |
| --- | --- | --- |
| Responses 流式保险丝 | 开启；阈值 `60 KB`，按 `instructions` 与 `tools` 两个字段的原始 JSON 值计算 | **设置 → AI → 流式保险丝** |
| Grok 服务端搜索 | 对 `xai.` 模型默认注入 `web_search` 与 `x_search`；同名工具不重复覆盖 | **设置 → AI → Grok 服务端搜索工具** |
| 弃用模型过滤 | 开启后从模型列表、请求路由与探测候选中统一排除 | **设置 → AI → 模型治理** |

<a id="codex"></a>

## Codex 接入

### 主配置

自定义模型提供方必须写在用户级 `~/.codex/config.toml`。Codex 的项目级
`.codex/config.toml` 不允许改写 `model_provider` 与 `model_providers`。

```toml
model = "xai.grok-4.3"
model_provider = "oci"

[model_providers.oci]
name = "oci-portal"
base_url = "https://<网关地址>/ai/v1"
env_key = "OCI_PORTAL_KEY"
wire_api = "responses"
```

### 自定义子代理

新版 Codex 可在 `~/.codex/agents/` 或项目级 `.codex/agents/` 放置独立 TOML
文件，并为子代理覆盖模型。每个文件都需要 `name`、`description` 和
`developer_instructions`：

```toml
# .codex/agents/oci-worker.toml
name = "oci-worker"
description = "通过 OCI Portal 网关执行通用开发任务。"
developer_instructions = """
完成被分配的开发任务，保持改动聚焦，并返回验证结果。
"""
model = "xai.grok-4.3"
```

> [!IMPORTANT]
> `Codex CLI 0.144.1` 已实测主会话和 multi-agent 子代理全链路可用。
> 内置 worker 可能先尝试 `gpt-5.6-luna` 或 `gpt-5.4`；网关没有对应渠道时
> 会出现少量 404，随后由 Codex 回落到可用模型。自定义 agent 的模型覆盖是否
> 直接生效取决于 Codex 版本；0.144.1 的实测主要依赖自动回落。

Codex 工具兼容现状：

| 工具形态 | 网关处理 | 验证状态 |
| --- | --- | --- |
| `function` | 原样透传 | 可用 |
| `namespace` | 子工具拍平为限定名 `function`，响应时还原 | multi-agent 已端到端实测；MCP 同路径有单测 |
| `custom` | 顶层普通工具转换为 `function`，调用与历史记录双向回转 | 可用，但存在降级边界 |
| `custom:apply_patch` | 直接剥离，让模型回落到其他编辑方式 | 有意限制 |
| `tool_search` | namespace 已完整展开，目录搜索语义冗余，直接剥离 | 有意降级 |

配置语法参考 [Codex Subagents](https://learn.chatgpt.com/docs/agent-configuration/subagents)
与 [Codex Advanced Configuration](https://learn.chatgpt.com/docs/config-file/config-advanced)。

<a id="limitations"></a>

## 已知限制

### `instructions` / `tools` 大体量流式断流

> [!WARNING]
> `instructions` 与 `tools` 两个字段的原始 JSON 值合计超过约 **64.5 KB** 时，
> 上游流式请求可能在推理阶段静默断连：连接直接 EOF，不发送 `error` 或终态事件。
> 同一请求改为非流式实测可正常完成；单独扩大 `input` 未触发该限制。

该问题于 2026-07-13 通过字节级二分定位，2026-07-16 在 Chicago 复测仍存在：
`70.4 KB` 断流、`59.7 KB` 正常，API Key 与签名鉴权表现一致。本文及设置页中的
`KB` 均按 `1024 B` 计算。

| 协议 | 网关保护 | 客户端表现 |
| --- | --- | --- |
| Responses | 保险丝默认开启；超过 `60 KB` 时改走非流式上游，并合成最小 SSE 序列 | 结果语义保留，但不再增量输出 |
| Chat Completions / Messages | 客户端尚未收到内容就断流时，自动改用非流式重做 | 合成对应 chunk / event 序列 |
| 已开始输出的流 | 无法透明重试；调用日志记录提前终止 | 客户端可能只收到部分事件 |

Responses 合成的最小事件序列为：`response.created` →
`response.output_item.done` → `response.completed`。保险丝可在
**设置 → AI → 流式保险丝** 调整或关闭。

<details>
<summary><strong>历史问题：完整请求体体积断流（已由上游修复）</strong></summary>

2026-07-15 曾在完整请求体约 `82 KB`（含 `input`）时观测到纯体积流式断流。
2026-07-16 复核 `83 KB`、真实 Codex 形态 `104.5 KB`、`200 KB` 与 `400 KB`
请求均正常完成；Chicago 与 Phoenix、签名与 API Key 两条路径结果一致。

</details>

### ZDR 与文件输入

Responses 的 `input_file` 内容块（`file_url` / `file_data`）实测会被上游拒绝：

```text
File content is currently unsupported for ZDR customers
```

网关强制 `store:false`，属于 ZDR 请求形态，因此当前不能通过该端点上传或引用文件。

<a id="compatibility"></a>

## 字段兼容矩阵

> [!IMPORTANT]
> 本项目提供兼容接口，而不是 OpenAI、Anthropic 或 xAI 协议的完整实现。部分 OCI
> OpenAI 兼容行为来自实测，未见 Oracle 文档合同，可能随上游调整。

### 矩阵索引

[Responses](#compat-responses) · [Chat Completions](#compat-chat) · [Messages](#compat-messages) · [Embeddings](#compat-embeddings) · [语音生成](#compat-audio) · [Rerank](#compat-rerank) · [Moderations](#compat-moderations) · [Models](#compat-models)

<details>
<summary><strong>展开参考规格</strong></summary>

- [OpenAI Responses](https://developers.openai.com/api/reference/resources/responses/methods/create)
- [OpenAI Chat Completions](https://developers.openai.com/api/reference/resources/chat/subresources/completions/methods/create)
- [OpenAI Embeddings](https://developers.openai.com/api/reference/resources/embeddings/methods/create)
- [OpenAI Audio Speech](https://developers.openai.com/api/reference/resources/audio/methods/speech)
- [OpenAI Moderations](https://developers.openai.com/api/reference/resources/moderations/methods/create)
- [Anthropic Messages](https://platform.claude.com/docs/en/api/messages/create)
- [Cohere Rerank](https://docs.cohere.com/reference/rerank)

</details>

| 标记 | 含义 |
| :---: | --- |
| ✅ | 网关直接支持 |
| ➡️ | 原样保留或透传；是否生效由 OCI 上游决定 |
| 🔄 | 网关执行字段或协议转换后支持 |
| ◐ | 部分支持、存在前置条件或语义降级 |

<a id="compat-responses"></a>

### OpenAI Responses

**`POST /ai/v1/responses` · 无状态主接口**

网关以原始 JSON 为基底保留未知字段，但会强制关闭上游存储，并执行下表列出的
Codex 工具兼容改写。请求会重新编码，不承诺字节级原样转发。

<details open>
<summary><strong>核心字段</strong></summary>

| 标准字段 | 状态 | 网关行为 |
| --- | :---: | --- |
| `model` | ◐ | 必填；通过密钥白名单并匹配可用渠道后送往上游 |
| `input` | ➡️ | 支持字符串或 item 数组；普通内容保留，Codex 工具历史项可能改写 |
| `instructions`、`max_output_tokens` | ➡️ | 类型可解析后保留，不做范围或模型能力校验 |
| `temperature`、`top_p` | ➡️ | 保留，不做取值范围校验 |
| `parallel_tool_calls` | ◐ | 通常保留；若全部工具被剥离，则与 `tool_choice` 一并删除 |
| `text` / `text.format` / `text.verbosity` | ➡️ | 整个对象保留；是否生效由 OCI 模型决定 |
| `reasoning` | ➡️ | 整个对象保留；`effort` 不校验档位 |
| `tool_choice` | ◐ | 普通形态保留；namespace 对象会重限定，全部工具被剥离时删除 |
| `store` | 🔄 | 无论客户端传什么，上游请求都强制改写为 `false` |
| `stream` | ◐ | 支持 SSE；`instructions` 与 `tools` 的原始 JSON 值合计超过保险丝阈值时，预防性改走非流式上游（默认开启、`60 KB`，见[已知限制](#limitations)） |
| 其余标准与未知顶层字段 | ➡️ | `context_management`、`include`、`metadata`、`prompt`、`prompt_cache_key`、`service_tier`、`truncation`、`user` 等均保留，由 OCI 决定是否接受 |

</details>

<details>
<summary><strong>工具兼容</strong></summary>

| 工具或参数 | 状态 | 网关行为 |
| --- | :---: | --- |
| `tools[].type=function` | ➡️ | 非流式与流式均可，工具对象保留 |
| `web_search` / `x_search` / `code_interpreter` | ◐ | Oracle 文档化的 xAI 服务端工具；参数与限制遵循 [xAI 规格](https://docs.oracle.com/en-us/iaas/Content/generative-ai/get-started-agents.htm#xai-compatible-tools) |
| `tools[].type=mcp` | ➡️ | 远程 MCP 由上游直连，`server_url`、`require_approval`、`authorization` 等保留 |
| `tools[].type=namespace` | 🔄 | 子 `function` 上提并限定命名；响应、历史调用和 `tool_choice` 会反向还原；组内非 `function` 子工具被剥离 |
| `tools[].type=custom` | ◐ | 顶层非 `apply_patch` 工具转为带 `input` schema 的 `function`；响应与多轮历史双向回转；`format` 会删除 |
| `custom:apply_patch` | ◐ | 整体剥离；Grok 系未针对 Codex 补丁格式训练，模型应回落其他编辑方式 |
| `tools[].type=tool_search` | ◐ | 请求可被接受，但工具本身直接剥离 |
| `web_search.external_web_access=true` | 🔄 | 删除上游不识别的字段，保留 `web_search` |
| `web_search.external_web_access=false` | ◐ | 上游没有“仅缓存检索”对应能力，按不越权原则剥离整个工具 |

</details>

本地拒绝（返回 400）：

- 非空 `previous_response_id`
- 非 `null` 的 `conversation`
- `background:true`
- 未列入白名单的工具类型，例如 `web_search_preview`、`file_search`、
  `computer`、`image_generation`、`shell`

响应边界：

- 无工具还原且未触发流式升级时，普通响应保持直通语义
- namespace / custom 调用会在非流式响应与命中的 SSE `data` 事件中定向还原
- 普通 SSE 不补 `data: [DONE]`，reasoning 增量不会被过滤
- 未知模型返回 404，无可用渠道返回 503
- 上游错误使用 OpenAI 风格错误外壳，但不保证字段与标准 OpenAI 完全一致

<a id="compat-chat"></a>

### OpenAI Chat Completions

**`POST /ai/v1/chat/completions` · 存量客户端兼容层**

请求先转换为 Responses，再将 OCI Responses 响应桥接回 Chat Completions。
只有下表字段会进入上游请求。

<details>
<summary><strong>展开字段矩阵</strong></summary>

| 标准字段 | 状态 | 网关行为 |
| --- | :---: | --- |
| `model` | ◐ | 必填，受密钥白名单和可用渠道限制 |
| `messages` | 🔄 | 必填，转换为 Responses `input` / `instructions` |
| `system` / `developer` 消息 | ◐ | 文本按顺序合并为 `instructions`；块数组中的非文本内容忽略 |
| `user` / `assistant` 文本 | 🔄 | 字符串和 `text` 块分别转为 `input_text` / `output_text` |
| `image_url` | ◐ | URL 或 data URI 转为 `input_image`；`detail` 忽略 |
| assistant `tool_calls` / `role=tool` | 🔄 | 转为 `function_call` / `function_call_output` |
| `max_completion_tokens` | 🔄 | 转为 `max_output_tokens`，优先于 `max_tokens` |
| `max_tokens` | 🔄 | 未提供 `max_completion_tokens` 时转为 `max_output_tokens` |
| `temperature`、`top_p`、`parallel_tool_calls` | ◐ | 写入 Responses，不校验范围或模型能力 |
| `stream` | 🔄 | Responses SSE 转为 `chat.completion.chunk`，末尾补 `data: [DONE]` |
| `stream_options.include_usage` | 🔄 | 控制终块后的独立 usage 块 |
| `tools[].type=function` | ◐ | 支持 `name`、`description`、`parameters`；`strict` 忽略 |
| `tool_choice` | ◐ | 支持 `auto` / `none` / `required` 和具名 function |
| `response_format` | ◐ | `json_object`、`json_schema` 转为 Responses `text.format` |
| `reasoning_effort` | ◐ | 转小写后映射为 `reasoning.effort` |
| `store` | 🔄 | 客户端取值忽略，上游始终使用 `store:false` |

</details>

不支持（返回 400）：`input_audio`、`file`、`refusal` 等消息内容块，以及
`function` 之外的工具类型。

<details>
<summary><strong>静默忽略字段</strong></summary>

消息级 `name` / `refusal` / `audio` / 旧式 `function_call`；`stop`、`seed`、
`n`、`frequency_penalty`、`presence_penalty`、`logprobs`、`top_logprobs`、
`logit_bias`；`user`、`audio`、`modalities`、`prediction`、`metadata`、
`moderation`、`prompt_cache_key`、`safety_identifier`、`service_tier`、
`verbosity`、`web_search_options`、`stream_options.include_obfuscation`
及其他未知字段。

</details>

响应边界：

- 非流式固定生成一个 `choices[0]`；文本合并，函数调用转为 `tool_calls`
- `finish_reason` 只生成 `stop`、`tool_calls`、`length`
- reasoning、logprobs、refusal、annotations、audio、service tier 和 system fingerprint 不返回
- usage 保留 `prompt_tokens`、`completion_tokens`、`total_tokens` 与
  `prompt_tokens_details.cached_tokens`
- 已开始输出的流中断不会转换成标准 SSE 错误事件

<a id="compat-messages"></a>

### Anthropic Messages

**`POST /ai/v1/messages` · Anthropic 协议转换层**

支持 `Authorization: Bearer` 与 `x-api-key`，但不校验或使用
`anthropic-version`、`anthropic-beta` 请求头。

<details>
<summary><strong>展开顶层字段矩阵</strong></summary>

| 标准字段 | 状态 | 网关行为 |
| --- | :---: | --- |
| `model` | ◐ | 用于模型与渠道选择；空字符串通常最终返回模型不存在 |
| `max_tokens` | 🔄 | 缺省或 ≤0 时使用 8192，再转为 `max_output_tokens` |
| `messages` | ◐ | 必须非空；角色、交替顺序和空内容不做完整校验 |
| `system` | ◐ | 支持字符串或 text 块数组；文本块拼接，附加字段忽略 |
| `temperature`、`top_p` | ◐ | 写入 Responses，不校验范围或模型能力 |
| `stream` | 🔄 | Responses SSE 桥接为 Anthropic 标准事件序列 |
| `tools` | ◐ | 每个工具转为 Responses `function`；服务端工具类型不保留原语义 |
| `tool_choice` | ◐ | 支持 `auto`、`any`、`none`、具名 `tool` |
| `output_config.effort` | 🔄 | 转小写后映射为 `reasoning.effort` |

</details>

内容块兼容：

| `messages[].content` | 状态 | 网关行为 |
| --- | :---: | --- |
| 字符串 / `text` | 🔄 | user 转 `input_text`，assistant 历史转 `output_text` |
| `image` | ◐ | 仅支持 `base64` 与 `url` source |
| `tool_use` | 🔄 | 转为 `function_call`，保留 ID、名称与输入 |
| `tool_result` | ◐ | 转为 `function_call_output`；块数组只拼接 text，`is_error` 与非文本结果丢失 |
| `null` / 空块数组 | ◐ | 消息可能从上游 input 中消失，不返回参数错误 |

不支持（返回 400）：`document`、服务端工具结果及未知内容块。历史
`thinking` / `redacted_thinking` 会删除。

<details>
<summary><strong>静默忽略字段</strong></summary>

`top_k`、`stop_sequences`、`metadata`、`thinking`、`output_config` 其余子字段、
`cache_control`、`container`、`inference_geo`、`service_tier` 及其他未知顶层字段。

</details>

响应边界：

- 仅将 Responses `output_text` 转为 `text`，`function_call` 转为 `tool_use`
- `stop_reason` 只生成 `end_turn`、`tool_use`、`max_tokens`
- 不生成 Anthropic thinking / signature 内容块
- usage 只保留 `input_tokens`、`output_tokens` 与 `cache_read_input_tokens`
- 流式上游错误与无终态断流会转成 Anthropic `error` 事件

<a id="compat-embeddings"></a>

### OpenAI Embeddings

**`POST /ai/v1/embeddings` · 向量化专用端点**

| 标准字段 | 状态 | 网关行为 |
| --- | :---: | --- |
| `model` | ◐ | 必填，受白名单限制，且需要 `EMBEDDING` 能力渠道 |
| 字符串 `input` | ✅ | 包装为单个输入后调用 OCI |
| 字符串数组 `input` | ✅ | 按原顺序调用 OCI |
| `dimensions` | ◐ | 映射为 OCI 输出维度，不校验范围或模型能力 |
| `encoding_format=float` | ✅ | 返回 float 数组；省略时相同 |

不支持（返回 400）：token ID 数组、空数组、`null` 和
`encoding_format=base64`。`user` 与其他未知字段静默忽略。

响应使用标准 `object:"list"` 外壳，向量为 `float32` 数组，不支持流式。

<a id="compat-audio"></a>

### 语音生成

两个端点最终使用同一 OCI xAI TTS 上游与渠道调度：

#### OpenAI Audio Speech

**`POST /ai/v1/audio/speech`**

| 标准字段 | 状态 | 网关行为 |
| --- | :---: | --- |
| `model` | ◐ | 必填，受白名单限制，需要 `TTS` 能力渠道；当前为 `xai.grok-tts` |
| `input` | ◐ | 必填非空，随后保留 |
| `voice` | ➡️ | 使用 xAI 音色 `ara` / `eve` / `leo` / `rex` / `sal` |
| `response_format` | ➡️ | 实测 `mp3` 可用，其余格式由上游决定 |
| `language`（扩展） | 🔄 | 上游必填；缺省时注入 `"auto"` |
| `speed`、`instructions` 与未知字段 | ➡️ | 保留，是否生效由上游决定 |

#### xAI TTS

**`POST /ai/v1/tts`**

接受 [xAI 官方 TTS 格式](https://docs.x.ai/developers/model-capabilities/audio/text-to-speech)，
转换为 OpenAI 兼容形态后进入同一上游。

| 字段 | 状态 | 网关行为 |
| --- | :---: | --- |
| `text` | 🔄 | 必填非空，转换为 `input` |
| `language` | ◐ | 必填，接受 BCP-47 或 `auto` |
| `voice_id` | 🔄 | 转为 `voice`；缺省交给上游默认值 `eve` |
| `output_format` | ➡️ | `{codec, sample_rate, bit_rate}` 对象保留，实测生效 |
| `speed` | ➡️ | 保留，实测可用 |
| `model`（网关扩展） | ◐ | 缺省注入 `xai.grok-tts`，可覆盖，受白名单限制 |
| 其余未知字段 | ➡️ | 保留，是否生效由上游决定 |

共同响应边界：

- 成功响应为一次性完整音频，`Content-Type` 透传上游，缺省 `audio/mpeg`
- 不提供 HTTP 流式音频或 WebSocket 代理
- 无 token 用量口径，调用日志只记时延与渠道

<a id="compat-rerank"></a>

### Rerank

**`POST /ai/v1/rerank` · Cohere / Jina 风格协议**

上游走 OCI typed 面，模型为 `cohere.rerank-v4.0-pro` 或 `-fast`。

| 字段 | 状态 | 网关行为 |
| --- | :---: | --- |
| `model` | ◐ | 必填，受白名单限制，需要 `RERANK` 能力渠道 |
| `query` | ✅ | 必填非空 |
| `documents` | ◐ | 仅接受字符串数组；旧版 `{"text": ...}` 对象数组返回 400 |
| `top_n` | ✅ | 可选，限制返回条数 |
| `return_documents` | ✅ | 为 `true` 时回带原文 |

`max_tokens_per_doc` 与未知字段静默忽略。响应按相关度降序，
`results[].index` 指向输入下标，`relevance_score` 为 0～1 浮点；无 token 用量口径。

<a id="compat-moderations"></a>

### Moderations

**`POST /ai/v1/moderations` · OpenAI 外壳映射 OCI Guardrails**

| 标准字段 | 状态 | 网关行为 |
| --- | :---: | --- |
| 字符串 `input` | ✅ | 单条审核 |
| 字符串数组 `input` | ✅ | 逐条审核，单次 1～8 条 |

不支持（返回 400）：多模态 input、空字符串条目、空数组或超过 8 条。
`model` 接受但忽略，不参与白名单判断。

响应边界：

- categories 使用 OCI 原生维度 `overall` / `blocklist` / `prompt_injection`
- 任一维度得分 ≥ 0.5 时 `flagged=true`
- PII 命中放在扩展字段 `results[].pii`，包含 `text`、`label`、`score`、
  `offset` 与 `length`，不参与 `flagged`
- 实测中文人名与手机号识别较弱，英文 PII 识别正常
- 响应 `model` 恒为 `oci-guardrails`

<a id="compat-models"></a>

### Models

**`GET /ai/v1/models` · 当前密钥可见模型列表**

响应使用 OpenAI Models 列表外壳，只返回同时通过以下条件的模型：

1. 存在于当前渠道目录
2. 匹配密钥绑定的渠道分组
3. 不在全局模型黑名单
4. 命中密钥模型白名单（配置时）
5. 未被「过滤弃用模型」开关排除

网关不提供标准的单模型检索端点。

<a id="implementation"></a>

## 附录：实现索引

| 端点 / 能力 | 主要实现 |
| --- | --- |
| Responses 直通与 Codex 工具兼容 | [`airesponses.go`](../internal/service/airesponses.go) · [`responses.go`](../internal/aiwire/responses.go) |
| Chat Completions 转换 | [`chatresponses.go`](../internal/service/chatresponses.go) · [`openai.go`](../internal/aiwire/openai.go) |
| Anthropic Messages 转换 | [`anthresponses.go`](../internal/service/anthresponses.go) · [`anthropic.go`](../internal/aiwire/anthropic.go) |
| 渠道路由与 Embeddings | [`aigateway_chat.go`](../internal/service/aigateway_chat.go) |
| TTS 上游 | [`genai_speech.go`](../internal/oci/genai_speech.go) · [`aigateway_extras.go`](../internal/service/aigateway_extras.go) |
| Rerank / Moderations 上游 | [`genai_guard.go`](../internal/oci/genai_guard.go) · [`rerank.go`](../internal/aiwire/rerank.go) · [`moderations.go`](../internal/aiwire/moderations.go) |
| HTTP Handler 与流式桥接 | [`aigateway.go`](../internal/api/aigateway.go) · [`aigateway_extras.go`](../internal/api/aigateway_extras.go) |

本文是兼容性快照，不替代 Swagger。标准接口、Codex 客户端与 OCI 上游均可能
变化，最终行为以当前版本代码、运行时 Swagger 和实测结果为准。

[返回顶部](#top)
