
사내 RAG 시스템 구축하며 뼈저리게 느낀 5가지 실패 사례 (그리고 해결책)
- AI
- 25 May, 2026
최근 모든 기업이 'AI 도입'을 외치며 가장 먼저 시도하는 것이 바로 RAG(Retrieval-Augmented Generation, 검색 증강 생성) 기반의 사내 챗봇 또는 지식 검색 시스템입니다. "사내 문서를 벡터 DB에 넣고 LLM(대형 언어 모델)을 연결하면 끝!"이라는 벤더사들의 감언이설에 속아 프로젝트를 시작하셨다면, 아마 지금쯤 깊은 좌절감을 맛보고 계실 확률이 높습니다.
저 또한 작년 한 해 동안 수십만 건의 사내 문서(PDF, Word, Confluence 등)를 활용한 RAG 시스템을 구축하면서 처참한 실패와 멘붕의 연속을 경험했습니다.
단순히 튜토리얼 수준을 넘어 실제 프로덕션 환경에서 RAG를 굴리려다 마주한 현실적인 문제 5가지와, 이를 어떻게 꾸역꾸역 해결해 나갔는지 제 피, 땀, 눈물이 담긴 실무 노하우를 공유합니다.
1. "표와 이미지는 무시하시나요?" - 더러운 데이터 파싱의 저주
가장 먼저 부딪힌 장벽은 랭체인(LangChain) 튜토리얼에서는 결코 알려주지 않는 '문서 파싱(Parsing)'의 현실이었습니다.
사내 문서의 70% 이상은 PDF와 PPT였습니다. 문제는 이 문서들이 예쁜 텍스트로만 이루어진 게 아니라 복잡한 2단 표, 다이어그램, 스캔본 이미지가 뒤섞여 있다는 점이었습니다. 일반적인 PDF 파서(PyPDF 등)를 돌렸더니, 표 안의 데이터가 순서도 없이 뒤죽박죽으로 추출되어 벡터 DB에 들어갔습니다.
당연히 AI는 엉뚱한 답변을 내놓았죠. "2025년 3분기 매출액은 얼마인가요?"라고 물어보면, 표의 헤더와 본문을 매칭하지 못해 헛소리를 하기 일쑤였습니다.
🛠 어떻게 해결했나? (Vision 모델의 도입) 결국 단순 텍스트 파싱을 포기하고, Multimodal LLM(Vision 기능이 있는 모델)과 OCR을 결합한 파이프라인을 구축했습니다. 복잡한 표나 레이아웃이 있는 페이지는 아예 이미지로 캡처한 뒤, LLM에게 "이 이미지를 Markdown 형식의 표로 정확히 변환해줘"라고 지시하여 텍스트화한 후 임베딩했습니다. 비용과 파싱 시간은 늘어났지만, 정보 검색 정확도는 비약적으로 상승했습니다.
2. Chunking의 딜레마: 쪼개면 맥락을 잃고, 합치면 노이즈가 된다
문서를 벡터 DB에 넣기 위해 적당한 크기로 자르는 청킹(Chunking) 작업. 이거 정말 지옥이었습니다.
처음에는 토큰 수 1,000개 단위로 기계적으로 문서를 잘랐습니다(Fixed-size chunking). 그랬더니, 문서의 중요한 문맥이 A 청크와 B 청크 사이에서 동강 나버렸습니다. "이 정책의 예외 사항은..."으로 A가 끝나고, B는 "다음과 같습니다."로 시작하는 식이죠. 이렇게 잘린 조각을 검색해서 LLM에게 주니 맥락을 전혀 이해하지 못했습니다.
🛠 어떻게 해결했나? (Semantic Chunking & Parent-Child 구조) 기계적인 분할 대신, 의미 기반(Semantic) 분할과 Parent-Child Retrieval 방식을 도입했습니다.
- 문서를 '의미'가 연결되는 단위(단락이나 섹션 단위)로 쪼갭니다.
- 벡터 DB에는 아주 작게 자른 Child 청크를 저장하여 '정밀한 검색'을 가능하게 합니다.
- 하지만 실제 LLM에게 컨텍스트를 던져줄 때는, 검색된 Child가 속한 **전체 원본 문단(Parent Chunk)**을 통째로 넘겨주어 맥락 상실을 방지했습니다.
3. "그 문서는 어제 폐기됐는데요?" - 동적 데이터 동기화의 지옥
RAG 시스템을 사내에 오픈했더니 가장 많이 들어온 클레임이 "AI가 옛날 규정을 정답인 것처럼 말해요!" 였습니다.
사내 규정, 메뉴얼, 부서 정보는 매일 업데이트됩니다. 하지만 우리의 벡터 DB는 일주일 전에 밀어 넣은 과거 데이터에 머물러 있었죠. 파일 시스템이나 Confluence의 변경 사항을 실시간으로 감지해서 벡터 DB의 특정 청크만 업데이트하거나 삭제하는 과정은 상상 이상으로 복잡했습니다.
🛠 어떻게 해결했나? (Metadata 활용과 주기적 Sync) 모든 문서 청크에 문서 ID, 최종 수정일자, 버전, 접근 권한을 나타내는 메타데이터(Metadata)를 철저하게 부여했습니다. 그리고 배치(Batch) 스크립트를 작성해 매일 새벽 원본 시스템의 수정일자와 벡터 DB의 메타데이터를 비교하여, 변경/삭제된 문서의 벡터만 핀셋처럼 골라내어 재임베딩(Re-embedding)하는 파이프라인을 구축했습니다.
4. RAG도 환각(Hallucination)을 합니다
흔히 "RAG를 쓰면 문서에 있는 내용만 대답하니까 할루시네이션이 없다"고 오해합니다. 절대 아닙니다.
검색된 문서(Context)에 사용자가 원하는 정답이 아예 없는 경우, LLM은 자존심을 굽히지 않고 자신이 가진 사전 학습 지식을 동원해 그럴싸한 거짓말을 지어내기 시작했습니다. 특히 사내 은어나 약어가 섞인 질문을 받으면 소설을 쓰는 수준이었습니다.
🛠 어떻게 해결했나? (Strict Prompting & 하이브리드 검색)
- 프롬프트 엔지니어링 강화: 시스템 프롬프트에 "반드시 제공된 Context 내에서만 답변해. Context에 정보가 부족하면 절대 지어내지 말고 '제공된 문서에서 정보를 찾을 수 없습니다'라고 말해." 라고 수십 번 강조(협박)했습니다.
- 하이브리드 검색(Hybrid Search) 도입: 벡터 기반의 의미 검색(Semantic Search)만으로는 '특정 제품명'이나 '부서 코드' 같은 정확한 키워드 검색에 취약했습니다. 그래서 전통적인 키워드 검색 엔진(BM25, Elasticsearch 등)을 벡터 검색과 결합하여, 두 결과를 융합(Reciprocal Rank Fusion)하는 방식으로 검색 품질을 끌어올려 엉뚱한 문서를 가져오는 일을 방지했습니다.
5. 비용 폭탄: 너무 많은 Context가 부른 참사
정확도를 높이겠다고 검색 엔진이 찾아온 관련 문서(Context) 10~20개를 그대로 LLM 프롬프트에 우겨넣었습니다. 답변은 잘 나왔지만, 한 달 뒤 클라우드 청구서를 보고 경악을 금치 못했습니다.
매번 질문을 할 때마다 수만 개의 토큰을 입력으로 소모했기 때문에 API 비용이 기하급수적으로 늘어난 것입니다. 또한, 입력 컨텍스트가 너무 길어지면 LLM이 정작 중요한 중간 내용은 까먹는 'Lost in the middle' 현상까지 발생했습니다.
🛠 어떻게 해결했나? (Reranking 모델의 구원) 검색된 결과를 무식하게 다 밀어넣는 대신, Reranker (재순위화) 모델을 파이프라인 중간에 끼워 넣었습니다.
- 초기 검색에서 관련 있을 법한 문서를 넉넉하게(20개) 가져옵니다.
- 가볍고 빠른 Reranking 모델(Cross-Encoder 등)을 사용하여 사용자의 질문과 가장 연관성이 높은 문서 3~4개만 엄선하여 순위를 다시 매깁니다.
- 이 핵심적인 3~4개의 문서만 LLM에게 넘겨줍니다. 결과적으로 답변의 질은 유지하면서 토큰 사용량(비용)과 응답 지연 시간(Latency)을 획기적으로 줄일 수 있었습니다.
마무리하며: RAG는 '검색 엔진' 공사입니다
직접 몸으로 부딪혀본 RAG는 '마법의 AI 지팡이'가 아니라, 극도로 지루하고 정교한 데이터 엔지니어링이자 고도화된 검색 엔진(Search Engine)을 구축하는 노동이었습니다.
LLM의 성능을 탓하기 전에, **"우리가 LLM에게 얼마나 깨끗하고 정확한 문맥을 떠먹여 주고 있는가?"**를 먼저 고민해야 합니다. 사내 RAG 도입을 준비 중이시라면, 겉멋 든 AI 프레임워크보다 '데이터 정제 파이프라인'에 예산과 시간을 70% 이상 투자하시기를 강력히 권장합니다. 그게 결국 실패를 줄이는 가장 빠른 지름길입니다.










