多模态能力已经成为大模型的标配。从 OCR 识图到图表分析,从代码截图到复杂场景描述,国产多模态模型的能力在过去一年里突飞猛进。本文梳理主流国产多模态模型的 API 接入方式,用真实测试场景对比各自的输出质量,并给出选型建议。
主流国产多模态模型一览
| 模型 | 提供方 | 特点 |
|---|---|---|
| Qwen-VL-Max | 阿里云(通义) | 中文理解强,支持高分辨率,文档理解能力突出 |
| DeepSeek-VL2 | DeepSeek | 开源模型,推理能力强,细节描述准确 |
| GLM-4V | 智谱 AI | 多轮对话体验好,中文场景优化 |
| MiniMax-VL | MiniMax | 长上下文支持,适合多图分析 |
这四个模型均支持 Chat Completions 兼容格式,content 字段可以传数组,混合 text 和 image_url 两种类型。
Vision API 消息格式
基础结构
Vision 请求与普通文本请求的区别在于 content 从字符串变成了数组:
{
"model": "qwen-vl-max",
"messages": [
{
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {
"url": "https://example.com/image.png"
}
},
{
"type": "text",
"text": "这张图片里写了什么?"
}
]
}
]
}
图片传入方式:URL vs Base64
方式一:URL 链接(适合公开可访问的图片)
content = [
{
"type": "image_url",
"image_url": {"url": "https://example.com/chart.png"}
},
{"type": "text", "text": "分析这张折线图的趋势"},
]
方式二:Base64 编码(适合本地文件、私有图片)
import base64
def image_to_base64(file_path: str, mime_type: str = "image/png") -> str:
with open(file_path, "rb") as f:
data = base64.b64encode(f.read()).decode("utf-8")
return f"data:{mime_type};base64,{data}"
content = [
{
"type": "image_url",
"image_url": {"url": image_to_base64("screenshot.png")}
},
{"type": "text", "text": "读取图中的文字内容"},
]
Base64 方式无需图片公网可达,适合处理用户上传文件;URL 方式更省带宽,但图片必须公开可访问。
完整代码示例(Qwen-VL)
安装与配置
pip install openai python-dotenv
# .env
QWEN_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx
单图理解
import os
import base64
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
client = OpenAI(
api_key=os.getenv("QWEN_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
def analyze_image_url(image_url: str, question: str) -> str:
"""通过 URL 传入图片"""
response = client.chat.completions.create(
model="qwen-vl-max",
messages=[
{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": image_url}},
{"type": "text", "text": question},
],
}
],
max_tokens=1024,
)
return response.choices[0].message.content
def analyze_image_file(file_path: str, question: str) -> str:
"""通过 Base64 传入本地图片"""
with open(file_path, "rb") as f:
b64 = base64.b64encode(f.read()).decode()
# 根据扩展名判断 MIME 类型
ext = file_path.rsplit(".", 1)[-1].lower()
mime = {"jpg": "image/jpeg", "jpeg": "image/jpeg",
"png": "image/png", "webp": "image/webp"}.get(ext, "image/png")
data_url = f"data:{mime};base64,{b64}"
response = client.chat.completions.create(
model="qwen-vl-max",
messages=[
{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": data_url}},
{"type": "text", "text": question},
],
}
],
)
return response.choices[0].message.content
多图输入
def compare_images(image_urls: list[str], question: str) -> str:
"""多图对比分析"""
content = []
for url in image_urls:
content.append({"type": "image_url", "image_url": {"url": url}})
content.append({"type": "text", "text": question})
response = client.chat.completions.create(
model="qwen-vl-max",
messages=[{"role": "user", "content": content}],
)
return response.choices[0].message.content
# 对比两张产品设计稿的差异
result = compare_images(
["https://cdn.example.com/v1.png", "https://cdn.example.com/v2.png"],
"对比这两张设计稿,列出所有视觉差异",
)
多轮视觉对话
def visual_conversation():
"""保持图片上下文的多轮对话"""
history = []
# 第一轮:发送图片并提问
history.append({
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": "https://cdn.example.com/code.png"}},
{"type": "text", "text": "这段代码有什么问题?"},
],
})
resp1 = client.chat.completions.create(
model="qwen-vl-max", messages=history
)
assistant_reply = resp1.choices[0].message.content
history.append({"role": "assistant", "content": assistant_reply})
print("AI:", assistant_reply)
# 第二轮:追问,无需再次发图片
history.append({
"role": "user",
"content": [{"type": "text", "text": "如何修复这个问题?给出修复后的代码"}],
})
resp2 = client.chat.completions.create(
model="qwen-vl-max", messages=history
)
print("AI:", resp2.choices[0].message.content)
四大测试场景实测对比
测试方法:用同一张图片,向四个模型发送相同 Prompt,评分维度:准确率(40%)+ 细节完整度(30%)+ 中文表达(30%)。
场景一:OCR 文字识别
测试图片:一张含表格和手写注释的合同扫描件
| 模型 | 印刷体识别 | 手写识别 | 表格结构 | 综合得分 |
|---|---|---|---|---|
| Qwen-VL-Max | ★★★★★ | ★★★★☆ | ★★★★★ | 4.7 |
| DeepSeek-VL2 | ★★★★★ | ★★★★☆ | ★★★★☆ | 4.5 |
| GLM-4V | ★★★★☆ | ★★★☆☆ | ★★★★☆ | 4.0 |
| MiniMax-VL | ★★★★☆ | ★★★☆☆ | ★★★☆☆ | 3.7 |
结论:OCR 场景 Qwen-VL-Max 表现最好,文档理解是其核心优势,尤其是表格结构还原非常准确。
场景二:图表数据理解
测试图片:一张含多条折线的销售趋势图(含坐标轴、图例)
Prompt:"请分析这张折线图,指出哪个产品销量增长最快,以及在哪个季度出现了明显下滑"
Qwen-VL-Max 输出(节选):
"从图表来看,产品 B(蓝线)在 Q1-Q3 增速最快,同比增长约 47%。而产品 A 在 Q2 到 Q3 区间出现明显下滑,跌幅约 23%,这与图中该时段折线的陡降趋势吻合。"
DeepSeek-VL2 输出(节选):
"蓝色折线对应产品 B 增长最为显著。产品 A 红线在第二季度末至第三季度初有明显下行,降幅较大。"
Qwen 给出了量化数据,DeepSeek 描述较为定性。两者都识别出了正确的趋势,但 Qwen 在数值推断上更大胆(当然准确性依赖图表清晰度)。
场景三:代码截图分析
测试图片:一段 Python 代码截图,含一个典型的 KeyError 异常
| 模型 | Bug 定位 | 修复建议 | 代码可读性说明 |
|---|---|---|---|
| Qwen-VL-Max | 准确 | 完整 | 有 |
| DeepSeek-VL2 | 准确 | 完整 | 有,更详细 |
| GLM-4V | 准确 | 基础 | 无 |
| MiniMax-VL | 准确 | 基础 | 无 |
代码场景 DeepSeek-VL2 解释最详细,习惯性给出 "为什么会这样" 的推理链,适合学习场景。
场景四:场景描述
测试图片:一张繁华商业街的街景照片
Prompt:"详细描述这张图片中的场景,包括人物、建筑、文字标识等细节"
| 模型 | 中文标识识别 | 人物数量估算 | 氛围描述 |
|---|---|---|---|
| Qwen-VL-Max | ★★★★★ | ★★★★☆ | ★★★★☆ |
| DeepSeek-VL2 | ★★★★☆ | ★★★★★ | ★★★★☆ |
| GLM-4V | ★★★★☆ | ★★★☆☆ | ★★★★★ |
| MiniMax-VL | ★★★☆☆ | ★★★☆☆ | ★★★★☆ |
中文标识(店铺名、广告牌)识别 Qwen 最准;GLM-4V 的氛围描述最有文采。
图片 Token 消耗对比
Vision 请求的 Token 消耗与图片分辨率直接相关。以下是 Qwen-VL-Max 的参考数据:
| 图片尺寸 | 估算 Image Tokens |
|---|---|
| 512×512 | ~340 tokens |
| 1024×768 | ~680 tokens |
| 1920×1080 | ~1500 tokens |
| 高清文档(A4 扫描) | ~2000-3000 tokens |
节省 Token 的建议:
- OCR 场景:保持原始分辨率,压缩会降低文字清晰度,反而影响识别率
- 图表分析:1024px 宽度通常足够,无需传 4K 图
- 场景描述:可以适当降低分辨率,768px 以上即可满足
实际应用选型建议
按场景选模型
| 应用场景 | 推荐模型 | 原因 |
|---|---|---|
| 企业文档 OCR | Qwen-VL-Max | 表格还原、中文印刷体识别最佳 |
| 数据图表分析 | Qwen-VL-Max | 数值推断能力强 |
| 代码审查/Debug | DeepSeek-VL2 | 推理链详细,解释到位 |
| 内容审核/场景描述 | GLM-4V | 中文叙述自然,多轮对话体验好 |
| 批量图片处理 | MiniMax-VL | 长上下文,适合一次处理多图 |
接入架构建议
用户上传图片
↓
压缩/格式转换(统一为 JPEG/PNG,控制分辨率)
↓
转 Base64 或上传到 CDN 获取 URL
↓
调用 Vision API
↓
解析返回内容 → 业务逻辑
生产环境中,图片最好先上传到自有 CDN 再传 URL,避免 Base64 膨胀请求体(Base64 比原文件大约 33%),同时也方便日志追踪。
值得一提的是,不同多模态模型在图片字段的细节上存在一些差异(比如 image_url 的嵌套结构、Base64 的 MIME 前缀要求等)。笔者在开发 TheRouter 时专门对多模态请求做了格式统一处理,上游无论是哪个模型,应用层只需按标准格式发送一次即可。
错误处理注意事项
Vision 请求有几个特有的错误场景:
from openai import BadRequestError
try:
result = analyze_image_url(url, question)
except BadRequestError as e:
if "image" in str(e).lower():
# 图片格式不支持、分辨率过高、内容违规等
print(f"图片处理失败: {e}")
else:
raise
常见错误原因:
- 图片 URL 不可访问(防盗链、临时链接过期)
- 图片格式不支持(建议统一转 JPEG/PNG)
- 单图分辨率过高(部分模型有上限,通常 8K×8K 以内安全)
- 图片内容触发安全审核(色情、暴力等)
小结
多模态 API 的接入本身并不复杂,关键在于理解 content 数组的构造方式,以及 Base64 和 URL 两种图片传入方式的适用场景。
选型上没有万能答案:
- 文档/OCR 类首选 Qwen-VL-Max
- 代码分析类首选 DeepSeek-VL2
- 内容生成/描述类GLM-4V 中文体验更流畅
建议在正式接入前,用你自己的真实业务图片做一轮测试,不同图片质量和场景差异很大,实测结果比任何 Benchmark 都可靠。
本文代码均在 Python 3.10+ 下测试通过。所有模型 API 均需在对应平台申请账号并获取 API Key。
作者:TheRouter 开发者,专注 AI 模型路由网关。项目主页:therouter.ai