본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 26. 12:26

에이전트 검색은 비용 곡선의 문제다: Claude Code가 RAG를 사용하지 않는 이유

요약

Claude Code가 코드 검색에 RAG 대신 grep 방식을 사용하는 근본적인 이유를 비용 곡선 관점에서 분석합니다. 인덱스 기반 검색의 높은 유지보수 비용과 대비하여, LLM 툴 루프 방식의 경제적 효율성과 정확성을 설명합니다.

핵심 포인트

  • RAG의 높은 구축 및 유지보수 비용 문제
  • 코드 검색에서 정밀도(Precision)의 중요성
  • LLM 툴 루프 방식의 선형적 비용 구조
  • Claude Code의 내부 동작 원리 분석

최근 유행하는 인터뷰 질문이 하나 있습니다: "왜 Claude Code는 코드를 검색하기 위해 RAG를 사용하지 않고 grep을 사용할까요?"

흔히 알려진 답변은 다음과 같습니다: 청킹(chunking)은 코드 구조를 깨뜨리고, 벡터(vectors)는 코드가 정확성을 요구할 때 근사치만을 제공하며, 인덱스(indexes)는 최신 상태를 유지하기 어렵고, 콜드 스타트(cold-start)는 느리며, 검색(retrieval)은 블랙박스라는 것입니다. 이 다섯 가지 모두 실제적인 문제입니다. 하지만 이 중 어느 것도 진짜 이유는 아닙니다.

이것들은 증상일 뿐입니다. 진짜 이유는 RAG보다 오래되었고, LLM보다 오래되었으며, _검색(retrieval)_이라는 용어보다 더 오래되었습니다. 그것은 바로 **비용 곡선(cost curve)**입니다.

요약(tl;dr) — 인덱스 기반 검색(Index-based retrieval)은 높은 구축 비용과 더불어, 코드 변경(churn) × 인덱스 복잡성에 따른 비선형적(nonlinear) 유지보수 비용을 지불해야 합니다. LLM 도구 루프 검색(LLM tool-loop retrieval)은 초기 비용이 들지 않으며, LLM이 실제로 실행하는 쿼리에 대해서는 프로젝트 규모와 거의 무관한 쿼리당 비용을 지불합니다. 대부분의 중소규모 리포지토리(repos)에서는 이 두 방식의 교차점(crossover)에 도달하지 않습니다. "Anthropic이 모델을 신뢰한다"는 프레임은 낭만적이지만, 실제 답은 더 냉혹합니다. 구축 비용은 0이고, 쿼리당 비용은 인덱스 드리프트(index drift)보다 빠르게 상쇄되므로, 수학적으로는 grep이 정답이라는 것입니다.

또한 정밀도(precision) 축이 있는데, 대부분의 엔지니어는 비용보다 이를 더 중요하게 생각합니다. 벡터 RAG(Vector RAG)는 설계상 근사치를 제공합니다. getUserByIdgetUserByEmail과 함께 반환되는 이유는 그것들이 의미론적으로 인접하기 때문입니다. 코드는 대개 정확한(exact) 결과를 원하며, grep은 이를 무료로 제공합니다. 심볼 그래프(Symbol-graph) 인덱스(Sourcegraph, Kythe, LSP)는 정밀도를 우선시하지만, LLM의 동반자가 되지는 못했습니다 — 아래에서 다룹니다.

이 내용은 파일:라인 인용 기능이 포함된 Claude Code의 공개적으로 유출된 빌드 스냅샷을 바탕으로 검증되었습니다. 핵심은 다음과 같습니다: Explore 서브 에이전트의 "3개 이상의 쿼리가 필요할 때 사용하라"는 규칙은 기능 플래그(tengu_amber_stoat) 뒤에 숨겨져 있으며, 병렬 아키텍처(Fork)와 A/B 테스트 중입니다. 정석적인 답변은 조건부입니다. _그것_이 바로 당신에게 합격 통보를 안겨줄 답변입니다.

중요한 프레임: 시간에 따른 총 비용

어떤 검색 시스템을 선택하든, 당신은 서로 다른 일정에 따라 세 가지 항목에 대해 비용을 지불하게 됩니다:

  • Build cost (구축 비용) — 검색을 빠르게 만드는 구조를 조립하기 위한 일회성 작업입니다. 인덱스(Index)의 경우, 이는 청킹(Chunking) + 임베딩(Embedding) + 삽입(Insert) 과정입니다. 툴 루프(Tool-loops)의 경우, 이 비용은 0입니다.
  • Maintain cost (유지 비용) — 기초 데이터가 변경됨에 따라 구조를 정확하게 유지하기 위한 지속적인 작업입니다. 인덱스의 경우, 이는 무효화(Invalidation), 재인덱싱(Reindex), 드리프트 조정(Drift reconciliation)입니다. 툴 루프의 경우

