mcpField
D
document-extraction

document-extraction

github.com/andrewyngドキュメント14.0k60 回インストール21 週間前に更新
リポジトリ

document-extraction について

document-extractionは、LandingAIのAgentic Document Extraction(ADE)で文書を処理する手順をまとめたガイドです。文書データの解析、抽出、分類を行う開発者向けに、Markdownや構造化JSON、スキーマ定義、非同期処理、位置情報を扱います。

主な機能

  1. 01文書をMarkdownとチャンクに解析
  2. 02JSON SchemaまたはPydanticでデータ抽出
  3. 03複数文書の分類と分割
  4. 04非同期解析ジョブの実行
  5. 05ページ番号とバウンディングボックスで位置表示

活用シーン

  1. 01請求書や銀行明細から項目を抽出
  2. 02大容量または複数ページの文書を処理
  3. 03混在する文書群を分類して分割
  4. 04抽出内容の原文書内の位置を特定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/andrewyng/context-hub --skill document-extraction

インストール後、Claude Code で/document-extractionを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

.env-sample
.gitignore
references/
chunk-types.md
extraction-schemas.md
file-formats.md
troubleshooting.md
use-cases.md

詳細

ドキュメント抽出(ADE)

概要

LandingAI の Agentic Document Extraction(ADE)は、テンプレートやトレーニングを必要とせずにドキュメントを解析、抽出、分類するドキュメント処理 SaaS です。主に次の 3 つの機能を提供します。

  1. 解析:ドキュメントを階層構造の JSON 表現を含む構造化 Markdown に変換します
  2. 抽出:JSON スキーマまたは Pydantic モデルを使って、特定の構造化データを抽出します
  3. 分割:複数ドキュメントを含むバッチを種類ごとに分類して分割します

主なメリット:

  • ML のトレーニングやテンプレートは不要です
  • レイアウトに依存しない解析(あらゆるドキュメント構造に対応します)
  • 20 種類以上のファイル形式に対応します(PDF、画像、スプレッドシート、プレゼンテーション)
  • 正確な視覚的グラウンディング(バウンディングボックス、ページ番号)
  • さまざまなドキュメントの種類に最適化された複数のモデル

クイックスタート

1. インストール

ユーザーの承認なしにパッケージをグローバルにインストールしないでください。必ず最初にローカルの Python 環境を確認してください。

1. .venv/bin/python       — uv-managed (this project)
2. venv/bin/python        — standard Python venv
3. uv run python          — if pyproject.toml exists
4. poetry run python      — if poetry.lock exists
5. python3                — system fallback; warn the user

ローカル環境を使ってインストールします:landingai-ade、python-dotenv

2. API キーの設定

ユーザーが document-extraction スキルと同じディレクトリに、API キーを含む .env ファイルをすでに作成している場合があります。必ず最初にこのパスを確認してください(ls -la .*/skills/document-extraction/.env)。また、この SKILL.md ファイルと同じディレクトリも確認してください。

見つからない場合は、作成方法を案内してください。以下のスクリプトは、一般的な場所にある .env を検索して読み込みます。

.venv/bin/python - << 'EOF'
import os
from pathlib import Path
from dotenv import load_dotenv

# Load API key: prefer existing env var, then .env file lookup
if os.environ.get("VISION_AGENT_API_KEY"):
    print("API key found in existing environment variable")
else:
    def _find_env():
        for d in [Path.cwd().resolve(), *Path.cwd().resolve().parents]:
            for candidate in [
                # ADD the directory where the document-extraction skill is located
                d / '.env',
                d / 'document-extraction/.env',
                d / 'skills/document-extraction/.env',
            ]:
                if candidate.is_file():
                    return candidate
        return None
    env = _find_env()
    if env:
        load_dotenv(env)
        print(f"API key loaded from: {env}")
    else:
        print("Warning: VISION_AGENT_API_KEY not set and no .env found")
EOF

キーが見つからない場合は、https://va.landing.ai/settings/api-key から API キーを取得するようユーザーに案内してください。

.env-sample を .env にコピーし、API キーを追加します。

cp .env-sample .env

.env を編集して、キーを追加します。

VISION_AGENT_API_KEY=your_actual_api_key_here

注: .env ファイルはセキュリティのため、gitignore の対象です。上級ユーザーは、環境変数を直接設定することもできます:export VISION_AGENT_API_KEY=<your-key>

