Grok 图像理解接入

2026-11-04 17:18 更新

把图片地址塞进 content,模型却像没看见——这是图像理解接入最常见的失败。原因是 content 的形态变了:纯文本请求里它是字符串,带图片时必须变成对象数组,每一项声明自己是图片还是文本。写成字符串,请求可能照常返回,但模型只看到了那句问题。

这一节把「怎么组织图文请求」讲成可校验的结构。

一、问题不是「模型能不能看图」,而是「请求怎么声明图」

官方给的对比很直接:纯文本时 content 是一段字符串;带图片时,content 变成对象列表,图片用 {"type": "input_image", "image_url": ...},文字用 {"type": "input_text", "text": ...}。

两个细节决定成败:

  • image_url 可以是公网 URL,也可以是 base64 的 data URL(data:image/jpeg;base64,...)。
  • 图文顺序任意,文字在前、图片在后都可以。

还有一条容易被忽略的官方提示:发送图片时,建议不要在服务端保存请求/响应历史,否则请求可能失败。如果你的实现默认把每轮对话存到服务端,需要为带图请求单独处理。

二、最小可运行示例:图文请求构造与校验

下面的脚本不联网、不需要真实密钥。它构造一个图文 content,并检查三件最容易错的事:有没有图片项、有没有文本项、图片地址形态对不对。

"""图文 content 构造与校验(mock)。"""

from urllib.parse import urlparse

DATA_MIME_OK = ("data:image/jpeg", "data:image/jpg", "data:image/png")

def build_content(image_url: str, question: str, detail: str = "high") -> list[dict]:
    return [
        {"type": "input_image", "image_url": image_url, "detail": detail},
        {"type": "input_text", "text": question},
    ]

def check_content(content: list[dict]) -> list[str]:
    errors: list[str] = []
    types = [c.get("type") for c in content]
    if "input_image" not in types:
        errors.append("缺少 input_image")
    if "input_text" not in types:
        errors.append("缺少 input_text")
    for c in content:
        if c.get("type") != "input_image":
            continue
        url = c.get("image_url", "")
        if url.startswith("data:image/"):
            if not url.startswith(DATA_MIME_OK):
                errors.append("data URL 的 MIME 不在 jpeg/png 内")
            continue
        if not url.startswith("http"):
            errors.append("image_url 既不是公网 URL 也不是 data URL")
            continue
        # 只看 path,避免把 ?token=... 的签名 URL 误判成非图片
        if not urlparse(url).path.lower().endswith((".jpg", ".jpeg", ".png")):
            errors.append("图片格式不在 jpg/jpeg/png 内")
    return errors

def offline_check() -> None:
    cases = [
        ("合法", build_content("https://example.com/chart.png", "这张图说明了什么?")),
        ("带查询参数", build_content("https://cdn.example.com/a.png?token=abc", "看图")),
        ("缺文本", [{"type": "input_image", "image_url": "https://example.com/a.png"}]),
        ("格式不对", build_content("https://example.com/report.gif", "看图")),
        ("data URL 用 svg", build_content("data:image/svg+xml;base64,PHN2Zz4=", "看图")),
    ]
    for label, content in cases:
        errs = check_content(content)
        print(f"{label}:" + ("通过" if not errs else ";".join(errs)))

if __name__ == "__main__":
    offline_check()

真正上线时,把 build_content() 的返回直接作为 input[0].content;check_content() 放在发请求之前,挡掉「地址写成了 PDF」「忘了放文本」这类结构性错误。

三、输入限制与三个易错点

项 官方口径
单图大小 最大 20MiB
图片数量 无限制
支持格式 jpg / jpeg / png
图文顺序 任意

三件要强调的事:

  • 只有三种格式。webp、gif 都不在列表里,先转码再传;转码本身也可能改变画质,涉及识别精度时要留意。
  • 20MiB 是单图上限。多图没有数量限制,但总量会推高 token 消耗;批量识图前先估一次成本。
  • detail 影响精细度。官方示例用 detail: "high";对表格、小字、图表这类任务,低精度可能直接丢信息。

四、预期输出与异常分支

运行校验器,预期输出:

合法:通过
带查询参数:通过
缺文本:缺少 input_text
格式不对:图片格式不在 jpg/jpeg/png 内
data URL 用 svg:data URL 的 MIME 不在 jpeg/png 内

换成真实请求时,若出现异常,按下面顺序定位:

现象 优先怀疑 第一步动作
模型答得像没看图 content 还是字符串 改成对象数组并确认有 input_image
请求直接失败 服务端存了历史 关闭带图请求的历史存储
图片读不出来 地址不可公网访问 换公网 URL 或转 base64
小字识别不准 detail 太低 提高到 high 并控制图片尺寸

最后一行尤其重要:图像理解的失败经常不是「模型不行」,而是传给它的图已经被压缩到看不清。

五、判据卡

判断项 该这么做 不该这么做
content 形态 对象数组,声明 image/text 直接塞字符串
图片地址 公网 URL 或 data URL 传本地文件路径
格式 jpg / jpeg / png 直接传 webp / gif
历史存储 带图请求单独关闭 沿用默认存储
精度 图表小字用 high 一律用最低精度

这张卡的重点是请求结构先对,再谈识别效果。五条里有三条在说:模型看到的东西,取决于你声明了什么。

六、来源与核验

  • 官方 Image Understanding:https://docs.x.ai/developers/model-capabilities/images/understanding(核验日期 2026-11-04)。content 对象数组结构、input_image / input_text、公网 URL 与 data URL、detail 参数、20MiB / jpg-png / 无数量上限 / 任意顺序,以及「不建议在服务端存储带图请求历史」的提示,均以该页为准。
  • 官方模型页:https://docs.x.ai/developers/models(核验日期 2026-11-04)。支持图像输入的模型以该页为准。
  • 本节不承诺任何识别准确率;具体效果取决于图片质量、任务类型与模型版本。

七、动手试

  1. 用同一张含小字的截图,分别用 detail: "high" 与默认值各问一次,比较识别结果差异。
  2. 给你的请求加一道自检:当 content 是字符串却带了图片时直接报错,而不是发出去等模型「无视」。
  3. 设计一条带图请求的存储策略:说明哪些字段可以落库、哪些必须丢弃,以及为什么。
以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号