flowchart LR
가 전체 논거입니다. 이 게시물의 나머지 부분은 증거, 즉 소스 코드에서 비용 곡선 선택이 어떻게 보이는지, 그리고 Anthropic이 어디서 헤징(hedging)하고 있는지에 대한 내용입니다. 무언가 흥미로운 결론이 나올 수 있는 힌트: 대부분의 설명자들이 인용하는 정형화된

  1. 청킹 (Chunking)은 구조를 파괴합니다. 여러 청크에 걸쳐 나뉜 함수는 if/else 구문의 양쪽 절단을 모두 잃게 되며, 호출 그래프 (call-graph) 관계가 청크 사이에서 파편화됩니다. AST 인식 (AST-aware) 청커가 존재하지만, 이는 개선된 수준일 뿐 해결된 것은 아닙니다.
  2. 벡터 (Vectors)는 근사치입니다. getUserByIdgetUserByEmailgetUserByName과 함께 반환되는 이유는 이들이 의미론적으로 인접해 있기 때문입니다. 정확한 심볼 (symbol) 검색은 이를 아주 쉽게 능가합니다. 중요한 차이점: 이는 특히 **벡터 RAG (vector RAG)**에 해당되는 이야기입니다. 심볼 그래프 인덱스 (Symbol-graph indexes) — Sourcegraph, Kythe, Glean, LSP 기반 코드 검색 — 는 다른 범주입니다. 이들은 청킹된 벡터가 아니라 함수/클래스/참조를 기준으로 인덱싱합니다. 이들은 정확한 답을 제공하며

왜일까요? 코드 검색의 기준점(baseline) — 즉, LLM이 개입하는 깨끗한 파일 시스템 상의 grep — 이 이미 충분히 잘 작동하기 때문입니다. 여기에 인덱스(index)를 추가하는 것은 인덱스 자체가 근본 원인인 증상들을 해결하기 위해 엔지니어링 비용을 지불하는 것과 같습니다. 인덱스를 제거하면 고통도 사라집니다. 남은 비용은 쿼리당 LLM 왕복(round-trips) 비용이며, 비용 곡선(cost-curve) 프레임워크에 따르면 이는 교차점(crossover) 아래에서는 수용 가능한 수준입니다.

그것이 바로 grep을 사용하는 이유입니다. 그 외의 모든 것은 그 결정 위에 쌓이는 엔지니어링 세부 사항일 뿐입니다.

그렇다면 왜 심볼 그래프(Symbol-Graph) 또한 LLM 동반자가 되지 못했는가?

만약 심볼 그래프 인덱스가 정밀도를 우선시하고, 언어를 인식하며, FAANG 규모에서 검증되었다면, 자연스러운 질문은 이것입니다. 왜 그것들이 LLM 코딩 에이전트의 기본 동반자가 되지 못했는가? 왜 MCP 기반의 LSP가 아니라 grep인가?

그 답은 벡터 RAG(vector-RAG)의 답변과 같은 형태를 띱니다. 즉, 기능 비교표에는 나타나지 않는 부분에서 발생하는 높은 마찰(friction) 때문입니다. 다만 구체적인 마찰의 종류가 다를 뿐입니다.

  1. 빌드 비용이 다른 방식으로 높습니다. 심볼 그래프 인덱스는 심볼(symbols)을 해석하기 위해 프로젝트를 컴파일(또는 준컴파일)해야 합니다. Rust, C++, 대규모 TypeScript 또는 Java 코드베이스의 경우, 콜드 스타트(cold start) 시 수 분에서 수십 분이 소요됩니다. "Claude Code를 열고 바로 작업을 시작한다"는 경험은 그런 통행료를 지불할 수 없습니다.
  2. 언어에 종속적이며 이식성이 낮습니다. LSP는 언어당 하나의 서버가 필요합니다. Tree-sitter 지원이 도움이 되긴 하지만 균일하지는 않습니다. grep 기반의 에이전트는 설정 없이 어떤 언어의 어떤 텍스트에서도 작동하지만, 심볼 그래프 기반의 에이전트는 프로젝트의 언어 서버(language-server) 매트릭스를 그대로 물려받아야 합니다.
  3. LLM의 추론 방식과 API/포맷이 일치하지 않습니다. LSP는 깊게 중첩된 JSON(위치, 범위, 문서 계층 구조)을 반환하지만, grep은 file:line: content를 반환합니다. 후자는 거의 문자 그대로 LLM의 네이티브 방언(native dialect)에 가깝고, 전자는 적응 과정이 필요합니다. 이러한 변환 비용(translation tax)은 실제로 존재합니다.
  4. 커버리지가 보기보다 좁습니다. 심볼 그래프는 코드를 구조로서 모델링합니다.

