# Llama 4 マルチモーダル実践：画像理解を本番の『型安全な構造化抽出』に使う

> Llama 4 はネイティブマルチモーダル。帳票・レシート・名刺・図面・スクショといった画像を、推測させずに構造化データへ落とす本番パイプラインを、AWS Bedrock Converse の画像入力・Zodによる境界検証・信頼度ゲート・人手レビュー・PII保護まで実コードで解説します。

- 公開日: 2026-06-25
- 著者: 友田 陽大
- タグ: Llama, マルチモーダル, 生成AI, AWS Bedrock, OCR, TypeScript, Python
- URL: https://tomodahinata.com/blog/llama-4-multimodal-vision-image-understanding-production

## 要点

- Llama 4 は早期融合のネイティブマルチモーダル。テキストと画像を同じモデルで扱い、画像→構造化データの抽出が現実的な精度で回る
- Bedrock Converse の画像ブロックで投入：format(png/jpeg/gif/webp)＋bytes。最大20枚・各3.75MB/8000pxの制約。SDKがbase64を処理
- 鉄則は『推測させない』。出力はZodで境界検証し、金額・型番など誤れない値は信頼度ゲート＋人手 or マスタ照合に回す
- 落とし穴は幻覚フィールド・低解像度・多ページ・画像トークン課金。前処理（回転補正・リサイズ）と評価で品質を担保する
- 画像はPII の塊（本人確認書類等）。バイト列をログに残さない・最小権限・マスキングを設計に織り込む

---

## この記事のゴール

