키워드 검색이 사내 문서에서 실패하는 이유와 AI 검색

왜 사내 검색은 유독 잘 안 되는가

사내 문서 검색이 구글 검색보다 체감상 훨씬 나쁘다고 느끼는 분들이 많습니다. 이유는 검색 엔진의 성능 차이가 아니라 데이터와 질의의 성격 차이입니다. 사내 문서는 부서마다 용어가 다르고(“연차 이월”과 “미사용 휴가 이연”이 같은 제도를 가리키는 식), 약어와 프로젝트 코드명이 섞여 있으며, 최신 버전과 구버전 문서가 함께 색인됩니다. 이런 환경에서 전통적인 키워드 검색이 어디서 어떻게 실패하는지, 그리고 왜 벡터 검색을 도입한다고 문제가 자동으로 풀리지 않는지를 실무 관점에서 정리합니다.

키워드 검색(BM25)의 한계는 알고리즘이 아니라 어휘 불일치입니다

대부분의 사내 검색 시스템은 여전히 역색인(inverted index) 기반의 BM25 알고리즘을 사용합니다. BM25 자체는 20년 넘게 검증된 안정적인 알고리즘이고, 문제는 알고리즘이 아니라 “질의어와 문서에 쓰인 단어가 정확히 일치해야 찾아진다”는 근본 가정입니다. 사용자가 “연차 이월 규정”을 검색했는데 인사 규정 문서에는 “미사용 연차의 익년도 이연 처리”라고 쓰여 있다면, 두 표현의 의미는 같지만 문자열은 다르므로 BM25는 이 문서를 낮은 순위로 매기거나 아예 찾지 못합니다. 한국어 특유의 조사·어미 변화, 띄어쓰기 편차, 동의어·약어 문제까지 겹치면 형태소 분석기를 아무리 잘 튜닝해도 어휘 불일치 문제 자체는 해결되지 않습니다.

구분 키워드 검색 (BM25) 의미 검색 (벡터/임베딩)
매칭 기준 정확한 단어·형태소 일치 의미적 유사도(임베딩 거리)
동의어·다른 표현 인식하지 못함 유사한 벡터로 인식 가능
정확한 코드명·번호 정확히 찾음 오히려 놓치거나 유사 항목과 혼동
연산 비용 낮음, 실시간 색인 갱신 용이 임베딩 생성·벡터DB 운영 비용 발생
결과 설명 가능성 매칭된 단어를 보여주기 쉬움 왜 유사한지 설명하기 어려움

한국어 형태소 분석이 특히 까다로운 이유

영어는 공백으로 토큰이 대체로 구분되지만, 한국어는 조사·어미가 어간에 결합되면서 같은 단어가 표면형만 수십 가지로 달라집니다(“검색은”, “검색이”, “검색을”, “검색하며” 등). 형태소 분석기(Mecab, Kkma, Komoran 등)를 도입해도 신조어·전문용어·프로젝트 코드명은 사전에 없어 잘못 분리되는 경우가 흔합니다. 사내 검색 품질 개선 프로젝트에서 형태소 분석기 사용자 사전에 부서 용어·프로젝트명·약어를 직접 등록하는 작업이 의외로 큰 비중을 차지하는 이유입니다.

하이브리드 검색이 실제로 하는 일

“벡터 검색으로 바꾸면 해결된다”는 것도 절반만 맞는 이야기입니다. 벡터 검색은 의미적 유사도는 잘 잡지만, 정확한 코드명·문서번호·법령 조항 번호 같은 정확 매칭에는 오히려 키워드 검색보다 약합니다. 그래서 실무에서는 둘을 함께 쓰는 하이브리드 검색을 씁니다.

# 의사코드: BM25와 벡터 검색 결과를 RRF(Reciprocal Rank Fusion)로 결합
def hybrid_search(query, k=60):
    bm25_results = bm25_search(query)            # [(doc_id, rank), ...]
    vector_results = vector_search(embed(query))  # [(doc_id, rank), ...]

    scores = {}
    for rank, (doc_id, _) in enumerate(bm25_results):
        scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank + 1)
    for rank, (doc_id, _) in enumerate(vector_results):
        scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank + 1)

    return sorted(scores.items(), key=lambda x: x[1], reverse=True)