EU エンドポイント: EU エンドポイントを使用する場合は、クライアントの初期化時に environment="eu" を設定してください。

3. 基本的な解析の例
from dotenv import load_dotenv
load_dotenv()  # Load API key from .env

from landingai_ade import LandingAIADE
from pathlib import Path

client = LandingAIADE()

# Parse a document
response = client.parse(
    document=Path("document.pdf"),
    model="dpt-2-latest"
)

# Access results
print(f"Pages: {response.metadata.page_count}")
print(f"Chunks: {len(response.chunks)}")
print("\nMarkdown output:")
print(response.markdown[:500])  # First 500 chars

# Save Markdown for extraction
with open("output.md", "w", encoding="utf-8") as f:
    f.write(response.markdown)
4. 基本的な抽出の例
from dotenv import load_dotenv
load_dotenv()

from landingai_ade import LandingAIADE
from landingai_ade.lib import pydantic_to_json_schema
from pydantic import BaseModel, Field
from pathlib import Path

# Define extraction schema using Pydantic
class Invoice(BaseModel):
    invoice_number: str = Field(description="Invoice number")
    invoice_date: str = Field(description="Invoice date")
    total_amount: float = Field(description="Total amount in USD")
    vendor_name: str = Field(description="Vendor name")

# Convert to JSON schema
schema = pydantic_to_json_schema(Invoice)

client = LandingAIADE()

# Extract from parsed markdown
response = client.extract(
    schema=schema,
    markdown=Path("output.md"),  # From parse step
    model="extract-latest"
)

# Access extracted data
print(response.extraction)
# Output: {'invoice_number': 'INV-12345', 'invoice_date': '2024-01-15', ...}

# Check extraction metadata (traceability)
print(response.extraction_metadata)

ドキュメントの解析

ローカルファイルの解析
from dotenv import load_dotenv
load_dotenv()

from landingai_ade import LandingAIADE
from pathlib import Path

client = LandingAIADE()

response = client.parse(
    document=Path("/path/to/document.pdf"),
    model="dpt-2-latest"
)

# Work with chunks
for chunk in response.chunks:
    print(f"Type: {chunk.type}, Page: {chunk.grounding.page}")
    print(f"Content: {chunk.markdown[:100]}...")
リモート URL の解析
response = client.parse(
    document_url="https://example.com/document.pdf",
    model="dpt-2-latest"
)
スプレッドシートの解析

スプレッドシート(CSV、XLSX)は、ドキュメントとは異なるレスポンスタイプを返します。主な違いは次のとおりです。

フィールドドキュメント(ParseResponse)スプレッドシート(SpreadsheetParseResponse)
metadata.page_count✓✗(sheet_count、total_rows、total_cells、total_chunks、total_images を使用)
splits[].pages✓✗(シートインデックスの配列である sheets を使用)
grounding(トップレベル)✓✗(スプレッドシートにはありません)
チャンクのグラウンディング常にあり任意(テーブルチャンクでは null、埋め込み画像チャンクではあり)
response = client.parse(
    document=Path("data.xlsx"),
    model="dpt-2-latest"
)

# Spreadsheet metadata
print(f"Sheets: {response.metadata.sheet_count}")
print(f"Total rows: {response.metadata.total_rows}")
print(f"Total cells: {response.metadata.total_cells}")

# Splits use 'sheets' instead of 'pages'
for split in response.splits:
    print(f"Sheet indices: {split.sheets}")
    print(f"Markdown: {split.markdown[:200]}...")
モデルの選択

ドキュメントに適したモデルを選択してください。

モデル最適な用途チャンクの種類
dpt-2-latestロゴ、署名、ID カードを含む複雑なドキュメントtext、table、figure、logo、card、attestation、scan_code、marginalia
dpt-2-miniシンプルでデジタルネイティブなドキュメント(より高速で低コスト)text、table、figure、marginalia
dpt-1⚠️ 2026 年 3 月 31 日に非推奨 — dpt-2 に移行してくださいtext、table、figure、marginalia

推奨: コストや速度が重要で、扱うドキュメントがシンプルな場合を除き、dpt-2-latest を使用してください。

バージョンの固定: 本番環境では、再現性を確保するため日付付きバージョン(例:dpt-2-20260302)を使用してください。

大きなファイルの解析(非同期)

