본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 27. 05:40

Treasure Hunt Engine: 문서가 진실을 말하지 않게 된 순간

요약

대규모 코퍼스 환경에서 검색 엔진의 지연 시간과 환각 현상을 해결하기 위한 아키텍처 개선 사례를 다룹니다. ANN 인덱스 갱신 주기 불일치 문제를 해결하기 위해 DiskANN에서 Rust 기반 커스텀 HNSW로 전환하고 인메모리 버퍼를 도입했습니다.

핵심 포인트

  • ANN 인덱스와 실제 데이터 간의 동기화 격차 해결
  • DiskANN에서 Rust 기반 커스텀 HNSW 방식으로 전환
  • 인메모리 버퍼 도입을 통한 인덱싱 지연 시간 단축
  • 최신 데이터를 반영하기 위한 리랭커 모델의 정기적 미세 조정

우리가 실제로 해결하고 있었던 문제

우리 SRE 팀은 6개월 만에 8 TB에서 147 TB로 성장한 코퍼스 (Corpus)를 대상으로 Treasure Hunt Engine을 실행했습니다. 매주 화요일 03:47 UTC마다 클러스터는 지연 시간 (Latency) 위반이 없는 120만 건의 검색 요청을 보고했습니다. 하지만 운영자들이 백엔드에서 전혀 관련 없는 27,000개의 문서 ID를 반환하는 동안 UI가 4.3초 동안 멈추는 현상을 발견하기 전까지는 말이죠. Veltrix 문서에는 이것이 불가능하다고 되어 있었고, 온콜 (On-call) 런북 (Runbook)에는 쿼리 샤드 (Query shards)를 확장하라고 되어 있었습니다. 둘 다 틀렸습니다.

문서상으로는 엔진이 결정론적인 BM25 변형 모델을 사용하는 것으로 암시되었으나, 실제 쿼리 플랜 (Query plan)은 2단계 검색 (Two-stage retrieval)을 보여주었습니다. 즉, DiskANN v1.2를 기반으로 구축된 근사 최근접 이웃 (ANN, Approximate Nearest Neighbor) 필터가 먼저 작동하고, 이어서 GPU 클러스터에서 실행되는 리랭커 (Reranker)가 작동하는 방식이었습니다. ANN 단계는 지연 시간을 80 ms로 제한해야 했으나, 그 화요일에는 412 ms까지 치솟았습니다. ANN 레이어가 이미 쓰레기 데이터를 보내버렸기 때문에 리랭커는 오류를 수정할 기회조차 얻지 못했습니다.

우리가 처음에 시도했던 것 (그리고 실패한 이유)

우리는 부하를 흡수하기 위해 Veltrix가 권장하는 해결책인 GPU 리랭커 노드 6개를 추가했습니다. 지연 시간은 다시 72 ms로 떨어졌지만, 그다음 주 화요일에 우리는 4,000개의 환각 (Hallucinated) 문서를 목격했습니다. 리랭커는 MS MARCO 데이터셋으로 미세 조정 (Fine-tuned)된 70억 개의 파라미터를 가진 T5 리랭커를 사용하고 있었습니다. 이 미세 조정은 2023년의 정적 데이터셋을 기반으로 수행되었습니다. 우리의 코퍼스는 매일 진화하고 있었고, 리랭커는 새로운 어휘를 본 적이 없었습니다. 엔진의 YAML 파일에 하드코딩된 0.75의 점수 임계값 (Score threshold)은 완전히 잘못 조정되어 있었습니다.

우리는 임계값을 0.82로 높여보았습니다. 정밀도 (Precision)는 63 %에서 71 %로 향상되었지만, 재현율 (Recall)은 89 %에서 78 %로 떨어졌습니다. 우리의 검색 KPI는 엄격했습니다: 95 % 정밀도에서 85 % 재현율을 달성하는 것이었습니다. 우리는 이제 목표치 미달인 상태에서 여전히 환각 현상을 겪고 있었습니다.

아키텍처 결정

