更新于

Anthropic Vision 多图输入的最佳实践


单图输入(“这张图里有什么”)已经是大部分开发者熟悉的用法,但当一次请求里需要放进 3 张、10 张甚至更多图片时——比如比较两版 UI 截图的差异、把一份 PDF 拆成多页图片让模型整体理解、批量审核一组商品图——请求结构、图片排列顺序、token 预算都需要单独设计,否则很容易遇到模型”看串图”或者成本失控的问题。本文聚焦 Claude Vision API 的多图输入场景,跨模型的视觉能力对比和图片计费细节,站内已有专门文章,这里不重复展开。

一、多图请求的基本结构

Claude 的 messages 格式里,一条 user 消息的 content 可以是一个数组,里面混合多个 image 类型的内容块和 text 类型的内容块,顺序完全由你控制:

import anthropic

client = anthropic.Anthropic()

message = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "这是改版前的界面:"},
                {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": img1_b64}},
                {"type": "text", "text": "这是改版后的界面:"},
                {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": img2_b64}},
                {"type": "text", "text": "请指出两版界面的具体差异,按模块列出。"},
            ],
        }
    ],
)
print(message.content[0].text)

关键点在于:每张图片前面紧跟一段说明性文字,标明这张图是什么,比让模型自己从图片顺序去猜”第一张是改版前还是改版后”要可靠得多。这是多图场景和单图场景最大的实践差异——单图不需要这种”引导文字”,多图几乎必须要有。

二、图片顺序:紧邻的文字说明比”图片在前”或”图片在后”更重要

一个常见的误解是”要不要把所有图片放在最前面,文字说明放在最后面”。实际测试中更稳定的做法是文字-图片交替排列,即每张图片紧跟在描述它的文字之后,而不是把一堆图片堆在一起,最后统一说明。原因是模型处理 content 数组时是按顺序理解的,“紧邻上下文”能显著降低模型把描述和图片对应错的概率,尤其当图片数量超过 5 张时,这个差异会更明显。

排列方式说明适用图片数量
文字-图片交替每张图前面紧跟该图的说明文字任意数量,尤其推荐 5 张以上
全部图片在前 + 统一说明在后图片堆叠,最后统一给指令仅推荐 2-3 张且图片本身有明确编号水印时使用
全部图片在前 + 逐条编号说明图片堆叠,但说明文字里显式写”第 1 张图…第 2 张图…”作为交替排列的备选方案,效果次之

如果你的场景是”文档翻页比对”(比如一份合同前后两版的逐页比较),建议在每页图片对应的文字里显式带上页码,而不是依赖模型自己数第几张图,这样即使后续调整了图片顺序,也不会引起误解。

三、图片数量与 token 预算

Claude 对单次请求的图片数量本身有上限(具体数值以官方文档为准,且会随版本调整),但更实际的约束是 token 预算——每张图片都会消耗一定数量的 token,图片越多、分辨率越高,消耗越大,具体的计费规则和不同分辨率下的 token 数换算可参考站内《多模态 LLM 图片 token 计费详解》,这里只强调多图场景下的预算控制策略:

  • 控制单张图片的分辨率:如果任务不需要读取图片里的极小文字(比如只是判断整体布局是否变化),在发送前把图片压缩到合理分辨率,能显著降低总 token 消耗,尤其是图片数量多的场景,这个优化的收益会被放大。
  • 拆分超大批量任务:如果要处理几十张图片,不要在一次请求里塞满,而是分批发送、分批处理,一方面避免单次请求 token 超预算,另一方面也便于失败重试时只重跑出错的那一批,而不是整个大批次。
  • 优先级排序:如果图片数量已经接近上限,把最关键的图片放在请求里靠前的位置,因为极端情况下模型对靠前内容的关注度通常更稳定。

四、实战场景一:UI 回归检测

