0에서 RAG 시스템까지: 성공과 실패

From zero to a RAG system: successes and failures

요약

개발자가 1TB 규모의 기술 문서로부터 자연어 질문에 답하는 로컬 LLM 기반 RAG 시스템을 구축한 경험을 공유합니다. Ollama, nomic-embed-text, LlamaIndex를 활용하여 문서 필터링, 임베딩 생성, 벡터 검색 등의 문제들을 해결했습니다.

핵심 포인트

  • 대규모 비정형 문서를 처리하기 위해 파일 타입별 필터링으로 54% 파일 감소 및 RAM 오버플로우 해결
  • Ollama와 LlamaIndex를 Python으로 통합하여 로컬 LLM 기반 RAG 시스템 구축
  • 벡터화, 임베딩, 인덱싱 과정에서 대용량 문서 처리 최적화 필요

왜 중요한가

엔터프라이즈 규모의 문서 데이터로부터 효율적인 RAG 시스템을 구축할 때 실무적 노하우와 장애물 극복 방법을 제시합니다.

📄 전문 번역

회사 전체 프로젝트 기록을 검색할 수 있는 AI 챗봇 만들기

몇 달 전 회사에서 로컬 LLM을 활용한 내부 채팅 도구를 만들어달라는 요청을 받았습니다. 처음엔 별 것 아닌 작업처럼 보였는데, 요구사항이 들어오면서 상황이 달라졌어요.

요구사항은 이랬습니다:

  • 빠른 응답 속도 (정말 빠르게!)
  • 거의 10년치 회사 프로젝트 전체에 대한 답변 가능
  • 검색 엔진이 아닌 자연어 질문 기반 도구
  • 원문 참조 자료 제공
  • OrcaFlex 파일 정보 우선 처리 (해양산업용 시뮬레이션 소프트웨어)

그리고 마지막으로 1TB 규모의 프로젝트 자료를 넘겨받았습니다. 기술 문서, 보고서, 분석자료, 규정, CSV 파일 등이 뒤섞여 있었죠. 이때부터 감정의 롤러코스터가 시작됐습니다.

처음부터 말씀드리자면, 이 과정은 결코 빠르거나 쉽지 않았습니다. 그래서 이 경험을 공유하고 싶어요. 초기의 실수부터 최종 프로덕션 아키텍처까지 모든 과정을 담아봤습니다. 그리고 실은 저도 이런 작업을 처음 해봤고, RAG(Retrieval-Augmented Generation)가 뭔지도 몰랐어요.

문제별로 어떻게 해결했는지 이야기해보겠습니다.

문제 1: 적절한 기술 스택 선택

먼저 사용할 기술을 정해야 했습니다.

로컬 언어 모델이 필수였어요. 보안상 외부 API에 의존할 수 없었거든요. 조사 결과 Ollama가 LLaMA 모델을 로컬에서 실행하기에 가장 안정적이고 사용하기 쉬웠습니다. 여러 임베딩을 테스트해봤는데, nomic-embed-text가 기술 문서에서 가장 좋은 성능을 보였어요.

다음은 RAG 엔진이 필요했습니다. 문서 인덱싱, 임베딩 생성, 벡터 데이터베이스 저장, 쿼리 처리를 조율해줄 도구였죠. 아무리 빠른 언어 모델이 있어도, 관련 정보를 찾아낼 수 없다면 소용없으니까요.

책의 색인을 생각해보면 쉽습니다. 색인이 없으면 처음부터 끝까지 읽어야 하지만, 좋은 색인이 있으면 바로 해당 페이지로 갈 수 있잖아요. 이 과정을 간단히 "인덱싱"이라고 부르겠습니다 (실제론 벡터화와 인덱싱 과정입니다).

조사 결과 LlamaIndex라는 성숙한 오픈소스 프레임워크를 찾았습니다.

프로그래밍 언어는 Python을 선택했어요. 여러 이유가 있지만, 제가 Python으로 가장 편하고 생산성 있게 작업할 수 있다는 게 가장 큰 이유입니다. 게다가 Ollama와 LlamaIndex 모두 뛰어난 Python SDK를 제공하고 있었습니다.

이제 개발을 시작할 준비가 됐다고 생각했어요. 처음 스크립트를 짜서 RAG 시스템으로 간단한 테스트를 해봤는데, 정말 적은 코드로도 잘 작동했습니다. "몇 주면 끝낼 수 있겠네"라고 생각했죠. 정말 틀렸어요.

문제 2: 혼란스러운 문서 상태

다음은 실제 문서를 다루는 단계였습니다. 여기서부터 말이에요.

Azure 폴더에는 엄청난 양의 기술 문서가 있었어요. 수백 GB, 수천 개 파일, 여러 포맷, 폴더 구조 이외엔 조직이 전혀 없었습니다. 모든 데이터 엔지니어의 악몽이죠 (농담입니다).

팔을 걷어붙이고 RAG 출력을 디스크로 저장하게 한 뒤 첫 번째 스크립트를 실행했습니다. 그런데 LlamaIndex가 몇 분 안에 제 노트북의 RAM을 가득 채웠고, OS가 먹통이 되어버렸어요. 아무리 설정을 만지고, 캐싱 시스템을 시도해도 결국 항상 같은 결과였습니다.

원인을 찾아봤더니 문제는 엄청 큰 파일들이었어요. 비디오, 시뮬레이션, 백업 파일 같은 것들인데, RAG 시스템에 아무 도움이 안 되는 것들이었죠. 그런데 LlamaIndex는 이걸 마치 텍스트처럼 처리하려고 했어요. GB 단위의 파일은 처리하기 위해 통째로 메모리에 로드되는데, 이는 자살 행위나 다름없었습니다.

파이프라인에 필터링 시스템을 추가했습니다. 파일 확장자와 이름 패턴으로 제외할 파일들을 정의한 거죠.

카테고리제외 확장자
비디오mp4, avi, mov, mkv, wmv, flv, webm, m4v, mpg, mpeg, 3gp, mts...
이미지jpg, jpeg, png, gif, bmp, tiff, svg, ico, webp, heic, psd...
실행 파일exe, dll, msi, bat, sh, app, dmg, so, jar...
압축 파일zip, rar, 7z, tar, gz, bz2, xz
시뮬레이션sim, dat
임시 파일tmp, temp, cache, log, swp, pyc, crdownload, partial...
백업bak, 3dmbak, dwgbak, dxfbak, pdfbak, stlbak, old, bkp, original...
이메일msg, pst, eml, oft

처리 비용이 높으면서 가치가 없는 CSV, JSON 같은 파일도 제거했습니다. 반대로 PDF, DOCX, XLSX, PPTX 같은 파일들은 평문으로 변환해서 LlamaIndex가 문제없이 처리할 수 있게 했어요.

결과는 인상적이었습니다. 인덱싱 대상 파일이 54% 줄어들었어요. 당연히 RAM도 더 이상 터지지 않았습니다.

드디어 안심하고 인덱싱을 시작할 수 있었어요.

문제 3: 451GB 문서를 인덱싱하기

RAG에서는 문서 임베딩을 포함한 벡터 인덱스 파일을 만들어야 합니다. 벡터는 문서의 수치적 표현으로, 문서들 간의 유사성을 측정할 수 있게 해줍니다. LlamaIndex는 이 과정을 자동화해주지만, 451GB를 인덱싱하는 건 또 다른 도전이었어요.