最大 1 GB または 6,000 ページのファイルには、Parse Jobs を使用してください。

import time
from dotenv import load_dotenv
load_dotenv()

from landingai_ade import LandingAIADE
from pathlib import Path

client = LandingAIADE()

# Step 1: Create parse job
job = client.parse_jobs.create(
    document=Path("large_document.pdf"),
    model="dpt-2-latest"
)

job_id = job.job_id
print(f"Job {job_id} created")

# Step 2: Poll for completion
while True:
    response = client.parse_jobs.get(job_id)
    if response.status == "completed":
        print(f"Job {job_id} completed")
        break
    print(f"Progress: {response.progress * 100:.0f}%")
    time.sleep(5)

# Step 3: Access results
# Results are in response.data (or response.output_url for large results)
if response.data:
    print(f"Chunks: {len(response.data.chunks)}")
    with open("output.md", "w", encoding="utf-8") as f:
        f.write(response.data.markdown)
elif response.output_url:
    # Results > 1MB are returned as a presigned URL
    print(f"Download results from: {response.output_url}")

ジョブステータスのレスポンスフィールド:

  • job_id、status(pending、processing、completed、failed、cancelled)、progress(0-1)
  • data:完了時の ParseResponse(または SpreadsheetParseResponse)。結果が 1 MB 未満の場合に含まれます
  • output_url:結果が 1 MB を超える場合、または output_save_url が使用された場合の、署名付き S3 URL。有効期限は 1 時間です。GET のたびに新しい URL が生成されます。
  • metadata:同期解析の場合と同じです(filename、page_count、duration_ms など)
  • failure_reason:ジョブが失敗した場合のエラーメッセージ
ゼロデータ保持(ZDR)

組織で ZDR が有効になっている場合、解析結果の保存先となる output_save_url を指定する必要があります。結果は API レスポンスとして返されません。ZDR はデフォルトでは有効になっていません。通常、output_save_url には S3 バケットへの書き込み権限を持つ署名付き URL を使用しますが、HTTP PUT リクエストによるファイルアップロードに対応した他のストレージソリューションも使用できます。

job = client.parse_jobs.create(
    document=Path("sensitive_document.pdf"),
    model="dpt-2-latest",
    output_save_url="https://your-bucket.s3.amazonaws.com/output.json"
)
解析ジョブの一覧表示

オプションのページネーションとステータスフィルターを指定して、すべての非同期解析ジョブを一覧表示します。

# List recent jobs
jobs_response = client.parse_jobs.list(page=0, page_size=10)
for job in jobs_response.jobs:
    print(f"{job.job_id}: {job.status} ({job.progress:.0%})")

# Filter by status
completed = client.parse_jobs.list(status="completed", page_size=5)
print(f"Completed jobs: {len(completed.jobs)}, more: {completed.has_more}")

使用可能なステータスフィルター: pending、processing、completed、failed、cancelled

解析出力について

解析では、以下を含む ParseResponse が返されます。

  • markdown:HTML アンカータグを含む、ドキュメント全体の Markdown
  • chunks:抽出された要素の配列(それぞれに一意の ID、タイプ、コンテンツ、チャンクごとのグラウンディング情報が含まれます)
  • grounding:要素 ID と詳細な位置情報(ページ、バウンディングボックス、グラウンディングタイプ、表のセル位置)を対応付ける辞書です。構造についてはJSON レスポンスを参照してください。
  • metadata:処理情報 — filename、org_id、page_count、duration_ms、credit_usage(浮動小数点数)、job_id、version、failed_pages
  • splits:チャンクをグループ化する分割オブジェクトの配列です。常に含まれます。デフォルトでは単一の "full" 分割が含まれ、split="page" が使用された場合はページごとの分割が含まれます。注: 解析の分割では class フィールド(値:"full" または "page")を使用します。これは Split API の classification フィールドとは異なります。

一般的なチャンクタイプ: text、table、figure、logo、card、attestation、scan_code、marginalia

チャンクタイプの詳細については、references/chunk-types.mdを参照してください。

chunk.markdown 内のアンカータグプレフィックス: すべてのチャンクの markdown フィールドには、 チャンク UUID を埋め込んだ HTML アンカータグがプレフィックスとして付きます。 <a id='abc123...'></a>\n\nActual content…。これにより、ドキュメント全体の Markdown から個々のチャンクにリンクできます。文字列検索、表示、 または RAG インデックス作成の前に、このタグを取り除いてください。

