우리가 에이전틱 검색을 개선한 방법

TMT

https://entire.io/blog/improving-agentic-search-in-coding-agents

TL;DR

우리는 실제 코딩 에이전트 트레이스를 분석하고, 공개 벤치마크를 만든 뒤, ripgrep⁠, fff, pgr⁠를 비교해 에이전틱 코드 검색에 실제로 도움이 되는 것이 무엇인지 확인했습니다. 가장 분명한 결론은, 검색 속도만 빠르게 만드는 것은 도움이 되긴 하지만 그 폭이 크지 않고, 대신 더 잘 정렬된 결과가 첫 검색에서의 적중률을 높여 에이전트가 올바른 코드를 더 빨리 찾도록 돕는다는 것이었습니다.

에이전트는 어떻게 검색할까?

코딩 에이전트가 작업하는 모습을 가만히 지켜보면 한 가지가 아주 빠르게 눈에 들어옵니다. 에이전트는 파일, 심볼, 정의, 레퍼런스, 테스트 케이스, 임포트, 호출 지점 등등을 찾느라 굉장히 많은 시간을 검색에 쓰고 있다는 점입니다. 검색은 에이전트 루프 안에서 부수적인 작업이 아니라, 에이전트가 하는 일 가운데 핵심 작업 중 하나입니다.

Agent Trace

Entire에서는 AI 에이전트 트레이스를 캡처해, 에이전트와 팀원들이 서로 검색하고 공유할 수 있도록 제공합니다. 우리는 각 트레이스를 체크포인트(checkpoint) 라고 부릅니다. 여기에는 사용자 프롬프트, 에이전트 응답, 툴 호출, 그리고 그 결과로 나온 코드 diff가 모두 담겨 있습니다. 지난 몇 개월 동안 우리는 실제 개발 과정에서 생성된 수십만 개의 체크포인트를 수집했습니다.

우리는 수십억 개의 체크포인트를 효율적으로 검색할 수 있는 코드 및 시맨틱 검색 인프라를 구축하고 있습니다. 검색 자체는 새로운 문제가 아닙니다. grep⁠, ripgrep⁠, fzf⁠, fff⁠ 같은 도구들은 로컬 환경에서 이미 꽤 빠릅니다. 우리는 원시적인 속도만으로는 에이전틱 코드 검색을 개선하는 데 필요한 핵심 병목을 해결할 수 없다고 보고 있었습니다. 그래서 실제로 무엇이 중요한지 검증해 보기로 했습니다.

무엇이 중요한지 알아내기 위해, 오픈 소스 Entire CLI 리포지토리에서 실제 개발 중에 생성된 체크포인트를 가져와 분석에 활용했습니다. 고객 데이터는 일절 사용하지 않았습니다. 원본 데이터는 여기에서 확인할 수 있습니다.

해당 공개 데이터셋은 대략 다음과 같습니다.

  • 분석한 체크포인트 총수: 1,983⁠
  • 분석한 툴 호출 총수: 202,142⁠
  • 검색 관련 툴 호출: 98,555⁠ (전체 툴 호출의 48.8%⁠)

검색 관련 툴 호출을 조금 더 들여다보면:

에이전트 툴 호출 분포

Category (카테고리)Count (개수)Percentage (비율)
Read / file retrieval (파일 읽기 / 파일 가져오기)48,32249.0%
Bash search fallback (Bash 검색 폴백)23,18023.5%
Grep / content search (Grep / 콘텐츠 검색)23,13623.5%
Other (기타)3,9174.0%

Grep / content search 카테고리에서는, 에이전트가 심볼, 문자열, 정규식 패턴 등을 찾기 위해 grep⁠ 같은 전용 콘텐츠 검색 툴을 사용해 파일 내용을 직접 검색했습니다. Bash search fallback 카테고리에서는, 에이전트가 grep⁠, find⁠, ls⁠, 셸 파이프라인, 존재 여부 확인, 파일 탐색 명령 등 셸 명령들을 조합해 검색과 유사한 작업을 수행했습니다.

다시 말해, Bash search fallback은 더 넓고 더 지저분한 영역입니다. 에이전트가 “이건 셸을 써서 찾아봐야겠다”라고 판단한 경우이고, Grep / content search는 말 그대로 전용 검색 툴을 직접 호출하는 상황입니다.

