우리는 코드 검색 엔진에 사고 능력을 가르쳤습니다 — 무엇이 망가졌고 무엇이 해결했는지에 대하여
요약
오픈 소스 시맨틱 코드 검색 엔진 Octocode에 LLM 추론 단계를 도입하며 겪은 시행착오와 해결책을 다룹니다. 단순 LLM 재순위화가 재현율을 떨어뜨리는 문제를 상호 순위 융합(RRF) 방식으로 해결하는 과정을 설명합니다.
핵심 포인트
- LLM 재순위화 도입 시 MRR은 상승하나 Recall@10은 하락할 수 있음
- 유사도(Similarity)와 실제 관련성(Relevance) 사이의 간극 존재
- LLM이 검색 결과를 대체하게 하지 말고 하이브리드 방식과 융합해야 함
- RRF(Reciprocal Rank Fusion)를 통해 재현율 하한선을 유지하며 품질 개선 가능
Octocode는 Rust(Apache-2.0)로 구축된 우리의 오픈 소스 시맨틱 코드 검색 엔진 (semantic code search engine)입니다. 이는 Octomind의 코드 검색 레이어이며, https://github.com/muvon/octocode에서 가져올 수 있습니다.
지난달 우리는 검색 파이프라인 (retrieval pipeline)에 LLM 추론 (reasoning) 단계를 추가했습니다. 첫 번째 버전은 상황을 더 악화시켰습니다.
Hit@10이 7포인트 하락했습니다. Recall@10이 7.5포인트 하락했습니다. 모델이 관련이 없다고 판단하여 실제 정답(true positives)들을 제거해 버린 것입니다.
우리가 무엇을 배웠는지, 무엇을 출시했는지, 그리고 왜 "문맥적 검색 (contextual retrieval) 추가"가 모두가 주장하는 것처럼 만능 해결책이 아닌지에 대해 설명하겠습니다.
문제점: 유사도(Similarity)는 관련성(Relevance)이 아니다
Octocode는 하이브리드 검색 (hybrid retrieval) — 벡터 검색 (vector search)과 키워드 중첩 (keyword overlap)을 사용합니다. 잘 작동합니다. 하지만 간극이 존재합니다. 쿼리(query)와 가장 많은 토큰을 공유하는 스니펫(snippet)이 정작 질문에 답을 주는 코드가 아닌 경우가 많습니다.
"어디에서 요청이 재시도 가능한지(where do we decide a request is retryable) 결정하는가"라고 물으면, 유사도 랭커(similarity ranker)는 다음과 같은 것들을 제공합니다:
- 재시도 설정 구조체 (retry config struct)
- 재시도 상수 (retry constant)
- 해당 단어를 네 번이나 언급하는 테스트 코드
실제로 호출을 수행하는 함수는? 7위입니다.
벡터 검색은 유사도에 따라 순위를 매깁니다. 하이브리드 방식은 키워드 매칭을 추가합니다. 하지만 둘 다 코드를 읽지는 않습니다. 코드가 무엇을 하는지 알지 못합니다.
첫 번째 시도: 순수 LLM 재순위화 (Pure LLM Reranking)
우리는 하이브리드 검색 이후에 LLM 추론 단계를 추가했습니다. 모델은 후보 코드 본문을 읽고, 그것들이 실제로 쿼리에 답을 하는지에 따라 재순위화 (re-ranks)를 수행합니다. 새로운 인덱스도, 재인덱싱 (reindexing)도 필요 없습니다. 단지 검색과 결과 사이에 위치하는 재순위화 도구 (reranker)일 뿐입니다.
127개의 쿼리로 테스트했습니다. 결과는 다음과 같습니다:
| 지표 (Metric) | 이전 (Before) | 이후 (After) | 변화 (Change) |
|---|---|---|---|
| MRR | 0.595 | 0.752 | +0.157 |
| ... |
MRR과 NDCG는 상승했습니다. 랭킹 품질은 개선되었습니다. 하지만 Hit@10과 Recall@10은 하락했습니다.
LLM이 너무 공격적이었습니다. 모델은 자신이 관련 있다고 판단한 것만 반환하고, 6~10위 사이에 있는 실제 정답(true positives)들을 조용히 버렸습니다. 상위 랭킹은 좋아졌지만, 재현율(recall)의 하한선은 나빠졌습니다.
해결책: 교체하지 말고 융합하라 (Fuse, Don't Replace)
LLM이 랭킹 (ranking)을 대체하게 두지 마세요. 상호 순위 융합 (Reciprocal Rank Fusion, RRF)을 통해 하이브리드 랭킹 (hybrid ranking)과 융합 (fuse)해야 합니다.
score = 1/(k + hybrid_rank) + reasoning_weight * 1/(k + reasoning_rank)
하이브리드 순위 (hybrid rank)는 항상 기여하며, 이것이 여러분의 재현율 (recall) 하한선이 됩니다. 추론 순위 (reasoning rank)는 상위권 (head)을 견인합니다.
동일한 127개 쿼리에 대한 최종 융합 결과:
| 지표 (Metric) | 이전 (Before) | 이후 (After) | 변화 (Change) |
|---|---|---|---|
| MRR | 0.595 | 0.809 | +36% |
| ... |
모든 지표가 상승했습니다. Hit@5가 0.953이라는 것은 20번 중 19번은 정답이 상위 5개 안에 포함됨을 의미합니다.
우리가 튜닝한 것 (그리고 중요하지 않았던 것)
추론 가중치 (Reasoning weight): 2.0일 때 가장 좋았습니다. 가중치를 5로 높여도 이득은 없으며 재현율 (recall)만 희생됩니다.
후보군 (Candidates): 25개가 최적의 지점 (sweet spot)입니다. 40개를 시도해 보았으나 모든 면에서 결과가 더 나빴습니다.
컨텍스트 수준 (Context level): 전체 코드 본문 (Full code bodies)이 압도적으로 승리했습니다. 시그니처만 사용하는 방식 (Signatures-only)이 가장 성능이 낮았습니다.
LLM 온도 (LLM temperature): 1.0이 0.3과 0.0을 이겼습니다. 직관에 어긋나지만, 모델은 일반적인 샘플링 (sampling)을 할 때 더 잘 추론합니다. 경직된 디코딩 (Stiff decoding)은 모델을 더 멍청하게 만들었습니다.
효과가 없었던 것: 컨텍스트 검색 (Contextual Retrieval)
인덱싱 시점에 설명을 추가하는 Anthropic의 컨텍스트 검색 (contextual retrieval) 방식은 어디에서나 추천됩니다. 저희도 테스트해 보았습니다.
Hit@5: −0.008
Recall@10: −0.019
이 방식은 랭킹 (ranking)을 위해 재현율 (recall)을 희생합니다. 코드의 경우, 이는 순손실입니다. "컨텍스트 검색을 추가하라"는 조언은 맹목적으로 따르는 조언 (cargo-culted advice)일 뿐, 보편적인 승리 공식이 아닙니다. 저희는 이를 적용하지 않았습니다.
활성화 방법
이 기능은 현재 Octocode의 master 브랜치에 포함되어 있습니다 (아직 출시되지는 않았으며, 곧 출시될 예정입니다). 기본값은 꺼져 있으며, 하나의 설정 플래그로 제어합니다:
[search.reasoning]
enabled = true
model = "deepseek:deepseek-v4-flash"
...
또는 다른 제공자 (provider:model)로 교체할 수 있습니다:
[search.reasoning]
enabled = true
model = "openai:gpt-4o-mini"
...
어떠한 provider:model 조합도 작동합니다. 시맨틱 검색 (semantic search)당 한 번의 LLM 호출이 발생합니다. structural_search는 순수한 grep 상태를 유지합니다. 재인덱싱 (reindex)은 필요하지 않습니다.
요점 (The Takeaway)
LLM 재랭킹 (reranking)은 효과가 있습니다. 하지만 하이브리드 랭킹 (hybrid ranking)을 하한선으로 유지할 때만 그렇습니다. 융합 (Fusion)이 교체 (replacement)보다 낫습니다. 그리고 실제 워크로드에서 테스트하지 않은 채 "모범 사례 (best practices)"를 맹목적으로 따르지 마세요.
Octocode는 Apache-2.0 라이선스 하에 오픈 소스로 제공됩니다. 벤치마크 스위트 (benchmark suite), 정답 데이터셋 (ground truth dataset), 그리고 가공되지 않은 결과값 (raw results)은 모두 다음 리포지토리에서 확인할 수 있습니다: https://github.com/muvon/octocode
이 기능은 현재 마스터 (master) 브랜치에 병합되었으며, 아직 출시되지는 않았으나 곧 출시될 예정입니다.
모든 수치와 튜닝 세부 사항이 포함된 전체 기술 보고서: https://muvon.io/blog/reasoning-retrieval-code-search
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기