import re
_ANCHOR_RE = re.compile(r"<a[^>]*></a>\s*", re.IGNORECASE)

def chunk_text(ch) -> str:
    """Return clean chunk markdown without the anchor prefix."""
    return _ANCHOR_RE.sub("", ch.markdown or "").strip()

# Example: fingerprint match against a section of the full markdown
intro_chunks = [ch for ch in response.chunks
                if chunk_text(ch)[:80] in intro_markdown]
解析レスポンスの保存

SDK には、parse()、extract()、split() の save_to パラメーターが組み込まれており、JSON レスポンスをフォルダーに自動で保存できます。

from pathlib import Path

# Parse and auto-save response JSON to output/ folder
response = client.parse(
    document=Path("document.pdf"),
    model="dpt-2-latest",
    save_to="output/"  # Creates output/document_parse_output.json
)

# Response is still returned normally for immediate use
print(response.markdown[:200])

save_to パラメーターは以下の処理を行います。

  • フォルダーが存在しない場合は作成します。
  • ファイル名を {input_filename}_{method}_output.json にします(例:document_parse_output.json)。
  • client.parse()、client.extract()、client.split() で使用できます。
  • クライアント側の利便機能です。API 呼び出し後、レスポンス全体をローカルに保存します。

手動でシリアライズする場合(カスタムファイル名や選択的な保存など)は、model_dump() を使用してください。

import json

response_dict = response.model_dump()
with open("parse_response.json", "w", encoding="utf-8") as f:
    json.dump(response_dict, f, indent=2, ensure_ascii=False)

# Save markdown separately for extraction
with open("document_parsed.md", "w", encoding="utf-8") as f:
    f.write(response.markdown)

重要: レスポンス全体をシリアライズするには、必ず model_dump() を使用してください。フィールドを選んで辞書を手動で作成しないでください。splits 配列やグラウンディング情報全体などの重要なデータを取りこぼす可能性があります。

解析パラメーター
response = client.parse(
    document=Path("document.pdf"),
    model="dpt-2-latest",
    split="page",       # Optional: organize chunks by page
    password="secret",   # Optional: decrypt protected files (ZDR only)
    save_to="output/",   # Optional: auto-save response JSON
)
パスワード保護されたファイルの解析

ゼロデータ保持(ZDR)が有効な組織では、password パラメーターを渡すことで、パスワード保護されたファイルを解析できます。対応形式:PDF、DOC、DOCX、ODT、PPT、PPTX、XLSX。

# Sync parse
response = client.parse(
    document=Path("encrypted.pdf"),
    password="document_password",
    model="dpt-2-latest"
)

# Async parse jobs
job = client.parse_jobs.create(
    document=Path("encrypted.pdf"),
    password="document_password",
    model="dpt-2-latest"
)

注: ZDR が有効でない場合、API は HTTP 422 を返します。パスワードが正しくない場合、API は復号エラーとともに HTTP 422 を返します。暗号化されていないドキュメントでは、このパラメーターは無視されます。

構造化データの抽出

スキーマ定義

JSON Schema または Pydantic モデルを使用して、抽出するデータを定義します。

Pydantic を使用する方法(Python で推奨):

from pydantic import BaseModel, Field
from landingai_ade.lib import pydantic_to_json_schema

class BankStatement(BaseModel):
    account_holder: str = Field(description="Account holder name")
    account_number: str = Field(description="Account number")
    beginning_balance: float = Field(description="Beginning balance in USD")
    ending_balance: float = Field(description="Ending balance in USD")

schema = pydantic_to_json_schema(BankStatement)

JSON Schema を使用する方法:

schema = {
    "type": "object",
    "properties": {
        "account_holder": {
            "type": "string",
            "description": "Account holder name"
        },
        "account_number": {
            "type": "string",
            "description": "Account number"
        },
        "beginning_balance": {
            "type": "number",
            "description": "Beginning balance in USD"
        },
        "ending_balance": {
            "type": "number",
            "description": "Ending balance in USD"
        }
    },
    "required": ["account_holder", "account_number"]
}
抽出ワークフロー
from dotenv import load_dotenv
load_dotenv()

from landingai_ade import LandingAIADE
from pathlib import Path

client = LandingAIADE()

# Step 1: Parse document
parse_response = client.parse(
    document=Path("bank_statement.pdf"),
    model="dpt-2-latest"
)

