地味だが価値のあるユースケース
過去20年間、非構造化文書から構造化データを抽出するには、OCRパイプライン、正規表現ルール、エッジケース対応、ベンダーごとのレイアウトテンプレートを含む四半期単位のプロジェクトが必要でした。LLMにJSONスキーマを厳守させれば、コードは30行で済み、初回から正確に動作し、1日で出荷できます。以下の例は、独立したOpenAI互換ゲートウェイであるKunavo上で実行されますが、このパターンはモデル側のものであり、どのモデルに対しても同じように機能します。
請求書からのデータ抽出をお考えですか?このページは文書横断の概要です。専用の請求書データ抽出ガイドでは、請求書という1種類の文書について、従来のテンプレートとモデルによる手法とビジョンLLM呼び出しの比較、スキーマ制約付きPythonチュートリアルの全編、算術ガードレール、2層モデルルーティング、請求書単位のコストを詳しく説明しています。
この方法が特に効果を発揮するカテゴリ:
- 請求書、領収書、発注書
- 契約書、法的合意書(当事者、日付、義務を抽出)
- 履歴書 / CV(ATS対応の構造に解析)
- メール署名またはWebページからのリード情報の補完
- 医療記録、検査報告書(PIIの取り扱いを含む)
- 不動産物件情報、商品カタログ
- メールの振り分けと構造化取り込み
30行で実装する基本パターン
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%)。レコード単位ではなく、フィールド単位の精度を追跡します。