이 초기 분석만으로도 두 가지가 바로 드러났습니다.

  1. 검색은 에이전트 동작의 1급(first-order) 연산이다. 전체 툴 호출의 거의 절반이 검색 관련이었습니다.
  2. 검색 워크플로는 파편화되어 있다. 에이전트는 파일 읽기, bash 기반 검색, grep 스타일 콘텐츠 검색 사이를 왔다 갔다 합니다. 이는 ripgrep⁠의 원시 출력 결과를, 정렬도 하지 않은 채 그대로 보여주는 것보다 더 나은 기본 검색 표면(search surface)을 제공할 여지가 있다는 뜻이었습니다.

초기 분석을 마친 뒤, 우리는 좀 더 깊이 파고들기로 했습니다.

더 빠른 검색이 병목은 아니었다

검색 품질을 개선하기 전에, 우리는 더 단순한 가설부터 검증해 봤습니다. “어쩌면 코딩 에이전트에게는 그저 더 빠른 검색 실행 속도가 필요할지도 모른다”는 가설이었습니다.

그래서 이 가설을 직접 검증하기 위해, 공개된 entireio/cli⁠ 체크포인트 중 검색 의존도가 높은 60개 작업으로 구성된 검색 민감(sensitive) 태스크 세트를 중심으로 전용 공개 벤치마크를 만들었습니다. 벤치마크 패키지는 여기에서 볼 수 있습니다.

이 태스크들은 사람이 손으로 작성한 평가용 프롬프트가 아닙니다. 실제 공개 체크포인트 트랜스크립트에서 가져온 프롬프트들 가운데, 검색 의존도가 높고 리포지토리만으로 답을 구할 수 있는 프롬프트들만 걸러 구성한 세트입니다. 다시 말해, 이 벤치마크는 외부 서비스, 웹 검색, 비공개 컨텍스트에 의존하지 않고, 검색만을 강하게 스트레스 주도록 설계되었습니다.

우리는 두 가지 조건을 비교했습니다.

  • baseline: 원본 ripgrep⁠
  • fff: 바이그램 인덱스, mmap⁠, SIMD 가속 스캐닝, frecency 기반 랭킹을 사용한 상태 저장 MCP 검색 서버

fff⁠는 ripgrep⁠보다 훨씬 빠릅니다. 따라서 만약 원시 검색 지연(latency)이 진짜 병목이라면, 이 속도 차이는 에이전트의 엔드 투 엔드 실행 시간에서 매우 큰 차이로 이어져야 합니다.

하지만 실제로는 다소 온건한 수준의 개선만 나타났습니다.

이 60개 태스크로 구성된 공개 벤치마크에서, fff⁠search_code⁠의 중앙값 지연 시간을 14.7ms⁠에서 1.7ms⁠까지 줄였지만, 엔드 투 엔드 전체 소요 시간 시간은 38.57s⁠에서 36.99s⁠로만 줄었습니다. 전체 요약은 여기에서 확인할 수 있습니다.

Metric (메트릭)Baseline (ripgrep)fff
Avg wall clock per run (실행당 평균 전체 소요 시간)38.57s36.99s
Avg tool calls (실행당 평균 툴 호출 횟수)19.1217.90
Avg total tool execution time per run (실행당 툴 총 실행 시간 평균)0.140s0.055s
Tool execution share of wall clock (전체 시간 중 툴 실행 비율)0.4%0.1%
Avg search_code duration (search_code 평균 실행 시간)15.5ms5.7ms
Median search_code duration (search_code 중앙값 실행 시간)14.7ms1.7ms

속도 벤치마크 비교

즉, 더 빠른 검색은 어느 정도 도움이 되기는 했습니다. 하지만 툴 레벨에서 큰 폭의 속도 개선이 있었음에도, 엔드 투 엔드 관점에서의 효과는 제한적이었습니다. 애초에 툴 실행이 전체 실행 시간에서 차지하는 비중이 극도로 작았기 때문입니다. 이 벤치마크에서는 베이스라인에서 실제 툴 실행이 전체 전체 소요 시간의 0.4%⁠, fff⁠에서는 0.1%⁠에 불과했습니다.