# Save markdown
with open("parsed.md", "w", encoding="utf-8") as f:
    f.write(parse_response.markdown)

# Step 2: Extract structured data
extract_response = client.extract(
    schema=schema,  # Your JSON schema
    markdown=Path("parsed.md"),
    model="extract-latest"
)

# Access extracted data
print(extract_response.extraction)

# Check traceability (which chunks provided each field)
for field, metadata in extract_response.extraction_metadata.items():
    print(f"{field}: from chunks {metadata.chunk_ids}")
URL から抽出

markdown_url を使用すると、リモートでホストされている Markdown ファイルから抽出できます。

extract_response = client.extract(
    schema=schema,
    markdown_url="https://example.com/parsed_document.md",
    model="extract-latest"
)
一般的なスキーマパターン

詳しいスキーマパターンについては、references/extraction-schemas.md を参照してください。

ネストされたオブジェクト:

class Address(BaseModel):
    street: str
    city: str
    zip_code: str

class Invoice(BaseModel):
    invoice_number: str
    billing_address: Address  # Nested object

配列(リスト):

class LineItem(BaseModel):
    description: str
    quantity: int
    amount: float

class Invoice(BaseModel):
    invoice_number: str
    line_items: list[LineItem]  # Array of objects

列挙型(制限された値):

class BankStatement(BaseModel):
    account_type: str = Field(
        description="Account type",
        enum=["Checking", "Savings"]  # Only these values allowed
    )

Null 許容フィールド:

class Patient(BaseModel):
    first_name: str
    middle_name: str | None = Field(default=None)  # Optional field
    last_name: str
ドキュメントの分類

種類ごとのフィールドを抽出する前に、ドキュメントを分類します。

from dotenv import load_dotenv
load_dotenv()

from landingai_ade import LandingAIADE
from pydantic import BaseModel, Field
from landingai_ade.lib import pydantic_to_json_schema
from pathlib import Path

# Step 1: Define classification schema
class DocumentType(BaseModel):
    document_type: str = Field(
        description="Document classification",
        enum=["Invoice", "Receipt", "Bank Statement", "Other"]
    )

client = LandingAIADE()

# Step 2: Parse document
parse_response = client.parse(
    document=Path("document.pdf"),
    model="dpt-2-latest"
)

# Step 3: Classify document
classification_schema = pydantic_to_json_schema(DocumentType)
classification_response = client.extract(
    schema=classification_schema,
    markdown=parse_response.markdown,
    model="extract-latest"
)

doc_type = classification_response.extraction["document_type"]
print(f"Classified as: {doc_type}")

# Step 4: Extract based on type
if doc_type == "Invoice":
    schema = pydantic_to_json_schema(InvoiceSchema)
elif doc_type == "Receipt":
    schema = pydantic_to_json_schema(ReceiptSchema)
else:
    print("Unsupported document type")
    exit()

# Extract type-specific fields
extract_response = client.extract(
    schema=schema,
    markdown=parse_response.markdown,
    model="extract-latest"
)

ドキュメントの分類と分割

Split API を使用するタイミング

1 つのファイルに複数のドキュメントが含まれており、それらを分割する必要がある場合は、Split API を使用します。

  • 金融サービス:銀行取引明細書、公共料金の請求書、本人確認書類を分割します
  • 医療:問診票、医療報告書、薬剤リストを分割します
  • 会計:複数の請求書と領収書を分割します
  • 学術:論文本文と参考文献を分割します
分割分類

split_class を使用して、ドキュメントの分類方法と分割方法を定義します。

from dotenv import load_dotenv
load_dotenv()

from landingai_ade import LandingAIADE
from pathlib import Path

client = LandingAIADE()

# Step 1: Parse multi-document PDF
parse_response = client.parse(
    document=Path("batch.pdf"),
    model="dpt-2-latest"
)

# Step 2: Define split classes
split_classes = [
    {
        "name": "Invoice",
        "description": "Commercial invoices with itemized charges",
        "identifier": "Invoice Number"  # Separate by invoice number
    },
    {
        "name": "Receipt",
        "description": "Payment receipts showing transaction details",
        "identifier": "Receipt Date"
    },
    {
        "name": "Bank Statement",
        "description": "Monthly bank account statements"
    }
]

