회사에서 M365 Copilot을 쓴다. 내 OneDrive와 SharePoint에 수년 치 리서치 리포트, 회의록, 분석 자료가 쌓여 있다. 어느 날 Copilot에게 "작년 Q3에 우리가 추정한 시장 규모가 어디 있지?"라고 물었다. 가져온 답은 엉뚱한 문서의 요약이었다. 똑같은 모델을 쓰는 데도 chat에서 직접 물어보는 것보다 결과가 한참 빈약했다.
문제는 모델이 아니다. 내 자료가 방대한 탓에 검색 자체가 안 되는 것이다. 아무리 좋은 LLM도 찾지 못한 정보를 생성할 수는 없다. 그러면 어떻게 해야 하는가. 검색 시스템 자체를 진화시켜야 한다. 회사 보고서 검색을 Text RAG에서 GraphDB까지 4단계로 키우는 로드맵을 정리했다.
Phase 1: Text RAG — 기본기부터
첫 단계는 전통적인 RAG다. 보고서 PDF를 파싱해서 텍스트 청크로 나누고, 각 청크를 임베딩해서 벡터 DB에 저장한다. 질문이 들어오면 의미적으로 가까운 청크를 찾아 LLM 컨텍스트로 넘긴다. 화려하지 않지만, 없으면 아무것도 시작되지 않는다.
기술 스택은 명확하다. PyMuPDF로 PDF를 파싱하고, BGE-m3 같은 다국어 임베딩 모델로 청크를 벡터화하고, ChromaDB나 Qdrant에 저장한다. 한국어 보고서가 주력이므로 임베딩 모델 선택이 중요하다. 영어 특화 모델을 쓰면 "시장 규모"와 "market size"를 다른 것으로 인식한다. chunk size는 512 토큰, overlap은 64 정도가 무난하다. LlamaIndex나 LangChain으로 파이프라인을 묶고, 프론트엔드에서 질문을 받으면 백엔드에서检索 → LLM 생성 → 답변 + 출처를 반환하는 구조다.
Phase 1만 구축해도 즉각적 효과가 있다. "작년 리서치에서 언급된 시장 규모 찾아줘" 같은 질문에 답할 수 있다. 출처 페이지도 표시된다. 하지만 한계가 명확하다. 보고서에 있는 표, 차트, 다이어그램의 시각 정보는 사라진다. 텍스트로만 추출하기 때문이다. 그리고 문서 간 관계를 이해하지 못한다. "A보고서가 인용한 B데이터" 같은 연결이 안 보인다. 단일 프로젝트 안에서는 쓸 만하지만, 자료가 넘쳐나기 시작하면 부족하다. 내 경우는 아직 회사 차원의 도입이 아니라 개인 관심이다. 산업별로 보고서를 모아서 넣어보고 싶다. 리서치 회사에서 일하는 사람으로서, 내가 다루는 산업 리포트들을 내 손으로 검색 가능한 지식 베이스로 만들어보는 게 목표다.
Phase 2: PixelRAG — 텍스트가 놓치는 시각 정보
두 번째 단계에서는 문서를 이미지로도 본다. PDF 각 페이지를 이미지로 렌더링해서 CLIP 기반 모델로 임베딩한다. 텍스트 벡터와 이미지 벡터를 동시에 운영하는 것이다.
회사 보고서를 떠올려보자. 경쟁사 비교 표, 시장 점유율 파이차트, 공급망 다이어그램. 이런 시각 정보가 보고서 가치의 절반 이상이다. 근데 텍스트 RAG는 이걸 다 버린다. 표 안의 숫자를 텍스트로 추출하면 레이아웃이 깨지고, 차트는 아예 사라진다. PixelRAG는 이 문제를 정면으로 공략한다. "경쟁사 비교표가 있는 페이지 찾아줘"라는 질문에 표 이미지 자체를 반환한다.
기술적으로는 JINA-CLIP-v2로 이미지 임베딩을 생성하고, Qdrant에서 텍스트 벡터와 이미지 벡터를 별도 컬렉션으로 관리한다. 검색 시 두 벡터를 동시에 쿼리해서 점수를 융합한다. 이를 하이브리드 검색이라고 부른다. 텍스트가 의미를 잡고, 이미지가 시각을 잡는다. 융합 방법은 Reciprocal Rank Fusion을 쓰면 된다. 각 검색 결과의 순위를 점수화해서 더하는 방식인데, 구현이 간단하면서도 효과가 좋다.
GPT-4o나 Claude 3.5 Sonnet 같은 멀티모달 LLM이 최종 답변을 생성할 때 페이지 스캔 이미지와 텍스트를 함께 읽고 답한다. M365 Copilot이 놓치는 시각 정보를 이렇게 보완할 수 있다. Phase 1에서 "표가 있었는데 숫자가 깨져서 나왔다"는 문제가 Phase 2에서는 사라진다. 페이지 전체 스캔을 LLM이 직접 보기 때문이다.
Phase 3: GraphRAG — 문서 간 관계를 추론하다
Phase 1~2를 구축하면 단일 프로젝트는 꽤 잘 검색된다. 근데 여러 자료가 복합으로 얽히기 시작하면 한계에 부딪힌다. 내가 겪은 M365 Copilot의 문제가 정확히 여기다. 자료가 방대해지면 "이 보고서와 관련된 모든 의사결정 흐름은?" 같은 질문에 답할 수 없다. 텍스트 RAG는 각 문서를 독립적으로 검색한다. 문서 A가 문서 B를 인용하고, B가 프로젝트 C에 영향을 미치는 관계를 추론하지 못한다.
GraphRAG가 이 간극을 메운다. Microsoft가 오픈소스로 공개한 GraphRAG 엔진이 핵심이다. 문서에서 엔티티(사람, 조직, 프로젝트, 개념)와 관계를 LLM으로 자동 추출해서 지식 그래프를 구성한다. 커뮤니티 탐지 알고리즘으로 엔티티들을 주제별로 클러스터링하고, 각 클러스터를 LLM이 요약한다. 질문이 들어오면 로컬 검색(직접 관련 엔티티 중심)과 글로벌 검색(커뮤니티 요약 기반 전체 추론)을 조합해서 답한다.
내 판단으로는, 이 단계가 회사 보고서 검색에서 진짜 전환점이다. Phase 1은 단일 프로젝트 정도를 다루는 데 충분하다. 근데 여러 자료가 복합으로 얽히면 GraphRAG가 필수가 된다. 아직은 탐색 단계지만, 1년 안에 필요해질 것이다. 회사 자료가 쌓이는 속도를 생각하면, 지금부터 아키텍처를 고민하지 않으면 나중에 따라잡기 어려워진다.
Phase 4: GraphDB — 그래프를 영구적으로 저장하다
마지막 단계는 GraphRAG의 결과를 Neo4j 같은 영구 GraphDB로 이관하는 것이다. GraphRAG만 쓰면 그래프가 인메모리에만 존재한다. 새 보고서가 들어올 때마다 다시 구축해야 한다. GraphDB에 저장하면 서버를 재시작해도 관계가 유지되고, 새 데이터가 들어오면 그래프에 증분 추가할 수 있다.
Neo4j에서 Cypher 쿼리로 정밀한 관계 질의가 가능하다. "A부서 리포트가 의존하는 모든 프로젝트"를 쿼리할 수 있고, "가장 많이 인용되는 보고서 Top 10"도 조회할 수 있다. 그래프 기반 추천 — "이 보고서를 읽었다면 이것도 읽어보세요" — 도 자연스럽게 구현된다. 영향력 분석도 가능하다. 특정 프로젝트가 지연되면 어떤 보고서가 영향받는지 그래프를 따라가면 된다.
다만 GraphDB는 스키마 설계가 제일 시간을 잡아먹는다. 노드 타입을 Document, Person, Organization, Project, Concept으로 정의하고, 관계 타입을 MENTIONS, CITES, DEPENDS_ON, INFLUENCES로 설계하는 일이 쉽지 않다. 잘못 설계하면 나중에 전부 갈아엎어야 한다. 그래서 GraphDB는 Phase 3에서 충분히 데이터가 쌓이고, 어떤 엔티티와 관계가 반복적으로 등장하는지 패턴이 보인 뒤에 추가하는 것이 안전하다.
나는 산업별로 보고서를 먼저 모으고 있다. Phase 1부터 차근차근 쌓아올릴 생각이다. 당장 전부 구축하려 하지 않고, 하나씩 만들어보면서 이 경험이 다음 단계 설계에 녹아들게 하려는 거다. 전체 로드맵은 약 10~13주 예상이다.
1년 안에 회사 보고서 검색이 지금과 완전히 다른 모습이 될 수 있다. M365 Copilot이 내 자료를 못 찾는 건 Copilot의 한계가 아니라, 검색 인프라의 한계다. 내 자료를 내가 통제하는 검색 시스템 위에 올리면, 같은 모델이라도 결과가 달라진다. 검색 품질이 LLM 품질을 결정하는 시대에, 인프라를 직접 설계한다는 건 곧 답의 품질을 직접 설계한다는 뜻이다.