MarkTechPost AI生成式AI

使用 NVIDIA NeMo Retriever、託管 NIM、LanceDB、重新排序與基於事實生成建立多模態 RAG 管線

2026年8月7日 21:13

重點摘要

在本教學中,我們將使用 NVIDIA NeMo Retriever 建立一個先進的多模態檢索增強生成管線。首先設定 Python 3.12 環境、安裝必要套件,並在無需 GPU 或外部 API 金鑰的情況下進行離線 PDF 文字提取。接著,我們透過託管的 NVIDIA NIM 端點來偵測頁面元素、提取表格、圖表與資訊圖形、產生稠密向量嵌入,並將處理後的內容儲存至 LanceDB。最後,我們實作了稠密檢索、視覺語言重新排序、後設資料過濾搜尋、附行內引用的基於事實回應生成,以及輕量級的 recall-at-k 評估,以驗證跨多模態文件內容的檢索品質。

站內 AI 整理稿

In this tutorial, we build an advanced multimodal retrieval-augmented generation pipeline with NVIDIA NeMo Retriever.We begin by configuring a Python 3.12 environment, installing the required packages, and performing offline PDF text extraction without relying on a GPU or external API key.

We then extend the workflow with hosted NVIDIA NIM endpoints to detect page elements, extract tables, charts, and infographics, generate dense vector embeddings, and store the processed content in LanceDB.

Finally, we implement dense retrieval, vision-language reranking, metadata-filtered search, grounded response generation with inline citations, and a lightweight recall-at-k evaluation to validate retrieval quality across multimodal document content.