# Step 3: Split document
split_response = client.split(
    markdown=parse_response.markdown,
    split_class=split_classes
)

# Step 4: Process each split
for split in split_response.splits:
    print(f"Type: {split.classification}")
    print(f"Identifier: {split.identifier}")
    print(f"Pages: {split.pages}")
    print(f"Content: {split.markdowns[0][:200]}...")

分割クラスの構成要素:

  • name(必須):ドキュメントの分類ラベル(例:「Invoice」)
  • description(任意):分類のコンテキスト(詳しいほど精度が向上します)
  • identifier(任意):各インスタンスを一意に識別するフィールド(一意の値ごとに個別の分割を作成します)
  • 上限: リクエストあたり最大 19 個の分割クラス

URL からの分割: リモートでホストされている Markdown ファイルから分割することもできます。

split_response = client.split(
    markdown_url="https://example.com/parsed_document.md",
    split_class=split_classes
)

出力形式

Markdown

ADE はドキュメントを構造化された Markdown に変換します。

# Document Title

## Section 1

Paragraph text...

| Column 1 | Column 2 |
|----------|----------|
| Data 1   | Data 2   |

<::Caption: Bar chart showing quarterly revenue::>

機能:

  • トレーサビリティのための HTML アンカータグ(チャンク ID へのリンク)
  • 視覚要素のための特殊な区切り記号:<::Caption: description::>
  • スプレッドシートデータのための HTML テーブル
  • 構造と階層を保持
JSON レスポンス

Parse は、最上位に 5 つのフィールドを持つ構造化 JSON を返します。

{
  "markdown": "# Document...",
  "chunks": [
    {
      "id": "7d58c5cf-e4f5-4a7e-ba34-0cd7bc6a6506",
      "type": "text",
      "markdown": "Content...",
      "grounding": {
        "page": 0,
        "box": { "left": 0.1, "top": 0.2, "right": 0.9, "bottom": 0.3 }
      }
    }
  ],
  "splits": [
    {
      "class": "full",
      "identifier": "full",
      "pages": [0],
      "markdown": "# Document...",
      "chunks": ["7d58c5cf-e4f5-4a7e-ba34-0cd7bc6a6506"]
    }
  ],
  "grounding": {
    "7d58c5cf-e4f5-4a7e-ba34-0cd7bc6a6506": {
      "box": { "left": 0.1, "top": 0.2, "right": 0.9, "bottom": 0.3 },
      "page": 0,
      "type": "chunkText",
      "confidence": 0.95,
      "low_confidence_spans": []
    },
    "0-1": {
      "box": { "left": 0.15, "top": 0.4, "right": 0.85, "bottom": 0.7 },
      "page": 0,
      "type": "table"
    },
    "0-2": {
      "box": { "left": 0.15, "top": 0.4, "right": 0.5, "bottom": 0.55 },
      "page": 0,
      "type": "tableCell",
      "position": { "row": 0, "col": 0, "rowspan": 1, "colspan": 1,
                     "chunk_id": "ef24b1ea-..." }
    }
  },
  "metadata": {
    "filename": "document.pdf",
    "org_id": "org-123",
    "page_count": 5,
    "duration_ms": 1500,
    "credit_usage": 2.0,
    "job_id": "abc-123",
    "version": "dpt-2-20260302",
    "failed_pages": []
  }
}

最上位の grounding は、要素 ID(チャンクの場合は UUID、テーブル/セルの場合は {page}-{base62})をキーとするディクショナリです。各値には box、page、type が含まれ、さらに confidence と low_confidence_spans が含まれる場合があります(信頼度スコアを参照)。テーブルセルのエントリには position フィールドも含まれます(グラウンディングとトレーサビリティを参照)。

グラウンディングのタイプ対応表

グラウンディングのタイプには、チャンクのタイプと区別するために chunk という接頭辞が付いています。table と tableCell はグラウンディング専用のタイプであり、対応するチャンクタイプはありません。

グラウンディングタイプチャンクタイプ説明
chunkTexttextテキストコンテンツ
chunkTabletableテーブルチャンク(全体の位置)
chunkFigurefigure図と画像
chunkMarginaliamarginaliaヘッダー、フッター、ページ番号
chunkLogologo企業ロゴ(DPT-2)
chunkCardcardID カード、免許証(DPT-2)
chunkAttestationattestation署名、スタンプ(DPT-2)
chunkScanCodescan_codeQR コード、バーコード(DPT-2)
table(グラウンディング専用)テーブルチャンク内の HTML <table> 要素
tableCell(グラウンディング専用)テーブル内の個々のセル