설정 파일(config files), 주석(comments), 문자열(strings), 생성된 코드(generated code), 마크다운(markdown), 환경 파일(.env files), 셸 스크립트(shell scripts), README 등은 실제 코딩 세션에서 일급 객체(first-class) 컨텍스트입니다. 하지만 심볼 그래프는 이를 놓칩니다. Grep은 텍스트인 것이라면 무엇이든 커버합니다.

  1. 승리는 의도(intent) 질문이 아닌 구조(structure) 질문을 위한 것입니다. "getUserById가 어디에 정의되어 있나요?"라는 질문에는 심볼 그래프(symbol-graph)가 정확합니다. "로그인 흐름이 어떻게 작동하나요?"라는 질문에는 다시 grep + 읽기(read)로 돌아가야 합니다. 실제 코딩 업무에는 이 두 가지 종류가 모두 존재합니다. 한 종류만 해결하는 인프라를 구축하는 것은 절반의 정답을 위해 높은 고정 비용을 지불하는 것과 같습니다.

  2. 그 아래에서 제약 조건이 역전되었습니다. 심볼 그래프는 제약 조건이 *인간의 주의력 대역폭(human attention bandwidth)*이었던 세상을 위해 설계되었습니다. 즉, 개발자에게 읽을 수 있는 하나의 정확한 답변을 제공하는 것입니다. LLM은 그러한 제약이 없습니다. LLM은 30개의 grep 검색 결과를 저렴하게 읽고 그 사이의 관계를 추론할 수 있습니다. 병목 현상은 "검색의 정밀도(precision of retrieval)"에서 "검색 결과를 읽는 모델의 유창성(fluency of the model reading the retrieval)"으로 이동했습니다. 심볼 그래프는 더 이상 비용이 많이 들지 않는 부분을 최적화하고 있는 셈입니다.

한 줄 요약: 심볼 그래프는 인간용 IDE를 위해 구축된 정밀 도구입니다. LLM은 인간용 IDE가 아닙니다. 이들의 검색 병목 현상은 다릅니다. 이들은 하나의 비싼 정밀 호출보다 여러 번의 저렴한 반복을 선호합니다. 한 세션 동안 30번의 grep을 수행할 수 있는 에이전트에게 심볼 그래프를 설치하는 것은, 이미 운전을 할 줄 아는 사람에게 두 번째 운전사를 고용하는 것과 대략 비슷합니다.

이것이 바로 몇 안 되는 기존의 LLM ↔ 심볼 그래프 통합 사례들(LSP를 통한 Cursor의 @symbol 참조, Sourcegraph Cody, LSP 백엔드를 사용하는 Codeium)이 해당 제품들에서 검색의 중추(backbone)가 아닌 *부가적인 편의 기능(additive niceties)*인 이유이기도 합니다. 중추는 여전히 Claude Code와 마찬가지로 텍스트에 대한 grep입니다.

세 가지 기본 요소(Primitives) 검토

아래의 소스 경로는 분석 목적으로 제가 디스크에 보유하고 있는, 공개적으로 유포된 Claude Code의 비공개 빌드 스냅샷에서 가져온 것입니다. API와 정확한 줄 번호는 달라질 수 있습니다. 아래의 설계 선택 사항들은 제가 검토한 스냅샷에서 안정적이었으며, 현재 공개된 Claude Code 릴리스에서 관찰된 런타임 동작과 일치합니다.

Grep — 구조화된 출력과 "shell out 금지" 강제 조항이 포함된 ripgrep

src/tools/GrepTool/prompt.ts:7-16에서 가져온 Grep 도구 설명은 짧고 명확합니다:

ripgrep을 기반으로 구축된 강력한 검색 도구

  Usage:
...

AI 자동 생성 콘텐츠

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

원문 바로가기
0

댓글

0