关于 document-extraction
document-extraction 提供使用 LandingAI 的 Agentic Document Extraction(ADE)处理文档的操作指南,面向需要解析、提取或分类文档数据的开发者。它介绍 Markdown 与结构化 JSON 输出、模式定义、异步解析及结果定位信息。
主要功能
- 01将文档解析为 Markdown 和分块
- 02按 JSON Schema 或 Pydantic 提取数据
- 03分类并拆分多文档批次
- 04支持异步解析任务
- 05提供页码与边界框定位信息
适用场景
- 01从发票或银行对账单提取字段
- 02解析大型或多页文档
- 03分类并拆分混合文档批次
- 04定位提取内容在原文档中的位置
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ andrewyng/ context-hub --skill document-extraction安装后在 Claude Code 中输入/document-extraction确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
.env-sample.gitignorereferences/chunk-types.mdextraction-schemas.mdfile-formats.mdtroubleshooting.mduse-cases.md详细介绍
文档提取(ADE)
概述
LandingAI 的 Agentic Document Extraction(ADE)是一款文档处理 SaaS,无需模板或训练即可解析、提取和分类文档。它提供三项主要功能:
- 解析:将文档转换为结构化 Markdown,并以分层 JSON 表示
- 提取:使用 JSON 架构或 Pydantic 模型提取特定的结构化数据
- 拆分:按类型对多文档批次进行分类和拆分
主要优势:
- 无需机器学习训练或模板
- 与布局无关的解析(适用于任何文档结构)
- 支持 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-2 | text、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_pagessplits:对块进行分组的分段对象数组。始终存在——默认包含单个"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 类型仅用于定位(没有对应的块类型):
| 定位类型 | 块类型 | 描述 |
|---|---|---|
chunkText | text | 文本内容 |
chunkTable | table | 表格块(整体位置) |
chunkFigure | figure | 图形和图像 |
chunkMarginalia | marginalia | 页眉、页脚、页码 |
chunkLogo | logo | 公司徽标(DPT-2) |
chunkCard | card | 身份证件、许可证(DPT-2) |
chunkAttestation | attestation | 签名、印章(DPT-2) |
chunkScanCode | scan_code | QR 码、条形码(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)
- 表格/单元格 ID 按页使用连续的 base62 编号:
- 定位类型:每个条目都包含一个使用带前缀名称的
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 错误代码、解析失败、提取准确性问题、架构验证错误和性能指导。