Extract は次を返します。

{
  "extraction": {
    "invoice_number": "INV-12345",
    "total": 1250.00
  },
  "extraction_metadata": {
    "invoice_number": {
      "chunk_ids": ["chunk-uuid-1"]
    },
    "total": {
      "chunk_ids": ["chunk-uuid-2"],
      "cell_ids": ["2-a5"]
    }
  },
  "metadata": {
    "filename": "markdown.md",
    "org_id": "org-123",
    "duration_ms": 850,
    "credit_usage": 1.0,
    "job_id": "abc-456",
    "version": "extract-20251024",
    "schema_violation_error": null,
    "fallback_model_version": null
  }
}

Extract のメタデータフィールド:

  • schema_violation_error:抽出結果がスキーマに一致する場合は null です。抽出データがスキーマに完全には準拠しない場合は、詳細なエラーメッセージが含まれます(HTTP 206 レスポンス)。抽出では引き続き部分データが返され、クレジットが消費されます。
  • fallback_model_version:通常は null です。指定されたバージョンで最初の抽出に失敗し、フォールバックが使用された場合、実際に使用されたモデルのバージョンが含まれます。
グラウンディングとトレーサビリティ

解析された各要素には、最上位の grounding 辞書に正確な位置情報が含まれます。

  • ページ参照:0 始まりのページ番号
  • バウンディングボックス:位置を示す正規化座標(0~1)
    • left、top、right、bottom
    • ピクセルに変換するには、画像の寸法を乗算します
  • 要素 ID:チャンクには UUID、テーブルとテーブルセルには {page}-{base62}
    • テーブル/セル ID は、ページごとに連番の base62 方式で付与されます:0-1、0-2、...、0-9、0-a、...、0-z、0-A、...、0-Z、0-10 など
    • 番号はページごとにリセットされます(例:ページ 1 の最初のテーブル → 1-1)
  • グラウンディングの型:各エントリーには、接頭辞付きの名前を使う type フィールドがあります(例:chunkText、chunkTable)。グラウンディング型の対応表を参照してください。
  • テーブルセルの位置:tableCell エントリーには、row、col(いずれも 0 始まり)、rowspan、colspan、および親テーブルのチャンク UUID である chunk_id を含む position オブジェクトがあります
  • 抽出メタデータ:各フィールドの提供元となったチャンク/セルを示します

チャンクごとのグラウンディング(各チャンクオブジェクト内)には、box と page のみが含まれます。最上位の grounding 辞書には、type と、テーブルセルの場合は position も追加されます。

例:

# Per-chunk grounding (basic location)
for chunk in response.chunks:
    print(f"Chunk {chunk.id} on page {chunk.grounding.page}")
    bbox = chunk.grounding.box
    print(f"Location: ({bbox.left}, {bbox.top}) to ({bbox.right}, {bbox.bottom})")

# Top-level grounding (detailed, with type and position)
# NOTE: grounding values are Pydantic models — use attribute access, not dict access
for elem_id, info in response.grounding.items():
    print(f"{elem_id}: type={info.type}, page={info.page}")
    if info.type == "tableCell" and info.position:
        print(f"  Cell at row={info.position.row}, col={info.position.col}")

重要: response.grounding は Dict[str, Grounding] です。外側のコンテナは辞書なので .items() や .get() を使用できますが、各値は Pydantic モデルです。辞書アクセス(info["type"])ではなく、属性アクセス(info.type、info.box.left)を使用してください。