에이전트는 대부분의 시간을 ripgrep⁠이 끝나기를 기다리는 데 쓰고 있지 않았습니다. 훨씬 느린 루프, 즉 툴을 둘러싼 모델 추론, 결과 해석, 다음 단계 계획 수립에 시간을 쓰고 있었던 것입니다.

Agent loop bottleneck

이런 관점에서 시스템을 바라보면, 이 결과는 그리 놀랍지 않습니다. 검색 호출 시간을 수십 밀리초에서 서브 밀리초대로 줄이는 것은 툴 레이어에서는 분명 진전이지만, 각 호출이 여전히 수초 단위의 모델 추론, 결과 해석, 다음 단계 계획 루프 안에 묶여 있다면 전체 시스템에는 거의 영향을 주지 못합니다.

추론 단계 하나를 제거하는 것과 동일한 효과를 내기 위해, 추정치로 왕복 2초짜리 인퍼런스 한 번을 기준으로 하면, 여섯 번의 검색 호출 각각에서 약 330ms⁠씩을 줄이거나, 원래 지연 시간의 검색 호출 130⁠개 이상을 전부 0ms로 만들어야 합니다.

그래서 다음 질문이 생겼습니다.

어떻게 하면 각 검색 결과를 에이전트에게 더 유용하게 만들어, 에이전트가 같은 자리를 맴도는(thrashing) 일을 줄이고 더 빨리 코드 읽기 단계로 넘어가게 만들 수 있을까?

이 질문을 검증하기 위해, 우리는 pgr⁠라는 자체 로컬 검색 툴을 만들었습니다.

검색 표면 비교

우리가 테스트한 시스템들

우리는 최종적으로 세 가지 시스템을 비교했습니다.

1. 베이스라인: 원본 ripgrep⁠

이 조건은 컨트롤 그룹입니다. 에이전트는 벤치마크를 위해 정의한 동일한 네 개의 툴 인터페이스를 사용했지만, search_code⁠는 별다른 후처리 없이 순수 ripgrep⁠으로 구현했습니다. 결과는 ripgrep⁠이 내놓는 순서에 거의 그대로 따라 반환되었고, 그 위에 어떤 랭킹 레이어도 올리지 않았습니다.

이 조건은 다음과 같은 가장 단순한 질문에 답합니다.

강력한 표준 로컬 검색 툴은 있지만, 추가적인 “지능”은 없는 상태에서 에이전트 검색 동작은 어떻게 보일까?

2. fff⁠: 더 빠른 인덱스 기반 검색

fff⁠는 바이그램 인덱스, mmap⁠, SIMD 가속 스캐닝, frecency 기반 랭킹을 사용하는 상태 저장 MCP 검색 서버입니다. 원시 속도에 초점을 맞춰 설계되었습니다. 만약 원시 검색 속도가 핵심 병목이라면, fff⁠는 엔드 투 엔드 결과에서 아주 큰 폭의 개선을 보여야 했습니다.

이 연구에서 fff⁠가 유용했던 이유도 바로 여기에 있습니다. 검색 스캔 속도와 검색 유용성을 분리해 볼 수 있는 대비군을 제공해줬기 때문입니다.

3. pgr⁠: 에이전트 지향 랭킹 기반 검색

pgr⁠는 우리가 에이전트를 위해 만든 검색 툴입니다.

로컬 코드 검색의 단순함은 유지하되, 에이전트가 처음에 무엇을 보게 되는지를 바꾸는 데 집중했습니다.

  • 정의(Definitions)를 먼저 보여주고
  • 테스트나 vendor 코드보다 소스 파일을 우선 보여주며
  • 결과를 묶어서(grouped) 잘라(trimmed) 주고
  • 다음 단계가 더 분명해지도록 결과 표현을 더 풍부하게 구성했습니다.

pgr 데모 애니메이션

pgr⁠가 MCP 서버로 어떻게 보이는지 보고 싶다면, 인터페이스가 의도적으로 매우 단순하다는 점이 먼저 눈에 들어올 것입니다. 표준 입출력 위에서 JSON-RPC를 말합니다. 서버를 초기화하고, 사용 가능한 툴 목록을 가져온 뒤, search_code⁠를 호출하는 구조입니다.

printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \
  '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"search_code","arguments":{"query":"CheckpointStore","max_files":5}}}' \
  | ~/.cargo/bin/pgr

