乐于分享
好东西不私藏

如何使用AI从文档中准确提取所有内容

如何使用AI从文档中准确提取所有内容

如何使用AI从文档中准确提取所有内容

作者:AI拉呱(Errol Yan)
定位:AI领域深度内容与实战方法分享

TL;DR

文档解析器在处理现实文档中常见的复杂布局时面临困难,例如具有合并单元格的表格、跨页符号和错位的文本。此外,大量信息存在于图表或图形中,需要准确提取。本文将带您深入了解一个解析器,它能从文档中准确提取所有多模态数据并保留精确的布局。它演示了如何使用它作为支持多个模型提供商的可重用Python包。

从文档中准确提取内容对于AI应用至关重要。例如,在处理用AI生成销售草稿的采购订单时,AI代理或LLM首先需要准确理解采购订单内容及其确切布局。

错位的表格标题会导致LLM读取错误的数量,从而导致价格计算错误。类似地,由于跨页表格中断导致的遗漏行项可能会导致LLM完全跳过某个产品。

许多现实客户文档(如采购订单或物料清单)包含混乱的表格。例如,以下是采购订单的2页(内容已更改以保护隐私,但保留了原始布局)。

表格标题和行数据之间有文本。当然,这不是添加此文本的正确位置。它可能已被添加到表格之前或之后的某个其他位置。但从客户文档中期望此类结构非常普遍。此文本在同一表格的其他位置也会不必要地重复。

该表格跨越多页,行数据部分地跨页写入。例如,第一页包含第三项(030)的部分数据,后跟表格页脚,以及下一页的页眉和标题(重复)。

专门的解析器(如PyMuPDF、PyMuPDF4LLMDocling)无法准确提取此表格结构。

即使这些解析器也无法正确提取此类混乱的表格布局。

一切都取决于某些特定的提示词

本月早些时候,LlamaIndex推出了一个开源框架(ParseBench),用于基准测试文档解析器在将PDF转换为AI代理实际可以使用的输出方面的效果。他们测试了14种不同的方法:通用视觉LLM、专门解析器及其自有的LlamaParse。

他们的基准结果发表在以下研究中:

这些结果显示,代理解析(如他们自有的LlamaParse)和基于LLM的解析(如使用Gemini 3 Flash)优于专门的文档解析器。

我很想知道他们如何让基于LLM的解析工作得这么好。所以我查看了实际的研究论文。

我预期会有一些聪明的架构技巧。一个微调的模型,或一个具有验证循环的多步骤管道。

相反,我发现了一些特定的提示词。这些是我们从未想到过使用的提示词。

这些提示词有什么特别之处?

当您要求LLM以Markdown格式输出表格(大多数解析器的默认格式)时,它不会正确保留合并单元格和多级标题的布局。例如,一个两行标题跨越多列的采购订单会变得平面和不明确。

LlamaIndex提议的提示词使用HTML colspan 和 rowspan 属性提取表格,这些属性编码了完整的结构。这些提示词要求LLM将表格转换为HTML格式(<table><tr><th><td>),并使用 colspan 和 rowspan 属性来保留合并单元格和分层标题。

类似地,对于图表或图形,LLM被要求使用平面组合列标题将其转换为表格,使得每个数据单元格的行包含其所有标签。

该论文提议为OpenAI和Claude模型使用共享系统提示。对于Google模型,用户提示略有不同。

以下是我们将用于构建可重用多模态解析器包的LlamaParse为OpenAI和Claude模型提议的系统和用户提示。

