
RAG 시스템을 구축하다 보면, 문서의 전체적인 맥락을 관통하는 거대하고 추상적인 질문에 부딪히게 됩니다.
"이 회사의 올해 사업 전략을 요약해 줘" 같은 질문이 대표적입니다.
기존의 단순 청크 분할 방식으로는 이러한 하이레벨 질문에 답하기 어렵다 보니, 이를 해결하기 위한 대안으로 랩터 알고리즘이 자주 거론됩니다.
구조만 보면 랩터는 매우 그럴싸해 보입니다.
하지만 이 기술을 그대로 실무 프로덕션에 도입하면 높은 확률로 실패를 맛보게 됩니다.
왜 랩터가 현실의 기업 데이터에서 제대로 작동하지 않는지, 학습을하기 위해서 포스팅하게되었습니다.
랩터의 핵심 아이디어는 '청크들을 군집화 하고 요약하여 트리 구조의 계층적 임베딩을 만들자'는 것입니다.
구체적인 작동 방식은 데이터 구축 시점과 사용자 질의 시점으로 나뉩니다.
기본 청크 및 임베딩 생성: 원본 문서를 스플릿하여 수많은 청크로 쪼개고, 각 청크의 임베딩을 생성합니다.
이 기본 청크들을 트리의 최하단인 '터미널 리프 노드'라고 부릅니다.
차원 축소: 임베딩 모델이 뱉어낸 고차원 벡터를 계산 효율성을 위해 유맵 알고리즘을 사용해 5차원 또는 2차원 수준으로 대폭 축소합니다.
군집화: 축소된 저차원 벡터들을 바탕으로 서로 유사한 청크들끼리 묶어 그룹을 만듭니다.
LLM 기반 요약 및 재임베딩: 하나의 클러스터에 모인 청크들의 텍스트를 모아서 LLM에게 전달합니다.
"이 데이터들을 요약해 봐"라고 요청하여 요약문을 생성한 뒤, 이 요약문으로 다시 임베딩 벡터를 만듭니다. 이 요약본 임베딩이 바로 상위의 부모 노드가 됩니다.
재귀적 반복: 생성된 부모 노드들을 대상으로 다시 차원 축소와 군집화, 요약을 반복하여 최상위 노드가 만들어질 때까지 거대한 계층적 트리를 쌓아 올립니다.
사용자가 질문을 던지면 시스템은 트리 전체의 임베딩과 유사도를 비교합니다.
사용자가 추상적이고 포괄적인 질문을 던지면, 트리의 상위에 있는 '요약본 부모 노드'의 임베딩과 유사도가 높아져 거시적인 답변을 얻습니다.
사용자가 구체적이고 상세한 질문을 던지면, 트리의 바닥에 있는 '원본 청크'의 임베딩과 유사도가 높아져 세부적인 답변을 얻습니다.
여기서 더 나아가 최상위 부모 노드부터 검색한 뒤 관련 있는 자식 노드로 좁혀 내려가는 드릴다운 방식을 쓰거나, 다중 벡터 스토어, 셀프 쿼리 등과 결합하여 응용하기도 합니다.
이론은 완벽해 보이지만, 현실의 기업 데이터는 랩터가 가정하는 것처럼 아름답지 않습니다.
첫 번째 복병은 상이한 컨텍스트를 가진 데이터들이 하나의 클러스터로 뒤섞이는 현상입니다.
임베딩 모델은 문장의 의미론적 구조에 기반하여 벡터 숫자를 생성합니다.
예를 들어 하나의 문서 안에 '한국의 역사' 장과 '일본의 역사' 장이 공존한다고 가정해 봅시다.
문서를 쪼개다 보면 다음과 같은 청크들이 발생할 수 있습니다.
두 문장은 역사적 배경과 컨텍스트가 완전히 다릅니다.
하지만 '지배자의 죽음'이라는 시면틱 구조가 매우 유사하기 때문에, 임베딩 벡터를 만들어 군집화를 수행하면 두 청크는 같은 클러스터 묶음으로 기어 들어가게 됩니다.
이렇게 컨텍스트가 다른 청크들이 한 그룹으로 묶이면, LLM이 이를 모아 요약할 때 한국 역사와 일본 역사가 뒤죽박죽 섞인 아무짝에도 쓸모없는 혼종 요약문이 탄생합니다.
이를 막으려면 데이터를 넣을 때 "여기서부터 여기까지는 한국 역사 영역이니 다른 데이터와 섞지 마라"와 같이 명확한 컨텍스트 격벽을 쳐야 합니다.
그러나 현실 실무에서는 파이프라인을 통해 수많은 문서가 자동으로 슬라이싱되어 들어옵니다.
결국 사람이 일일이 개입해서 수동으로 문서를 분류하고 경계를 지정해 주어야 한다는 의미인데, 이는 대용량 데이터를 다루는 자동화 시스템에서 실상 불가능에 가깝습니다.
만약 원본 문서 자체가 '세종대왕의 일대기'처럼 단일한 주제와 정합된 컨텍스트만 다루고 있다면 역사적 내용과 경제적 내용이 섞여 요약되어도 무방합니다.
어차피 세종대왕이라는 하나의 큰 바운더리 안에 있으니까요. 하지만 온갖 비즈니스 맥락이 뒤섞인 기업용 문서에서는 이 컨텍스트 분리 실패로 인해 트리의 상부 노드 전체가 오염됩니다.
기업 내부 데이터나 크롤링한 뉴스 기사 데이터를 다루다 보면 가장 흔하게 발생하는 문제가 바로 유사 시멘틱 구조의 무한 반복입니다.
소위 '기레기'라 불리는 양산형 기사나 기업의 정형화된 보고서, 관계형 데이터베이스의 테이블을 그대로 문장으로 치환한 데이터들을 보면 문장의 구조가 완전히 판박이인 경우가 많습니다.
이 데이터들은 주어와 숫자 같은 명사만 바뀔 뿐, 전체적인 문장 구조가 똑같습니다.
임베딩 모델에 이를 넣으면 벡터 값이 거의 동일하게 나옵니다.
구조가 똑같으니 이 청크들은 하나의 클러스터로 강력하게 결합합니다.
문제는 그다음 단계인 LLM 요약입니다.
LLM이 이 엇비슷한 구조의 문장들을 모아서 요약하면, 알맹이인 구체적인 기업 정보나 수치들은 증발하고 "여러 기업들의 2026년 1분기 실적 수치에 대한 내용이다"라는 껍데기만 남은 무의미한 요약문이 만들어집니다.
클러스터링은 성공했을지언정 그 결과물인 부모 노드가 아무런 정보 가치를 가지지 못하므로, 계층적 트리 구조 전체가 통째로 무력화됩니다.
텍스트의 정교한 다양성이 확보되지 않은 기업용 데이터 환경에서 랩터가 무용지물이 되는 결정적인 이유입니다.
랩터가 실무에서 망가지는 가장 근본적이고 치명적인 원인은 학습 알고리즘의 손실 함수와 군집화 알고리즘 간의 수학적 모순에 있습니다.
이 메커니즘은 다소 복잡하므로 원리부터 상세히 짚어보겠습니다.
우리가 사용하는 대부분의 임베딩 모델은 훈련될 때 '긍정 쌍'과 '부정 쌍'의 의미론적 유사도를 비교하며 학습합니다.
이때 역전파와 그래디언트 미분을 통해 모델 내부의 숫자들이 조정되는 기준, 즉 손실 함수가 코사인 유사도로 설계되어 있습니다.
임베딩 모델의 출력값인 벡터 숫자는 고유의 절대적인 의미를 지닌 값이 아닙니다.
오직 "이 벡터와 저 벡터를 코사인 유사도 함수로 계산했을 때, 의미가 비슷하면 높은 값이 나오고 다르면 낮은 값이 나오도록" 최적화되어 짜인 결과물일 뿐입니다.
벡터 DB에서 임베딩 검색을 할 때 코사인 유사도를 필수로 사용해야 하는 이유도, 코사인 유사도가 특별히 대단한 함수여서가 아니라 애초에 모델이 그렇게 태어났기 때문입니다.
임베딩 벡터는 오직 코사인 유사도 공간 안에서만 의미론적 정당성을 가집니다.
그런데 랩터 알고리즘은 계산 비용을 줄이겠다는 이유로, 이 고차원 벡터를 유맵을 통해 5차원이나 2차원으로 축소해 버립니다.
유맵은 고차원 공간에 존재하는 데이터 포인트들 간의 상대적인 위상적 거리 관계만을 보존하면서 차원을 환원하는 알고리즘입니다.
유맵을 거치고 나면 다음과 같은 비극이 발생합니다.
그나마 데이터 시각화 용도로 플로팅할 때는 거리가 한눈에 보이니 유용할지 몰라도, 의미론적 연산을 이어가야 하는 RAG 파이프라인에서는 치명타입니다.
더 큰 문제는 유맵이 정해진 데이터 집합 안에서의 상대적 관계만을 계산한다는 점입니다. 예를 들어 A, B, C 세 명의 관계를 분석해 유맵 공간을 만들어 놨다고 한다면
그런데 내일 새로운 PDF 문서가 입력되어 D라는 새로운 청크가 들어오면 어떻게 될까요? D는 기존에 만들어진 유맵 좌표계에 녹아들 수 없습니다.
D를 포함한 전체 데이터셋을 가지고 처음부터 유맵 축소를 다시 계산해야 합니다.
데이터가 추가될 때마다 매번 전체 차원 축소와 전체 클러스터링을 새로 해야 하는 미션 크리티컬한 부하가 발생합니다.
차원이 축소되어 코사인 유사도를 쓸 수 없게 되니, 랩터 구현체들은 클러스터링을 할 때 K-Means나 GMM 알고리즘을 사용합니다.
K-Means: 화면 좌표상의 유클리드 거리를 기준으로 점들이 가까이 있으면 묶어버리는 방식입니다.
GMM: 데이터가 정규분포를 따르고 있을 것이라는 가정하에 확률적으로 군집 경계를 설정하는 방식입니다.
여기서 심각한 수학적 왜곡이 생깁니다.
물론 수학적으로 100차원 이상의 초고차원 공간에서 벡터가 정규화되어 있다면, 유클리드 거리가 가까운 것과 코사인 각도가 가까운 것은 대략 비슷한 결과로 수렴합니다.
내적 연산과 거리 연산이 비등해지기 때문입니다.
하지만 우리는 앞에서 유맵을 통해 차원을 아주 낮게 조져놓은 상태입니다.
저차원 공간에서의 유클리드 거리는 원래 고차원 임베딩 모델이 의도했던 코사인 각도와 아무런 상관관계가 없습니다.
코사인 유사도로는 완전히 반대 방향에 있는 의미의 문장이, 저차원 유클리드 공간에서는 가깝다는 이유로 하나의 클러스터로 묶이는 대참사가 일어납니다.
또한 GMM이 요구하는 '청크 임베딩이 정규분포를 따를 것'이라는 가정 역시 현실에선 성립하지 않습니다.
실제 비즈니스 청크들은 날씨, 법률, 재무 등 극단적으로 튀는 도메인 파편들로 구성되어 있어 정규분포 곡선으로 이쁘게 정렬되지 않습니다.
결국 엉터리 기준으로 군집화가 묶이게 되는 것입니다.
그렇다면 임베딩의 성질을 온전히 지키면서 군집화를 할 방법은 정녕 없는 걸까요? 당연히 있습니다. 바로 계층적 병합 군집화 알고리즘을 사용하는 것입니다.
HAC 알고리즘의 핵심은 군집 기준 연산에 코사인 유사도를 직접 사용할 수 있다는 점입니다. 임베딩 차원을 구태여 유맵으로 축소하여 파괴하지 않고, 원래의 고차원 벡터 상태 그대로 코사인 유사도가 높은 녀석들끼리 계단식으로 묶어 올라가는 방식입니다.
이 방식만이 임베딩 모델의 출생 원리와 완벽하게 부합하는 정석적인 군집화입니다.
| 군집화 방식 | 차원 축소 여부 | 핵심 연산 기준 | 임베딩 정합성 | 실무 데이터 적용 적합성 |
|---|---|---|---|---|
| 일반적인 랩터 (UMAP + K-Means/GMM) | 필요 | 유클리드 거리 / 정규분포 확률 | 파괴됨 | 매우 낮음 |
| 정석적인 계층 군집 | 불필요 | 코사인 유사도 | 보존됨 | 높음 |
과거에는 모든 임베딩 간의 코사인 유사도를 전수 비교해야 하는 HAC의 연산 비용이 지나치게 비싸서 기피되기도 했습니다.
하지만 자본과 컴퓨팅 자원이 충분한 현대의 엔터프라이즈 환경이라면, 랩터의 유맵 알고리즘을 쓰느니 고차원 고정 상태에서 HAC를 돌려 격벽을 치는 것이 백번 안전합니다.
랩터 논문을 읽어보면 기존 RAG 대비 검색 향상도가 매우 높다고 찬사를 늘어놓습니다.
하지만 벤치마크에 사용된 그 데이터셋들을 뜯어보면, 컨텍스트가 완벽하게 통제되어 있고 유맵-K-Means를 먹여도 코사인 유사도와 기가 막히게 일치하도록 정교하게 정제된 '실험실 전용 데이터'들입니다.
현실의 거친 비즈니스 데이터, 포맷이 반복되는 데이터, 컨텍스트가 혼재된 문서들을 랩터 파이프라인에 밀어 넣으면 계층 구조 자체가 거대한 쓰레기통으로 변합니다.
현업에서 거시적인 질의 구조를 해결하고 싶다면, 수학적 모순 덩어리인 랩터를 무작정 도입하기보다 다음 사항을 먼저 검토하시길 권장한다고 합니다.
유행하는 논문의 알고리즘이라고 해서 덥석 구현체 코드를 가져다 쓰기 전에, 그 밑바닥에 흐르는 벡터의 수학적 원리를 먼저 짚어보는 것이 실패하지 않는 RAG 서비스를 만들수있다 생각합니다.