개발 과정에서 우리는 랭킹 로직과 출력 포맷을 모두 반복적으로 다듬었습니다. 아래에 나오는 공개 벤치마크 결과는 버전별 결과물이 아니라 최종 pgr⁠ 설정을 기준으로 한 것입니다.

왜 이 조건들이 중요했나

이 세 시스템을 함께 비교하면, 서로 다른 가설들을 한 번에 검증할 수 있습니다.

  • 더 빠른 검색이 실제로 도움이 되는가?
  • 더 나은 랭킹이 실제로 도움이 되는가?
  • 에이전트 지향적인 결과 표현 방식이 실제로 도움이 되는가?

그래서 이 벤치마크 스택이 그렇게 중요해졌습니다. 서로 다른 시스템은 에이전트 루프의 서로 다른 지점을 개선하고 있었고, 단 하나의 집계 지표만으로는 각 시스템이 어디를 개선했는지 분리해 볼 수 없었기 때문입니다.

벤치마크 스택

여러 시스템을 비교할 수 있게 되자, 다음 질문은 “어떻게 평가할 것인가”였습니다. 처음에는 단일 엔드 투 엔드 벤치마크 하나면 충분할 거라고 예상했습니다. 같은 태스크를 에이전트에게 주고, 검색 백엔드만 바꿔 끼운 뒤, 툴 호출 수, 비용, 전체 소요 시간을 측정하는 방식입니다. 이론적으로는 이것이 우리가 알고 싶은 바로 그 지표입니다. 하지만 실제로는 이 하나만으로는 충분하지 않았습니다.

간단히 짚고 넘어가자면, 우리 벤치마크 하니스에서 에이전트는 search_code⁠라는 단일 툴 인터페이스를 통해 리포지토리를 검색하며, 이 인터페이스 뒤에 서로 다른 검색 시스템을 연결해 둡니다.

{
  "name": "search_code",
  "arguments": {
    "query": "CheckpointStore",
    "max_files": 5
  }
}

따라서 우리가 “첫 번째 search_code 쿼리”나 “search_code 지연 시간” 얘기를 할 때, 이는 서로 다른 백엔드 아래에서 평가되는 동일한 추상 코드 검색 툴 호출을 의미하지, 별도의 제품이나 모델 기능을 의미하지 않습니다.

이번 공개 릴리스에서 최종적으로 사용한 벤치마크 스택은 세 개의 레이어로 구성됩니다.

  1. 속도 벤치마크
    극적으로 더 빠른 검색 실행이, 엔드 투 엔드 실행 시간을 실제로 줄여주는지 측정합니다.
  2. 넓은 혼합 워크로드 벤치마크
    다양한 프롬프트에 대해 전체 에이전트 루프를 엔드 투 엔드로 돌린 뒤, 툴 호출 수, 비용, 전체 소요 시간을 측정합니다.
  3. 오프라인 검색 품질 벤치마크
    에이전트 트레이스에 남아 있는 실제 search_code⁠ 쿼리를 서로 다른 백엔드에 리플레이한 뒤, 에이전트는 더 이상 진행시키지 않은 채 검색 품질만 직접 평가합니다.

각 레이어는 서로 다른 질문에 답해 주고, 세 가지를 함께 봤을 때 어느 하나의 단일 지표만 봤을 때보다 훨씬 더 명확한 그림을 얻을 수 있습니다.

단순한 것부터 시작하기

우리는 처음에 “더 좋은 랭킹을 제공하는 검색 툴을 에이전트에게 주면, 더 나은 검색 결과, 더 적은 검색 횟수, 더 적은 툴 호출, 더 낮은 비용으로 이어질 것이다”라고 예측했습니다.

그래서 먼저 소규모 엔드 투 엔드 파일럿으로 시작해 본 뒤, 점차 스케일을 키우기로 했습니다. 벤치마크 패키지는 여기에 있습니다.

초기 파일럿

파일럿에서는 공개 entireio/cli⁠ 태스크 세트에서 처음 25개 태스크를 사용했습니다. 우리는 동일한 네 개 툴 인터페이스를 기준으로 baseline⁠, fff⁠, pgr⁠를 모두 테스트했고, 에이전트로는 Claude Sonnet을 사용했습니다.

