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. 02按 JSON 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,无需模板或训练即可解析、提取和分类文档。它提供三项主要功能:

  1. 解析:将文档转换为结构化 Markdown,并以分层 JSON 表示
  2. 提取:使用 JSON 架构或 Pydantic 模型提取特定的结构化数据
  3. 拆分:按类型对多文档批次进行分类和拆分

主要优势:

  • 无需机器学习训练或模板
  • 与布局无关的解析(适用于任何文档结构)
  • 支持 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>

欧盟端点: 如果使用欧盟端点,请在初始化客户端时设置 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包含徽标、签名、身份证件的复杂文档text、table、figure、logo、card、attestation、scan_code、marginalia
dpt-2-mini简单的数字原生文档(速度更快、成本更低)text、table、figure、marginalia
dpt-1⚠️ 已于 2026 年 3 月 31 日弃用——迁移到 dpt-2text、table、figure、marginalia

建议: 除非文档较简单且成本或速度至关重要,否则请使用 dpt-2-latest。

版本固定: 在生产环境中,请使用带日期的版本(例如 dpt-2-20260302)以确保可复现性。

解析大型文件(异步)

对于最大 1 GB 或 6,000 页的文件,请使用解析作业:

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:作业完成且结果小于 1 MB 时返回的 ParseResponse(或 SpreadsheetParseResponse)
  • 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
    )

可空字段:

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"
)

文档分类与拆分

何时使用拆分 API

如果单个文件中包含需要分开的多份文档,请使用拆分 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(必填):文档分类标签(例如,“发票”)
  • 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 会返回包含五个顶层字段的结构化 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)
chunkCardcard身份证件、许可证(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 条目包含一个 position 对象,其中有 row、col(从 0 开始索引)、rowspan、colspan 和 chunk_id(父表格块的 UUID)
  • 提取元数据:显示每个字段由哪些块/单元格提供

每块定位信息(位于每个块对象中)仅包含 box 和 page。顶层定位字典还包含 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.box.left),而不是字典访问(info["type"])。

置信度分数 {#confidence-scores}

顶层定位条目可能包含置信度信息:

  • 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}'")

说明:

  • 置信度仅存在于顶层定位信息中(不在每块定位信息中)
  • 并非所有定位条目都包含置信度(例如,table/tableCell 类型可能不包含)
  • 使用置信度分数标记可能需要人工审核的块

最佳实践

模型选择
  • 对大多数文档(复杂布局、徽标、签名)使用 dpt-2-latest
  • 对简单的数字原生文档使用 dpt-2-mini(速度更快、成本更低)
  • 在生产环境中固定版本以确保可复现性(例如,dpt-2-20260302)
  • 使用 extract-latest 进行提取(会自动使用最新模型)
  • 不要使用 dpt-1——该版本已于 2026 年 3 月 31 日弃用;请迁移到 dpt-2
架构设计
  • 具体明确:使用描述性字段名称(用 invoice_number,而不是 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 和 Extract API 在处理部分成功时都可能返回 HTTP 206(部分内容):

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(无需转换)
  • 使用高分辨率图像(300+ DPI),以提升 OCR 效果
  • 受密码保护的文件:使用 password 参数(需要 ZDR)。如果没有 ZDR,请在解析前移除密码保护
  • 测试 DOCX/PPTX 文件的转换效果(布局可能会发生变化)

完整的文件格式参考,请参阅 references/file-formats.md

使用场景

请参阅 references/use-cases.md,查看完整的示例:发票处理、表单数据提取、多文档分类、表格提取,以及使用 PyMuPDF 裁剪图表。

故障排除

请参阅 references/troubleshooting.md,了解 HTTP 错误代码、解析失败、提取准确性问题、架构验证错误和性能指导。

链接

官方文档
API 密钥
参考文件

评论

支持 Markdown