使用Nemotron构建文档处理RAG管道

4 阅读6分钟

如何使用Nemotron为RAG构建文档处理管道

如果AI智能体能够即时解析复杂的PDF,提取嵌套表格,并像读取文本文件一样“看到”图表中的数据,会怎样?借助某机构的Nemotron RAG,您可以构建一个高吞吐量的智能文档处理管道,以高精度处理海量文档工作负载。

本文逐步介绍多模态检索管道的核心组件。首先,展示如何使用开源NeMo Retriever库,通过GPU加速微服务将复杂文档分解为结构化数据。然后,演示如何将这些数据接入Nemotron RAG模型,以确保助手提供有依据、准确且可完全追溯到源头的答案。

模型与代码快速链接

访问以下教程资源:

🧠 Hugging Face上的模型:

  • nvidia/llama-nemotron-embed-vl-1b-v2 多模态嵌入模型
  • nvidia/llama-nemotron-rerank-vl-1b-v2 交叉编码器重排序模型
  • Nemotron RAG系列中的提取模型

☁️ 云端端点:

  • Nemotron OCR文档提取
  • nvidia/llama-3.3-nemotron-super-49b-v1.5 答案生成模型
  • 更多来自NIM的模型

🛠️ 代码与文档:

  • NeMo Retriever库 (GitHub)
  • 教程笔记本 Jupyter Notebook (GitHub)

前提条件

系统要求:

  • Python 3.10 至 3.12 (已在3.12上测试)
  • 本地模型部署需配备至少24 GB显存的某机构GPU
  • 250 GB磁盘空间 (用于模型、数据集和向量数据库)

API访问:

  • 某机构API密钥 (在build.nvidia.com免费获取)

Python环境:

[project]
name = "idp-pipeline"
version = "0.1.0"
description = "IDP Nemotron RAG Pipeline Demo"
requires-python = "==3.12"
dependencies = [
    "ninja", "packaging", "wheel", "requests", "python-dotenv", "ipywidgets",
    "markitdown", "nv-ingest==26.1.1", "nv-ingest-api==26.1.1", "nv-ingest-client==26.1.1",
    "milvus-lite==2.4.12", "pymilvus", "openai>=1.51.0",
    "transformers", "accelerate", "pillow", "torch", "torchvision", "timm"
]

所需时间: 完整实现约1-2小时 (如需编译flash-attn等GPU优化依赖则时间更长)

成果: 一个可用于生产环境的多模态RAG文档处理管道

为何传统OCR和纯文本处理在处理复杂文档时失效

构建管道前,需理解标准文本提取无法解决的几个核心挑战:

  • 结构复杂性:文档包含矩阵和表格,数据间关系至关重要。标准PDF解析器会合并行列,破坏结构——将“型号A:最高95°C”和“型号B:最高120°C”变成不可用的文本,导致制造、合规和决策中出现错误。
  • 多模态内容:关键信息存在于图表、示意图和扫描图像中,纯文本解析器会遗漏。性能趋势、诊断结果和流程图需要视觉理解。
  • 引用要求:受监管行业需要精确的引用以进行审计追踪。答案需要“第4.2节,第47页”这类可追溯的引用,而不仅仅是没有出处的事实。
  • 条件逻辑:“如果-那么”规则常跨多个部分。理解“0°C以下使用协议A,否则使用协议B”需要保留文档层次结构和跨页交叉引用——这对技术手册、政策和法规指南至关重要。

智能文档处理部署的关键考量

构建文档处理管道时,以下因素决定生产可行性:

  • 分块大小的权衡:较小的块 (256-512 tokens) 可实现精确检索但可能丢失上下文。较大的块 (1,024-2,048 tokens) 保留上下文但降低精度。对于企业文档,512-1,024 tokens配合100-200 token重叠可平衡两者需求。
  • 提取深度:决定是按页面分割内容还是保持文档完整。按页分割可实现精确引用和验证,而文档级分割则保持叙事流程和更广泛的上下文。根据是需要精确来源位置还是全面理解来选择。
  • 表格输出格式:将表格转换为Markdown,以LLM原生的格式保留行列关系,显著减少纯文本线性化导致的数值幻觉。
  • 库模式与容器模式:库模式 (SimpleBroker) 适用于开发和小型文档 (<100份)。生产部署需要容器模式配合Redis/Kafka,以实现跨数千份文档的水平扩展。

多模态RAG管道的组件有哪些?

