[RAGFlow 딥다이브] "쓰레기를 넣으면 쓰레기가 나온다" — 단순 텍스트 쪼개기의 환상을 부수는 차세대 RAG 아키텍처
1. The Hook (공감과 도발)
RAG(Retrieval-Augmented Generation) 프로젝트 해보신 분들, 솔직해집시다. 튜토리얼 영상이나 블로그에서 LangChain이나 LlamaIndex로 Hello World 띄울 때만 해도 세상을 다 가진 것 같지 않으셨나요? “와, 코드 10줄이면 내 문서로 챗봇을 만드네?” 하면서요. 하지만 그 얄팍한 환상은 실제 현업의 ‘날것(Raw)’ 문서를 집어넣는 순간 산산조각 납니다.
회사에서 굴러다니는 2단 편집된 논문, 헤더와 푸터가 엉망으로 섞인 사규 PDF, 셀 병합이 난무하는 재무제표를 기존의 PyPDF2나 pdfminer로 긁어오면 어떻게 되나요? 텍스트는 걸레짝이 되고, 2단 레이아웃은 좌우가 무식하게 짬뽕되어 읽히며, 표(Table) 안의 데이터는 그저 의미 없는 숫자와 단어의 나열로 변모합니다. 이걸 RecursiveCharacterTextSplitter 같은 걸로 1000 토큰씩 기계적으로 썰어서 벡터 DB에 쑤셔 넣습니다. 그리고 LLM에게 질문하죠.
결과는 어땠나요? 환각(Hallucination) 파티가 열립니다. 우리는 그동안 ‘어떻게 검색(Retrieval)할 것인가’에만 매몰되어, ‘어떻게 문서를 제대로 씹어먹을 것인가(Ingestion)’라는 가장 본질적인 문제를 외면해 왔습니다. 결국 쓰레기를 넣으면 쓰레기가 나오는 법(Garbage In, Garbage Out)입니다. 오늘 뜯어볼 RAGFlow는 바로 이 지독한 인제스천(Ingestion) 파이프라인의 고름을 짜내기 위해 등장한 무식하고도 정교한 괴물입니다.
2. TL;DR (The Core)
RAGFlow는 ‘문서를 단순한 텍스트 덩어리가 아닌, 시각적 구조를 가진 이미지(Visual Layout)로 먼저 이해해야 한다’는 철학(Deep Document Understanding)을 구현한 차세대 RAG 엔진입니다.
3. Deep Dive: Under the Hood (핵심 아키텍처 심층 분석)
사실 처음 RAGFlow의 아키텍처를 봤을 때 꽤 회의적이었습니다. “그냥 OCR 모델 하나 덧붙인 거 아니야?”라고 생각했죠. 하지만 밑바닥 코드를 까보고 나서, 이들이 문서를 대하는 태도가 완전히 다르다는 걸 깨달았습니다. RAGFlow의 핵심은 DDU(Deep Document Understanding), 즉 깊은 문서 이해입니다.
기존 방식(Naive Chunking) vs RAGFlow 아키텍처 비교
| 비교 항목 | 기존 RAG (LangChain / LlamaIndex 등) | RAGFlow (DDU Architecture) |
|---|---|---|
| 문서 인식 방식 | 텍스트 레이어 단순 추출 (바이트 스트림) | 문서를 이미지로 변환 후 CV 모델로 레이아웃 분석 |
| 청킹(Chunking) 기준 | 글자 수, 토큰 수 기반 기계적 분할 | 단락, 헤더, 표, 이미지 등 의미적(Semantic) 경계 |
| 표(Table) 처리 | 텍스트로 뭉개짐 (행/열 관계 완벽히 파괴) | OCR 및 표 구조 인식으로 HTML/JSON 형태로 관계 보존 |
| 2단 레이아웃 | 좌우 텍스트가 무작위로 섞여 문맥 단절 | 블록 기반 바운딩 박스(B-Box) 추적으로 순서 보장 |
| 검색 퀄리티 | 키워드 의존도 높음, 문맥 유실 심함 | 정확한 단락과 표 단위 검색으로 높은 정보 무결성 |
기존 파이프라인은 PDF에서 텍스트를 쭉 뽑아낸 뒤 길이에 맞춰 자릅니다. 반면, RAGFlow는 내부적으로 YOLO 계열의 객체 탐지(Object Detection) 모델과 LayoutLM 같은 비전 언어 모델(VLM)을 활용합니다. 문서를 먼저 이미지로 렌더링하고, 어디가 제목인지, 어디가 본문인지, 어디가 표인지 바운딩 박스(Bounding Box)를 칩니다.
이게 왜 중요할까요? 아래의 RAGFlow 내부 구조를 흉내 낸 구조화된 표 파싱 JSON 스니펫을 보시죠.
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"chunk_id": "chk_9876xyz",
"type": "table",
"source_bbox": [120, 450, 680, 800], // 문서 내 표의 실제 시각적 좌표
"content": {
"headers": ["연도", "매출액(억)", "영업이익(억)"],
"rows": [
["2024", "15,000", "1,200"],
["2025", "18,500", "2,100"]
]
},
"context": "2024~2025년 글로벌 사업부 실적 요약표"
}
기존 방식이었다면 "연도 매출액 영업이익 2024 15,000 1,200 2025..." 처럼 아무 의미 없는 문자열로 벡터화되었을 겁니다. RAGFlow는 이 표를 온전한 2차원 구조(HTML이나 JSON 형태)로 보존하여 임베딩합니다. LLM에게 컨텍스트를 넘길 때도 이 구조를 유지하기 때문에, “2025년 영업이익이 얼마야?”라는 질문에 LLM이 행과 열을 정확히 매핑하여 대답할 수 있는 거죠. 이 부분은 진짜 현업에서 수백 번 골머리를 앓았던 테이블 파싱의 저주를 시원하게 해결해 줍니다.
4. Pragmatic Use Cases (실무 적용 시나리오)
그렇다면 현업 개발자인 우리는 이걸 어떻게 써먹어야 할까요? 단순한 사내 FAQ 챗봇을 넘어서, 딥한 실무 시나리오 두 가지를 제안합니다.
시나리오 1: 대규모 감사 보고서 및 재무제표 팩트체크 시스템
금융권이나 대기업 백오피스에서 가장 원하는 건 ‘수십 페이지짜리 PDF 재무제표를 던져주고, 특정 지표의 변동 원인을 찾아내는 것’입니다. 기존 RAG에서는 숫자(Token)가 분할 과정에서 유실되거나 엉뚱한 행의 숫자와 결합하는 치명적 오류가 발생합니다. RAGFlow를 도입하면 파이프라인이 달라집니다. 재무제표 PDF가 업로드되면, RAGFlow의 비전 모델이 재무상태표와 손익계산서를 독립된 ‘표 청크’로 인식합니다. 주석에 달린 텍스트는 별도의 ‘텍스트 청크’로 분리하되, 메타데이터로 연결합니다. 기획자는 프롬프트에 “표 데이터를 분석할 때는 반드시 열(Column) 헤더를 기준으로 숫자를 매칭해”라고 지시만 하면 됩니다. 환각 없는 정확한 금융 데이터 추출 시스템이 가능해집니다.
시나리오 2: 스캔된 레거시 도면/계약서 멀티모달 RAG 구축
제조업이나 건설업 고객사에 가면, 텍스트 레이어조차 없는 10년 전 스캔 PDF(이미지) 수만 장이 쌓여있습니다. 기존에는 외부 OCR API(Google Vision 등)를 태운 뒤 텍스트만 발라내서 RAG를 구축하느라 비용과 시간이 이중으로 들었죠. 하지만 RAGFlow는 태생적으로 멀티모달과 OCR을 품고 있습니다. 내부 워커(Worker) 노드에 GPU를 할당하고, RAGFlow의 배치(Batch) 인제스천을 비동기로 돌리면 됩니다. 이미지 속 텍스트뿐만 아니라, 표의 테두리 선(Border)까지 인식해 구조화해주므로 별도의 파이프라인을 짤 필요가 없습니다. 이는 아키텍처의 복잡도를 극적으로 낮춰줍니다.
5. Honest Review & Trade-offs (진짜 장단점과 한계)
자, 칭찬은 여기까지 합시다. 세상에 은탄환(Silver Bullet)은 없고, 저는 RAGFlow를 운영 서버에 올리면서 꽤 많은 피눈물을 흘렸습니다. 시니어 엔지니어 입장에서 도입 전 반드시 짚고 넘어가야 할 트레이드오프를 말씀드리죠.
첫째, 인프라가 무식하게 무겁습니다. LangChain 기반의 가벼운 RAG는 Python 컨테이너 하나와 외부 Vector DB(Pinecone 등)면 끝납니다. 하지만 RAGFlow의 docker-compose.yml을 열어보면 기겁하실 겁니다. MySQL, MinIO(오브젝트 스토리지), Redis, Elasticsearch(또는 Infinity DB), 거기에 무거운 비전 및 OCR 모델을 돌리기 위한 Python 백엔드 컨테이너까지 띄워야 합니다. GPU 자원이 없다면 인제스천 속도는 처참해집니다. 가벼운 토이 프로젝트용으로는 절대 부적합합니다.
둘째, 실시간 업로드 및 즉시 질의에는 쥐약입니다. 사용자가 문서를 업로드하고 1초 만에 질문하길 원하나요? RAGFlow에서는 포기하시는 게 좋습니다. 문서를 이미지로 쪼개고, 레이아웃을 분석하고, OCR을 태우고, 청킹하는 과정은 엄청난 컴퓨팅 파워와 시간을 소모합니다. 즉, 이 아키텍처는 ‘비동기 배치(Batch) 기반의 지식 베이스 구축’에 특화되어 있지, 실시간 인터랙션에는 어울리지 않습니다.
셋째, 커스텀의 벽(Learning Curve)이 높습니다. 내부적으로 복잡한 파이프라인을 감추고 있다 보니, 한국어 특화 OCR 모델로 교체하거나 특정 레이아웃 파싱 로직을 우리 회사 양식에 맞게 튜닝하려고 할 때 코어 엔진을 직접 건드려야 하는 부담이 있습니다. 프레임워크가 제공하는 ‘마법’이 강력할수록, 그 마법을 통제하기는 더 어려워지는 법이죠.
6. Closing Thoughts (여운과 결론)
“AI 애플리케이션의 8할은 데이터 전처리다.” 현업에서 구르다 보면 이 뻔한 명제가 얼마나 뼈저린 진리인지 깨닫게 됩니다. 우리는 지난 1~2년간 LLM의 화려한 생성 능력에 취해, 정작 그 입으로 들어가는 밥(Data)이 상했는지 구조가 무너졌는지는 신경 쓰지 않았습니다.
RAGFlow는 단순히 새로운 툴이 아닙니다. RAG의 패러다임이 ‘문서 검색’에서 ‘문서 구조 이해’로 넘어가고 있다는 강력한 신호입니다. 무거운 인프라와 느린 속도라는 뚜렷한 단점에도 불구하고, 결코 타협할 수 없는 ‘정확도’와 ‘데이터 구조 보존’을 위해 현업 실무자라면 반드시 뜯어보고 테스트해 봐야 할 가치가 있습니다.
오늘 여러분의 RAG 시스템이 뱉어낸 환각 섞인 답변이 LLM의 멍청함 때문인지, 아니면 당신이 쑤셔 넣은 무참히 찢겨진 텍스트 조각 때문인지 다시 한번 고민해 보시기 바랍니다. 파이프라인의 진정한 혁신은 모델의 파라미터 수가 아니라, 이면의 끈질긴 데이터 엔지니어링에서 시작되니까요.
References
- https://github.com/infiniflow/ragflow
- https://arxiv.org/abs/1912.13318 (LayoutLM: Pre-training of Text and Layout for Document Image Understanding)
