为什么先做解析

文档 RAG 的常见失败不是向量库召回不准,而是解析阶段把两列表格拍成一列、把页眉页脚混进正文、丢掉页码。模型再强,也只能基于被破坏的文本回答。Docling 的定位就是把 PDF、DOCX、HTML 解析成保留版面与阅读顺序的统一结构,再输出 Markdown 或 JSON。

装与跑

pip install docling
# 先拿一份最难的扫描件试
docling ./contracts/2026-001.pdf --to md --output ./out

先用官方 CLI 跑一份最难的扫描件,确认输出里的标题层级、表格、页码是否保留;不要一上来就批量。批量脚本里给每份文件记录来源路径与页数,后面做引用回溯要靠它。

批量转换脚本

from pathlib import Path
from docling.document_converter import DocumentConverter

converter = DocumentConverter()
out = Path('out'); out.mkdir(exist_ok=True)

for pdf in Path('contracts').rglob('*.pdf'):
    try:
        doc = converter.convert(pdf).document
        md = doc.export_to_markdown()
        (out / (pdf.stem + '.md')).write_text(md, encoding='utf-8')
        print('ok', pdf)
    except Exception as e:
        print('fail', pdf, repr(e))

逐份转换、逐份落盘,失败的文件单独记日志,不要一个异常中断整批。转换结果是中间产物,原始文件保持只读;脚本里也不要顺手改写源目录。

切块规则

按标题层级切,不按固定字符数切;表格单独成块并保留表头;每块带上文件名、页码、标题路径三个元数据。这样回答里能给出「第几页、哪一节」,而不是只给一个文件名。

抽检清单

随机抽 20 份,检查:表格行列是否对齐、页码是否能回到原页、标题层级是否断裂、页眉页脚是否被清掉。四项里有一项系统性失败,就先修解析或换引擎,别急着加向量库。

先让机器读对,再让它答得快。