活用例に戻る
データ処理

AI データ抽出 — PDF、請求書、非構造化テキストからの構造化出力

地味ですが価値のあるユースケースです。請求書、領収書、契約書、リード、履歴書 — これまでパーサーを構築していたあらゆる場所で、JSON スキーマに従わせた LLM なら30行で、より正確に処理でき、四半期ではなく1日でリリースできます。

おすすめのモデル

最終確認日:。

地味だが価値のあるユースケース

過去20年間、非構造化文書から構造化データを抽出するには、OCRパイプライン、正規表現ルール、エッジケース対応、ベンダーごとのレイアウトテンプレートを含む四半期単位のプロジェクトが必要でした。LLMにJSONスキーマを厳守させれば、コードは30行で済み、初回から正確に動作し、1日で出荷できます。以下の例は、独立したOpenAI互換ゲートウェイであるKunavo上で実行されますが、このパターンはモデル側のものであり、どのモデルに対しても同じように機能します。

請求書からのデータ抽出をお考えですか?このページは文書横断の概要です。専用の請求書データ抽出ガイドでは、請求書という1種類の文書について、従来のテンプレートとモデルによる手法とビジョンLLM呼び出しの比較、スキーマ制約付きPythonチュートリアルの全編、算術ガードレール、2層モデルルーティング、請求書単位のコストを詳しく説明しています。

この方法が特に効果を発揮するカテゴリ:

  • 請求書、領収書、発注書
  • 契約書、法的合意書(当事者、日付、義務を抽出)
  • 履歴書 / CV(ATS対応の構造に解析)
  • メール署名またはWebページからのリード情報の補完
  • 医療記録、検査報告書(PIIの取り扱いを含む)
  • 不動産物件情報、商品カタログ
  • メールの振り分けと構造化取り込み

30行で実装する基本パターン

extract.py
import json
from openai import OpenAI
client = OpenAI(api_key="sk-kn-...", base_url="https://api.kunavo.com/v1")

# The schema is the output contract. Claude enforces a json_schema
# response_format (json_object it does not), so the reply has this shape
# unless max_tokens cuts it off (finish_reason == "length").
STR = {"type": ["string", "null"]}
NUM = {"type": ["number", "null"]}
INVOICE = {
    "type": "object",
    "properties": {
        "vendor": {"type": "string"},
        "invoice_number": STR, "date_iso": STR, "due_date_iso": STR,
        "currency": STR, "subtotal": NUM, "tax": NUM, "total": NUM,
        "line_items": {"type": "array", "items": {
            "type": "object",
            "properties": {"description": {"type": "string"},
                           "qty": NUM, "unit_price": NUM, "amount": NUM},
            "required": ["description", "qty", "unit_price", "amount"],
            "additionalProperties": False,
        }},
    },
    "required": ["vendor", "invoice_number", "date_iso", "due_date_iso",
                 "currency", "subtotal", "tax", "total", "line_items"],
    "additionalProperties": False,
}
RESPONSE_FORMAT = {"type": "json_schema",
                   "json_schema": {"name": "invoice", "schema": INVOICE}}
RULES = "Extract the invoice. Use null for missing fields. Dates in ISO 8601."

# Extract structured fields from an invoice PDF (after OCR)
def extract_invoice(ocr_text: str) -> dict:
    resp = client.chat.completions.create(
        model="claude-haiku-4-5",
        messages=[
            {"role": "system", "content": RULES},
            {"role": "user", "content": ocr_text},
        ],
        response_format=RESPONSE_FORMAT,
        max_tokens=1200,
    )
    return json.loads(resp.choices[0].message.content)

# Extract from an image directly (no OCR step needed)
def extract_invoice_from_image(image_url: str) -> dict:
    resp = client.chat.completions.create(
        model="claude-haiku-4-5",   # vision + an enforced schema
        messages=[
            {"role": "system", "content": RULES},
            {"role": "user", "content": [
                {"type": "text", "text": "Extract this invoice:"},
                {"type": "image_url", "image_url": {"url": image_url}},
            ]},
        ],
        response_format=RESPONSE_FORMAT,
        max_tokens=1200,
    )
    return json.loads(resp.choices[0].message.content)

フローは2つあります。テキストのみ(別途OCR処理を行った後)と、ビジョン直接方式(ビジョンモデルが画像を読み取り、1回の呼び出しでJSONを出力)です。ビジョン経路は構築が速い一方、呼び出し単価はやや高くなります。OCR後にLLMへ渡す経路は、OCRがページごとの一度きりのコストであるため、大規模処理では安価です。

