대부분의 팀은 여전히 첫 번째 검색 파이프라인을 같은 방식으로 구축합니다. 512개 정도의 고정된 토큰 제한을 정하고, 문서를 균일한 블록으로 나눈 뒤, 그 블록들을 벡터 데이터베이스에 입력합니다. 간단한 질문이 포함된 작은 데이터셋에서는 이 방식이 마법처럼 보일 수 있습니다. 하지만 실제 운영 환경에서는 무너집니다.

법률 계약서는 조항이 문장 중간에서 잘리면 의미 없는 파편으로 찢어집니다. API 문서는 하나의 청크가 서로 관련 없는 세 개의 함수를 한꺼번에 삼켜버리면 노이즈 섞인 엉망진창인 상태가 됩니다. 고객 지원 티켓은 세그먼트 간의 중첩(overlap)이 없으면 서사의 흐름을 모두 잃어버립니다. 결과는 뻔합니다. 지연 시간(latency)은 늘어나고, 재현율(recall)은 떨어지며, 생성 모델이 환각(hallucination)을 일으키게 만드는 답변이 나옵니다.

우리는 검색 레이어를 완전히 해체하고 다시 구축했습니다. 그 결과 재현율은 78%에서 95%로 급증했고, 지연 시간은 62% 단축되었으며, 파이프라인은 마침내 주말에 급하게 만든 임시방편(weekend hack)이 아닌 실제 인프라처럼 작동하게 되었습니다. 실제로 효과가 있었던 방법들을 소개합니다.

스마트 청킹: 토큰보다 구조가 우선이다

첫 번째 실수는 모든 문서가 동일한 언어로 작성되었다고 가정하는 것입니다. 512토큰 청크는 서사적인 산문에는 적합할지 모르나, 그 외의 경우에는 거의 쓸모가 없습니다. 우리는 소스 문서의 구조(anatomy)를 존중하는 전략으로 전환했습니다.

법률 문서의 경우, 재귀적 청킹(recursive chunking)을 사용합니다. 알고리즘은 먼저 섹션이나 조항(article)과 같은 상위 경계에서 분할을 시도합니다. 섹션이 여전히 너무 길면 하위 섹션, 단락, 문장 순으로 찾아 들어갑니다. 이를 통해 조항의 논리적 계층 구조를 보존할 수 있습니다. 경업 금지 약정(non-compete agreement)이 온전하게 유지되며, 정의(definitions) 부분이 배상(indemnity) 조항으로 흘러 들어가지 않습니다.

API 문서는 구조 인식 청킹(structure-aware chunking)이 필요합니다. 함수 시그니처, 파라미터 테이블, 그리고 예시 요청은 함께 있어야 합니다. 고정된 토큰 수에 따라 나누면 파라미터는 한 청크에, 예시는 다른 청크에 남는 경우가 많습니다. 대신 우리는 문서 객체 단위로 청킹합니다. 하나의 청크가 완전한 엔드포인트나 단일 함수를 담도록 합니다. 그러면 검색기가 질문에 실제로 답할 수 있는 독립적인 참조 정보를 반환할 수 있습니다.

고객 지원 티켓은 자연스럽게 의미론적 청킹(semantic chunking)에 적합합니다. 토큰 경계에서 자르는 대신, 주제가 바뀌는 지점을 감지합니다. 로그인 불만으로 시작해 결제 질문으로 전환되는 티켓은 두 개의 일관된 조각으로 나뉩니다. 각 조각은 필요한 메타데이터를 포함하므로, 모델이 사용자가 실제로 어떤 문제에 관심을 두고 있는지 추측할 필요가 없습니다.

내부 위키는 더 복잡합니다. 산문, 표, 다이어그램, 임베디드 스레드가 뒤섞여 있습니다. 이런 경우에는 에이전틱 청킹(agentic chunking)을 사용합니다. 소형 언어 모델(SLM)이 내용을 미리 읽고 주제적으로 완결된 단위가 어디서 끝나는지 결정합니다. 데이터 수집(ingestion) 단계에서 비용은 조금 더 들지만, 새로운 페이지 형식마다 규칙을 수동으로 조정해야 하는 번거로운 작업을 없애줍니다.

하이브리드 검색: 모든 가능성을 고려하라

벡터 검색은 모호한 의미를 포착하는 데 탁월합니다. 업로드 속도에 대해 물으면 지연 시간(latency)과 대역폭(bandwidth)에 관한 단락을 기꺼이 반환합니다. 하지만 정확한 일치(exact match)를 처리하는 데는 취약하기로 유명합니다. 개발자가 에러 코드 ERR_CONNECTION_REFUSED를 검색하면, 밀집 임베딩(dense embeddings)은 이를 일반적인 노이즈로 취급하는 경우가 많습니다.

고전적인 키워드 알고리즘인 BM25는 그 반대 역할을 합니다. 정확한 문자열과 희귀 용어는 잘 잡아내지만, 의미론적 뉘앙스는 놓칩니다. 계약 체결(signing the agreement)에 관한 쿼리가 계약 실행(executing the contract)으로 태그된 콘텐츠를 찾아내지 못할 수도 있습니다.