多模态对话(OpenAI Responses 协议)
接口概述
支持图片、音频、文件的视觉理解大模型,兼容 OpenAI Responses API 格式:可对图片进行描述、分析、对比,支持音频转写与理解,支持文件内容提取与问答。
接口地址:
POST https://test.jw-info.com/v1/responses
与 Chat Completions 协议的区别
Chat Completions 与 Responses 协议在字段命名和结构上有所不同:
| 概念 | Chat Completions | Responses |
|---|---|---|
| 消息列表 | messages | input |
| 系统提示 | messages[].role: "system" | instructions(顶层字段) |
| 用户消息内容 | content 数组 | input 数组 |
| 输出长度上限 | max_tokens | max_output_tokens |
| 流式参数 | stream: true | stream: true |
请求头
| 请求头 | 值 | 是否必填 | 说明 |
|---|---|---|---|
| Content-Type | application/json | 是 | 请求体格式 |
| Authorization | Bearer {API_KEY} | 是 | 也可以用 x-api-key: {API_KEY},两种写法用同一把 Key |
| Accept | application/json | 否 | 响应格式 |
与纯文本的区别
在多模态场景下,input 是一个对象数组,每个对象代表一种内容类型;而纯文本场景中 input 可为字符串。
// 多模态:input 为数组
"input": [
{ "type": "input_text", "text": "描述这张图片" },
{ "type": "input_image", "image_url": "https://example.com/photo.jpg" }
]
// 纯文本:input 为字符串(仍支持,详见「OpenAI 兼容-Response」页)
"input": "你好,请帮我解答这个问题"
请求参数
顶层参数
| 参数名 | 类型 | 是否必填 | 说明 |
|---|---|---|---|
| model | string | 是 | 模型名,见模型广场与文末「可用模型」 |
| input | string / array | 是 | 纯文本传字符串;多模态传内容条目数组(见下节) |
| instructions | string | 否 | 系统级指令,用于设定角色与回答要求(替代 Chat 协议里的 system 消息) |
| max_output_tokens | integer | 否 | 输出长度上限(等价于 max_tokens) |
| temperature | float | 否 | 采样温度,范围 [0, 2] |
| top_p | float | 否 | 核采样,范围 [0, 1] |
| stream | boolean | 否 | 是否流式返回(SSE),默认 false |
| tools / tool_choice | array / string | 否 | 工具定义与选择策略 |
| previous_response_id | string | 否 | 引用上一轮响应 ID 做多轮对话 |
Content 类型详解
| type | 字段 | 说明 |
|---|---|---|
| input_text | text(string) | 文本内容 |
| input_image | image_url(string) | 图片 URL,或 data:image/...;base64, 编码 |
| input_image | detail(string,可选) | 图片解析精度:low / high / auto(默认 auto) |
| input_audio | audio_data(string) | 音频的 Base64 编码数据 |
| input_audio | audio_format(string) | 音频格式:wav / mp3 等 |
| input_file | file_id(string) | 已上传文件的 ID(与 file_data 二选一) |
| input_file | file_data(string) | 文件的 Base64 编码数据 |
| input_file | filename(string,可选) | 文件名(带扩展名,便于识别类型) |
约定:
| 项目 | 说明 |
|---|---|
| 图片格式 | image/jpeg、image/png、image/gif、image/webp |
| 图片地址 | 公网可直接访问的 URL;地址不可达或格式不支持会返回图片相关错误 |
| Base64 写法 | data:image/png;base64,……(前缀里的 MIME 类型要与实际格式一致) |
| 多图 | 在 input 数组里放多个 input_image 条目即可(用于对比、多页文档等) |
请求示例
1. 图片 URL 方式
curl https://test.jw-info.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-你的密钥" \
-d '{
"model": "qwen3.7-plus",
"instructions": "你是一个专业的图片分析助手,请用中文回答。",
"input": [
{ "type": "input_text", "text": "这张图片里有什么?请详细描述。" },
{ "type": "input_image", "image_url": "https://example.com/sample.jpg", "detail": "high" }
]
}'
from openai import OpenAI
client = OpenAI(api_key="sk-你的密钥", base_url="https://test.jw-info.com/v1")
resp = client.responses.create(
model="qwen3.7-plus",
instructions="你是一个专业的图片分析助手,请用中文回答。",
input=[
{"type": "input_text", "text": "这张图片里有什么?请详细描述。"},
{"type": "input_image", "image_url": "https://example.com/sample.jpg", "detail": "high"},
],
)
print(resp.output_text)
2. 图片 Base64 方式
curl https://test.jw-info.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-你的密钥" \
-d '{
"model": "qwen3.7-plus",
"instructions": "你是一个 OCR 识别助手。",
"input": [
{ "type": "input_text", "text": "请识别这张图片中的所有文字。" },
{ "type": "input_image", "image_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" }
]
}'
import base64
from openai import OpenAI
client = OpenAI(api_key="sk-你的密钥", base_url="https://test.jw-info.com/v1")
def encode_image(path: str) -> str:
with open(path, "rb") as f:
data = base64.b64encode(f.read()).decode("utf-8")
return f"data:image/{path.rsplit('.', 1)[-1]};base64,{data}"
resp = client.responses.create(
model="qwen3.7-plus",
instructions="你是一个专业的图片分析助手。",
input=[
{"type": "input_text", "text": "这张图片中有什么物体?"},
{"type": "input_image", "image_url": encode_image("photo.png")},
],
)
print(resp.output_text)
3. 多图对比
curl https://test.jw-info.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-你的密钥" \
-d '{
"model": "qwen3.7-plus",
"instructions": "你是一个专业的图片对比分析助手。",
"input": [
{ "type": "input_text", "text": "请对比这两张图片,分析它们的异同。" },
{ "type": "input_image", "image_url": "https://example.com/image1.jpg" },
{ "type": "input_image", "image_url": "https://example.com/image2.jpg" }
]
}'
4. 音频输入
curl https://test.jw-info.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-你的密钥" \
-d '{
"model": "qwen3.7-plus",
"instructions": "你是一个语音转文字助手。",
"input": [
{ "type": "input_text", "text": "请将这段录音内容转写成文字。" },
{
"type": "input_audio",
"audio_data": "UklGRiQAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQAAAAA=",
"audio_format": "wav"
}
]
}'
5. 文件输入
curl https://test.jw-info.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-你的密钥" \
-d '{
"model": "qwen3.7-plus",
"instructions": "你是一个专业的文档分析助手。",
"input": [
{ "type": "input_text", "text": "请总结这份文件的主要内容。" },
{ "type": "input_file", "file_data": "VGhpcyBpcyBhIHNhbXBsZSBmaWxlIGNvbnRlbnQu", "filename": "report.pdf" }
]
}'
file_data 是文件内容的 Base64 编码;若文件已上传到平台并拿到 ID,可改用 file_id。
6. 纯文本(兼容模式)
input 直接给字符串即为纯文本对话:
{
"model": "qwen3.7-plus",
"instructions": "你是一个有用的助手。",
"input": "你好,请介绍一下你自己"
}
响应格式
响应格式与纯文本 Responses API 相同。
响应参数
| 参数名 | 类型 | 说明 |
|---|---|---|
| id | string | 本次响应的唯一标识,可作为 previous_response_id 回传 |
| object | string | 固定值 response |
| created_at | integer | 创建时间戳(Unix 秒) |
| model | string | 实际使用的模型名称 |
| output | array | 输出内容列表 |
| output[].type | string | 输出类型,正常回答为 message |
| output[].role | string | 角色,固定值 assistant |
| output[].content | array | 内容片段数组 |
| output[].content[].type | string | 内容类型:output_text(文本)或 refusal(拒绝回答) |
| output[].content[].text | string | 文本内容 |
| status | string | 响应状态:completed、in_progress |
| usage.input_tokens | integer | 输入消耗的 token 数(图片 / 音频 / 文件折算后计入) |
| usage.output_tokens | integer | 输出消耗的 token 数 |
| usage.total_tokens | integer | 总 token 消耗 |
响应有两种形状:多数模型返回上表的普通对象;部分模型返回单个
response.completed事件体(与流式帧同形),此时字段在response.*下(response.output[]、response.usage)。按需取即可,示例见下。
非流式响应示例
普通对象:
{
"id": "resp_xxxxxxxxxxxxx",
"object": "response",
"created_at": 1710000000,
"model": "qwen3.7-plus",
"status": "completed",
"output": [
{
"id": "msg_xxxxxxxxxxxxx",
"type": "message",
"role": "assistant",
"content": [
{ "type": "output_text", "text": "这张图片展示了一座位于海边的灯塔……", "annotations": [] }
]
}
],
"usage": { "input_tokens": 150, "output_tokens": 80, "total_tokens": 230 }
}
单个事件体(部分模型):
{
"type": "response.completed",
"response": {
"id": "resp_xxxxxxxxxxxxx",
"status": "completed",
"output": [
{ "type": "message", "role": "assistant",
"content": [ { "type": "output_text", "text": "图片里是一只橘猫……" } ] }
],
"usage": { "input_tokens": 150, "output_tokens": 80, "total_tokens": 230 }
}
}
流式响应(stream=true)
event: response.created # 响应已创建
event: response.output_text.delta # 多次,delta 为增量文本
event: response.completed # response.usage 在这里给最终用量
每帧的 data: 是一个 JSON 对象,例如:
event: response.output_text.delta
data: {"type":"response.output_text.delta","delta":"这是","item_id":"msg_xxx","output_index":0,"content_index":0}
读取时兼容两种形状(Python):
data = resp.get("response") or resp # 普通对象 / 事件体都取到同一层
text = data["output"][0]["content"][0]["text"]
usage = data["usage"]
错误格式
模型侧报错时,接口返回 502,detail 里带上原始错误正文,便于定位:
{
"error": {
"message": "Invalid image URL: connection timeout",
"type": "invalid_request_error",
"code": "invalid_image_url"
}
}
常见错误码:
| 错误码 | 说明 |
|---|---|
| invalid_request_error | 请求参数错误 |
| invalid_image_url | 图片 URL 无法访问或格式不支持 |
| invalid_audio_format | 音频格式不支持 |
| rate_limit_exceeded | 请求频率超限 |
| context_length_exceeded | Token 数量超出模型限制 |
| authentication_error | API Key 无效 |
完整的 HTTP 状态码(401 / 402 / 429 / 502 等)与排查速查见「错误码」页。
可用模型
以下模型支持多模态输入,并同样支持纯文本对话:
| 模型 | 供应商 | 最大 Token | 说明 |
|---|---|---|---|
| qwen3.7-plus | 通义千问 | 128K | 旗舰多模态模型 |
| qwen3.6-plus | 通义千问 | 128K | 高性能多模态 |
| qwen3.6-flash | 通义千问 | 128K | 轻量快速多模态 |
| qwen3.5-plus | 通义千问 | 128K | 上一代旗舰 |
| qwen3.5-flash | 通义千问 | 128K | 上一代轻量版 |
| qwen3.5-122b-a10b | 通义千问 | 128K | 大参数 MoE 模型 |
| qwen3.5-397b-a17b | 通义千问 | 128K | 超大参数 MoE 模型 |
| qwen3.5-35b-a3b | 通义千问 | 128K | 轻量 MoE 模型 |
| minimax-m3 | MiniMax | 128K | MiniMax 多模态模型 |
| doubao-seed-2.0-pro | 豆包 | 128K | 豆包旗舰多模态 |
| doubao-seed-2.0-lite | 豆包 | 128K | 豆包轻量多模态 |
| doubao-seed-2.0-mini | 豆包 | 128K | 豆包极速多模态 |
| kimi-k3 | 月之暗面 | 128K | Kimi 旗舰多模态 |
| kimi-k2.7-code | 月之暗面 | 128K | Kimi 代码多模态 |
| kimi-k2.6 | 月之暗面 | 128K | Kimi 多模态 |
| kimi-k2.5 | 月之暗面 | 128K | Kimi 多模态 |
模型广场上带「视觉理解」标签的模型都支持图片输入;音频与文件输入只有部分模型支持,以实际调用结果为准。 本协议的支持度是模型级的:个别模型未开启相关能力时会直接报错说明,遇到时改用
/v1/chat/completions调同一模型即可(模型名与计费不变)。
计费说明
- 图片、音频、文件都会被折算成输入 token,与文本一起按该模型的输入单价计费;输出按输出单价计费。
- 每次调用的费用记入控制台「费用中心」,接口响应本身不返回费用。
- 余额不足会返回 402,需要管理员在控制台手工授信。