流式响应
实现实时流式响应
本页目录
概述
流式响应在模型生成过程中持续返回内容,适合聊天界面和长文本生成。
当客户端需要 Responses 形态时,使用 Responses streaming。当客户端使用 Chat Completions 形态时,使用 Chat Completions streaming。
共享路由上的流式请求仅对已通过流式认证的渠道可用。通过认证的渠道在探测中完成过真实流式请求,并验证了 SSE 终态用量证据(写入 channel_model_usage_evidence 的 sse_terminal 行)。未认证渠道的流式请求会被直接拒绝(model_unavailable),AnyPath 不会猜测用量或供应商收益。
流式可用范围
- 共享路由:已通过流式认证的渠道支持流式;未认证渠道的流式请求会被直接拒绝(
model_unavailable)。 - Chat Completions:客户端请求必须自带
stream_options.include_usage: true,网关不会代为注入;缺少该字段的流式请求会被拒绝。非 Anthropic 客户端跨协议调用 Anthropic 渠道的流式(转换后的 Chat)同样要求include_usage。 - Anthropic Messages、Gemini
:streamGenerateContent和 Responses:流式终态恒有用量,无需客户端额外操作。Gemini 协议的 Chat 流式不支持。 - Images:图片家族不支持流式。
流式结算方式
流式与非流式请求共用同一个结算闭环:上游分发前预先冻结部分余额(hold),以 SSE 终态用量证据确定计量用量,再从冻结金额中按实际用量扣费(capture),扣费不超过冻结金额。
如果客户端中途断连,网关会继续把上游流读到终态——供应商仍会完成本次生成——并按终态用量证据对实际生成量正常结算扣费,扣费不超过冻结金额。断连不等于免单:供应商已完成生成,调用方需为实际用量付账。只有在供应商返回错误、流超过 600 秒超时上限,或终态确实缺少用量证据时,冻结金额才会被释放(release),调用方不扣费。流式请求只有一次尝试,不做重试或切换。
选择端点形态
按客户端 API 形态选择流式接口:
- 已使用 Responses 的客户端:
POST /v1/responses - OpenAI Chat Completions 兼容客户端:
POST /v1/chat/completions - 不建议为不同的模型单独写一套流式处理逻辑
注意事项
- 收到增量内容后应立即追加到界面或终端
- 长时间连接要处理断开、超时和重试
- 重试时尽量保持原 API 类型不变
Responses Streaming
curl https://api.anypath.dev/v1/responses \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-mini",
"input": "Write a short poem.",
"stream": true
}'
from openai import OpenAI
client = OpenAI(
api_key="sk-your-api-key",
base_url="https://api.anypath.dev/v1"
)
stream = client.responses.create(
model="gpt-4o-mini",
input="Write a short poem.",
stream=True
)
for event in stream:
if event.type == "response.output_text.delta":
print(event.delta, end="", flush=True)
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: 'sk-your-api-key',
baseURL: 'https://api.anypath.dev/v1'
});
const stream = await client.responses.create({
model: 'gpt-4o-mini',
input: 'Write a short poem.',
stream: true
});
for await (const event of stream) {
if (event.type === 'response.output_text.delta') {
process.stdout.write(event.delta);
}
}
Chat Completions Streaming
如果你的框架仍使用 /v1/chat/completions 的 SSE 分片,可以继续这样调用。请求中需要设置 stream_options.include_usage: true,让流式终态携带用量;缺少该字段的 Chat Completions 流式请求会被网关拒绝:
stream = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "Write a short poem"}],
stream=True,
stream_options={"include_usage": True}
)
for chunk in stream:
content = chunk.choices[0].delta.content
if content:
print(content, end="", flush=True)
流结束条件
常见结束条件:
- Responses API:
response.completed - Chat Completions:
finish_reason: "stop" - 达到长度上限:
finish_reason: "length" - 工具调用:按响应里的工具事件继续处理
Web App 模式
async function streamChat(message) {
const response = await fetch('https://api.anypath.dev/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk-your-api-key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: message }],
stream: true,
stream_options: { include_usage: true }
})
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\\n').filter(line => line.startsWith('data: '));
for (const line of lines) {
const data = line.slice(6);
if (data === '[DONE]') return;
const parsed = JSON.parse(data);
const content = parsed.choices?.[0]?.delta?.content;
if (content) {
document.getElementById('output').textContent += content;
}
}
}
}
最佳实践
新项目优先选择 Responses streaming
如果客户端需要 Responses streaming,使用 /v1/responses。如果客户端需要 Chat Completions 形态,继续使用 /v1/chat/completions。
增量刷新输出
不要等完整响应结束后再显示内容,收到增量就追加。
处理断开和重试
长连接可能断开。重试时保留相同 API 类型和请求语义,避免重复执行有副作用的操作。客户端中途断连时,网关仍会把上游响应读到终态,并按实际生成量扣费——断连不会取消供应商的生成,也不会免除本次费用。
处理流式错误
流式响应可能在中途失败。此时网关会直接截断流:连接关闭,没有终态事件——不发错误分片,也不发 data: [DONE]。这是刻意设计:被截断的流绝不可能被误认为完整响应。
只要流缺少协议终态事件就结束了(Responses 的 response.completed、Messages 的 message_stop、Chat Completions 的最终 usage 分片加 [DONE]),就按失败处理。重试前记录响应头里的 X-Request-Id,便于事后追踪本次调用。
下一步
- 选择 API 类型时,请同时参考 API 概览
- 调试延迟或重复请求时,记录请求 ID
- 需要更完整的错误处理时,继续阅读错误处理指南