OPENAI_CLAUDE_SYSTEM_PROMPT = """You are a document parser. Your task is to convert document PDFs into clean, well-structured Markdown.  

Guidelines:  
- Preserve the document structure, including headings, paragraphs, lists, and tables.  
- Convert tables to HTML using `<table>`, `<tr>`, `<th>`, and `<td>`.  
- For existing tables in the document, use `colspan` and `rowspan` attributes to preserve merged cells and hierarchical headers.  
- For charts or graphs converted into tables, use flat combined column headers (for example, "Primary 2015" instead of separate header rows) so that each data cell's row contains all of its labels.  
- Describe images and figures briefly in square brackets, for example: `[Figure: description]`.  
- Preserve any code blocks with appropriate syntax highlighting.  
- Maintain reading order: left to right, top to bottom for Western documents.  
- Do not add commentary or explanations. Output only the parsed content.  

Additionally, wrap each layout element in a `<div>` tag with:  
- `data-bbox="[x1, y1, x2, y2]"` for the bounding box in normalized 0-1000 coordinates, where x is horizontal (left edge = 0, right edge = 1000) and y is vertical (top = 0, bottom = 1000). `x1, y1` is the top-left corner and `x2, y2` is the bottom-right corner.  
- `data-label="<category>"` where category is one of: `Caption`, `Footnote`, `Formula`, `List-item`, `Page-footer`, `Page-header`, `Picture`, `Section-header`, `Table`, `Text`, `Title`.  

Place elements in reading order. Every piece of content must be inside exactly one `<div>` wrapper."""  

OPENAI_CLAUDE_USER_PROMPT = """The attached PDF is read from the input folder next to this script.  

Parse the full document and output its content as clean markdown, with each layout element wrapped in a <div data-bbox="[x1,y1,x2,y2]" data-label="Category"> tag. Use HTML tables for any tabular data. For charts and graphs, use flat combined column headers. Output ONLY the parsed content with div wrappers and no explanations.  
"""

Google的Gemini模型使用相同的提示词,唯一的区别是 data-bbox 格式更改为其本机坐标顺序。

对于Gemini模型,使用以下系统和用户提示词:

GOOGLE_SYSTEM_PROMPT = """You are a document parser. Your task is to convert document PDFs into clean, well-structured Markdown.  

Guidelines:  
- Preserve the document structure, including headings, paragraphs, lists, and tables.  
- Convert tables to HTML using `<table>`, `<tr>`, `<th>`, and `<td>`.  
- For existing tables in the document, use `colspan` and `rowspan` attributes to preserve merged cells and hierarchical headers.  
- For charts or graphs converted into tables, use flat combined column headers (for example, "Primary 2015" instead of separate header rows) so that each data cell's row contains all of its labels.  
- Describe images and figures briefly in square brackets, for example: `[Figure: description]`.  
- Preserve any code blocks with appropriate syntax highlighting.  
- Maintain reading order: left to right, top to bottom for Western documents.  
- Do not add commentary or explanations. Output only the parsed content.  

Additionally, wrap each layout element in a `<div>` tag with:  
- `data-bbox="[y_min, x_min, y_max, x_max]"` for the bounding box in normalized 0-1000 coordinates where x is horizontal (left edge = 0, right edge = 1000) and y is vertical (top = 0, bottom = 1000). The order is `[y_min, x_min, y_max, x_max]`.  
- `data-label="<category>"` where category is one of: `Caption`, `Footnote`, `Formula`, `List-item`, `Page-footer`, `Page-header`, `Picture`, `Section-header`, `Table`, `Text`, `Title`.  

Place elements in reading order. Every piece of content must be inside exactly one `<div>` wrapper."""  

GOOGLE_USER_PROMPT = """Parse this document page and output its content as clean markdown, with each layout element wrapped in a <div data-bbox="[y_min,x_min,y_max,x_max]" data-label="Category"> tag.  
Use HTML tables for any tabular data. For charts/graphs, use flat combined column headers. Output ONLY the parsed content with div wrappers, no explanations.  
"""

与无法准确表现合并单元格的Markdown表格不同,混乱的现实世界表格采用带有 colspan 和 rowspan 的HTML表格。每个布局元素都在规范化坐标中获得边界框。这意味着下游代码可以在不依赖原始PDF渲染器的情况下重建页面的空间布局。

Google提示词使用不同的边界框坐标顺序([y_min, x_min, y_max, x_max]),因为这与Gemini模型本机产生的内容一致。

解析提示词在GitHub的 prompts.py 脚本中定义。

用于准确解析的多模态解析器

我将使用上述提示词的解析管道打包成一个Python类,该类读取PDF文档并让用户选择提供商和模型(OpenAI、Anthropic或Google)以及其他几个选项。

完整代码结构在GitHub仓库中。MultimodalParser类的完整实现在multimodal_parser.py中。

MultimodalParser 只有一个方法 parse(),它编排整个管道。

parser = MultimodalParser(  
    model_provider="google",  
    model="gemini-3.1-flash-lite-preview",  
    reasoning_effort="low",  
    merge_table=True,  
    create_html=True,  
)  
result = parser.parse("document.pdf")