전체 파일럿 결과는 여기에서 볼 수 있습니다.

MetricBaselinefffpgr
Avg wall clock (평균 전체 소요 시간)38.21s36.25s (-5.1%)36.88s (-3.5%)
Avg tool calls (평균 툴 호출 횟수)20.2020.00 (-1.0%)20.92 (+3.6%)
Avg cost (평균 비용)$0.5581$0.4161 (-25.4%)$0.4824 (-13.6%)
Avg search calls (평균 search_code 호출 횟수)8.047.64 (-5.0%)6.56 (-18.4%)

결과는 고무적이었지만, 결정적이라고 보기는 어려웠습니다. 두 대안 모두 검색 횟수를 줄이고, 베이스라인 대비 평균 전체 소요 시간을 개선했습니다. fff⁠는 비용을 가장 크게 낮췄고, pgr⁠는 검색 호출 수를 가장 많이 줄였습니다. 하지만 어느 쪽도 전체 툴 호출 수를 줄이지는 못했습니다.

그래서 우리는 스케일을 키우기로 했습니다.

연구 1: 넓은 혼합 워크로드 벤치마크

더 큰 공개 벤치마크에서는 동일한 셋업을 전체 60개 태스크 세트로 확장했습니다.

  • 총 60개 태스크
  • 1개 공개 리포지토리: entireio/cli
  • 4개 프롬프트 카테고리: code_understanding⁠, debug_or_validation⁠, implementation⁠, repo_task⁠
  • 각 조건별로 동일한 네 개 툴 인터페이스
  • 에이전트로 Claude Sonnet 사용

조건은 다음과 같습니다.

  • baseline: 원본 ripgrep⁠
  • fff: 속도에 최적화된 상태 저장 인덱스 기반 MCP 검색 서버
  • pgr: Rust로 구현된 MCP 검색 툴

전체 결과는 여기에서 확인할 수 있습니다.

Metric (메트릭)Baselinefffpgr
Avg wall clock (평균 전체 소요 시간)34.98s34.97s (-0.0%)33.67s (-3.8%)
Avg tool calls (평균 툴 호출 횟수)18.4518.72 (+1.4%)18.90 (+2.4%)
Median tool calls (툴 호출 횟수 중앙값)21.021.022.0
Avg cost (평균 비용)$0.4030$0.3797 (-5.8%)$0.3698 (-8.2%)
Avg search calls (평균 search_code 호출 횟수)6.125.70 (-6.8%)5.53 (-9.5%)

fff⁠는 검색 호출 수를 조금 줄였지만, 전체 소요 시간은 사실상 그대로였고 툴 호출 수는 약간 늘었습니다. pgr⁠는 세 그룹 중에서 가장 유망해 보였고, 더 적은 검색 호출 수와 함께 전체 소요 시간과 비용에서 소폭 개선을 보여줬습니다. 다만 이 경우에도 전체 툴 호출 수 자체는 줄어들지 않았습니다.

더 큰 벤치마크는 보다 미묘한 사실을 알려주었습니다.

  1. 더 나은 검색은 분명 어떤 국소적인(local) 에이전트 의사결정에는 영향을 주고 있었다.
  2. 하지만 그 변화는 전체 엔드 투 엔드 지표를 단일하게 깔끔하게 바꿀 만큼 크거나 안정적이지는 않았다.

왜 넓은 벤치마크에서는 신호가 희석되었을까?

태스크 간 편차가 여전히 컸기 때문입니다. 어떤 프롬프트는 짧고 곧바른 검색 → 읽기 → 답변 경로를 만들어 냈습니다. 하지만 다른 프롬프트들은 더 많은 검색, 더 많은 읽기, 더 많은 되돌아보기(backtracking)가 포함된 길고 복잡한 탐색 경로로 이어졌습니다. 이 편차가 워낙 크다 보니, 작은 국소 개선의 신호는 전체 집계에서 왜곡되거나 사라지는 경우가 많았습니다.

다시 말해, 넓은 벤치마크는 여전히 중요한 질문에 답해 줍니다.

이 개입(intervention)이 현실적인 엔드 투 엔드 워크로드에서도 살아남는가?

하지만 보다 진단적인 질문에는 답하지 못했습니다.