信頼度スコア {#confidence-scores}

最上位の grounding エントリーには、信頼度情報が含まれる場合があります。

  • confidence(float | None):チャンクの文字起こしに対する全体的な信頼度スコア(0.0~1.0)
  • low_confidence_spans(list | None):信頼度の低い特定のテキスト範囲。それぞれに以下が含まれます。
    • confidence(float):範囲単位の信頼度スコア
    • text(str):信頼度の低いテキスト
    • span(list):チャンク内の位置を示すマーカー
# Access confidence scores from top-level grounding
for elem_id, info in response.grounding.items():
    if info.confidence is not None:
        print(f"{elem_id}: confidence={info.confidence:.2f}")
    for span in info.low_confidence_spans or []:
        print(f"  Low confidence ({span.confidence:.2f}): "
              f"'{span.text}'")

注意:

  • 信頼度情報は最上位の groundingにのみ存在し、チャンクごとの grounding にはありません
  • すべての grounding エントリーに信頼度情報が含まれるわけではありません(例:table/tableCell 型には含まれない場合があります)
  • 信頼度スコアを使って、人による確認が必要なチャンクを特定してください

ベストプラクティス

モデルの選択
  • ほとんどのドキュメントには dpt-2-latest を使用してください(複雑なレイアウト、ロゴ、署名など)
  • シンプルなデジタルネイティブのドキュメントには dpt-2-mini を使用してください(より高速で低コスト)
  • 再現性を確保するため、本番環境ではバージョンを固定してください(例:dpt-2-20260302)
  • 抽出には extract-latest を使用してください(最新モデルが自動的に使用されます)
  • dpt-1 は使用しないでください — 2026 年 3 月 31 日に非推奨となりました。dpt-2 に移行してください
スキーマ設計
  • 具体的にする:number ではなく、説明的なフィールド名(invoice_number など)を使用します
  • 説明を追加する:「USD 表記」「YYYY-MM-DD 形式」など、形式の要件を含めます
  • シンプルに保つ:少数のフィールドから始め、必要に応じて追加します
  • 複雑さを抑える:最適なパフォーマンスを得るため、プロパティは 30 個未満にします
  • ドキュメントの構造に合わせる:フィールドを、ドキュメント内に現れる順に並べます

スキーマの詳細なパターンについては、references/extraction-schemas.mdを参照してください。

エラー処理
try:
    response = client.parse(document=Path("doc.pdf"), model="dpt-2-latest")
except Exception as e:
    print(f"Parse error: {e}")
    # Handle error (check file format, file size, API key, etc.)

try:
    extract_response = client.extract(schema=schema, markdown=response.markdown)
except Exception as e:
    print(f"Extract error: {e}")
    # Handle error (check schema validity, markdown format, etc.)
部分的な結果の処理(HTTP 206)

Parse API と Extract API はどちらも、処理が部分的に成功した場合に HTTP 206(Partial Content)を返すことがあります。

Parse 206:一部のページの解析に失敗しています。metadata.failed_pages を確認してください。

response = client.parse(document=Path("doc.pdf"), model="dpt-2-latest")
if response.metadata.failed_pages:
    print(f"Failed pages: {response.metadata.failed_pages}")
    # Remaining pages were parsed successfully

Extract 206:抽出は完了しましたが、データがスキーマに完全には一致していません。metadata.schema_violation_error を確認してください。

response = client.extract(schema=schema, markdown=markdown)
err = response.metadata.schema_violation_error
if err:
    print(f"Schema violation: {err}")
    # Extraction still returns partial data; credits are consumed

注意: 206 レスポンスでもクレジットを消費します。API は生成できた中で最良の結果を返します。

パフォーマンス
  • 大きなファイル:50 ページ超または 10 MB 超のファイルには Parse Jobs API(非同期)を使用します
  • バッチ処理:可能であれば、ドキュメントを並列処理します
  • 解析結果をキャッシュする:複数回の抽出で再解析を避けるため、Markdown を保存します
  • 解析を最適化する:ページ単位の構成が必要な場合は、split="page" パラメーターを使用します
ファイル形式
  • ネイティブドキュメントには、変換が不要な PDF を推奨します
  • OCR の精度を高めるため、高解像度の画像(300 DPI 以上)を使用してください
  • パスワードで保護されたファイル:password パラメーターを使用してください(ZDR が必要です)。ZDR を使用しない場合は、解析前にパスワード保護を解除してください
  • DOCX/PPTX ファイルは、変換後のレイアウトが変わる場合があるため、変換をテストしてください

ファイル形式の詳細については、references/file-formats.md を参照してください

ユースケース

請求書処理、フォームデータの抽出、複数ドキュメントの分類、表の抽出、PyMuPDF による図の切り抜きなど、実際の例については references/use-cases.md を参照してください。

トラブルシューティング

HTTP エラーコード、解析の失敗、抽出精度の問題、スキーマ検証エラー、パフォーマンスに関するガイダンスについては、references/troubleshooting.md を参照してください。

リンク

公式ドキュメント
API キー
参考ファイル

コメント