想让大模型看懂一张图片,核心在于两件事:一是把图片转成API能接受的编码形式,二是按照多Content Part的消息结构把文字和图片塞进同一条请求里。目前主流的多模态推理API(如OpenAI兼容风格接口)都采用统一的消息格式,理解了这套结构,换哪家服务商都能快速上手。本文从图片编码讲到消息组装,最后给出可以直接运行的完整示例。

一、为什么需要Base64编码,编码过程怎么做
HTTP请求的JSON体只能承载文本,无法直接嵌入二进制图片数据。Base64是一种把任意二进制字节映射到64个可打印字符的编码方案,编码后体积约为原始数据的4/3。图片经过Base64处理后,就能以纯字符串形式出现在JSON字段中,服务端再解码还原成原始图片字节。
Python中用base64标准库即可完成,常见写法如下:
import base64
def encode_image(path: str) -> str:
with open(path, "rb") as f:
return base64.b64encode(f.read()).decode("utf-8")
b64 = encode_image("test.jpg")
print(len(b64)) # 输出编码字符串长度
有几个容易踩的坑值得注意。第一,b64encode返回的是bytes,必须再decode("utf-8")成字符串,否则拼接进data URI会报类型错误。第二,部分接口要求URL安全变体,需要把/替换成_、+替换成-。第三,不要在编码字符串中手动加换行,某些工具默认76字符折行会导致服务端解析失败。
二、多Content Part消息结构详解
传统纯文本请求中,content字段就是一个字符串。而多模态请求把content升级为数组,数组中每个元素称为一个Content Part,通过type字段区分类型:text类型携带文字描述,image_url类型携带图片信息。模型会按数组顺序理解输入,因此把文字说明放在图片前面,通常能让模型带着问题去读图,效果更稳定。
图片的传递有两种方式:一是直接给公网可访问的图片URL,服务端自行下载;二是用data URI内嵌编码结果,格式为data:image/jpeg;base64,编码字符串。前者适合图片已上传到对象存储的场景,请求体小;后者适合本地图片或隐私敏感场景,但请求体会显著膨胀,一张2MB的图片编码后接近2.7MB。
结构示例如下(注意MIME类型要与实际图片格式匹配,PNG对应image/png):
payload = {
"model": "your-model-name",
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "这张图片里有什么内容?请详细描述。"},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{b64}",
"detail": "high" # 可选:low/high/auto,影响识别精度与token消耗
}
}
]
}
],
"max_tokens": 1024
}
需要提醒的是,多张图片就在content数组里追加多个image_url元素即可;system提示词的content仍可保持纯字符串形式,不必改成数组。另外detail参数会直接影响计费与速度,日常OCR类任务用默认值往往够用。
三、完整请求示例与常见问题排查
把编码和消息组装合起来,一个完整的调用流程如下,使用requests库发送,并处理流式与非流式两种响应:
import base64
import requests
API_KEY = "sk-xxxx"
URL = "https://api.ippipp.com/v1/chat/completions" # 以实际服务地址为准
b64 = base64.b64encode(open("photo.jpg", "rb").read()).decode("utf-8")
headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
payload = {
"model": "vision-model",
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": "图中的文字是什么?"},
{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{b64}"}}
]
}]
}
resp = requests.post(URL, json=payload, headers=headers, timeout=120)
resp.raise_for_status()
print(resp.json()["choices"][0]["message"]["content"])
实际调试中遇到的问题大多集中在三类。一是413请求体过大,多数网关对请求体限制在几MB到几十MB之间,超限时应在客户端压缩图片分辨率,而不是反复重试;二是MIME类型写错,比如把webp图片标成jpeg,部分服务会解码失败;三是图片本身过大导致模型自动降采样,细节丢失,这时可以裁剪出关键区域再编码,通常比调大detail参数更有效。
总结一下构建要点:编码环节保证字节正确转字符串,消息环节保证Content Part类型与顺序合理,传输环节控制好体积与格式。掌握这套流程后,无论是做图文问答、票据识别还是批量图片打标,只需替换text部分的提示词就能复用同一套请求骨架,开发效率会高很多。
多模态APIBase64编码Content Part修改时间:2026-09-13 04:52:24