이 개입은 에이전트 루프의 정확히 어느 부분을 개선하고 있는가?

이 구분이 생각보다 훨씬 중요했습니다.

넓은 벤치마크는, “검색 품질이 중요하지 않다”는 결론을 뒷받침하지 않습니다. 오히려, 에이전트의 전체 행동이 워낙 노이즈가 큰 탓에, 국소적인 개선이 최종 합계만 봐서는 사라져 보이거나 아주 부분적으로만 드러날 수 있다는 사실을 보여줬습니다.

이 인식이 다음 벤치마크 레이어로 이어졌습니다.

실험 1: 오프라인 검색 품질

넓은 벤치마크 결과가 혼재되어 있었지만, 우리는 여전히 랭킹이 도움이 될 것이라는 강한 직감을 가지고 있었습니다. 문제는, 전체 엔드 투 엔드 지표만으로는 검색 레이어 자체가 무엇을 하고 있는지 분리해 볼 수 없다는 점이었습니다.

그래서 다음 단계로, 에이전트를 루프에서 제거하고 검색 품질만 따로 평가하기로 했습니다.

우리는 entireio/cli⁠ 태스크 세트에서 나온 베이스라인 실행 결과를 기반으로 오프라인 리플레이 벤치마크를 만들었습니다. 벤치마크 패키지는 여기에서 볼 수 있습니다.

방법은 다음과 같습니다.

  1. 베이스라인 에이전트 트레이스에서 실제 search_code⁠ 쿼리를 추출합니다.
  2. 동일한 쿼리를 서로 다른 검색 백엔드에 리플레이합니다.
  3. 공개된 관련성 신호를 기준으로 반환된 파일들을 스코어링합니다.

우리는 베이스라인 에이전트가 해당 실행(run)에서 실제로 read_code⁠로 열어본 파일들을 관련성 라벨로 사용했습니다. 이 벤치마크는 넓은 혼합 워크로드 연구보다는 훨씬 좁은 범위를 다루지만, 훨씬 더 정확한 질문에 답해 줍니다.

같은 쿼리에 대해, 어떤 백엔드가 더 나은 후보를 반환하는가?

검색 예시

우리는 두 가지 버전으로 실험을 진행했습니다.

  • first-search 리플레이: 각 실행에서 첫 번째 search_code⁠ 쿼리만 사용
  • pre-read 리플레이: 베이스라인 에이전트가 처음으로 코드를 열기 전까지의 모든 search_code⁠ 쿼리를 사용

실험 1A: first-search 리플레이

이 실험은 전체 연구 중 가장 깔끔한 검색 품질 벤치마크였습니다.

우리는 네 가지를 측정했습니다.

  • MRR (Mean Reciprocal Rank): 첫 번째 관련 파일이 결과 리스트에서 얼마나 앞에 등장하는지 측정하는 지표로, 앞에 나올수록 더 큰 보상을 받습니다.
  • Hit@1: 최상위 결과가 관련 있는 파일일 확률
  • Hit@3: 상위 3개 안에 관련 있는 결과가 포함될 확률
  • 평균 출력 문자 수: 반환된 검색 결과의 총 문자 수로, 응답 크기와 토큰 부담을 대략적으로 가늠할 수 있는 프록시입니다.
Metric(메트릭)Baselinefffpgr
MRR0.31770.30590.4053
Hit@126.0%18.0%34.0%
Hit@334.0%42.0%42.0%
Avg output chars6565.91427.01587.1

first-search 검색 품질 메트릭

태스크 단위로 짝지은(paired) 비교 (N = 50⁠)에서,

  • MRR fff⁠ vs baseline: -0.012⁠, 95% CI [-0.089, +0.066]⁠
  • MRR pgr⁠ vs baseline: +0.088⁠, 95% CI [-0.007, +0.182]⁠
  • Hit@1 fff⁠ vs baseline: -8.0⁠포인트, 95% CI [-17.7, +1.7]⁠
  • Hit@1 pgr⁠ vs baseline: +8.0⁠포인트, 95% CI [-4.7, +20.7]⁠