精度ベンチマーク

公開請求書データセット(50社のベンダーから収集した請求書1,000件)で、200語のシステムプロンプトを使ったJSONモードの場合:

  • Claude Haiku 4.5:フィールド単位の精度96%
  • Claude Sonnet 4.6:フィールド単位の精度98%
  • 従来のテンプレート方式:既知のベンダーでは80〜90%、新規ベンダーでは0%

LLMは新しいベンダーのレイアウトもゼロショットで処理します。システムプロンプトに2〜3組の例(few-shot)を追加すると、HaikuはSonnetの精度に、はるかに低いコストで近づきます。

文書あたりのコスト

  • 請求書(入力約2Kトークン、出力約500):Haiku約$0.003、Sonnet約$0.02
  • 1ページの契約書(入力約5K):Haiku約$0.005、Sonnet約$0.04
  • 10ページの契約書(入力約50K、構造化要約を出力):Sonnet約$0.30
  • 履歴書(入力約3K):Haiku約$0.003
  • ビジョンによる領収書画像:Haikuで請求書とほぼ同じコスト。画像は約1.5K入力トークンとして計上

月10,000件の請求書を処理する場合、Haikuなら約$30です。最も近い商用代替(Rossum、またはAWS Textract+後処理)は、同じ量で月約$2,000〜5,000です。

精度を高く保つ5つのパターン

  • 明示的なnull処理:欠損フィールドには「N/A」や空文字列ではなくnullを使うようモデルに指示します。下流コードで「存在しない」と「意図的に空」を区別できます。
  • ISO 8601日付:明示的に指定します。指定しないとモデルが地域ごとの形式を選び、下流の解析が壊れます。
  • 通貨はISOコード:「$」ではなく「USD」、「€」ではなく「EUR」を使用します。$はUSD、CAD、AUDのいずれにもなり得るため、曖昧さを避けます。
  • JSONを検証:Pydantic / Zodでスキーマを強制します。無効な場合はエラーを含めて再プロンプトします。
  • 1週間は手動で1%を抜き取り確認し、その後は継続的に0.1%を確認します。レコード単位だけでなく、フィールド単位の精度を追跡します。

どのモデルを使うべきか

文書の種類推奨モデル
単純な構造化文書(請求書、領収書)Claude Haiku 4.5
長い契約書 / 合意書Claude Sonnet 5(長いコンテキストに対応)
ビジョン直接方式(OCRなしのPDF)Claude Haiku 4.5、または大きなページにはClaude Sonnet 5
高リスク(法務、医療)Claude Sonnet 5+人による確認
大量取り込み(1日100K件以上)Haiku 4.5+few-shot例+キャッシュ

コンプライアンスに関する考慮事項

PIIを含む文書(請求書には氏名や住所があり、医療記録にはあらゆる情報が含まれます)では、抽出前に仮名化するか、上流でZero Data Retentionを使用してください。地域別のパターンについてはコンプライアンスガイド、ドイツ向けの実務についてはDSGVO詳細ガイドをご覧ください。

開始:/app/signup——$10の追加チャージで約3,000件の請求書抽出を利用でき、残高に有効期限はありません。/docs/chatのチャットドキュメントでは、各モデルファミリーでresponse_formatが適用する内容と、ツール使用のパターンを説明しています。

よくある質問

LLMで文書からデータを抽出する費用はいくらですか?

Claude Haiku 4.5では文書1件あたり約0.003~0.005ドル、Claude Sonnet 4.6では約0.02~0.04ドルです。請求書を月に1万件処理する場合、約30ドルかかります。商用の抽出サービスでは2,000~5,000ドルかかります。

ゼロショットのLLMデータ抽出の精度はどの程度ですか?

約30行のコードで、ゼロショットでもフィールド単位の精度は95~98%です。OCRと正規表現によるパイプラインを置き換えるのに十分な精度です。

文書からのデータ抽出には、どのモデルを使えばよいですか?

請求書や領収書などの単純な構造化文書にはClaude Haiku 4.5を使います。長い契約書にはClaude Sonnet 4.6を使います。画像として直接読み取る文書にはClaude Haiku 4.5を使い、大きなページにはSonnet 4.6を使います。

本番環境で抽出精度を維持するにはどうすればよいですか?

5つの方法があります。nullの扱いを明示する、日付にISO 8601を使う、通貨にISOコードを使う、スキーマで検証して無効な出力には再プロンプトする、手作業で抜き取り確認する(最初の週は出力の1%、以降は0.1%)。レコード単位ではなく、フィールド単位の精度を追跡します。