多图输入一个很实用的场景是自动化 UI 回归测试——把改版前后的页面截图丢给模型,让它判断是否存在意外的视觉变化(不是让模型做像素级 diff,那用传统图像对比工具更准确,而是让模型判断”语义上的变化是否符合预期”,比如按钮位置是否离奇地变了、颜色是否符合设计规范)。

def check_ui_regression(before_img_b64: str, after_img_b64: str, expected_change: str) -> str:
    message = client.messages.create(
        model="claude-sonnet-4-5",
        max_tokens=512,
        messages=[
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": f"预期改动:{expected_change}\n\n改版前截图:"},
                    {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": before_img_b64}},
                    {"type": "text", "text": "改版后截图:"},
                    {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": after_img_b64}},
                    {"type": "text", "text": "请判断:1) 预期改动是否生效;2) 是否存在预期之外的额外视觉变化。分两点简洁回答。"},
                ],
            }
        ],
    )
    return message.content[0].text

这里的 expected_change 参数很关键——明确告诉模型”这次改动本来就应该改什么”,能大幅减少模型把”预期内的正常改动”误判为”异常”的情况,这是多图对比场景里比单纯”找不同”更实用的设计。

五、实战场景二:多页文档整体理解

把一份多页 PDF 转成图片后逐页输入,让模型对整体文档做理解或摘要,是另一个常见场景。这里的要点是给每页图片标注页码,并在最后的指令里提醒模型综合所有页面的信息,而不是只回答最后一页的内容:

def summarize_multi_page_doc(page_images: list[str]) -> str:
    content = []
    for i, img_b64 in enumerate(page_images, start=1):
        content.append({"type": "text", "text": f"第 {i} 页:"})
        content.append({"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": img_b64}})
    content.append({"type": "text", "text": f"以上是一份共 {len(page_images)} 页的文档,请综合所有页面内容给出整体摘要,不要只关注最后几页。"})

    message = client.messages.create(
        model="claude-sonnet-4-5",
        max_tokens=1024,
        messages=[{"role": "user", "content": content}],
    )
    return message.content[0].text

页数较多时(比如超过 15-20 页),建议先做一轮”每页单独摘要”,再把各页摘要文字(而不是原图)拼在一起做二次总结,这样能显著降低总 token 消耗,同时避免因为图片数量过多导致模型注意力被稀释、遗漏中间页面内容。

六、常见错误与排查

  • 图片和说明文字顺序错位:多图场景下最常见的错误是开发者在构造 content 数组时手滑,把图片和对应的文字说明顺序拼错,导致模型”张冠李戴”。建议在构造请求体的代码里加断言检查,确保图片和其紧邻的文字说明是配对生成的,而不是分两个循环分别 append。
  • 忽略图片格式限制:确认所有图片的 media_type 字段和实际图片格式一致,混用格式或者用错误的 MIME type 会导致请求报错或模型解析异常。
  • 一次性塞入过多高分辨率图片导致超时:如果图片数量多且分辨率高,请求体积会很大,网络较差的环境下容易超时,建议提前对图片做适当压缩,并设置合理的客户端超时时间和重试机制。
  • 通过中转访问时的兼容性:如果通过 API 中转服务访问 Claude Vision 能力,确认中转商的请求转发层对多图 content 数组的支持是完整的,部分中转在做协议适配时可能只测试过单图场景,多图场景建议先在测试环境跑通完整链路再上生产。

七、结论

多图输入不是”把多张图片塞进一个请求”这么简单,真正决定效果和成本的是三件事:图片和说明文字的紧邻排列顺序、按场景控制的分辨率与批次大小、以及针对具体任务设计的指令措辞(比如显式告知预期变化、显式要求综合所有页面)。把这几点做好,UI 回归检测、多页文档理解这类场景在 Claude Vision 上都能跑出比较稳定的效果。

八、相关阅读

如果你需要在国内稳定调用 Claude Vision API 处理多图任务,YoTradeApi 提供完整支持多模态请求的国内中转服务,免去直连不稳定带来的超时问题。