RRF는 두 검색 방식의 절대 점수를 직접 비교하지 않고 순위(rank)만 사용해 결합합니다. BM25 점수와 코사인 유사도는 스케일이 완전히 다르기 때문에 점수를 직접 더하면 한쪽이 결과를 지배하는데, RRF는 이 문제를 순위 기반 결합으로 우회합니다. 이후 결합된 상위 후보를 재순위화(reranking) 모델에 다시 통과시켜 최종 순서를 정하는 3단계 구조가 실무에서 가장 흔히 쓰입니다.

벡터 DB 선택 — 무엇을 기준으로 골라야 하는가

사내 검색 규모(문서 수, 동시 사용자 수, 갱신 빈도)에 따라 적합한 벡터 저장소가 달라집니다.

옵션 강점 고려할 점
pgvector (PostgreSQL 확장) 기존 RDB 인프라 재사용, 운영 부담 최소 대규모(수천만 벡터 이상)에서는 전용 벡터DB 대비 성능 열위
Milvus / Qdrant 등 전용 벡터DB 대규모 ANN 검색에 최적화, 필터링·샤딩 기능 풍부 별도 운영 인력·인프라 필요
관리형 SaaS (Pinecone 등) 운영 부담 없음, 빠른 도입 사내 문서를 외부 서비스에 올려야 하므로 데이터 반출 정책 검토 필수

사내 문서는 보안 등급이 있는 경우가 많아, 외부 SaaS형 벡터DB를 쓸 때는 데이터가 실제로 어느 리전에, 어떤 암호화 방식으로 저장되는지를 보안팀과 먼저 확인해야 합니다.

구현에서 실제로 결과 품질을 좌우하는 것

알고리즘보다 먼저 걸리는 것은 청킹(chunking) 전략입니다. 문서를 몇 토큰 단위로 잘라 임베딩할지에 따라 검색 품질이 크게 달라집니다. 너무 잘게 자르면 문맥이 끊겨 의미 검색이 오히려 부정확해지고, 너무 크게 자르면 하나의 청크에 여러 주제가 섞여 임베딩이 흐려집니다. 표와 목록이 많은 사내 규정 문서는 특히 청킹 경계에서 표가 잘리면 검색도, 이후 LLM 답변 생성도 함께 망가집니다. 또한 임베딩 모델을 한 번 정하고 색인을 만든 뒤 모델을 교체하면 기존 벡터와 새 벡터가 같은 공간에 있지 않으므로 전체 재색인이 필요합니다. 이 재색인 비용을 과소평가해서 임베딩 모델을 가볍게 바꾸는 경우가 실무에서 자주 문제를 일으킵니다.

청킹 전략 비교

방식 설명 적합한 문서 유형
고정 길이 청킹 토큰 수 기준으로 균등 분할, 일부 겹침(overlap) 부여 구조가 단순한 일반 텍스트 문서
구조 기반 청킹 제목·소제목·표 경계를 기준으로 분할 규정집, 매뉴얼처럼 계층 구조가 뚜렷한 문서
의미 기반 청킹 문장 임베딩 유사도 변화 지점을 경계로 분할 주제 전환이 잦은 회의록, 자유 서술 보고서

검색 품질을 숫자로 확인하는 법 — 평가 지표

“체감상 좋아진 것 같다”는 검색 품질 개선 프로젝트에서 가장 위험한 문장입니다. 최소한 다음 세 가지 지표는 골든셋 기준으로 정기 측정해야 합니다.

  • Recall@k: 상위 k개 결과 안에 정답 문서가 포함된 비율. 사내 검색에서는 k=5 또는 k=10 기준이 흔합니다.
  • MRR(Mean Reciprocal Rank): 정답 문서가 몇 번째 순위에 나왔는지의 역수 평균. 정답이 1위에 가까울수록 값이 높습니다.
  • NDCG(Normalized Discounted Cumulative Gain): 정답 문서의 순위뿐 아니라 관련도 등급까지 반영한 지표로, 복수의 관련 문서가 있는 질의에 적합합니다.

이 지표들을 임베딩 모델 교체, RRF의 k 파라미터 조정, 리랭커 도입 전후로 비교해야 “좋아졌다”는 주장이 근거를 갖습니다.

한계와 제언