진짜 원인은 ANN (Approximate Nearest Neighbor) 인덱스 갱신 주기였습니다. DiskANN v1.2는 48시간마다 인덱스를 재구축했지만, 우리의 인덱싱 파이프라인(indexing pipeline)은 매시간 30 GB의 새로운 문서를 밀어 넣고 있었습니다. 이 격차로 인해 ANN 인덱스는 항상 실제 데이터보다 6~10시간 뒤처져 있었습니다. 결과적으로 리랭커(reranker)는 더 이상 코퍼스(corpus)를 반영하지 못하는 인덱스의 결함을 보완해야만 했습니다.

우리는 과감한 결정을 내렸습니다: DiskANN에서 Rust로 구현된 커스텀 HNSW 방식으로 전환하고, 최근 24시간 동안의 문서를 위한 인메모리 버퍼(in-memory buffer)를 도입했습니다. 인덱스는 이틀마다가 아니라 매분마다 재구축되었습니다. ANN 인덱스 크기는 1.8 GB에서 2.4 GB로 늘어났지만, 인덱싱 지연 시간(indexing latency) 측면에서 한 자릿수(order of magnitude)의 성능 향상을 얻었습니다. 또한 리랭커를 30일간의 이동 창(rolling window)을 기반으로 매주 미세 조정(fine-tuning)되는 220 M 파라미터의 증류(distilled) 모델로 교체했습니다. 점수 임계값(score threshold)은 1시간 분량의 쿼리 로그 슬라이스(query log slice)를 대상으로 15분마다 실행되는 베이지안 보정(Bayesian calibration) 서비스에 의해 동적으로 설정되었습니다.

트레이드오프(tradeoff)는 메모리였습니다. HNSW 인덱스는 노드당 600 MB의 RAM을 더 사용했지만, 우리는 환각(hallucination) 비율을 해결하기 위해 인프라 비용을 10% 더 지불할 용의가 있었습니다.

변경 후 수치가 말해준 것

변경 이후, 화요일 03:47 UTC는 다시 평온해졌습니다. ANN 단계는 58 ms ± 12 ms로 안정화되었습니다. 리랭커의 정밀도(precision)는 92%, 재현율(recall)은 87%에 도달하며 우리의 KPI를 상회했습니다. 환각 비율(relevance score가 0.9보다 높지만 내용이 완전히 무관한 문서가 반환되는 비율)은 0.98%에서 0.03%로 급감했습니다. 메모리 비용은 노드당 640 MB가 추가되었지만, 이전에 추가했던 6개의 GPU 노드를 폐기함으로써 이를 상쇄했습니다. 순 비용: 인프라 예산 +1.4%, 온콜(on-call) 호출 -60%.

내가 다르게 했을 것이라면

저는 첫날부터 ANN 인덱스 신선도(staleness) 지표를 계측(instrumenting)해야 한다고 주장했을 것입니다. DiskANN 갱신 간격(refresh interval)은 JIRA 티켓 속에 파묻혀 있을 것이 아니라, 일급 SLO(Service Level Objective)로 드러났어야 했습니다. 또한 우리는 리랭커(reranker)의 미세 조정(fine-tuned)된 가중치를 너무 오랫동안 신뢰했습니다. 라이브 데이터의 24시간 슬라이스를 대상으로 매주 회귀 테스트(regression test)를 수행했다면, 보정 드리프트(calibration drift)가 장애로 이어지기 전에 포착할 수 있었을 것입니다. 마지막으로, ANN 인덱스에 10%의 합성된 오래된 데이터(synthetic stale data)를 주입하여 전체 파이프라인을 테스트했어야 합니다. 30분간의 카오스 실험(chaos experiment)을 통해 몇 달 더 일찍 실패 모드(failure mode)를 드러낼 수 있었을 것입니다. 문서는 이러한 점검 사항을 전혀 언급하지 않았습니다. 엔진이 결정론적(deterministic)이라고 가정했기 때문에 장애가 우리를 찾아낸 것이며, 사실 엔진은 연극적(theatrical)이었습니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0