Docling 的 RAG 集成实战:文档转换、检索级切块与三大框架 Loaders 详解
本篇基于 Docling 仓库中 RAG 集成参考文档(rag.md),讲清楚在检索增强生成(RAG)场景下 Docling 的完整用法:先完成文档转换、再产出带元数据(标题层级、页码)的检索就绪块(chunk)。读完后你将掌握三种现成框架 Loader(LangChain / LlamaIndex / Haystack)的接法、何时应绕过 Loader 直接使用 HybridChunker,以及如何在完全无本地模型的情况下通过 Service Client 远程切块构建 RAG 索引。
RAG 的两步走:转换 + 带元数据切块
对于 RAG,你通常想要两件事:
- 转换文档——把 PDF、DOCX 等原始文件解析为结构化中间表示
DoclingDocument; - 切分为检索就绪的块——按文档结构拆分,并且保留标题面包屑(headings)与页码等元数据。
Docling 的设计让这两步解耦:转换由 DocumentConverter 完成,切块由 chunker 类族完成(见 docling/chunking/init.py),框架 Loader 则把这两步封装成“convert + chunk”的一体化调用,让你不必手写胶水代码。两种路线的取舍:
- 省事路线:使用各框架的现成 Loader,一行安装即用;
- 控制路线:自己调用
DocumentConverter+HybridChunker,可自由选择切块策略与分词器(tokenizer),并与你的 embedding 模型对齐。
框架 Loaders:三个现成组件
Docling 与主流 RAG 框架的官方集成组件如下(来自 rag.md 的对照表):
| 框架 | 安装包 | 组件 |
|---|---|---|
| LangChain | langchain-docling |
DoclingLoader |
| LlamaIndex | llama-index-readers-docling(+ llama-index-node-parser-docling) |
DoclingReader + Docling node parser |
| Haystack | docling-haystack |
Docling converter 组件 |
各框架集成在仓库文档中另有说明页,可结合阅读:LangChain 集成、LlamaIndex 集成,以及配套示例 rag_langchain.ipynb、rag_llamaindex.ipynb、rag_haystack.ipynb。
LangChain:DoclingLoader
pip install langchain-docling
from langchain_docling import DoclingLoader
from langchain_docling.loader import ExportType
loader = DoclingLoader(
file_path=["report.pdf", "https://example.com/paper.pdf"],
export_type=ExportType.DOC_CHUNKS, # chunked; or ExportType.MARKDOWN
)
docs = loader.load() # list[langchain_core.documents.Document]
# each chunk keeps metadata: source, headings, page numbers
两个关键参数:
file_path支持本地路径与 http(s) URL 的混合输入;export_type决定输出形态:ExportType.DOC_CHUNKS直接产出切块后的Document列表(每个块保留 source、headings、页码元数据,可直接送入 embedder),ExportType.MARKDOWN则导出 Markdown 文本、交由 LangChain 侧自行切块。docs/concepts/chunking.md 中也把“导出 Markdown 后自定义切块”列为与原生 chunker 并列的第一种切块路线。
LlamaIndex:DoclingReader + DoclingNodeParser
LlamaIndex 的集成是“读写分离”的双组件设计(详见 llamaindex.md):Reader 负责把文件读成 Docling 数据模型,Node Parser 再基于 Docling 结构知识把文档解析为 LlamaIndex Node(即 embedding 用的 chunk)。
pip install llama-index-readers-docling llama-index-node-parser-docling
from llama_index.readers.docling import DoclingReader
from llama_index.node_parser.docling import DoclingNodeParser
reader = DoclingReader()
nodes = DoclingNodeParser().get_nodes_from_documents(
reader.load_data(file_path="report.pdf")
)
从 rag.md 的说明看,Reader 支持两种填充方式:无损序列化 Docling 数据模型(如 JSON),或导出为简化格式(如 Markdown,有损)。选择无损模式可以保留完整结构信息供下游节点解析使用。
Haystack:converter 组件
pip install docling-haystack
Haystack 侧是一个 Docling converter 组件,用法是把它放进 Haystack 的索引(indexing)流水线中;它会直接输出切块后的文档,可无缝接入后续的 writer / embedder 节点,无需额外的切块步骤。
注意(原文档提示):这些第三方 Loader 的包名与 API 可能随版本变化,接入前请以各框架官方的 Docling 集成文档中当前的导入路径为准。
跳过 Loaders:直接使用 HybridChunker
如果你已经用 DocumentConverter 完成了转换(例如需要精细控制流水线、选择 OCR 引擎、启用 heading 层级推断等),又只需要切块,就直接调用 HybridChunker 自己——这正是 rag.md “When to skip the loaders”一节推荐的做法。它的优势:
- 每个块显式暴露 headings(标题面包屑) 与 source page(来源页码);
- 可以自选 tokenizer,与你的 embedding 模型对齐,从而精确控制块大小。
代码:切块 + 上下文增强
from docling.chunking import HybridChunker
from docling_core.transforms.chunker.tokenizer.huggingface import HuggingFaceTokenizer
tokenizer = HuggingFaceTokenizer.from_pretrained(
model_name="sentence-transformers/all-MiniLM-L6-v2",
max_tokens=512,
)
chunker = HybridChunker(tokenizer=tokenizer, merge_peers=True)
for chunk in chunker.chunk(result.document):
embed_text = chunker.contextualize(chunk) # heading-prefixed text to embed
print(chunk.meta.headings) # heading breadcrumb
print(chunk.meta.origin.page_no) # source page
要点说明(结合 chunking/init.py 与 docs/concepts/chunking.md):
docling.chunking直接再导出docling-core的BaseChunker、BaseChunk、HierarchicalChunker、HybridChunker等类型,因此只安装docling包即可使用;BaseChunker接口只有两个方法:chunk(dl_doc) -> Iterator[BaseChunk]与contextualize(chunk) -> str。contextualize返回带标题前缀的增强文本,通常是喂给 embedding 模型的输入——它能显著提升检索命中率,因为块文本自带了章节上下文;merge_peers=True会合并“标题相同且偏小的相邻块”;- tokenizer 传的是
BaseTokenizer对象。docling-core 2.8.0 起 tokenizer API 有变更,直接传字符串不再有效。
若使用 OpenAI 系 tokenizer(需 pip install 'docling-core[chunking-openai]'):
import tiktoken
from docling_core.transforms.chunker.tokenizer.openai import OpenAITokenizer
tokenizer = OpenAITokenizer(
tokenizer=tiktoken.encoding_for_model("text-embedding-3-small"),
max_tokens=8192,
)
HybridChunker 的算法内涵
从 docs/concepts/chunking.md 的描述看,HybridChunker 并非简单的按字数切块,而是一个两趟(two-pass)的混合策略:
- 起点是分层切块:先用
HierarchicalChunker基于DoclingDocument的结构(章节、标题、列表项)生成初始块,并自动附带 headers 与 captions 等文档元数据; - 第一趟:按需拆分——仅当块超过 tokenizer 给出的 token 上限时才拆分;
- 第二趟:按需合并——把标题(和 captions)相同的偏小块合并,可通过
merge_peers关闭。
此外它还提供两个表格相关参数,对宽表场景很实用:
repeat_table_header(默认True):表格跨块时,在每个块开头重复表头,让每个块自含表格结构上下文;omit_header_on_overflow(默认False):在repeat_table_header=True基础上,当某行“不带表头能装下、带表头会溢出”时,为该特定行省略表头,最大化 token 利用率。
同族的 LineBasedTokenChunker(同样从 docling.chunking 导出)则面向表格、代码、日志等结构化内容:优先保持整行不被切断,支持为每个块附加重复前缀(如表头),并通过 omit_prefix_on_overflow 处理溢出。更多可运行示例见 hybrid_chunking.ipynb、line_based_chunking.ipynb 与 advanced_chunking_and_serialization.ipynb。
远程切块:Service Client 的 chunk()
对于“远程/大规模转换来喂 RAG 索引”的场景,rag.md 推荐直接用 Service Client 的 chunk()——它返回检索就绪的块,调用方机器上不需要任何本地模型。相关参考见 service-client.md。
基本用法
from docling.service_client import ChunkerKind
response = client.chunk(source="report.pdf", chunker=ChunkerKind.HYBRID)
# ChunkerKind.HYBRID or ChunkerKind.HIERARCHICAL
源码印证
从 service_client/client.py 可以看到 ChunkerKind 是一个字符串枚举,只有两个取值:
class ChunkerKind(str, Enum):
HYBRID = "hybrid"
HIERARCHICAL = "hierarchical"
而 chunk() 的实现(client.py#L1019-L1026)本质上是一次“提交 + 等待结果”的任务调用:
def chunk(
self,
source: SourceType,
chunker: ChunkerKind,
options: ConvertDocumentsRequestOptions | None = None,
) -> ChunkDocumentResponse:
job = self.submit_chunk(source=source, chunker=chunker, options=options)
return job.result(timeout=self._job_timeout)
即:先通过 submit_chunk 提交远程切块任务得到 ConversionJob 句柄,再在默认 job_timeout=300.0 秒内等待结果。source 支持本地路径、http(s) URL 等多种形态,与 convert() 一致。
服务端切块参数的默认值
从 datamodel/service/chunking.py 的 HybridChunkerOptions 可确认远程切块的服务端默认行为,与本地 HybridChunker 的示例保持一致:
max_tokens:每块最大 token 数,为None时自动从 tokenizer 提取;tokenizer:HuggingFace 模型名,默认sentence-transformers/all-MiniLM-L6-v2(可换成如Qwen/Qwen3-Embedding-0.6B以对齐你的 embedding 模型);merge_peers:默认True,合并标题相同的偏小相邻块。
BaseChunkerOptions 还暴露了几个影响块文本形态的开关(chunking.py#L23-L61):
use_markdown_tables:用 Markdown 表格而非三元组序列化表格;use_markdown_images:在块内启用图片引用,并给含图块加has_image元数据,便于识别图文块;image_placeholder:关闭 Markdown 图片序列化时使用的占位文本,默认![IMAGE];include_raw_text:响应中同时返回raw_text与text(上下文增强后)两个字段。
客户端侧的错误处理与本地 SDK 不同:Service Client 抛出类型化异常(ConversionError、ServiceUnavailableError、TaskTimeoutError、UsageLimitExceededError、ResultExpiredError 等,均定义在 service_client/exceptions.py),捕获基类 DoclingServiceClientError 即可统一处理。相关行为有专门测试覆盖,例如 test_service_client_fake_service.py 与 test_service_client_sdk_unit.py;远程调用的更多实战示例见 examples/service_client/chunk.py 与 batch.py。
选型小结
结合 rag.md 的决策框架,可以这样选择:
| 场景 | 推荐路线 | 依据 |
|---|---|---|
| 快速接入 LangChain / LlamaIndex / Haystack 应用 | 框架 Loaders | 封装 convert + chunk,免写胶水代码 |
| 需要精细控制流水线(OCR 引擎、heading 层级、VLM 等)再切块 | DocumentConverter + HybridChunker |
每块自带 headings 与页码,tokenizer 可对齐 embedding 模型 |
| 大规模/远程转换构建 RAG 索引,本机无 GPU/模型 | Service Client chunk(ChunkerKind.HYBRID) |
调用端零本地模型,服务侧保留热模型与并发 |
最后再强调原文档的一条重要提示:第三方 Loader 的包名与 API 可能变化,接入前请以各框架当前版本的 Docling 集成文档为准;本地 SDK 侧的 chunking 依赖 feat-chunking extra(若仅用 docling-core 则安装 docling-core[chunking]),OpenAI tokenizer 另需 chunking-openai extra。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00