하이브리드 검색을 도입해도 근본적으로 해결되지 않는 문제가 있습니다. 검색이 아무리 정확해도 원본 문서 자체가 오래되었거나 상충되는 내용을 담고 있으면 잘못된 답을 그대로 찾아줄 뿐입니다. 검색 품질 개선 프로젝트를 시작하기 전에 문서 정합성 정리가 선행되지 않으면, 검색 시스템만 고도화하고 실제 사용자 만족도는 크게 개선되지 않는 경우를 여러 번 봤습니다. 또한 재순위화 모델과 임베딩 API 호출이 늘어나면 응답 지연이 커지므로, 실시간성이 중요한 서비스라면 캐싱 전략과 함께 설계해야 합니다. 검색 시스템 하나만 바꾸는 프로젝트가 아니라, 문서 거버넌스와 함께 가는 프로젝트로 범위를 잡는 것을 권장합니다.

권한 필터는 검색 뒤에 붙이면 늦다

하이브리드로 상위 20개를 뽑은 뒤 권한을 걸면, 화면에 3개만 남거나 빈 칸이 됩니다. 사용자는 “검색이 죽었다”고 느낍니다. 부서·등급·문서 상태는 색인 메타에 넣고, 검색 쿼리 단계에서 필터합니다. 생성 단계의 시스템 프롬프트에 “비밀은 말하지 마”를 적어 두는 것은 통제가 아닙니다.

질의 유형 먼저 살릴 축 실패 예
부품번호·조항 번호 BM25·정확 토큰 임베딩만 켜서 유사 번호가 올라옴
제도·취지 질문 밀집 + 리랭크 키워드만 써서 동의어를 놓침
표가 본문인 규정 청크를 표 단위로 행이 잘려 조항이 다른 청크에 붙음

골든셋 없이 모델을 바꾸지 않는다

사내 검색의 정답은 MTEB 1등이 아닙니다. 현장 질의 50~100개를 모아, 기대 문서 ID와 조항을 적습니다. 임베딩을 바꾸거나 RRF k를 바꾸면 이 셋의 재현율만 보고 승인을 냅니다. 데모 질의 다섯 개로 “좋아졌다”고 하면, 다음 주 현업 질의에서 부품번호가 빠집니다.

리랭크는 상위 3~5개에만 씁니다. 20개에 교차 인코더를 올리면 지연이 검색 본체를 넘습니다. 캐시는 질의 정규화(공백·대소문자·조사) 키로 걸고, 권한 세션이 다른 사용자는 같은 캐시를 보지 못하게 합니다. 검색 프로젝트를 검색 엔진 교체로만 잡으면, 구버전 규정과 신설 규정이 같이 답으로 나옵니다. 유효일 필드가 없는 색인은 고도화가 아니라 오염입니다.

도입 로드맵 — 어디서부터 시작할 것인가

  1. 1단계: 현장 질의 50~100개로 골든셋을 만들고, 현행 키워드 검색의 Recall@5를 측정해 베이스라인을 확정합니다.
  2. 2단계: 문서 청킹 전략을 확정하고, 소규모 파일럿(한 부서·한 문서군)에서 하이브리드 검색을 구축합니다.
  3. 3단계: 골든셋 기준으로 Recall@k, MRR을 측정해 베이스라인 대비 개선폭을 확인합니다.
  4. 4단계: 권한 필터를 색인 메타 단계에 통합하고, 부서별 확대 적용 전 보안 검토를 거칩니다.
  5. 5단계: 문서 유효일·버전 관리 체계를 정비해 구버전 문서가 검색 결과를 오염시키지 않도록 합니다.

Takeaway

  • 사내 검색이 나쁜 근본 원인은 알고리즘이 아니라 부서·문서마다 다른 용어로 인한 어휘 불일치입니다.
  • 벡터 검색은 의미적 유사도에 강하지만 정확한 코드명·번호 매칭에는 키워드 검색보다 약할 수 있습니다.
  • RRF로 결합한 뒤 재순위화 모델을 거치는 3단계 하이브리드 구조가 실무 표준에 가깝습니다.
  • 청킹 전략과 문서 정합성 정리가 선행되지 않으면 검색 알고리즘을 아무리 고도화해도 체감 품질은 크게 개선되지 않습니다.
  • Recall@k, MRR, NDCG 같은 지표로 골든셋 기준 정기 측정 없이는 “좋아졌다”는 주장에 근거가 없습니다.
  • 벡터DB 선택은 규모와 보안 요구사항에 따라 pgvector, 전용 벡터DB, 관리형 SaaS 중 신중히 골라야 합니다.

댓글 남기기