跳到正文
openrouter blog·· 2026-08-14精選AI 評分75

如何透過 API 將圖片傳送給大語言模型:視覺指南

How to Send an Image to an LLM via API (Vision Guide)

AI 導讀

本文介紹如何在聊天請求中透過 content 陣列傳送文字與圖片,支援多種視覺模型且請求格式保持一致。

  • 請求格式:使用 messages 陣列,包含 type: text 與 type: image_url 兩個部分,支援公開網址與 base64 資料格式。
推薦理由

原文詳細拆解如何透過 API 傳送圖片給多模態大語言模型,開發者可據此評估公開網址與 base64 編碼的適用時機。

正文 · AI 翻譯

若您想要一個具備視覺功能的大型語言模型 (LLM) 讀取截圖、檢檢視表或回答有關照片的問題,您需要正確構建請求主體。本指南僅涵蓋影像輸入,意即模型閱讀您提供的圖片,而非生成或編輯圖片.

模式很簡單。傳送一條聊天訊息,其內容陣列包含文字部分和一個 image_url 部分,送至我們的 影像理解端點。之後請求結構保持不變,您只需更改 model 欄位以使用我們支援的任何具備視覺功能的模型。

一個模型在光學字元辨識 (OCR) 上表現較佳,另一個則能更可靠地閱讀 UI 截圖,還有一個在解析圖表時更為謹慎。由於輸入結構不變,您可以在不改動整合方式的情況下測試這些差異。

本指南涵蓋將影像送至多模態模型、在公開 URL 與 base64 上傳之間做選擇、構建多模態 RAG 管線,以及進入正式環境後實際重要的限制。

Tl;dr

我們透過 Chat Completions API 支援多模態影像理解。

  • 端點: POST /api/v1/chat/completions
  • 主體: 一個 messages 陣列,其中使用者訊息的 content 為一個部份清單,包含一個 {"type": "text"} 與一個 {"type": "image_url"}。
  • 模型: 任何支援影像輸入的 slug(例如 anthropic/claude-opus-4.8、google/gemini-3-flash-preview)。您可以自由切換,因為請求主體相同。

基本請求:將影像附加至聊天呼叫

請求為一條使用者訊息,其內容陣列包含兩個部份:文字部份與一個 image_url 部份。此後的指南皆以此請求為基礎。

訊息內容陣列

純文字聊天將 content 送為純字串。加入影像後,content 變為一個型別化物件陣列:

{
  "role": "user",
  "content": [
    { "type": "text", "text": "What's in this image?" },
    { "type": "image_url", "image_url": { "url": "https://example.com/receipt.jpg" } }
  ]
}

順序很重要,請先放置文字部份。這是我們解析陣列的方式。若您的使用情境確實需要先參照影像再說文字,請將此設定移至系統提示,而非嘗試重新排序內容陣列。

A single content array with a text part and an image part flows through the OpenRouter chat completions endpoint to any vision-capable model, including Claude, Gemini, Qwen-VL, and Llama Vision, and returns a structured text answer

base64 資料 URL 與託管影像 URL:何時使用哪一種

image_url.url 欄位接受兩種格式:純公開 HTTP(S) 連結,或以 data:image/jpeg;base64,<encoded-bytes> 格式編碼的 base64 資料 URL。使用哪一種取決於檔案已存放的位置。

若影像已經託管於公開位置、CDN、帶簽名連結的 S3 儲存桶或您自己的伺服器,請傳遞該 URL。請求保持小型,且供應商自行擷取位元組。

若影像為本機,或不應有公開 URL,例如使用者上傳的身分證或內部檔案,請將其編碼為 base64 並放入請求。請求會變大且上傳耗時更長,但檔案僅透過 API 呼叫離開您的系統。

Side-by-side comparison of a hosted URL, where the request stays small, the provider fetches the image, and a public link is required, against a base64 data URL, where the bytes travel inline, upload is slower, and the image never goes public

Base64 具有第二個優點。託管 URL 可能因存取控制、區域封鎖或簽名 URL 過期而失敗。若位元組已包含於請求中,則不會發生此類失敗。兩種格式皆支援 PNG、JPEG、WebP 與 GIF。

cURL、Python 與 TypeScript 的可執行範例

相同請求,三種語言。模型間唯一變更的行是 MODEL。

cURL(託管 URL)