[Llama 4 はネイティブマルチモーダル](/blog/meta-llama-open-weight-llm-production-guide#llama-4-とは何かネイティブマルチモーダル-moe)——テキストと画像を**後付けではなく最初から同じモデルで**扱います（early fusion）。これが効くのは、**「画像を見て、構造化データを返す」**タスクです。帳票・レシート・名刺・図面・スクリーンショット・本人確認書類……現場には“紙とスクショ”が溢れています。

本稿は、その画像理解を**デモではなく本番**——推測させない・型で縛る・誤れない値を守る・PIIを漏らさない——に仕上げます。

> **信頼性の開示**：「**生成に数値を推測させず、誤れない値はマスタ照合に分業させる**」という設計は、私が[音声接客の事例](/blog/production-voice-ai-sales-agent-bedrock-pgvector)で型番・サイズの誤答を構造的に潰したときの中核思想です。本稿の画像抽出も同じ規律——**LLMは読み取りの言葉、真実は検証**——で組みます。

---

## どんな場面で効くか

| 入力画像 | 抽出したい構造 | 価値 |
| --- | --- | --- |
| 請求書・領収書 | 取引先・金額・日付・明細 | 経理の手入力ゼロ化 |
| 名刺 | 氏名・会社・役職・連絡先 | CRM 自動登録 |
| 図面・仕様書 | 型番・寸法・材質 | 見積もり・発注の前処理 |
| スクリーンショット | エラー文・UI状態 | サポート/QAの自動分類 |
| 本人確認書類 | 氏名・生年月日・番号 | KYC（※PII保護が前提） |

共通するのは「**非構造な画像 → 後段システムが使える構造化データ**」。ここを LLM のマルチモーダルで埋めると、人手の転記が消えます。

---

## 投入する：Bedrock Converse の画像入力

[Bedrock の Converse API](/blog/meta-llama-open-weight-llm-production-guide#使い方baws-bedrock本番フルマネージド) は、メッセージに**画像ブロック**を混ぜられます。形式は `format`（`png` / `jpeg` / `gif` / `webp`）＋ `source.bytes`。**AWS SDK が base64 化を肩代わり**するので、生バイトを渡すだけです。

```python
# llama_vision.py — 画像＋指示を Llama 4 に渡し、テキストで理解させる
import boto3
from botocore.config import Config

_bedrock = boto3.client(
    "bedrock-runtime", region_name="us-east-1",
    config=Config(retries={"max_attempts": 4, "mode": "adaptive"}, read_timeout=60),
)
MODEL_ID = "us.meta.llama4-maverick-17b-instruct-v1:0"  # 画像理解は上位のMaverickが堅い

def read_image(path: str) -> dict:
    with open(path, "rb") as f:
        data = f.read()  # SDKがbase64を処理するので生バイトでよい
    ext = path.rsplit(".", 1)[-1].lower()
    fmt = "jpeg" if ext == "jpg" else ext  # jpg→jpeg に正規化
    return {"image": {"format": fmt, "source": {"bytes": data}}}

def describe(image_path: str, instruction: str) -> str:
    resp = _bedrock.converse(
        modelId=MODEL_ID,
        messages=[{"role": "user", "content": [read_image(image_path), {"text": instruction}]}],
        inferenceConfig={"maxTokens": 1024, "temperature": 0.0},  # 抽出は温度0で揺らさない
    )
    return resp["output"]["message"]["content"][0]["text"]
```

> 📌 **制約（公式）**：1メッセージあたり**画像は最大20枚**、各画像は**3.75MB・8000px 以下**。多ページ帳票は**ページ単位に分割**して投入します。温度は抽出では `0.0` が基本——創造性は不要、**毎回同じに読む**ことが品質です。

---

## 型で縛る：画像から構造化データへ（推測させない）

画像理解の出力も**信頼境界の外側**です。自由文ではなく**スキーマ準拠のJSON**を要求し、**Zodで境界検証**して初めて後段に流します。Vercel AI SDK なら画像パートと `generateObject` を組み合わせられます。

```ts
// lib/extract-receipt.ts — レシート画像 → 型安全な構造化データ
import { bedrock } from "@ai-sdk/amazon-bedrock";
import { generateObject } from "ai";
import { z } from "zod";

const Receipt = z.object({
  merchant: z.string().min(1),
  total: z.number().nonnegative(),
  currency: z.enum(["JPY", "USD", "EUR"]),
  purchasedAt: z.string().date(),                 // YYYY-MM-DD
  items: z.array(z.object({ name: z.string(), price: z.number() })).max(100),
  confidence: z.number().min(0).max(1),           // モデルに自己申告させる読み取り確度
});

export async function extractReceipt(image: Uint8Array) {
  const { object, usage } = await generateObject({
    model: bedrock("us.meta.llama4-maverick-17b-instruct-v1:0"),
    schema: Receipt,
    messages: [{
      role: "user",
      content: [
        { type: "image", image },
        { type: "text", text: "レシート画像から構造化データのみ抽出。読み取れない値は推測せず、confidenceを下げる。" },
      ],
    }],
  });
  // object は Receipt 準拠が型レベルで保証された安全な値。usage は画像トークン課金の可観測性。
  return { receipt: object, usage };
}
```

**何を返そうと `Receipt` を通った値しか後段に流れない**——これで「崩れたJSON」「想定外フィールド」を構造的に排除できます。

---

## 誤れない値を守る：信頼度ゲートと分業

ここが本番の肝です。**金額・型番・本人情報のような“誤ると事故”の値を、モデルの一発出力で確定させてはいけません**。音声接客で「数字はLLMでなくマスタ照合」と分業したのと同じ規律を、画像抽出にも敷きます。

```ts
// 抽出結果を“信頼度”と“検証可能性”で振り分ける（自動確定はしない）
type Routed =
  | { status: "auto"; receipt: Receipt }       // 高確度かつ検算一致 → 自動採用
  | { status: "review"; receipt: Receipt };     // 低確度 or 検算不一致 → 人手レビュー

function route(receipt: Receipt): Routed {
  const sumOfItems = receipt.items.reduce((a, b) => a + b.price, 0);
  const arithmeticOk = Math.abs(sumOfItems - receipt.total) < 1; // 明細合計と総額の検算
  const confident = receipt.confidence >= 0.9;
  return confident && arithmeticOk ? { status: "auto", receipt } : { status: "review", receipt };
}
```

ポイントは**検算（明細合計＝総額）という“モデルに依存しない真実”で裏取り**していること。LLM は読み取りの労を担い、**正しさはコードが保証**します。これにより、人手レビューを「全件」から「**怪しい一部だけ**」に絞れ、品質とコストを両立できます。

---

## 落とし穴と対策

- **幻覚フィールド**：読めない欄を“それっぽく”埋める。→ プロンプトで「**推測禁止・不明はnull/低confidence**」を明示し、`temperature=0`。スキーマで `nullable` を許容して“空”を表現可能にする。
- **低解像度・傾き・影**：読み取り精度が落ちる。→ **前処理**（リサイズ・回転補正・コントラスト）を1段挟む。8000px 上限・3.75MB 制約にも前処理で寄せる。
- **多ページ**：1リクエストに詰めすぎる。→ **ページ分割**し、ページごとに抽出して統合。
- **画像トークン課金**：画像は入力トークンを多く消費する。→ **解像度を必要十分に落とす**、難しい画像だけ上位モデルに回す（[コスト設計](/blog/llama-inference-cost-optimization-self-host-vs-api#コスト削減レバー効果の大きい順)）。
- **評価不在**：見た目で判断。→ **正解付き評価セット**でフィールド一致率（精度/再現率）を測り、回帰を検出してから出す。

---

## セキュリティ：画像は PII の塊

帳票・名刺・本人確認書類は**個人情報そのもの**です。設計に保護を織り込みます。

- **ログにバイト列・抽出本文を残さない**：可観測性は**メタデータ（モデル・トークン数・confidence・処理時間）だけ**で足ります。
- **最小権限**：画像ストレージ（S3等）は最小権限・暗号化・短命URL。処理後は保持ポリシーに従い削除。
- **マスキング**：番号類は後段で必要最小限に。表示UIでは伏字（アクセシブルに——読み上げで全桁を露出しない）。
- **入力検証**：ファイル形式・サイズ・枚数を**境界で検証**してから投入（[型安全の規律](/blog/typescript-type-safety-discipline-zod-nevererror-no-any)）。

> 抽出した構造化データは、最終的に**人が使う画面**へ流れます。伏字・ラベル・エラー表現を**アクセシブル**に設計してこそ、抽出パイプラインは“プロダクト”になります。

---

## よくある質問（FAQ）

**Q. OCR専用サービスと何が違う？**
A. 従来OCRは「文字を読む」まで。Llama 4 は「**読んで、意味を理解し、構造化して返す**」まで一気通貫。レイアウトが多様な帳票や、文脈依存の項目抽出に強い。一方で**誤れない値は必ず検算/マスタ照合**で裏取りする設計は OCR と同じく必須です。

**Q. どのモデルを使うべき？**
A. 画像理解は **Maverick** が堅い。大量・簡単なものは Scout でコストを抑え、難しい画像だけ上位へ回す**ルーティング**が費用対効果の最適点です。

**Q. 日本語の帳票も読める？**
A. 読めます。ただし**手書き・低解像度・特殊フォント**は精度が落ちるので、前処理と信頼度ゲート、人手レビュー経路を必ず用意してください。

**Q. 何枚まで一度に渡せる？**
A. 公式制約で**1メッセージ最大20枚・各3.75MB/8000px**。多ページや高解像度はページ分割・リサイズで寄せます。

**Q. セルフホストでも画像理解できる？**
A. できます。[vLLM で Scout/Maverick をサーブ](/blog/vllm-llama-self-hosting-production-inference-server)すれば、OpenAI互換の画像入力で同様に扱えます。データを外に出せない KYC 等はこちら。

---

## まとめ

Llama 4 のマルチモーダルは、「**紙とスクショを、後段が使えるデータに変える**」実務の道具です。鍵は派手な使い方ではなく、**規律**にあります。

1. **Converse の画像ブロック**で投入（format＋bytes、温度0）。
2. **Zodで境界検証**し、崩れた出力を構造的に排除する。
3. **誤れない値は検算/マスタ照合で裏取り**し、自動確定しない。
4. **PII保護**（ログ非出力・最小権限・マスキング）を織り込む。
5. **評価セット**で精度を測り、回帰を見てから出す。

> 帳票・本人確認・図面などの画像理解を、検算・人手レビュー・PII保護・コスト設計まで含めて本番に載せたいなら、[実績](/case-studies/ai-voice-chatbot)をご覧のうえご相談ください。**一人 × 生成AI**で、速く・安く・安全に。

### 出典・公式リソース

- [The Llama 4 herd（Meta AI）](https://ai.meta.com/blog/llama-4-multimodal-intelligence/) — ネイティブマルチモーダル
- [Bedrock Converse API（画像入力）](https://docs.aws.amazon.com/bedrock/latest/userguide/conversation-inference.html) — 画像ブロックの形式・制約
- [boto3 converse リファレンス](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-runtime/client/converse.html)
- [Vercel AI SDK](https://ai-sdk.dev/) — `generateObject` と画像パート

※ モデル・制約・料金は更新されます。実装前に一次情報を確認し、正解付き評価で精度を検証してください。
