AI 에이전트가 복잡한 PDF를 순식간에 분석하고, 중첩된 표를 추출하며, 차트 속 데이터까지 텍스트 파일 읽듯 자유자재로 시각화할 수 있다면 어떨까요? NVIDIA Nemotron RAG를 활용하면 대규모 문서 워크로드를 정확하고 정밀하게 처리하는 고성능 지능형 문서 처리 파이프라인을 구축할 수 있습니다.
본 포스팅에서는 멀티모달 검색 파이프라인의 핵심 구성 요소를 단계별로 살펴봅니다. 먼저 오픈 소스인 NVIDIA 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: 답변 생성 최적화 모델
- NVIDIA NIM 모델 더 보기
🛠️ 코드 및 문서
- NeMo Retriever 라이브러리 (GitHub)
- 튜토리얼 노트북 (Jupyter Notebook): GitHub에서 바로 실행 가능
사전 준비 사항
본 튜토리얼을 따라 하려면 다음 환경이 필요합니다.
시스템 요구 사양
- Python: 3.10 ~ 3.12 버전 (3.12 버전에서 테스트 완료)
- GPU: 최소 24GB 이상의 VRAM을 갖춘 NVIDIA GPU (로컬 모델 배포용)
- 디스크 공간: 최소 250GB (모델, 데이터셋, 벡터 데이터베이스 저장용)
API 환경
- NVIDIA 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", # Utils
"markitdown", "nv-ingest==26.1.1", "nv-ingest-api==26.1.1", "nv-ingest-client==26.1.1", # Ingest
"milvus-lite==2.4.12", "pymilvus", "openai>=1.51.0", # Database & API
"transformers", "accelerate", "pillow", "torch", "torchvision", "timm" # ML Core
]
소요 시간
전체 구현: 약 1~2시간 (flash-attn과 같이 GPU에 최적화된 의존성 패키지를 직접 컴파일할 경우 더 많은 시간이 소요될 수 있습니다.)
최종 결과물: 생산 환경에 즉시 적용 가능한 문서 처리용 멀티모달 RAG 파이프라인
본 튜토리얼은 직접 실습하며 배울 수 있도록 GitHub에서 실행 가능한 Jupyter Notebook 형태로 제공됩니다. 전체 구축 프로세스의 주요 특징은 다음과 같습니다.
- 잠겨 있는 데이터의 해방: NeMo Retriever 라이브러리를 활용해 복잡한 문서 속에 숨겨진 정보를 추출하는 것부터 시작합니다.
- 맥락을 이해하는 오케스트레이션: 마이크로서비스 아키텍처 기반의 파이프라인이 문서를 효율적으로 분해합니다. 추출된 데이터는 Nemotron RAG 모델에 최적화되어, 맥락을 정확히 파악하는 고속 시스템을 구축합니다.
- 고성능 병렬 변환: GPU 가속 컴퓨팅과 NVIDIA NIM 마이크로서비스를 통해 워크로드를 확장합니다. 이를 통해 방대한 데이터셋을 검색 가능한 지능형 데이터로 빠르게 병렬 변환합니다.
- 정밀한 검색 성능: 정제된 데이터를 Nemotron RAG에 공급하여, AI 에이전트가 복잡한 질문에도 정확한 표나 단락을 찾아내어 신뢰도 높은 답변을 내놓게 합니다.
- 출처 기반의 신뢰성: 검색 결과를 어시스턴트와 연결하여 근거가 확실한 답변을 제공합니다. 사용자는 답변의 근거가 된 특정 페이지나 차트를 투명하게 확인할 수 있습니다.
복잡한 문서 앞에서 기존 OCR과 텍스트 전용 방식이 한계를 드러내는 이유
파이프라인을 구축하기에 앞서, 일반적인 텍스트 추출 방식으로는 해결하기 어려운 핵심 과제들을 명확히 이해해야 합니다.
- 구조적 복잡성: 문서는 데이터 간의 관계가 핵심인 행렬과 표를 포함하고 있습니다. 표준 PDF 파서(Parser)는 행과 열을 하나로 합쳐버려 구조를 파괴하곤 합니다. 예를 들어 “모델 A: 최고 95°C”, “모델 B: 최고 120°C”라는 정보가 구조 없이 뒤섞이면 제조 현장이나 규정 준수 과정에서 치명적인 의사결정 오류를 초래합니다.
- 멀티모달 콘텐츠의 부재: 텍스트 전용 파서는 차트, 다이어그램, 스캔 이미지 속에 담긴 핵심 정보를 놓치기 쉽습니다. 성능 추세나 진단 결과, 공정 흐름도 등을 정확히 파악하려면 시각적 이해(Visual Understanding)가 반드시 뒷받침되어야 합니다.
- 엄격한 출처 인용: 규제 산업에서는 감사 추적을 위해 정밀한 인용이 필수입니다. 단순히 사실만 나열하는 것이 아니라, “제4.2절, 47페이지”처럼 출처가 명확한 참조 정보를 제공해야 신뢰를 얻을 수 있습니다.
- 조건부 로직 파악: “만약 ~라면”과 같은 규칙은 여러 섹션에 걸쳐 나타나는 경우가 많습니다. “0°C 미만에서는 프로토콜 A를, 그 외에는 프로토콜 B를 사용하라”는 지침을 이해하려면 문서의 계층 구조와 페이지 간 상호 참조 정보를 보존해야 합니다. 이는 기술 매뉴얼이나 규정 가이드라인 처리에 필수적인 요소입니다.
단순한 텍스트 파싱 대신, Nemotron RAG가 전용 추출 모델과 구조화된 임베딩, 그리고 인용 기반의 생성 방식을 채택한 이유가 바로 여기에 있습니다.
지능형 문서 처리(IDP) 배포 시 반드시 고려해야 할 핵심 요소
문서 처리 파이프라인을 구축할 때, 다음 요소들은 시스템의 실질적인 운영 가능 여부를 결정짓는 중요한 잣대가 됩니다.
- 청크 크기의 절충: 청크를 작게(256~512 토큰) 나누면 검색 정밀도는 높아지지만 맥락을 놓치기 쉽습니다. 반대로 크게(1,024~2,048 토큰) 잡으면 맥락은 유지되지만 정밀도가 떨어집니다. 기업용 문서의 경우, 512~1,024 토큰 크기에 100~200 토큰 정도를 겹치게 설정하여 두 요구 사항 사이의 균형을 맞추는 것이 좋습니다.
- 추출 깊이 설정: 콘텐츠를 페이지 단위로 나눌지, 문서 전체를 하나로 유지할지 결정해야 합니다. 페이지 단위 분할은 정밀한 인용과 검증에 유리하며, 문서 단위 분할은 전반적인 서사 흐름과 넓은 맥락을 파악하는 데 효과적입니다. 정확한 출처 정보가 필요한지, 혹은 종합적인 이해가 우선인지에 따라 선택하시기 바랍니다.
- 표 데이터 형식: 표를 마크다운 형식으로 변환하면 LLM에 친화적인 방식으로 행과 열의 관계를 보존할 수 있습니다. 이는 단순히 텍스트를 나열할 때 발생하는 수치 환각 현상을 획기적으로 줄여줍니다.
- 라이브러리 모드 vs 컨테이너 모드: 개발 단계나 100개 미만의 소규모 문서 처리에는 라이브러리 모드(SimpleBroker)가 적합합니다. 하지만 수천 권 이상의 문서를 다루는 대규모 운영 환경에서는 Redis나 Kafka를 활용한 컨테이너 모드를 선택해 수평적 확장성을 확보해야 합니다.
이러한 설정값들은 검색 정확도와 인용의 정밀도, 그리고 시스템 전체의 확장성에 직접적인 영향을 미칩니다.
멀티모달 RAG 파이프라인의 구성 요소는 무엇인가?
질문에 대한 인용 기반 답변을 생성하기 전에, 지능형 문서 처리 파이프라인은 세 가지 주요 단계를 거칩니다. 각 단계는 명확한 입력과 출력 계약을 가집니다.
1단계: 추출 (Nemotron 페이지 요소, 표/차트 추출 및 OCR)
- 입력: PDF 파일
- 출력: 구조화된 항목이 포함된 JSON — 텍스트 청크, 표 마크다운, 차트 이미지
- 실행 방식: 라이브러리, 셀프 호스팅(Docker), 그리고/또는 원격 클라이언트
2단계: 임베딩 (llama-nemotron-embed-vl-1b-v2)
- 입력: 추출된 항목(텍스트, 표, 차트 이미지)
- 출력: 항목당 2048차원 벡터 및 원본 콘텐츠
- 주요 기능: 멀티모달 — 텍스트만, 이미지만, 또는 이미지와 텍스트를 함께 인코딩
- 실행 방식: 로컬 GPU에서 실행하거나 NIM을 통해 원격 실행(곧 지원 예정)
3단계: 리랭킹 (llama-nemotron-rerank-vl-1b-v2)
- 입력: 임베딩 검색에서 선별된 Top-K 후보
- 출력: 관련성 기준으로 정렬된 목록(가장 높은 관련성 순)
- 주요 기능: 크로스 인코더 — (질문, 문서, 선택적 이미지)를 함께 입력으로 처리
- 실행 방식: 로컬 GPU에서 실행하거나 NIM을 통해 원격 실행(곧 지원 예정)
- 왜 중요한가: 겉보기에는 유사하지만 실제로는 잘못된 결과를 걸러내며, VLM 버전은 이미지까지 함께 확인해 관련성을 검증합니다.
파이프라인 구축 후 근거 기반의 답변 생성:
답변 생성 (Llama-3.3-Nemotron-Super-49B)
문서 처리 파이프라인 구축이 완료되면, 이를 바탕으로 답변을 생성할 수 있습니다.
- 입력값: 리랭킹을 거쳐 엄선된 최상위 문서들과 사용자의 질문
- 출력값: 명확한 근거와 인용 정보가 포함된 답변
- 핵심 역량: 엄격한 시스템 프롬프트를 준수하여 정확한 출처를 인용하며, 정보가 불확실할 경우 이를 명확히 밝혀 신뢰도를 높입니다.
- 실행 환경: 로컬 GPU 환경 또는 build.nvidia.com의 NIM 마이크로서비스를 통해 유연하게 실행할 수 있습니다.