curl https://openrouter.ai/api/v1/chat/completions \
  -H "Authorization: Bearer $OPENROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-opus-4.8",
    "messages": [
      { "role": "user", "content": [
        { "type": "text", "text": "What total is on this receipt?" },
        { "type": "image_url", "image_url": { "url": "https://example.com/receipt.jpg" } }
      ]}
    ]
  }'

Python(本機檔案 → base64)

import base64, os, requests

def to_data_url(path: str, mime: str = "image/jpeg") -> str:
    with open(path, "rb") as f:
        b64 = base64.b64encode(f.read()).decode("utf-8")
    return f"data:{mime};base64,{b64}"

MODEL = "anthropic/claude-opus-4.8"  # swap this one string for any vision model

resp = requests.post(
    "https://openrouter.ai/api/v1/chat/completions",
    headers={"Authorization": f"Bearer {os.environ['OPENROUTER_API_KEY']}"},
    json={
        "model": MODEL,
        "messages": [{
            "role": "user",
            "content": [
                {"type": "text", "text": "What total is on this receipt?"},
                {"type": "image_url", "image_url": {"url": to_data_url("receipt.jpg")}},
            ],
        }],
    },
)
print(resp.json()["choices"][0]["message"]["content"])

TypeScript(本機檔案 → base64)

import { readFile } from "node:fs/promises";

const MODEL = "anthropic/claude-opus-4.8"; // change only this to swap models
const bytes = await readFile("receipt.jpg");
const dataUrl = `data:image/jpeg;base64,${bytes.toString("base64")}`;

const res = await fetch("https://openrouter.ai/api/v1/chat/completions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: MODEL,
    messages: [{
      role: "user",
      content: [
        { type: "text", text: "What total is on this receipt?" },
        { type: "image_url", image_url: { url: dataUrl } },
      ],
    }],
  }),
});
const data = await res.json();
console.log(data.choices[0].message.content);

選擇視覺模型

OpenRouter 上的每個視覺模型皆採用相同的請求結構。切換模型時,只需改變 model 欄位,其他保持不變。這使您能在不改變整合方式的情況下比較模型。

什麼使模型具備視覺能力

並非目錄中的每個模型都能讀取圖片。當模型將文字模型與影像編碼器結合,允許同時輸入畫素與標記時,即可被歸類為視覺語言模型 (VLM)。在 OpenRouter 上,您可以直接檢查:若模型架構在 input_modalities 下列出 image,表示它支援圖片輸入。若向不列出此項的模型傳送 image_url,請求將失敗。先檢查目錄。

成本、上下文視窗以及各模型的適用場景

這些模型的請求結構相同,但行為各異。價格、上下文視窗、延遲,以及模型在 OCR、圖表或一般場景理解上的表現皆不相同。在決定使用前,請先將候選模型對照您的實際圖片進行測試。

模型輸入 $/M 令牌上下文適用於
anthropic/claude-opus-4.8$5.001M密集檔案,對圖表/表格進行仔細推理
anthropic/claude-sonnet-5$2.001M以較低成本進行平衡檔案理解
google/gemini-3-flash-preview$0.501M高量螢幕截圖及一般問答,低延遲
google/gemini-2.5-flash$0.301M經濟實惠的批次 OCR 與字幕
qwen/qwen3-vl-235b-a22b-instruct~$0.26256K開源權重 OCR 與多語言文字擷取
meta-llama/llama-4-scout~$0.101.3M開源權重通用視覺,適合自託管

隨著模型變更,價格與上下文視窗會變動。將此表格視為示例,請在依賴前從 /models 拉取即時資料。

將目錄篩選為具備視覺功能的模型

改用查詢目錄,而非硬編碼模型列表。

import requests

models = requests.get("https://openrouter.ai/api/v1/models").json()["data"]
vision = [m["id"] for m in models
          if "image" in m["architecture"]["input_modalities"]]
print(vision)  # models that accept image input

由於所有模型的請求主體相同,您可以在請求時從此列表中挑選任何模型。依照價格、上下文視窗或應用需求進行排序,而非預先硬編碼單一模型。

The OpenRouter models page filtered by input modality, showing the table view with per-model pricing, context length, latency, and throughput columns

傳送多張圖片與長檔案

單一請求中的多張圖片

您不必每個請求僅限一張圖片。可將所需數量的 image_url 部件加入內容陣列。這樣即可處理前後比較、多頁掃描,或一次涵蓋多張圖表的問題:

{
  "role": "user",
  "content": [
    { "type": "text", "text": "Which chart shows higher Q4 revenue?" },
    { "type": "image_url", "image_url": { "url": "https://example.com/2025.png" } },
    { "type": "image_url", "image_url": { "url": "https://example.com/2026.png" } }
  ]
}

實際限制:圖片數量、解析度與令牌成本

沒有統一上限。限制由各供應商與模型設定。每請求數張圖片通常沒問題,但在一次送出數十張前,請先檢視特定模型的端點頁面。每張圖片都會增加令牌數,因而成本隨圖片數量與解析度提升,尤其在傳送完整掃描檔案時更顯著。

何時在傳送前縮小尺寸或預先裁剪

手機拍攝的收據通常寬 4000 畫素。模型不需要那麼高解析度即可讀取底部總額。將圖片縮小至文字仍可辨識的最小尺寸。若已知影像中重要區域,請裁剪至該區域。這兩步都能降低令牌成本。裁剪亦可提升準確度,因為移除模型本來需要處理的視覺內容。

圖片令牌化運作方式

圖片被切割成區塊,轉換為嵌入向量,接著作為令牌處理;因此更高解析度會產生更多令牌與更高成本。以下說明其運作方式。影像編碼器(通常是 Vision Transformer)將圖片切割成固定尺寸的格網區塊。每個區塊被轉換為嵌入向量,代表該片段。這些嵌入向量被傳遞給語言模型作為令牌,與文字令牌混合。模型永遠不會看到原始畫素,而是看到區塊嵌入。

結果很簡單。畫素越多,產生的 patch 越多,patch 越多,所需的 token 也越多,進而影響費用。縮小影像會減少編碼器產生的 patch 數量。不同供應商對同一張影像所需 token 數量不同,若需精確數字,請參閱該模型端點頁面。

多模態 RAG:從包含圖片的檔案中檢索

多模態 RAG 同時索引圖片、圖表和掃描頁面與文字,檢索時可回傳視覺內容並在回答時將其傳遞給視覺模型。這解決了以下問題:大多數真實檔案並非純文字。季度報告的關鍵數字可能僅出現在條形圖中。純文字檢索管線依賴 OCR,OCR 經常會錯讀圖表或完全忽略。若索引未捕捉到該視覺內容,檢索就無法再次找到。

索引策略 A:將圖片摘要成文字,然後嵌入

在索引時,將每個圖表、圖形或掃描頁面送入 VLM,請其產生文字摘要。將該摘要與常規文字嵌入模型一起嵌入,並保留指向原始圖片的指標。優點是檢索完全基於文字,可直接使用您已執行的任何向量庫。缺點是檢索品質取決於摘要。VLM 在索引時遺漏的任何資訊,之後都無法被找到。

索引策略 B:原生多模態嵌入

跳過摘要步驟,直接將圖片嵌入,使用能將影像與文字對映到同一向量空間的多模態嵌入模型。文字查詢便可直接匹配圖片。這樣可以保留更多視覺細節,但您需要在堆疊中加入多模態嵌入模型,並且擁有可儲存其輸出的向量庫。若想重複使用現有工具且檔案相對簡單,請使用策略 A;若圖表與圖形包含的細節摘要可能會遺失,則使用策略 B。

Multimodal RAG architecture diagram: a document is parsed into text and image chunks, indexed either by summarizing images to text or with native multimodal embeddings, then retrieval assembles the question, top text matches, and top image matches into one vision-model prompt

組裝提示:將檢索到的文字與圖片輸入 VLM

回答步驟對兩種索引策略相同。挑選最佳匹配的文字與圖片片段,然後構建一個包含問題、檢索到的文字以及檢索到的 image_url 部分的單一內容陣列:

def answer(question, retrieved):
    content = [{"type": "text", "text": question}]
    for r in retrieved:
        if r["type"] == "text":
            content.append({"type": "text", "text": r["text"]})
        else:  # image chunk
            content.append({"type": "image_url",
                            "image_url": {"url": r["url"]}})
    return requests.post(
        "https://openrouter.ai/api/v1/chat/completions",
        headers={"Authorization": f"Bearer {os.environ['OPENROUTER_API_KEY']}"},
        json={"model": "anthropic/claude-opus-4.8", "messages":
              [{"role": "user", "content": content}]},
    ).json()

簡易端到端程式碼草圖