在生成带引用的答案之前,智能文档处理管道包含三个主要阶段:

阶段1:提取

  • 输入:PDF文件
  • 输出:包含结构化条目的JSON:文本块、表格Markdown、图表图像
  • 运行方式:库、自托管 (Docker) 和/或远程客户端

阶段2:嵌入

  • 输入:提取的条目 (文本、表格、图表图像)
  • 输出:每个条目2048维向量及原始内容
  • 关键能力:多模态——可编码纯文本、纯图像或图像与文本组合
  • 运行方式:本地GPU或远程NIM

阶段3:重排序

  • 输入:来自嵌入搜索的Top-K候选结果
  • 输出:排序后的列表 (最高相关性优先)
  • 关键能力:交叉编码器;同时处理 (查询、文档、可选图像)
  • 运行方式:本地GPU或远程NIM
  • 重要性:过滤掉“看起来相似但错误”的结果;VLM版本还能看到图像以验证相关性

生成答案

  • 输入:排名最高的文档 + 用户问题
  • 输出:有依据、带引用的答案
  • 关键能力:遵循严格的系统提示来引用来源、承认不确定性
  • 运行方式:本地或build.nvidia.com上的NIM

构建每个管道组件的代码

提取代码示例

# 启动nv-ingest (库模式) 并连接本地客户端
print("[INFO] Starting Ingestion Pipeline (Library Mode)...")
run_pipeline(block=False, disable_dynamic_scaling=True, run_in_subprocess=True, quiet=True)
time.sleep(15)  # 预热

client = NvIngestClient(
    message_client_allocator=SimpleClient,
    message_client_port=7671,          # 默认库模式端口
    message_client_hostname="localhost")

# 提交提取任务:保持表格为Markdown + 裁剪图表
ingestor = (Ingestor(client=client)
    .files([PDF_PATH])
    .extract(
        extract_text=True,
        extract_tables=True,
        extract_charts=True,           # 图表裁剪
        extract_images=False,          # 专注于图表/表格
        extract_method="pdfium",
        table_output_format="markdown"
    ))

job_results = ingestor.ingest()
extracted_data = job_results[0]

嵌入代码示例

# 向量数据库约定:2048维向量 + 原始载荷/元数据存入Milvus
HF_EMBED_MODEL_ID = "nvidia/llama-nemotron-embed-vl-1b-v2"
COLLECTION_NAME = "worldbank_peru_2017"
MILVUS_URI = "milvus_wb_demo.db"

milvus_client = MilvusClient(MILVUS_URI)
if milvus_client.has_collection(COLLECTION_NAME):
    milvus_client.drop_collection(COLLECTION_NAME)
milvus_client.create_collection(collection_name=COLLECTION_NAME, dimension=2048, auto_id=True)

# 多模态编码:纯文本 vs 纯图像 vs 图像+文本
with torch.inference_mode():
    if modality == "image_text":
        emb = embed_model.encode_documents(images=[image_obj], texts=[content_text])
    elif modality == "image":
        emb = embed_model.encode_documents(images=[image_obj])
    else:
        emb = embed_model.encode_documents(texts=[content_text])

重排序代码示例

# 阶段1:查询嵌入 -> 从Milvus密集检索 (高召回率)
with torch.no_grad():
    q_emb = embed_model.encode_queries([query])[0].float().cpu().numpy().tolist()

hits = milvus_client.search(
    collection_name=COLLECTION_NAME,
    data=[q_emb],
    limit=retrieve_k,
    output_fields=["text", "page", "source", "type", "has_image", "image_b64"])[0]

# 阶段2:VLM交叉编码器重排序 (查询 + 文档文本 + 可选文档图像) (高精度)
batch = rerank_inputs[i:i+batch_size]  # 从hits构建的字典列表
inputs = rerank_processor.process_queries_documents_crossencoder(batch)
inputs = {k: v.to("cuda") if isinstance(v, torch.Tensor) else v for k, v in inputs.items()}

with torch.no_grad():
    logits = rerank_model(**inputs).logits.squeeze(-1).float().cpu().numpy()

优化检索的后续步骤

智能文档处理管道上线后,通往生产环境的道路便已敞开。这套方案的优势在于其灵活性。可以尝试将新数据源连接到NeMo Retriever库,或使用专门的NIM微服务来优化检索精度。随着文档库的增长,您会发现此架构可作为构建多智能体系统的可扩展基础,从而理解企业知识的细微差别。FINISHED