fff⁠는 매우 유용한 대비군입니다. 우리가 테스트한 시스템 중 가장 빠른 검색 시스템이었지만, pgr⁠처럼 first-result 관련성을 개선하지는 못했습니다. fff⁠도 여전히 관련 있는 파일을 리스트 상단 어딘가에 띄우긴 했지만, 그 파일을 맨 위에 두는 일은 덜 했습니다.

이 프로젝트 전체에서 가장 분명한 결과 중 하나가 여기서 나옵니다.

정의 우선, 경로(path) 인식형 랭킹은 에이전트가 처음 보게 되는 검색 결과의 품질을 분명히 개선했다.

가장 큰 이득이 나타난 부분

이득은 에이전트가 단일한 명확한 정의를 확인하는 것이 아니라 불확실성을 헤쳐나가야 하는 프롬프트에서 더 크게 나타났습니다.

가장 큰 first-search 개선 효과는 대개 에이전트가 다음에 살펴볼 핵심 파일이나 코드 경로를 찾으려는 implementation 프롬프트에서 나왔습니다.

  • MRR: 0.3061 → 0.5000⁠
  • Hit@1: 14.3% → 42.9%⁠

이런 프롬프트들은 대체로 랭킹 품질이 영향을 미칠 수 있는 여지가 큽니다. 올바른 파일이 헬퍼, 테스트, 인접 구현 파일들 사이에 묻혀 있는 경우가 많기 때문입니다.

code_understanding 프롬프트에서는 이득이 더 작았지만, 방향성은 여전히 긍정적이었습니다.

  • MRR: 0.2760 → 0.3260⁠
  • Hit@1: 20.0% -> 24.0%

이건 직관적으로도 납득이 됩니다. 어떤 프롬프트는 이미 꽤 괜찮은 베이스라인 쿼리에서 시작하지만, 다른 것들은 훨씬 더 탐색적인(exploratory) 성격을 띠기 때문입니다.

작업 유형별 이득 그래프

실험 1B: Pre-Read 리플레이

더 넓은 범위의 리플레이 벤치마크에서는, 베이스라인 에이전트가 처음으로 코드를 열기 전까지 발행한 모든 ⁠search_code⁠ 쿼리를 사용했습니다.

즉, 첫 번째 검색만 측정하는 대신, 에이전트가 “어디를 읽어야 할지”를 아직 찾지 못한 미해결 검색 단계 전체를 본 것입니다. 에이전트가 올바른 읽기 위치를 찾기 위해 시도한 모든 쿼리를 포함합니다.

  • 쿼리 셋: 처음 read 이전의 검색 132개
  • 그룹: 42개 태스크에서 나온 42개 실행
  • 조건: ⁠baseline⁠, ⁠fff⁠, ⁠pgr⁠
  • 소스 파일: pre_read/SUMMARY.md, pre_read/results.json
MetricBaselinefffpgr
MRR0.22710.17640.2640
Hit@117.4%10.6%22.0%
Hit@324.2%23.5%28.8%
Avg output chars2225.7978.71449.4

Pre-read 검색 품질 메트릭

태스크 단위 짝지은 비교 (⁠N = 42⁠)에서:

  • MRRfff⁠ vs baseline: ⁠-0.048⁠, 95% CI ⁠[-0.115, +0.019]⁠
  • MRRpgr⁠ vs baseline: ⁠+0.067⁠, 95% CI ⁠[-0.007, +0.141]⁠
  • Hit@1fff⁠ vs baseline: ⁠-11.6⁠포인트, 95% CI ⁠[-21.5, -1.7]⁠
  • Hit@1pgr⁠ vs baseline: ⁠+5.1⁠포인트, 95% CI ⁠[-4.1, +14.4]⁠
  • Hit@3pgr⁠ vs baseline: ⁠+10.4⁠포인트, 95% CI ⁠[+0.8, +20.0]⁠

⁠pgr⁠에 대해서는 긍정적인 추세가 유지되었지만, 신뢰 구간이 더 넓어졌습니다.

이 결과는 유용한 사실을 알려줍니다.

  • first-search 구간에서의 이득이 가장 크고, 측정하기도 가장 쉽다.
  • 그 이후 쿼리 리포뮬레이션 구간은 훨씬 노이즈가 크다.
  • 검색 품질은 에이전트가 “처음 어디로 갈지” 결정할 때 가장 중요하다.