完整流程如下:將來原始檔解析為文字與圖片片段,對每個片段進行摘要或多模態嵌入索引,針對輸入查詢檢索前幾個匹配,組裝上述多模態提示,並使用視覺模型回答。解析、索引與檢索步驟是 RAG 所特有的。最終回答呼叫與本指南頂部所示的請求相同。若需將輸出作為結構化資料而非散文,請加入工具呼叫。

此方法不適用於以下情況

  • 即時影片理解。不要將每一幀都串流進聊天請求。您可以將幾個取樣幀送入圖片陣列,但這只是權宜之計,而非影片管線。真正的影片工作需要有意識的幀取樣、嚴格限制幀數,以及延遲處理,而此端點並未設計為此。
  • 低解析度下的畫素精準或密集小字 OCR。通用 VLM 可能會錯過來源影像中極小的字元。若每個字元都必須正確,請先放大或裁切,或改用專用 OCR 管線。
  • 生成或編輯影像。 本指南僅涵蓋影像輸入,意即模型閱讀你提供的圖片。建立新影像或修改現有影像則使用不同的請求結構。請參閱我們的 影像生成檔案。

結論

要將影像送給 LLM,請使用包含文字部分與 image_url 部分的內容陣列。請求結構無論 URL 指向已託管檔案或包含 base64 編碼的位元組皆相同。只需更改 model 欄位,即可使用相同的請求體對所有接受影像輸入的模型。多模態 RAG 管線在回覆時會以同樣的請求傳送,當檢索已挑選到正確影像後。

三件事要記得:

  1. 一個請求體適用於所有視覺模型。 切換模型時內容陣列不會改變。你只需改變一個字串。
  2. 根據影像所在位置選擇 URL 或 base64。 若是公開且已託管的影像,使用 URL。若是本地或私有影像,使用 base64。無論哪種方式,送出前先降解尺寸以降低 token 成本。
  3. RAG 在同一呼叫前加入檢索。 將圖表與掃描與文字一起索引,檢索正確專案,並使用開頭示範的請求將選定影像送給模型。

在目錄中瀏覽 具備視覺功能的模型,並可在它們之間切換,而不需改動整合。

常見問題

我能將影像送至 API 嗎?

是的。將 image_url 或 base64 資料 URL 部分與文字一起加入訊息內容陣列,任何具備視覺功能的模型都能閱讀。請求的結構不會因為不同提供者而改變。唯有 model 欄位會變。

你能用影像做 RAG 嗎?

是的。可在索引時將圖表、表格和掃描頁面以文字摘要的方式加入,或直接使用多模態嵌入模型將其嵌入。查詢時,檢索相關文字與影像片段,並將它們一起送給視覺模型一次請求。

多模態大型語言模型如何處理影像?

影像編碼器將影像分割成固定尺寸的區塊,將每個區塊轉換為嵌入向量,並將這些嵌入作為標記送入語言模型,與文字標記混合。模型只對這些嵌入進行推理,永遠不會直接處理原始畫素。

多模態大型語言模型如何對影像進行分詞?

流程是從區塊到嵌入再到標記。較高解析度的影像會產生更多區塊,進而產生更多標記,成本也更高。於傳送影像前先進行縮小,是直接控制成本的方法。

base64 還是 URL:我該選擇哪一個?

若影像已公開且託管於某處,請使用 URL,這樣請求體會較小。若影像為本地、私有,或供應商無法可靠取得,則改以 base64 編碼。

一次請求可送多少張影像?

沒有單一的通用數字,因為取決於供應商與模型。每次請求幾張影像通常是安全的,但在送出大量批次前,請先檢視模型的專屬端點頁面,因為每張影像都會增加標記數與成本。

所有模型都支援影像輸入嗎?

不會。只有在 input_modalities 下列出 image 的模型才會接受 image_url 部分。請查詢目錄以確認哪些模型符合條件,而不是假設任何模型都支援。

影像在標記上耗費多少?

它隨解析度擴充套件:畫素越多產生的區塊越多,區塊越多意味著令牌越多。不同供應商計算這些令牌的方式不同,因此如果在擴大使用前需要準確的成本估算,請先檢視模型的端點頁面。

我可以將影像輸入與工具呼叫或結構化輸出結合使用嗎?

可以。將工具呼叫加入視覺請求,模型會回傳型別化的 JSON,例如 { "total": 42.10 },而不是句子。這是從收據、表單或掃描檔案中提取結構化欄位的常見模式。

來源:openrouter blog · openrouter.ai