Files
Xin Wang 2649d64b55
Quality gate / backend (push) Canceled after 0s
Quality gate / frontend (push) Canceled after 0s
feat: harden public OpenAI API contracts
2026-09-07 14:25:48 +08:00

263 lines
7.1 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Stateful Responses 文本接口
description: 使用 OpenAI Responses 风格的 HTTP 与 SSE 接口调用平台助手。
---
# Stateful Responses 文本接口
`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
curl -X POST "https://api.example.com/v1/responses" \
-H "Authorization: Bearer $REALTIME_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "assistant:asst_xxx",
"input": "请介绍一下这个产品"
}'
```
响应中的 `id` 是下一轮使用的状态指针:
```json
{
"id": "resp_xxx",
"object": "response",
"status": "completed",
"model": "assistant:asst_xxx",
"previous_response_id": null,
"output": [
{
"id": "msg_xxx",
"type": "message",
"status": "completed",
"role": "assistant",
"content": [
{"type": "output_text", "text": "……", "annotations": []}
]
}
]
}
```
## 继续多轮对话
后续请求可以省略 `model`。服务端从父响应恢复助手、动态变量、消息和工具上下文:
```bash
curl -X POST "https://api.example.com/v1/responses" \
-H "Authorization: Bearer $REALTIME_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"previous_response_id": "resp_xxx",
"input": "它适合哪些行业?"
}'
```
同一个父响应可以创建多个独立分支。Response 只能由创建它的 API Key 查询或继续:
```bash
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`:
```json
{
"model": "assistant:asst_xxx",
"input": "给我一个简短介绍",
"stream": true
}
```
文本输出的主要事件依次为 `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。
## 动态变量
首轮可以传入项目扩展字段,后续请求会继承并可增量覆盖:
```json
{
"model": "assistant:asst_xxx",
"input": "查询我的权益",
"x_interactive_media": {
"variables": {
"customer_name": "王女士",
"membership_level": "gold"
}
}
}
```
## Client Tool 续传
当助手需要调用客户端工具时,Response 的 `output` 会包含 `function_call`:
```json
{
"type": "function_call",
"call_id": "call_xxx",
"name": "show_message",
"arguments": "{\"message\":\"请确认\"}"
}
```
客户端执行后,通过父响应和对应的 `call_id` 继续:
```json
{
"previous_response_id": "resp_xxx",
"input": [
{
"type": "function_call_output",
"call_id": "call_xxx",
"output": "{\"status\":\"ok\",\"data\":{\"action\":\"confirmed\"}}"
}
]
}
```
如果父链存在多个尚未完成的 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` 兼容接口。