따라서 이 벤치마크는 같은 기본 교훈을 다시 한 번 강화합니다.

랭킹은 검색 프로세스의 초반, 에이전트가 “무엇을 먼저 살펴볼지”를 결정하는 구간에서 가장 큰 도움을 준다.

실제로 유지된 것들

모든 벤치마크를 통틀어, 세 가지는 일관되게 유지되었습니다.

  1. 더 빠른 검색은 핵심 병목이 아니었다. fff⁠는 툴 레벨에서 극적으로 더 빨랐지만, 실제 엔드 투 엔드 개선 폭은 제한적이었습니다. 툴 실행 시간이 전체 전체 소요 시간 시간에서 차지하는 비중이 아주 작았기 때문입니다.
  2. 랭킹은 검색 품질을 분명히 개선했다. 실제 first-search 쿼리에서 ⁠pgr⁠는 항상 베이스라인보다 더 높은 first-result 관련성을 보여줬고, ⁠fff⁠는 그렇지 못했습니다.
  3. 가장 강한 행동 변화는 “국소 개선”이었다. 더 나은 검색은 특히 검색 품질이 실제로 중요한 태스크에서, 에이전트가 더 좋은 후보를 더 일찍 찾도록 도왔습니다. 하지만 이것이 모든 코딩 에이전트 태스크에서 일관된 보편 효율 향상으로 이어진 것은 아니었습니다.

유지되지 않은 것들

데이터가 뒷받침하지 않는 주장도 분명했습니다. 예를 들어, 아래와 같은 보편적인 명제는 지지되지 않습니다.

더 나은 코드 검색은 모든 코딩 에이전트 태스크에서 항상 더 적은 툴 호출과 더 낮은 비용으로 이어진다.

넓은 혼합 워크로드에서는 태스크 간 편차가 너무 커서, 작은 국소 개선이 쉽게 묻혀버렸습니다. 검색 행동이 개선되었더라도, 총 툴 호출 수와 총 비용은 여전히 노이즈가 컸습니다. 이 지표들 자체는 여전히 유용한 다운스트림 메트릭이지만, 검색 개입을 평가하는 가장 민감한 지표는 아니었다는 사실이 드러났습니다.

앞으로의 과제

이번 연구에서는 언어 모델을 고정시키고, 에이전트 루프를 둘러싼 검색 시스템에만 초점을 맞췄습니다. 이 선택 덕분에 검색 품질, 결과 표현, 툴 동작의 영향을 더 쉽게 분리해 볼 수 있었지만, 동시에 여러 중요한 질문들을 열린 상태로 남겨 두었습니다.

첫째, 이번 벤치마크들은 여러 프런티어 모델들에 걸쳐 반복 실행되어야 합니다. 그래야 관찰된 효과가 특정 모델에만 국한된 것인지, 아니면 서로 다른 플래너들 전반에 걸쳐 일반적인 현상인지 확인할 수 있습니다. 어떤 모델은 랭킹 품질에 더 민감할 수 있고, 또 어떤 모델은 더 풍부한 결과 포맷이나 더 명확한 “검색 결과 없음(empty state)” 처리에서 더 큰 이득을 볼 수 있습니다.

둘째, 벤치마크 스위트는 최신 리트리버 모델과, 순수한 어휘 기반(lexical) 랭킹이 아니라 시맨틱 매칭에 최적화된 검색 시스템들을 포함하도록 확장될 필요가 있습니다. 다음 단계로 유용한 실험은, 이런 시맨틱 검색 접근법들을 ⁠ripgrep⁠, ⁠fff⁠, ⁠pgr⁠와 같은 동일한 벤치마크 스택 위에서 비교해 보는 것입니다. 이때는 검색 품질 메트릭과 엔드 투 엔드 메트릭을 모두 활용해야 합니다.

마지막으로, 공개 벤치마크 셋 자체를 더 넓히고, 관련성 라벨링을 개선하며, 이번에 관찰된 국소적인 이득이 더 크고 다양한 워크로드에서도 유지되는지를 검증해야 합니다. 여기서 핵심이 되는 방법론적 질문은 단순히 “검색이 좋아졌는가?”가 아니라, “어떤 종류의 검색 개선에 어떤 벤치마크 레이어가 가장 민감하게 반응하는가?” 입니다.

Edit this page