Copy CodeCopiedUse a different Browserimport sys, os, subprocess, textwrap, json, time, warnings warnings.filterwarnings("ignore") assert sys.version_info[:2] == (3, 12), ( f"nemo-retriever requires Python 3.12.x (found {sys.version.split()[0]})." "Colab's default runtime is 3.

12; if you changed it, switch back." ) def sh(cmd): print(f"$ {cmd}") subprocess.

run(cmd, shell=True, check=False) try: import nemo_retriever print("nemo-retriever already installed") except ImportError: sh("pip install -q --ignore-installed PyJWT nemo-retriever openai") import nemo_retriever print("nemo-retriever version:", nemo_retriever.

__version__) from nemo_retriever import create_ingestor try: from nemo_retriever.io import to_markdown, to_markdown_by_page except ImportError: from nemo_retriever.common.io import to_markdown, to_markdown_by_page try: from nemo_retriever.

retriever import Retriever except ImportError: from nemo_retriever.graph.retriever import Retriever import pandas as pd pd.set_option("display.max_colwidth", 160) DOC = "multimodal_test.pdf" if not os.path.exists(DOC): sh(f"curl -sL -o {DOC} " "https://raw.githubusercontent.

com/NVIDIA/NeMo-Retriever/main/data/multimodal_test.pdf") print("document:", DOC, os.path.getsize(DOC), "bytes") DOCS = [DOC] print("\n=== STAGE 1: offline text extraction (no API key) ===") offline = ( create_ingestor(run_mode="inprocess", allow_no_gpu=True) .files(DOCS) .

extract( extract_text=True, extract_tables=False, extract_charts=False, extract_images=False, extract_infographics=False, use_page_elements=False, extract_page_as_image=False, method="pdfium", ) ) df_offline = offline.ingest() print("rows:", df_offline.shape, "\ncolumns:", list(df_offline.

columns)) print("\npage 1 text preview:\n", df_offline.iloc[0]["text"][:400]) We configure the Python 3.12 environment, install NVIDIA NeMo Retriever, and import the required ingestion and retrieval components.

We download the sample multimodal PDF and define it as the input document for the pipeline.We then perform CPU-based offline text extraction with PDFium and inspect the extracted rows, columns, and page content.Copy CodeCopiedUse a different Browserfrom getpass import getpass if not os.environ.

get("NVIDIA_API_KEY"): try: from google.colab import userdata os.environ["NVIDIA_API_KEY"] = userdata.get("NVIDIA_API_KEY") except Exception: os.environ["NVIDIA_API_KEY"] = getpass("NVIDIA_API_KEY (nvapi-...): ").strip() API_KEY = os.environ.get("NVIDIA_API_KEY", "").strip() HAVE_KEY = API_KEY.

startswith("nvapi-") print("API key present:", HAVE_KEY) PAGE_ELEMENTS_URL = "https://ai.api.nvidia.com/v1/cv/nvidia/nemotron-page-elements-v3" OCR_URL = "https://ai.api.nvidia.com/v1/cv/nvidia/nemotron-ocr-v1" TABLE_STRUCT_URL = "https://ai.api.nvidia.

com/v1/cv/nvidia/nemotron-table-structure-v1" GRAPHIC_ELEM_URL = "https://ai.api.nvidia.com/v1/cv/nvidia/nemotron-graphic-elements-v1" EMBED_URL = "https://integrate.api.nvidia.com/v1/embeddings" RERANK_URL = "https://ai.api.nvidia.

com/v1/retrieval/nvidia/llama-nemotron-rerank-vl-1b-v2/reranking" CHAT_URL = "https://integrate.api.nvidia.com/v1" EMBED_MODEL = "nvidia/llama-nemotron-embed-1b-v2" RERANK_MODEL = "nvidia/llama-nemotron-rerank-vl-1b-v2" LLM_MODEL = "nvidia/llama-3.3-nemotron-super-49b-v1.5" LANCEDB_URI, TABLE = ".

/lancedb", "colab_demo" df = df_offline if HAVE_KEY: print("\n=== STAGE 2: multimodal ingest via hosted NIMs ===") ing = ( create_ingestor( run_mode="inprocess", allow_no_gpu=True, error_policy="collect", ) .files(DOCS) .

extract( extract_text=True, extract_tables=True, extract_charts=True, extract_infographics=True, extract_images=False, method="pdfium", dpi=200, table_output_format="markdown", page_elements_invoke_url=PAGE_ELEMENTS_URL, ocr_invoke_url=OCR_URL, table_structure_invoke_url=TABLE_STRUCT_URL, graphic_elements_invoke_url=GRAPHIC_ELEM_URL, api_key=API_KEY, request_timeout_s=120.

0, split_config={"text": {"max_tokens": 512, "overlap_tokens": 64}}, ) .dedup(content_hash=True, bbox_iou=True, iou_threshold=0.45) .

embed( embedding_endpoint=EMBED_URL, model_name=EMBED_MODEL, embed_model_name=EMBED_MODEL, api_key=API_KEY, input_type="passage", inference_batch_size=16, nim_http_max_concurrent=8, ) .

vdb_upload( vdb_op="lancedb", vdb_kwargs={ "uri": LANCEDB_URI, "table_name": TABLE, "overwrite": True, "create_index": True, "index_type": "IVF_HNSW_SQ", "metric": "l2", }, ) ) t0 = time.time() df = ing.ingest(show_progress=True) print(f"ingested in {time.time()-t0:.1f}s -> {df.

shape}") We securely load the NVIDIA API key and define the hosted NIM endpoints for layout detection, OCR, table extraction, graphic analysis, embedding, reranking, and generation.

We create a multimodal ingestion pipeline that extracts text, tables, charts, and infographics while applying token-aware chunking and content deduplication.We generate embeddings for the extracted content and upload the resulting vectors and metadata to a LanceDB table.

Copy CodeCopiedUse a different Browserprint("\n=== Extraction inspection ===") for col in ["tables", "charts", "infographics", "images"]: if col in df.columns: n = int(df[col].apply(lambda v: len(v) if isinstance(v, (list, tuple)) else 0).

sum()) print(f" {col:<14} {n}") pages = to_markdown_by_page(df) print("\npages rendered to markdown:", list(pages.keys())) print("\n--- page 1 markdown (first 900 chars) ---\n", pages[min(pages)][:900]) full_md = to_markdown(df) if full_md: with open("extracted.md", "w") as f: f.