一些值得理解的参数:

  • • reasoning_effort — 模型的思考预算:"low""medium""high"。更高的努力可以提高复杂布局的准确性,但速度更慢且成本更高。
  • • merge_table — 当为 True 时,向用户提示附加指令,告诉模型合并跨页分割的表格。
  • • additional_instructions — 附加到用户提示的额外指令,用于特定领域的规则。
  • • create_html — 当为 True 时,将清理的markdown渲染为HTML文档。

parse() 方法首先将PDF读取为原始字节并将其编码为base64字符串,以便可以将其嵌入到JSON API有效负载中并发送到具有上述特定于提供商的提示词的选定LLM。

然后根据选定的提供商构建正确的消息结构,因为OpenAI、Claude和Google各自期望其内容以不同方式格式化。

在LLM API调用后,模型返回其原始响应,这是markdown文本和 <div> 包装器的组合,其中包含页面上每个布局元素的边界框坐标。清理过程删除模型可能包装在输出周围的任何代码块边界。另一个方法以清洁markdown的形式从这些 <div> 包装器中提取实际内容。

如果选项 create_html=True,清洁markdown会转换为样式化的HTML文档,您可以直接在浏览器中打开以直观检查提取。

每个调用都返回一个**UsageRecord**以及解析的内容,它提供了令牌消费和相关成本的详细信息。

如何使用

多模态解析器已被创建为可重用软件组件。此软件组件可以安装为独立的Python包,如下所示:

pip install "gaik[multimodal-parser]"

以下是使用 gemini-3.1-flash-lite-preview 和低推理努力来解析同一采购订单的最小示例。此示例以原始markdown、清洁markdown和HTML格式保存解析输出。

from pathlib import Path
from
 dotenv import load_dotenv
from
 gaik.software_components.parsers.multimodal_parser import MultimodalParser  

load_dotenv()  

OUTPUT_DIR = Path(__file__).parent / "output"

def
 save_result(result, prefix: str) -> None:
    """Save parse results to the output directory."""

    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)  

    raw_path = OUTPUT_DIR / f"{prefix}_raw.md"
    raw_path.write_text(result.raw_markdown, encoding="utf-8")  

    clean_path = OUTPUT_DIR / f"{prefix}_clean.md"
    clean_path.write_text(result.clean_markdown, encoding="utf-8")

    print
(f"Saved: {raw_path}")
    print
(f"Saved: {clean_path}")

    if
 result.html is not None:  
        html_path = OUTPUT_DIR / f"{prefix}_clean.html"
        html_path.write_text(result.html, encoding="utf-8")
        print
(f"Saved: {html_path}")  

parser = MultimodalParser(  
    model_provider="google",  
    model="gemini-3.1-flash-lite-preview",  
    reasoning_effort="low",  
    merge_table=True,  
    create_html=True,  
)  
result = parser.parse("sample_PO.pdf")  
save_result(result, "output_google")

对于同一采购订单,正确合并和结构化的输出如上所示(HTML格式)。

观察与最终思考

即使较小的模型(如 gemini-3.1-flash-lite-preview 和 gpt-5.4-mini),其中 reasoning_effort 设置为低,也能准确提取混乱的采购订单。一切都取决于使用正确的提示词。

应该注意的是,此解析在准确性比速度更重要的情况下很有用,不需要快速或实时响应。例如,在采购订单处理中,准确价格计算的准确解析比速度更重要。

增加推理努力会大幅增加处理时间和成本。较大的模型(如 gpt-5.4,推理努力设置为 high)会变得非常缓慢。因此,"high" 推理,特别是对于较大的模型,应仅用于具有高度复杂布局的文档。

关于成本和速度,gemini-3.1-flash-lite-preview 表现突出。

additional_instructions 参数可用于提供用例特定的解析指令。例如,对于法律文档,可以设置为”完全按照源中出现的方式保留脚注编号“。


关注 AI拉呱

如果这篇内容对你有启发,欢迎关注「AI拉呱」,获取更多 AI 前沿洞察、实战教程与趋势解读。

下期在看

下期将继续带来该主题的进阶拆解与实操案例,建议先收藏本文,避免错过更新。