각 파이프라인 구성 요소를 위한 구현 코드
문서 처리 파이프라인의 각 단계별 시작 코드를 직접 실행해 보세요.
데이터 추출 (Extraction)
데이터 추출은 PDF의 ‘픽셀과 레이아웃’ 정보를 구조화된 쿼리 가능 단위로 변환하는 과정입니다. 이는 검색 및 추론 모델이 가공되지 않은 페이지 좌표나 평면화된 텍스트만으로는 문서의 본래 의미를 완벽히 파악할 수 없기 때문입니다. NeMo Retriever 라이브러리는 모든 데이터를 단순히 일반 텍스트로 취급하지 않습니다. 대신 텍스트, 표, 차트, 그래픽을 각각 분리하여 처리하는 전용 추출 기능을 통해 문서 고유의 구조(표는 표대로, 그림은 그림대로)를 온전히 보존합니다. 이번 튜토리얼에서는 세계은행(World Bank)의 ‘Peru 2017 Country Profile‘ 보고서를 활용합니다. 이 보고서는 서술형 문장, 차트, 복잡한 부록 표가 뒤섞여 있어, 추출 성능이 뒷받침되지 않으면 기업용 RAG 시스템에서 오류를 일으키기 쉬운 고난도 테스트 케이스입니다.
# Start nv-ingest (Library Mode) and connect a local client (SimpleClient on port 7671).
print("[INFO] Starting Ingestion Pipeline (Library Mode)...")
run_pipeline(block=False, disable_dynamic_scaling=True, run_in_subprocess=True, quiet=True)
time.sleep(15) # warmup
client = NvIngestClient(
message_client_allocator=SimpleClient,
message_client_port=7671, # Default LibMode port
message_client_hostname="localhost"
)
# Submit an extraction job: keep tables as Markdown + crop charts (for downstream multimodal RAG).
ingestor = (Ingestor(client=client)
.files([PDF_PATH])
.extract(
extract_text=True,
extract_tables=True,
extract_charts=True, # chart crops
extract_images=False, # focus on charts/tables
extract_method="pdfium",
table_output_format="markdown"
)
)
job_results = ingestor.ingest()
extracted_data = job_results[0]
임베딩 (Embedding)
임베딩은 추출된 각 항목을 고정된 크기의 벡터로 변환하는 과정입니다. 이를 통해 방대한 문서 컬렉션 속에서도 밀리초(ms) 단위의 빠른 유사도 검색이 가능해집니다. 시각적 요소가 풍부한 PDF의 잠재력을 온전히 끌어내려면 멀티모달 임베더 사용이 필수적입니다. 이 모델은 문서 페이지를 단순 텍스트뿐만 아니라 이미지, 또는 이미지와 텍스트의 결합 형태로 임베딩하도록 설계되었습니다. 덕분에 기존 방식에서는 무시되기 일쑤였던 차트와 표도 답변의 핵심 근거로 검색할 수 있습니다. 본 파이프라인에서는 각 항목을 2,048차원 벡터로 변환하여 Milvus 벡터 데이터베이스에 인덱싱합니다. 이후 검색된 상위 결과(Top-K)는 성능 극대화를 위해 리랭킹 단계로 전달됩니다.
# Vector DB contract: 2048-dim vectors + original payload/metadata stored in 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)
# Multimodal encoding: text-only vs image-only vs image+text (table markdown + chart/table crop).
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])
# (Notebook then L2-normalizes emb[0] and inserts {vector, text, page, type, has_image, image_b64, ...} into Milvus.)
리랭킹 (Reranking)
리랭킹은 임베딩 기반 검색 이후에 수행되는 정밀 최적화 단계입니다. 모든 문서를 크로스 인코더로 순위를 매기기엔 연산 비용이 너무 높기 때문에, 먼저 임베더가 걸러낸 상위 후보군을 대상으로만 리랭킹을 진행합니다. 기업용 PDF 문서 처리에서 멀티모달 크로스 인코더 리랭커는 그 가치가 더욱 빛납니다. 사용자가 신뢰하는 실제 근거물인 표나 도표(텍스트 병행 가능)를 직접 대조하여 연관성을 판단하기 때문입니다. 덕분에 단순히 ‘겉모양만 비슷한’ 결과는 걸러내고, ‘실제 질문에 답변이 되는’ 고품질 데이터를 최상단으로 끌어올립니다. 본 튜토리얼의 노트북에서는 Milvus에서 검색된 결과(Hits)를 바탕으로 리랭킹을 시작합니다. 이후 각 후보군에 로짓 점수를 할당하고 정렬하는 스코어링 루프를 거쳐, 답변 생성에 필요한 최종 컨텍스트를 완성합니다.
# Stage 1: embed query -> dense retrieve from Milvus (high recall).
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]
# Stage 2: VLM cross-encoder rerank (query + doc_text + optional doc_image) (high precision).
batch = rerank_inputs[i:i+batch_size] # list of {"question","doc_text","doc_image"} dicts (built from 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()
# (Notebook then attaches logits as scores and sorts valid_hits descending.)
검색 최적화를 위한 다음 단계
지능형 문서 처리 파이프라인이 구축되었다면, 이제 실제 서비스 환경으로 나아갈 준비가 끝났습니다. 이 파이프라인의 진정한 강점은 뛰어난 유연성에 있습니다. 새로운 데이터 소스를 NeMo Retriever 라이브러리에 연결해 보거나, 특화된 NIM 마이크로서비스를 활용해 검색 정확도를 한층 더 높여보세요.
문서 라이브러리가 방대해질수록, 이 아키텍처는 기업 지식의 세밀한 뉘앙스까지 파악하는 멀티 에이전트 시스템의 견고한 기반이 되어줄 것입니다. 특히 LLM 라우터를 통해 최신 모델들을 NVIDIA Nemotron과 함께 운용하면, 성능은 높게 유지하면서 비용과 효율성까지 동시에 잡을 수 있습니다. 실제로 Justt는 Nemotron을 도입해 데이터 추출 오류율을 25% 낮추었으며, 이를 통해 고객들에게 더욱 신뢰도 높은 금융 차지백 분석 서비스를 제공하고 있습니다.
이제 수많은 업계 선도 AI 데이터 플랫폼 파이프라인 제공업체가 채택한 NVIDIA Blueprint for Enterprise RAG 개발자 커뮤니티에 참여하세요. 관련 리소스는 build.nvidia.com, GitHub, 그리고 NGC 카탈로그에서 지금 바로 확인하실 수 있습니다.
NVIDIA 뉴스를 구독하고 LinkedIn, X, Discord, YouTube. 채널을 팔로우하여 NVIDIA Nemotron의 최신 소식을 가장 빠르게 접해 보세요.