feat: harden public OpenAI API contracts
This commit is contained in:
@@ -0,0 +1,361 @@
|
||||
---
|
||||
title: 单租户生产化开发计划
|
||||
description: 以标准接口、实时可观测性、运行可靠性和全链路质量门禁为主线的建设计划。
|
||||
icon: list-checks
|
||||
---
|
||||
|
||||
# 单租户生产化开发计划
|
||||
|
||||
## 目标
|
||||
|
||||
本计划把当前平台从“功能完整的单租户 MVP”推进到“可以稳定对外提供服务的单租户生产平台”。建设顺序固定为:
|
||||
|
||||
1. 标准接口契约;
|
||||
2. 实时可观测性与 SLO;
|
||||
3. 生产运行可靠性;
|
||||
4. 全链路质量门禁。
|
||||
|
||||
顺序不能颠倒:先确定平台对调用方承诺的行为,再测量真实质量,然后根据数据加固运行时,最后用自动化门禁持续证明质量。
|
||||
|
||||
## 范围
|
||||
|
||||
本计划包含:
|
||||
|
||||
- OpenAI-compatible Responses 和 Realtime 公开接口;
|
||||
- HTTP、SSE、WebSocket 和 WebRTC 的协议契约;
|
||||
- Pipecat Pipeline、Provider、工具、知识库和后台任务的指标与追踪;
|
||||
- 单实例优先的生产部署、优雅停机、任务恢复和资源保护;
|
||||
- 协议、浏览器媒体链路、弱网、故障和负载测试。
|
||||
|
||||
本计划暂不包含:
|
||||
|
||||
- 多用户、组织、工作空间和 RBAC;
|
||||
- `/v1/chat/completions` 兼容层;
|
||||
- 完整实现 OpenAI Responses 的所有可选能力;
|
||||
- SIP、跨区域部署和 Realtime 断线续传;
|
||||
- 助手草稿、发布版本和环境晋级体系。
|
||||
|
||||
<Note>
|
||||
即使暂不建设完整权限体系,公网部署前仍必须移除默认凭证、分离签名密钥、启用 TLS,并设置基本的请求与并发限制。
|
||||
</Note>
|
||||
|
||||
## 当前基线
|
||||
|
||||
- `POST /v1/responses` 和 `GET /v1/responses/{response_id}` 已支持持久化状态、`previous_response_id`、SSE 和 Client Tool 续传。
|
||||
- `/v1/realtime/client_secrets`、`/v1/realtime/calls` 和 `/v1/realtime` WebSocket 已支持标准事件与项目扩展事件。
|
||||
- Realtime 已支持 WebRTC、WebSocket、Server VAD、PTT、打断、函数调用和条件视觉输入。
|
||||
- 后端现有 342 个自动化测试,并通过统一入口处理本地 NLTK 运行环境。
|
||||
- 前端可以通过构建和 lint,已增加官方 SDK 契约测试,但尚无系统性的组件测试和浏览器端到端测试。
|
||||
- Responses 已启用 Provider token usage 采集;延迟等 Pipecat metrics 尚未启用,健康检查仍只有进程存活语义。
|
||||
- 知识库处理、通话后分析、Webhook 和批量测试仍有进程内任务或 Worker。
|
||||
|
||||
## 里程碑一:标准接口契约
|
||||
|
||||
### 目标
|
||||
|
||||
让第三方调用方只依赖公开文档、OpenAPI 和标准 SDK 即可完成接入,并清楚知道哪些 OpenAI 能力受支持、哪些能力被平台锁定或尚未实现。
|
||||
|
||||
### 1.1 建立兼容性规范
|
||||
|
||||
- [x] 将公开协议命名为 `OpenAI-compatible subset v1`。
|
||||
- [x] 为 Responses 请求字段、返回对象、SSE 事件和错误码维护兼容矩阵。
|
||||
- [x] 为 Realtime 客户端事件、服务端事件、传输限制和扩展事件维护兼容矩阵。
|
||||
- [x] 区分三种字段状态:支持、平台锁定、不支持。
|
||||
- [x] 为 `x.interactive_media.*` 扩展增加独立版本号和能力协商说明。
|
||||
- [x] 规定新增字段向后兼容、废弃字段通知和破坏性变更升级规则。
|
||||
|
||||
### 1.2 补全公开 API Schema
|
||||
|
||||
- [x] 为 Responses create、retrieve 和错误对象建立 Pydantic 模型。
|
||||
- [x] 使用判别联合描述 `message`、`function_call` 和 `function_call_output`。
|
||||
- [x] 在 OpenAPI 中声明 JSON、multipart/form-data、application/sdp 和 text/event-stream。
|
||||
- [x] 为 Realtime JSON 事件维护可校验的 JSON Schema。
|
||||
- [x] 为所有公开响应声明状态码、错误结构和示例。
|
||||
- [x] 生成并提交稳定的 OpenAPI snapshot,CI 检查未审查的契约变化。
|
||||
|
||||
### 1.3 完善 Responses 资源接口
|
||||
|
||||
- [x] 增加 `GET /v1/responses/{response_id}/input_items`,支持稳定排序和分页。
|
||||
- [x] 增加 `DELETE /v1/responses/{response_id}`。
|
||||
- [x] 删除 Response 时使用逻辑删除或内部 tombstone,不能破坏已有子 Response 的祖先链。
|
||||
- [x] 增加 `Idempotency-Key`:同 Key、同请求返回原结果;同 Key、不同请求返回冲突。
|
||||
- [x] Provider 可以提供 Token 统计时返回真实 `usage`;无法提供时保持 `null` 并写入兼容说明。
|
||||
- [x] 暂不实现 background 时,明确拒绝 `/cancel`,而不是静默接受。
|
||||
|
||||
### 1.4 增加模型发现与统一错误
|
||||
|
||||
- [x] 增加 `GET /v1/models`,列出当前可以通过公开接口调用的助手。
|
||||
- [x] 第一版继续返回 `assistant:asst_xxx`;响应结构为未来稳定助手别名保留字段。
|
||||
- [x] 所有公开 HTTP 错误统一为 OpenAI 风格的 `error` 对象。
|
||||
- [x] 所有 HTTP 响应返回或透传 `X-Request-ID`。
|
||||
- [x] Realtime `error.event_id` 必须关联原客户端事件。
|
||||
- [x] 401、404、409、422、429、503 的使用规则写入协议文档。
|
||||
|
||||
### 1.5 SDK 契约测试
|
||||
|
||||
- [x] 使用官方 OpenAI Python SDK 测试 Responses 非流式、多轮和 SSE。
|
||||
- [x] 使用官方 OpenAI JavaScript SDK 测试相同场景。
|
||||
- [x] 测试 Client Tool 调用及 `function_call_output` 续传。
|
||||
- [x] 测试跨 API Key 隐藏、重复幂等键和不支持字段。
|
||||
- [x] 对 Realtime WebSocket 事件运行 JSON Schema 与事件顺序测试。
|
||||
|
||||
### 验收标准
|
||||
|
||||
- OpenAPI 中所有公开 HTTP 接口都有请求体、响应体和错误 schema。
|
||||
- 官方 Python 和 JavaScript SDK 可以通过自定义 `base_url` 完成三轮 Responses 对话。
|
||||
- 非流式结果、SSE 最终结果和 GET 查询结果语义一致。
|
||||
- 公开兼容矩阵与代码自动化测试一一对应。
|
||||
- 调用方不阅读项目源码也能完成首次接入。
|
||||
|
||||
## 里程碑二:实时可观测性与 SLO
|
||||
|
||||
### 目标
|
||||
|
||||
能够回答“慢在哪里、错在哪里、影响了多少会话”,并用可量化指标定义实时对话质量。
|
||||
|
||||
### 2.1 建立统一关联标识
|
||||
|
||||
每次执行使用以下层级:
|
||||
|
||||
```text
|
||||
request_id
|
||||
└─ session_id / response_id
|
||||
└─ conversation_id
|
||||
└─ turn_id
|
||||
├─ asr span
|
||||
├─ llm span
|
||||
├─ tts span
|
||||
├─ knowledge span
|
||||
└─ tool span
|
||||
```
|
||||
|
||||
- [ ] 使用 `contextvars` 在异步任务中传播关联标识。
|
||||
- [ ] HTTP、SSE、WebSocket、WebRTC、后台任务和 Webhook 使用同一套标识命名。
|
||||
- [ ] 日志中输出关联标识,但不把提示词、转写、密钥或动态变量作为默认日志字段。
|
||||
- [ ] 指标标签禁止使用 response ID、session ID 等高基数字段。
|
||||
|
||||
### 2.2 接入 Metrics 和 Tracing
|
||||
|
||||
- [ ] 启用 Pipecat Pipeline metrics。
|
||||
- [ ] 接入 Prometheus 指标端点。
|
||||
- [ ] 接入 OpenTelemetry SDK,并允许通过 OTLP 环境变量配置 exporter。
|
||||
- [ ] 为 FastAPI、HTTP Provider 调用和 PostgreSQL 增加基础自动插桩。
|
||||
- [ ] 为 Pipeline 阶段、工具、知识库、SSE 和后台任务增加业务 span。
|
||||
- [ ] exporter 不可用时不得阻塞或终止实时对话。
|
||||
|
||||
### 2.3 第一批指标
|
||||
|
||||
| 指标 | 类型 | 推荐标签 |
|
||||
| --- | --- | --- |
|
||||
| 活跃 Realtime 会话 | Gauge | channel、runtime_mode |
|
||||
| 会话建立和结束 | Counter | channel、status、reason |
|
||||
| 用户停说到首音频 | Histogram | runtime_mode、provider |
|
||||
| ASR final 延迟 | Histogram | interface_type、status |
|
||||
| LLM 首 Token 延迟 | Histogram | interface_type、status |
|
||||
| TTS 首音频延迟 | Histogram | interface_type、status |
|
||||
| 打断处理延迟 | Histogram | channel、status |
|
||||
| 工具调用延迟 | Histogram | tool_type、status |
|
||||
| 知识库检索延迟 | Histogram | mode、status |
|
||||
| Responses 请求 | Counter/Histogram | stream、status |
|
||||
| 后台任务 | Counter/Histogram | kind、status |
|
||||
|
||||
- [ ] 统一定义成功、取消、客户端断开、超时和内部失败状态。
|
||||
- [ ] Provider 错误按鉴权、限流、超时、网络和服务端错误分类。
|
||||
- [ ] WebRTC 首版从服务端可见统计开始;浏览器 `getStats()` 上报作为后续增强。
|
||||
|
||||
### 2.4 仪表盘与初始 SLO
|
||||
|
||||
- [ ] 建立 Realtime 总览、Provider、Responses、工具与后台任务仪表盘。
|
||||
- [ ] 至少展示 p50、p95、p99 和最近错误样本。
|
||||
- [ ] 先采集基线,再确认正式阈值。
|
||||
- [ ] 为会话建立失败率、首音频延迟、Provider 错误率和任务积压设置告警。
|
||||
|
||||
初始候选目标:
|
||||
|
||||
| 项目 | 候选目标 |
|
||||
| --- | --- |
|
||||
| Realtime 会话建立成功率 | ≥ 99.5% |
|
||||
| 用户停说到首音频 | p95 ≤ 2 秒 |
|
||||
| 服务端打断处理 | p95 ≤ 250 ms |
|
||||
| 平台自身导致的 turn 失败率 | ≤ 0.5% |
|
||||
| Responses 非流式成功率 | ≥ 99.5% |
|
||||
|
||||
正式 SLO 必须在目标部署环境和真实 Provider 上取得基线后确认。
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 可以从一次失败的会话追踪到具体 Provider、工具或存储阶段。
|
||||
- 仪表盘能展示首音频延迟、错误率、活跃会话和任务积压。
|
||||
- 关闭监控后端不会影响对话主链路。
|
||||
- 日志和指标不泄漏用户内容或密钥。
|
||||
|
||||
## 里程碑三:生产运行可靠性
|
||||
|
||||
### 目标
|
||||
|
||||
在单租户、单区域、单个 Realtime API 进程优先的约束下,实现可恢复、可排空、有限流和可备份的生产运行方式。
|
||||
|
||||
### 3.1 Realtime 进程生命周期
|
||||
|
||||
- [ ] 增加服务状态:starting、ready、draining、stopped。
|
||||
- [ ] draining 后停止签发 Client Secret,并拒绝新 Calls 和 WebSocket 会话。
|
||||
- [ ] 已建立会话在可配置的宽限期内继续运行。
|
||||
- [ ] 宽限期结束后取消剩余 Pipeline,并持久化明确终态。
|
||||
- [ ] 统一 WebRTC、WebSocket、RTVI 和 Responses 的关闭及取消路径。
|
||||
- [ ] 为 Pipeline 启动、关闭和资源释放增加超时保护。
|
||||
|
||||
Realtime Pipeline 与媒体连接绑定,继续保留在 API 进程内,不迁移到普通任务队列。
|
||||
|
||||
### 3.2 健康检查和资源保护
|
||||
|
||||
- [ ] 增加 `/health/live`,只判断事件循环和进程是否存活。
|
||||
- [ ] 增加 `/health/ready`,检查数据库、迁移版本、必要配置和对象存储。
|
||||
- [ ] readiness 失败时不接收新会话,但 liveness 不应因此触发无限重启。
|
||||
- [ ] 设置全局活跃会话上限和每 API Key 并发上限。
|
||||
- [ ] 为请求体、音频缓冲、SSE 队列和工具结果设置大小上限。
|
||||
- [ ] 数据库连接池、HTTP 连接池和线程池使用显式上限。
|
||||
- [ ] 达到容量上限时返回可识别的 429 或 503。
|
||||
|
||||
### 3.3 Provider 可靠性策略
|
||||
|
||||
- [ ] 统一 Provider 错误分类和超时配置。
|
||||
- [ ] 只有在尚未向客户端输出内容时才允许自动重试。
|
||||
- [ ] 流式输出开始后禁止透明重试,避免重复文字、音频或工具调用。
|
||||
- [ ] 对新会话实现轻量熔断和恢复探测。
|
||||
- [ ] 模型资源测试与生产请求共享同一套连接和错误分类逻辑。
|
||||
- [ ] 备用 Provider 或模型作为后续可选能力,不在第一批强制实现。
|
||||
|
||||
### 3.4 迁移后台任务
|
||||
|
||||
第一批迁移以下任务:
|
||||
|
||||
- 知识库文档解析与向量化;
|
||||
- 通话后分析;
|
||||
- Webhook 投递;
|
||||
- 批量测试和 Prompt 改进。
|
||||
|
||||
实现约束:
|
||||
|
||||
- [ ] 使用 Redis + ARQ 作为单租户 MVP 队列。
|
||||
- [ ] PostgreSQL 保存任务业务状态,Redis 只负责投递、租约和重试。
|
||||
- [ ] 每类任务都有幂等键、最大重试次数和明确终态。
|
||||
- [ ] Worker 崩溃后任务可以重新领取。
|
||||
- [ ] 重复执行不能重复发送 Webhook 或写入重复结果。
|
||||
- [ ] API 能查询任务状态,服务启动不再直接恢复和执行全部后台工作。
|
||||
|
||||
### 3.5 生产部署和恢复
|
||||
|
||||
- [ ] 增加生产 API 镜像,移除 `--reload`。
|
||||
- [ ] 前端使用 `next build` 与 `next start` 或静态生产部署。
|
||||
- [ ] 数据库迁移作为独立部署步骤,不能由多个 API 实例同时执行。
|
||||
- [ ] 为 PostgreSQL 和对象存储编写备份、恢复和校验步骤。
|
||||
- [ ] 设置日志轮转、磁盘水位和录音/Response 保留策略。
|
||||
- [ ] 完成一次从备份恢复到新环境的演练。
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 服务进入 draining 后不接收新会话,已有会话可以正常结束或在超时后被正确取消。
|
||||
- Worker 被强制终止后,未完成任务可以恢复且不会重复产生副作用。
|
||||
- Provider 超时不会无限占用 Pipeline 或连接。
|
||||
- 数据库或对象存储不可用时 readiness 会失败并给出可诊断原因。
|
||||
- 生产部署不运行开发热更新服务。
|
||||
|
||||
## 里程碑四:全链路质量门禁
|
||||
|
||||
### 目标
|
||||
|
||||
把协议正确性、实时体验和故障恢复变成每次变更都能重复验证的发布条件。
|
||||
|
||||
### 4.1 测试分层
|
||||
|
||||
| 层级 | 运行时机 | 内容 |
|
||||
| --- | --- | --- |
|
||||
| 单元和组件测试 | 每次提交 | 协议解析、状态机、工具、工作流、指标 |
|
||||
| 契约测试 | 每次提交 | OpenAPI、JSON Schema、Python/JS SDK |
|
||||
| 服务集成测试 | 每次提交 | PostgreSQL、Redis、对象存储、Fake Provider |
|
||||
| 浏览器媒体测试 | 主分支或发布前 | WebRTC、假麦克风、DataChannel、打断 |
|
||||
| 基础设施测试 | 每日或发布前 | TURN、弱网、故障注入 |
|
||||
| 真实 Provider smoke | 每日或发布前 | 限量 ASR、LLM、TTS、Realtime 调用 |
|
||||
| 负载和长稳测试 | 发布前 | 并发、容量、内存、连接和任务泄漏 |
|
||||
|
||||
### 4.2 每次提交门禁
|
||||
|
||||
- [ ] 提供一个无需隐藏环境变量的后端测试命令。
|
||||
- [ ] 运行后端全部测试、前端 lint 和 production build。
|
||||
- [ ] 从空数据库执行所有 Alembic migrations。
|
||||
- [ ] 校验 OpenAPI snapshot 和 Realtime JSON Schema。
|
||||
- [ ] 使用 Fake Provider 完成 Responses 三轮对话、分支和 Client Tool 续传。
|
||||
- [ ] 测试 SSE 断开、Pipeline 失败、超时和取消后的数据库终态。
|
||||
- [ ] 测试 Worker 幂等、重试和任务恢复。
|
||||
|
||||
### 4.3 浏览器和媒体链路
|
||||
|
||||
- [ ] 使用 Playwright Chromium 假麦克风输入固定音频文件。
|
||||
- [ ] 验证 WebRTC SDP、远端音频轨道和 `oai-events` DataChannel。
|
||||
- [ ] 验证 Server VAD、PTT、打断和 Client Tool。
|
||||
- [ ] 使用固定 PCM fixture 测试 Realtime WebSocket。
|
||||
- [ ] 在独立环境中强制只走 TURN,避免测试误用直连路径。
|
||||
- [ ] 保存失败时的浏览器日志、协议事件和服务端 trace。
|
||||
|
||||
### 4.4 弱网、故障和负载
|
||||
|
||||
- [ ] 使用 Linux `tc netem` 注入延迟、抖动、丢包和短时断网。
|
||||
- [ ] 注入 ASR、LLM、TTS、工具、数据库、Redis 和对象存储超时。
|
||||
- [ ] 验证客户端断开后 Pipeline 与资源及时释放。
|
||||
- [ ] 对 Responses HTTP/SSE 和 Realtime WebSocket 运行并发测试。
|
||||
- [ ] 使用 aiortc 测试客户端运行 WebRTC 并发场景。
|
||||
- [ ] 运行 30 至 60 分钟长连接 soak test,观察内存、Task 和连接数量。
|
||||
|
||||
### 4.5 发布判定
|
||||
|
||||
一次生产发布至少满足:
|
||||
|
||||
- [ ] 单元、契约、集成和浏览器关键路径全部通过。
|
||||
- [ ] 没有未审查的公开协议变化。
|
||||
- [ ] p95 首音频延迟未超过允许回归范围。
|
||||
- [ ] 错误率、超时率和异常断开率未超过阈值。
|
||||
- [ ] 没有持续增长的 Pipeline、asyncio Task、数据库连接或 WebRTC peer。
|
||||
- [ ] 备份恢复和 Worker 恢复机制在当前版本仍然有效。
|
||||
|
||||
## 推荐交付批次
|
||||
|
||||
### 批次 A:契约与工程入口
|
||||
|
||||
- 修复统一测试命令;
|
||||
- 建立后端、前端和 migration CI;
|
||||
- 为 Responses 增加 Pydantic/OpenAPI schema;
|
||||
- 增加统一错误对象、Request ID 和 OpenAPI snapshot;
|
||||
- 增加 Python SDK Responses 契约测试。
|
||||
|
||||
### 批次 B:Realtime 契约与观测基础
|
||||
|
||||
- 建立 Realtime 事件 JSON Schema;
|
||||
- 增加 JavaScript SDK 和 WebSocket 契约测试;
|
||||
- 建立关联 ID 和结构化日志;
|
||||
- 接入 Prometheus 与 OpenTelemetry;
|
||||
- 输出第一版运行基线仪表盘。
|
||||
|
||||
### 批次 C:生命周期与 Worker
|
||||
|
||||
- 增加 live、ready 和 draining;
|
||||
- 增加会话、缓冲和连接池上限;
|
||||
- 统一 Provider 超时和重试边界;
|
||||
- 引入 ARQ Worker 并逐类迁移后台任务;
|
||||
- 增加生产镜像与备份恢复说明。
|
||||
|
||||
### 批次 D:全链路发布门禁
|
||||
|
||||
- 建立 PostgreSQL、Redis、对象存储和 Fake Provider 集成环境;
|
||||
- 增加 Playwright WebRTC 与 PCM WebSocket 测试;
|
||||
- 增加 TURN、弱网、故障注入和真实 Provider smoke;
|
||||
- 建立负载、长稳测试和发布阈值。
|
||||
|
||||
## 总体验收
|
||||
|
||||
完成本计划后,平台应满足以下定义:
|
||||
|
||||
1. 对外接口有明确、可生成、可测试的稳定契约;
|
||||
2. 每个请求、会话和对话轮次都可以被测量和追踪;
|
||||
3. 服务、Provider 或 Worker 故障不会留下无法恢复的模糊状态;
|
||||
4. 发布前可以自动证明标准接口、实时媒体链路和核心 SLO 没有回归;
|
||||
5. 无需引入多用户体系,也能作为单租户生产服务安全、稳定地运行。
|
||||
@@ -46,7 +46,11 @@
|
||||
"groups": [
|
||||
{
|
||||
"group": "开始与对接",
|
||||
"pages": ["index", "integrations", "tool-resources", "responses-api", "realtime-protocol"]
|
||||
"pages": ["index", "integrations", "tool-resources", "openai-compatibility", "responses-api", "realtime-protocol"]
|
||||
},
|
||||
{
|
||||
"group": "开发与质量",
|
||||
"pages": ["development-plan"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
---
|
||||
title: OpenAI 兼容范围
|
||||
description: OpenAI-compatible subset v1 的字段、事件、错误与版本兼容矩阵。
|
||||
icon: brackets
|
||||
---
|
||||
|
||||
# OpenAI-compatible subset v1
|
||||
|
||||
平台公开协议命名为 **OpenAI-compatible subset v1**。它兼容 OpenAI Responses 与 Realtime 的核心调用方式,但只承诺本页列出的子集;没有列为“支持”的 OpenAI 字段,不能视为已经实现。
|
||||
|
||||
字段分为三种状态:
|
||||
|
||||
| 状态 | 含义 |
|
||||
| --- | --- |
|
||||
| 支持 | 字段会被校验并产生文档描述的效果 |
|
||||
| 平台锁定 | 能力存在,但值来自助手配置;调用方提交时返回 `immutable_configuration` 或 `immutable_session_field` |
|
||||
| 不支持 | 当前版本不实现;显式提交时返回 `unsupported_parameter`、`unsupported_operation` 或 `invalid_event` |
|
||||
|
||||
## HTTP 资源
|
||||
|
||||
| 接口 | 状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `GET /v1/models` | 支持 | 返回可通过公开协议调用的 `assistant:asst_xxx` |
|
||||
| `POST /v1/responses` | 支持 | 非流式 JSON 或 Responses SSE |
|
||||
| `GET /v1/responses/{id}` | 支持 | 只允许创建它的长期 API Key 查询 |
|
||||
| `GET /v1/responses/{id}/input_items` | 支持 | `after`、`limit`、`order` 游标分页 |
|
||||
| `DELETE /v1/responses/{id}` | 支持 | 逻辑删除;既有子 Response 的祖先链仍可恢复 |
|
||||
| `POST /v1/responses/{id}/cancel` | 不支持 | subset v1 不支持 background,固定返回 `unsupported_operation` |
|
||||
| `POST /v1/realtime/client_secrets` | 支持 | 使用长期 Key 签发短期、绑定助手的令牌 |
|
||||
| `POST /v1/realtime/calls` | 支持 | `multipart/form-data` 或原始 `application/sdp` |
|
||||
| `GET /v1/realtime` WebSocket upgrade | 支持 | 服务端或自定义客户端 Realtime 连接 |
|
||||
| `/v1/chat/completions` | 不支持 | 不提供旧 Chat Completions 兼容层 |
|
||||
|
||||
## Responses 请求字段
|
||||
|
||||
| 字段 | 状态 | subset v1 行为 |
|
||||
| --- | --- | --- |
|
||||
| `model` | 支持 | 首轮必填,格式为 `assistant:asst_xxx`;后续可继承 |
|
||||
| `input` 字符串 | 支持 | 转换为一条 `user` 文本消息 |
|
||||
| `input[].message` | 支持 | 仅文本 `input_text` / `output_text` |
|
||||
| `input[].function_call_output` | 支持 | 只能解析父链尚未完成的 Client Tool call ID |
|
||||
| `previous_response_id` | 支持 | 恢复祖先上下文,允许从同一父节点分支 |
|
||||
| `stream` | 支持 | `false` 返回 JSON;`true` 返回 SSE |
|
||||
| `store` | 支持但固定 | 只能省略或为 `true` |
|
||||
| `x_interactive_media.variables` | 支持 | 首轮赋值,后续继承并增量覆盖 |
|
||||
| `instructions` | 平台锁定 | 来自助手配置 |
|
||||
| `tools`、`tool_choice` | 平台锁定 | 来自助手及工具绑定 |
|
||||
| `background`、`conversation` | 不支持 | 状态只通过 `previous_response_id` 管理 |
|
||||
| `include`、`reasoning`、`text` | 不支持 | 显式拒绝,不静默忽略 |
|
||||
| `temperature`、`top_p`、`truncation` | 不支持 | 由底层助手和模型资源控制 |
|
||||
| 图片、文件输入 | 不支持 | 文本接口只接受文本;实时图片走 Realtime item |
|
||||
|
||||
Response 返回标准 `response` 对象。`output` 当前可能包含 `message` 或 `function_call`。如果底层 Provider 能稳定提供 token 统计,`usage` 返回真实值;当前无法取得时明确返回 `null`,不会估算。
|
||||
|
||||
## Responses SSE 事件
|
||||
|
||||
| 事件 | 状态 | 顺序约束 |
|
||||
| --- | --- | --- |
|
||||
| `response.created` | 支持 | 第一个事件 |
|
||||
| `response.in_progress` | 支持 | 紧随 created |
|
||||
| `response.output_item.added` / `done` | 支持 | 每个输出项各一组 |
|
||||
| `response.content_part.added` / `done` | 支持 | 文本输出项使用 |
|
||||
| `response.output_text.delta` / `done` | 支持 | delta 为零到多个,done 恰好一个 |
|
||||
| `response.function_call_arguments.delta` / `done` | 支持 | Client Tool 参数使用;done 恰好一个 |
|
||||
| `response.completed` | 支持 | 正常终态,最后一个事件 |
|
||||
| `error` + `response.failed` | 支持 | 失败终态 |
|
||||
|
||||
每个事件都有从 `0` 开始单调递增的 `sequence_number`。流式终态、同一 Response 的非流式结果和随后 GET 的资源语义一致。
|
||||
|
||||
## Realtime 客户端事件
|
||||
|
||||
以下客户端事件属于 Core 支持范围:
|
||||
|
||||
- `session.update`
|
||||
- `conversation.item.create`
|
||||
- `conversation.item.truncate`
|
||||
- `input_audio_buffer.append`
|
||||
- `input_audio_buffer.commit`
|
||||
- `input_audio_buffer.clear`
|
||||
- `output_audio_buffer.clear`
|
||||
- `response.create`
|
||||
- `response.cancel`
|
||||
|
||||
会话中的 `model`、`instructions`、`voice`、`tools` 和 `tool_choice` 为平台锁定字段。`output_modalities` 与 Server VAD / PTT 参数可更新。WebSocket 支持 Base64 PCM16 音频;WebRTC 音频走媒体轨道,事件走 `oai-events` DataChannel。连续视频只通过协商后的 WebRTC video track 提供。
|
||||
|
||||
服务端事件的完整名称与最小 envelope 由仓库中的 `backend/contracts/openai-realtime-server-events.schema.json` 定义;客户端事件由 `backend/contracts/openai-realtime-client-events.schema.json` 定义。
|
||||
|
||||
## Interactive Media Extensions v1
|
||||
|
||||
所有扩展事件都使用 `x.interactive_media.*` 命名空间,并独立版本化为字符串 `"1"`。
|
||||
|
||||
客户端先协商能力:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "x.interactive_media.capabilities.update",
|
||||
"event_id": "evt_caps_001",
|
||||
"version": "1",
|
||||
"capabilities": ["dynamic_variables", "workflow_events"]
|
||||
}
|
||||
```
|
||||
|
||||
服务端以 `x.interactive_media.capabilities.updated` 返回 `capabilities`、`rejected` 和实际 `version`。只有协商成功后,服务端才发送相应扩展事件。当前能力为:
|
||||
|
||||
| capability | 作用 |
|
||||
| --- | --- |
|
||||
| `dynamic_variables` | 运行中更新声明过的动态变量 |
|
||||
| `workflow_events` | 接收节点、业务事件、变量和错误事件 |
|
||||
| `handoff` | 接收人工接管和通话结束事件 |
|
||||
| `video_track` | 协商项目扩展的 WebRTC 视频轨道 |
|
||||
|
||||
扩展事件缺少版本或使用未知版本时返回 `invalid_event`;未知 capability 会出现在 `rejected` 中,不会被静默启用。
|
||||
|
||||
## 错误与状态码
|
||||
|
||||
所有公开 HTTP 错误统一返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": {
|
||||
"type": "invalid_request_error",
|
||||
"code": "response_not_ready",
|
||||
"message": "Previous response is in_progress",
|
||||
"param": "previous_response_id"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| HTTP 状态 | 使用规则 |
|
||||
| --- | --- |
|
||||
| `400` | schema 合法但字段不支持、平台锁定或业务语义无效 |
|
||||
| `401` | Bearer Key 缺失、无效、过期,或令牌类型不适用于接口 |
|
||||
| `404` | 资源不存在、已删除或属于另一个 API Key |
|
||||
| `409` | 父响应未结束、幂等键冲突或资源状态冲突 |
|
||||
| `422` | JSON、路径或查询参数不符合公开 schema |
|
||||
| `429` | 请求、并发或容量限制;当前为预留标准状态 |
|
||||
| `500` | 运行中不可恢复的内部失败 |
|
||||
| `503` | 服务暂时不能接收请求;当前为预留标准状态 |
|
||||
| `504` | Responses 生成超过服务端超时 |
|
||||
|
||||
每个 HTTP 响应都带 `X-Request-ID`。调用方传入符合格式的 ID 时服务端透传,否则生成 `req_...`。Realtime `error` 事件中的 `error.event_id` 指向导致错误的客户端 `event_id`。
|
||||
|
||||
## 兼容性规则
|
||||
|
||||
- subset v1 内新增可选字段、可选事件字段和新错误码属于向后兼容变更。
|
||||
- 新增必须由调用方主动使用的扩展 capability 属于向后兼容变更。
|
||||
- 删除字段、改变字段含义、改变既有事件顺序或把可选字段改为必填,必须升级协议主版本。
|
||||
- 平台锁定或不支持的字段转为支持,可以在 v1 内发布,但必须同步 schema、兼容矩阵、示例和 SDK 契约测试。
|
||||
- 废弃项至少在开发者文档中标记一个发布周期;破坏性变更不得在原版本中静默上线。
|
||||
@@ -6,7 +6,7 @@ icon: radio
|
||||
|
||||
# Realtime 兼容协议设计
|
||||
|
||||
> 当前实现版本为 `Interactive Media Realtime Extensions v1`。OpenAI 兼容接口与现有 `/api/webrtc/offer`、`/ws/voice`、`/ws/stream`、RTVI 消息并行提供;RTVI 不是待删除的迁移接口。
|
||||
> 当前公开协议为 `OpenAI-compatible subset v1`,扩展版本为 `Interactive Media Realtime Extensions v1`。完整兼容矩阵见 [OpenAI 兼容范围](/openai-compatibility)。OpenAI 兼容接口与现有 `/api/webrtc/offer`、`/ws/voice`、`/ws/stream`、RTVI 消息并行提供;RTVI 不是待删除的迁移接口。
|
||||
|
||||
## 设计目标
|
||||
|
||||
@@ -40,6 +40,8 @@ Realtime 协议适配层
|
||||
|
||||
普通兼容客户端不声明扩展能力时,服务端不会发送 `x.interactive_media.*` 事件。它仍可使用音频、文本、图片、转写、回复流、打断和函数调用,但不会获得工作流节点、动态变量、连续视频等项目专属状态。
|
||||
|
||||
客户端和服务端事件的机器可校验版本分别保存在 `backend/contracts/openai-realtime-client-events.schema.json` 与 `backend/contracts/openai-realtime-server-events.schema.json`。所有服务端事件含唯一 `event_id`;错误事件中的 `error.event_id` 指向触发错误的客户端事件。
|
||||
|
||||
## 接口概览
|
||||
|
||||
假设服务地址为 `https://api.example.com`:
|
||||
@@ -507,6 +509,7 @@ Qwen Realtime provider 只允许在 provider 会话首次配置前选择 PTT 或
|
||||
{
|
||||
"event_id": "evt_capabilities_001",
|
||||
"type": "x.interactive_media.capabilities.update",
|
||||
"version": "1",
|
||||
"capabilities": [
|
||||
"workflow_events",
|
||||
"dynamic_variables",
|
||||
@@ -522,6 +525,7 @@ Qwen Realtime provider 只允许在 provider 会话首次配置前选择 PTT 或
|
||||
{
|
||||
"event_id": "evt_server_001",
|
||||
"type": "x.interactive_media.capabilities.updated",
|
||||
"version": "1",
|
||||
"capabilities": [
|
||||
"workflow_events",
|
||||
"dynamic_variables",
|
||||
@@ -532,7 +536,7 @@ Qwen Realtime provider 只允许在 provider 会话首次配置前选择 PTT 或
|
||||
}
|
||||
```
|
||||
|
||||
服务端只发送已接受能力对应的扩展事件。扩展版本与 OpenAI Realtime Core 独立演进。
|
||||
服务端只发送已接受能力对应的扩展事件。所有扩展事件使用字符串 `version: "1"`;扩展版本与 OpenAI Realtime Core 独立演进。
|
||||
|
||||
### 扩展事件目录
|
||||
|
||||
@@ -555,6 +559,7 @@ Qwen Realtime provider 只允许在 provider 会话首次配置前选择 PTT 或
|
||||
{
|
||||
"event_id": "evt_variables_001",
|
||||
"type": "x.interactive_media.session.variables.update",
|
||||
"version": "1",
|
||||
"update_id": "update_001",
|
||||
"variables": {
|
||||
"user_name": "王先生",
|
||||
@@ -567,6 +572,7 @@ Qwen Realtime provider 只允许在 provider 会话首次配置前选择 PTT 或
|
||||
{
|
||||
"event_id": "evt_server_002",
|
||||
"type": "x.interactive_media.session.variables.updated",
|
||||
"version": "1",
|
||||
"update_id": "update_001",
|
||||
"status": "accepted"
|
||||
}
|
||||
@@ -578,6 +584,7 @@ Qwen Realtime provider 只允许在 provider 会话首次配置前选择 PTT 或
|
||||
{
|
||||
"event_id": "evt_server_003",
|
||||
"type": "x.interactive_media.workflow.node_active",
|
||||
"version": "1",
|
||||
"nodeId": "collect_materials"
|
||||
}
|
||||
```
|
||||
@@ -588,6 +595,7 @@ Qwen Realtime provider 只允许在 provider 会话首次配置前选择 PTT 或
|
||||
{
|
||||
"event_id": "evt_server_004",
|
||||
"type": "x.interactive_media.call.ended",
|
||||
"version": "1",
|
||||
"reason": "assistant_completed"
|
||||
}
|
||||
```
|
||||
@@ -625,13 +633,13 @@ Qwen Realtime provider 只允许在 provider 会话首次配置前选择 PTT 或
|
||||
|
||||
| code | 含义 |
|
||||
| --- | --- |
|
||||
| `authentication_failed` | API Key 或临时令牌无效 |
|
||||
| `assistant_not_found` | 助手不存在、未发布或不可访问 |
|
||||
| `session_field_locked` | 客户端尝试覆盖服务端锁定配置 |
|
||||
| `unsupported_event` | 当前协议版本不支持该事件 |
|
||||
| `capability_not_enabled` | 未协商或无权使用某项扩展 |
|
||||
| `response_in_progress` | 已有活动回复且当前请求不能并发执行 |
|
||||
| `tool_result_timeout` | Client 工具未在规定时间内返回 |
|
||||
| `invalid_api_key` | API Key 或临时令牌无效 |
|
||||
| `invalid_model` | 助手不存在、格式错误或不适用于当前运行时 |
|
||||
| `immutable_session_field` | 客户端尝试覆盖服务端锁定配置 |
|
||||
| `invalid_event` | 事件名或事件字段不符合当前 schema |
|
||||
| `extension_not_negotiated` | 使用了尚未协商的扩展能力 |
|
||||
| `input_audio_buffer_not_committed` | 手动音频缓冲尚未提交 |
|
||||
| `input_audio_buffer_too_large` | 音频超过单次缓冲上限 |
|
||||
| `internal_error` | 运行时出现不可恢复错误 |
|
||||
|
||||
错误只终止相关事件;只有鉴权失败、协议严重错误或运行时不可恢复时才关闭整个连接。
|
||||
|
||||
@@ -5,10 +5,19 @@ description: 使用 OpenAI Responses 风格的 HTTP 与 SSE 接口调用平台
|
||||
|
||||
# Stateful Responses 文本接口
|
||||
|
||||
`POST /v1/responses` 为 Pipeline 助手提供文本调用。服务端保存每轮输入和输出,后续请求通过 `previous_response_id` 恢复上下文。语音、视频和长连接交互继续使用 `/v1/realtime`。
|
||||
`POST /v1/responses` 是 **OpenAI-compatible subset v1** 的有状态文本接口。服务端保存每轮输入和输出,后续请求通过 `previous_response_id` 恢复上下文。语音、视频和长连接交互继续使用 `/v1/realtime`。字段和事件边界见 [OpenAI 兼容范围](/openai-compatibility)。
|
||||
|
||||
接口使用后台创建的长期 `sk-rt-...` API Key。短期 `ek-rt-...` Client Secret 不能调用文本接口。
|
||||
|
||||
## 发现可用助手
|
||||
|
||||
```bash
|
||||
curl "https://api.example.com/v1/models" \
|
||||
-H "Authorization: Bearer $REALTIME_API_KEY"
|
||||
```
|
||||
|
||||
返回对象中的 `id` 可直接作为 Responses 或 Realtime 的 `model`。`capabilities` 表明该助手支持 `responses`、`realtime` 或两者。
|
||||
|
||||
## 首轮请求
|
||||
|
||||
```bash
|
||||
@@ -65,6 +74,54 @@ curl "https://api.example.com/v1/responses/resp_xxx" \
|
||||
-H "Authorization: Bearer $REALTIME_API_KEY"
|
||||
```
|
||||
|
||||
## 官方 SDK
|
||||
|
||||
Python:
|
||||
|
||||
```python
|
||||
from openai import OpenAI
|
||||
|
||||
client = OpenAI(
|
||||
api_key="sk-rt-...",
|
||||
base_url="https://api.example.com/v1",
|
||||
)
|
||||
|
||||
first = client.responses.create(
|
||||
model="assistant:asst_xxx",
|
||||
input="第一轮",
|
||||
)
|
||||
second = client.responses.create(
|
||||
previous_response_id=first.id,
|
||||
input="第二轮",
|
||||
)
|
||||
third = client.responses.create(
|
||||
previous_response_id=second.id,
|
||||
input="第三轮",
|
||||
)
|
||||
print(third.output_text)
|
||||
```
|
||||
|
||||
JavaScript:
|
||||
|
||||
```js
|
||||
import OpenAI from "openai";
|
||||
|
||||
const client = new OpenAI({
|
||||
apiKey: "sk-rt-...",
|
||||
baseURL: "https://api.example.com/v1",
|
||||
});
|
||||
|
||||
const first = await client.responses.create({
|
||||
model: "assistant:asst_xxx",
|
||||
input: "第一轮",
|
||||
});
|
||||
const second = await client.responses.create({
|
||||
previous_response_id: first.id,
|
||||
input: "第二轮",
|
||||
});
|
||||
console.log(second.output_text);
|
||||
```
|
||||
|
||||
## SSE 流式输出
|
||||
|
||||
设置 `stream: true` 后返回 `text/event-stream`:
|
||||
@@ -77,7 +134,37 @@ curl "https://api.example.com/v1/responses/resp_xxx" \
|
||||
}
|
||||
```
|
||||
|
||||
主要事件依次为 `response.created`、`response.in_progress`、`response.output_text.delta`、`response.output_text.done` 和 `response.completed`。连接中断会取消运行,并把 Response 标记为 `cancelled`。
|
||||
文本输出的主要事件依次为 `response.created`、`response.in_progress`、`response.output_text.delta`、`response.output_text.done` 和 `response.completed`。Client Tool 参数通过 `response.function_call_arguments.delta` 与 `response.function_call_arguments.done` 返回。连接中断会取消运行,并把 Response 标记为 `cancelled`。
|
||||
|
||||
每个 SSE 事件都有连续的 `sequence_number`。Python SDK 可直接迭代:
|
||||
|
||||
```python
|
||||
stream = client.responses.create(
|
||||
model="assistant:asst_xxx",
|
||||
input="流式介绍",
|
||||
stream=True,
|
||||
)
|
||||
for event in stream:
|
||||
if event.type == "response.output_text.delta":
|
||||
print(event.delta, end="")
|
||||
```
|
||||
|
||||
## 幂等重试
|
||||
|
||||
创建请求可以携带 `Idempotency-Key`:
|
||||
|
||||
```bash
|
||||
curl -X POST "https://api.example.com/v1/responses" \
|
||||
-H "Authorization: Bearer $REALTIME_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Idempotency-Key: order-A123-turn-1" \
|
||||
-d '{"model":"assistant:asst_xxx","input":"查询订单 A123"}'
|
||||
```
|
||||
|
||||
- 同一 API Key、同一幂等键、相同请求会返回原 Response,并带 `X-Idempotent-Replayed: true`。
|
||||
- 相同幂等键对应不同请求时返回 `409 idempotency_key_conflict`。
|
||||
- 原请求仍在生成时返回 `409 idempotency_key_in_use`。
|
||||
- 幂等键最长 255 个字符;建议调用方使用业务请求 ID 或 UUID。
|
||||
|
||||
## 动态变量
|
||||
|
||||
@@ -126,10 +213,50 @@ curl "https://api.example.com/v1/responses/resp_xxx" \
|
||||
|
||||
如果父链存在多个尚未完成的 Client Tool,本轮必须一次提交全部对应结果。
|
||||
|
||||
## 输入项与删除
|
||||
|
||||
输入项接口支持稳定游标分页,默认按倒序返回 20 项:
|
||||
|
||||
```bash
|
||||
curl "https://api.example.com/v1/responses/resp_xxx/input_items?order=asc&limit=20" \
|
||||
-H "Authorization: Bearer $REALTIME_API_KEY"
|
||||
```
|
||||
|
||||
继续翻页时把上一页 `last_id` 传给 `after`。`limit` 范围为 1 到 100。
|
||||
|
||||
删除 Response:
|
||||
|
||||
```bash
|
||||
curl -X DELETE "https://api.example.com/v1/responses/resp_xxx" \
|
||||
-H "Authorization: Bearer $REALTIME_API_KEY"
|
||||
```
|
||||
|
||||
删除使用内部 tombstone。该 ID 随后查询或作为新父响应时返回 404;已经存在的子 Response 仍可沿内部祖先链恢复上下文。正在生成的 Response 返回 409,不能通过删除来取消。
|
||||
|
||||
subset v1 不支持 background,因此 `POST /v1/responses/{id}/cancel` 明确返回 `400 unsupported_operation`。
|
||||
|
||||
## 请求关联与错误
|
||||
|
||||
所有 HTTP 响应都返回 `X-Request-ID`。可以在请求中传入自己的安全标识并由服务端透传,便于关联调用方日志;没有提供时服务端生成 `req_...`。
|
||||
|
||||
错误统一使用 OpenAI 风格 envelope:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": {
|
||||
"type": "invalid_request_error",
|
||||
"code": "response_not_found",
|
||||
"message": "Response not found",
|
||||
"param": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 首版边界
|
||||
|
||||
- 仅支持 `runtimeMode=pipeline` 的 Prompt、Workflow、Dify 和 FastGPT 助手。
|
||||
- 只支持文本 `message` 和 `function_call_output` 输入。
|
||||
- `store` 必须为 `true` 或省略。
|
||||
- 不支持 `conversation`、`background`、图片、文件以及调用方覆盖 instructions 或 tools。
|
||||
- `usage` 只在 Provider 提供可靠 token 统计时返回;否则为 `null`,不会估算。
|
||||
- 不提供 `/v1/chat/completions` 兼容接口。
|
||||
|
||||
Reference in New Issue
Block a user