write(full_md) print("\nfull document markdown -> extracted.

md") if HAVE_KEY: print("\n=== STAGE 3: dense retrieval ===") retriever = Retriever( run_mode="service", top_k=5, rerank=False, vdb_kwargs={"uri": LANCEDB_URI, "table_name": TABLE}, embed_kwargs={ "embedding_endpoint": EMBED_URL, "model_name": EMBED_MODEL, "embed_model_name": EMBED_MODEL, "api_key": API_KEY, "input_type": "query", }, ) QUERIES = [ "Given their activities, which animal is responsible for the typos in my documents?

", "What is the most expensive gadget and how much does it cost?", "Which animal is at the beach?", ] def show(hits, label=""): print(f"\n--- {label} ---") for i, h in enumerate(hits, 1): meta = h.get("metadata") if isinstance(meta, str): try: meta = json.

loads(meta) except Exception: meta = {} page = (meta or {}).get("page_number", "?") score = h.get("_distance", h.get("rerank_score", "")) body = " ".join(str(h.get("text", "")).split())[:180] print(f" {i}.p{page} score={score} {body}") show(retriever.

query(QUERIES[0]), "single query") for q, hits in zip(QUERIES, retriever.queries(QUERIES, top_k=3)): show(hits, q[:60]) We inspect the extracted multimodal elements and convert the processed document into page-level and full-document Markdown.

We configure a dense retriever that embeds user queries and searches the LanceDB vector index for the most relevant document chunks.We test both individual and batched queries while displaying page numbers, similarity scores, and retrieved text previews.

Copy CodeCopiedUse a different Browserif HAVE_KEY: print("\n=== STAGE 4: retrieve + VL rerank ===") reranking = Retriever( run_mode="service", top_k=5, rerank=True, vdb_kwargs={"uri": LANCEDB_URI, "table_name": TABLE}, embed_kwargs={ "embedding_endpoint": EMBED_URL, "model_name": EMBED_MODEL, "emb

Related

相關文章

MarkTechPost AI生成式AI

NVIDIA AI 推出 NOOA:將 AI 代理轉化為單一 Python 類別的物件導向框架

NVIDIA 實驗室開源了 NOOA(NVIDIA 物件導向代理),這是一個與模型無關的 Python 框架,用於建構 AI 代理。傳統的代理開發分散在提示模板、工具架構、回呼程式碼和工作流程圖中,而 NOOA 將所有這些整合到一個 Python 類別中:方法代表模型可採取的動作,欄位代表代理狀態,文件字串作為提示,型別註解則是執行時期強制執行的合約。主體為「...」的方法由 LLM 驅動的迴圈在執行時期完成,而具有正常主體的方法則保持確定性的 Python 程式碼。開發者與模型因此共享同一介面,使代理行為能像一般軟體一樣進行測試、追蹤、重構和版本控制。NVIDIA 報告在 SWE-bench Verified 上達到 82.2%,在 CyberGym L1 上達到 86.8%,平均 RHAE 為 85.1%。

3 小時前

六巨頭定AI插件新標準,撞臉Claude,Anthropic沒上桌

六大科技巨頭(AWS、Anysphere、GitHub、微軟、OpenAI、Vercel)聯合發布AI智能體插件統一開放規範Agent Plugins 1.0.0,旨在統一插件打包格式,減少開發者重複勞動。該規範的結構與Anthropic的Claude Code插件系統高度相似,但Anthropic並未參與制定,而是繼續經營自己的封閉生態。

4 小時前
鈦媒體生成式AI

DeepSeek重啟融資,三年市值對齊騰訊?

DeepSeek重啟第二輪融資,以5000億元人民幣估值尋求籌集80億美元,但網傳一份由小型醫藥私募發起的專項基金募資材料引發網友質疑,後經DeepSeek員工證實部分數據屬實。該公司近期宣布API大幅漲價,可能打破其以低價換規模的估值邏輯,面臨客戶流失風險。市場關注其能否從「價格屠夫」轉型為價值提供商,以及三年內市值能否對齊騰訊等巨頭。

5 小時前