0Guhn
0Guhn

TEI + Qdrant로 Claude Code 멀티 에이전트 시스템 만들기

#MCP#TEI#RAG#Qdrant#Claude Code

TL;DR

TEI(Text Embeddings Inference)로 코드를 벡터화하고, Qdrant에 저장해서, Claude Code의 에이전트 9개가 코드를 읽지 않고 검색하는 시스템을 만들었다.

1. 왜 만들었나

Claude Code의 한계

Claude Code는 강력하지만, 전체적으로 코드베이스를 파악할 때 파일을 하나씩 열어서 읽는다.

Read src/auth.ts          → 200줄 소비
Read src/middleware.ts     → 150줄 소비
Read src/utils/token.ts    → 100줄 소비
...

코드 품질, 보안 등 어쩔 수 없이 전체적으로 읽을 경우가 있는데 소비가 크다.

코드 리뷰어나 보안 이슈를 체크하는 에이전트가 Read 도구 없이 코드를 파악하고, 토큰 비용을 절감할 수 있을 것 같아서 시도해보았다.

2. 아키텍처

계층 구성
Claude Code 9개 에이전트 (Morpheus, Neo, Seraph, ...)
↓ MCP Protocol (stdio)
mcp-code-rag Rust 바이너리. 인덱싱/검색 브릿지
↓ HTTP / gRPC
TEI (e5-base) 텍스트 → 벡터 변환
Qdrant 벡터 저장 + 유사도 검색

구성 요소

컴포넌트 역할 위치
mcp-code-rag MCP 서버. 인덱싱/검색 요청 처리 로컬 (Rust 바이너리)
TEI (e5-base) 텍스트 → 768차원 벡터 변환 Docker
Qdrant 벡터 저장 + 코사인 유사도 검색 Docker
Claude Code Agents 코드 탐색 시 MCP 도구로 검색 로컬

3. 왜 이 스택인가

최신 임베딩 모델이나 최적의 조합을 찾는 게 목적이 아니다. GPU 없는 NAS에서 RAG 파이프라인이 실제로 돌아가는지 테스트하는 게 목적이었다. 그래서 가볍고 셀프 호스팅이 쉬운 조합을 골랐다.

TEI + e5-base

  • TEI — Hugging Face 공식 임베딩 서버. Docker 한 줄이면 배포 끝
  • e5-base — 768차원. CPU에서 ~50ms/query로 충분히 실용적
  • query: / passage: 프리픽스로 비대칭 검색을 지원해서, 짧은 질문 → 긴 코드 청크 매칭에 유리

Rust로 MCP 서버를 만든 이유

  • 바이너리 하나 — 실행 파일 하나로 배포 끝. 런타임 의존성 0
  • 메모리 — 상주 메모리 ~15MB. Python 서버는 200MB+
  • Claude Code MCP — stdio 기반 JSON-RPC. Rust의 serde + tokio가 최적
  • 외부 통신 — HTTP + gRPC 비동기 처리

4. 핵심 플로우

4.1 인덱싱 (코드 → 벡터)

프로젝트 디렉토리


[walkdir] 파일 순회 (max depth: 10)


[filter] 52개 디렉토리 + 60개 확장자 제외
         (node_modules, target, .git, 이미지, 바이너리...)


[증분 체크] 파일 수정 시간 비교
         → 변경된 파일만 처리


[chunk] 1500자 단위로 분할 (300자 오버랩)


[TEI] 각 청크 → "passage: {content}" → 768차원 벡터


[Qdrant] UUID v5 기반 upsert (100개 배치)
         Collection: "code-rag-{project_name}"

왜 1500자 청킹인가?

  • 너무 크면 → 검색 정밀도 하락 (노이즈)
  • 너무 작으면 → 함수 하나가 여러 청크로 쪼개져 맥락 손실
  • 1500자 + 300자 오버랩 → 함수 경계에서 잘리는 것을 방지

4.2 검색 예시 — 코드 리뷰 에이전트

[코드리뷰_에이전트] 보안 감사 시작


search_codebase("인증 처리 로직", project_name="my-app")


검색 결과 수신 (Top 10, 유사도 0.5 이상만):


search_codebase("SQL 쿼리 생성", project_name="my-app")


search_codebase("사용자 입력 검증", project_name="my-app")


수집된 코드 조각들로 보안 보고서 생성

결과: Read 0회, 검색 3회로 보고서 완성. 파일을 하나도 열지 않고 코드베이스의 보안 취약점을 분석한다.

4.3 자동 인덱싱

에이전트: search_codebase("에러 핸들링", project_name="blog")


[Collection 확인] "my-app" 존재?

    ├─ No → 자동 인덱싱 트리거 → 인덱싱 완료 후 검색

    └─ Yes → 즉시 검색

에이전트가 인덱싱을 직접 호출할 필요 없다. 첫 검색 시 자동으로 인덱스가 생성된다.

5. 실전 수치

항목
TEI 임베딩 속도 ~50ms/query (CPU)
인덱싱 (1000파일) ~3분 (증분 시 변경분만)
검색 응답 ~200ms (캐시 miss), ~5ms (캐시 hit)
mcp-code-rag 메모리 ~15MB
벡터 차원 768 (e5-base)
캐시 TTL 5분
최대 인덱싱 파일 5,000개
청크 크기 1,500자 (300자 오버랩)

6. MCP 도구

mcp-code-rag가 Claude Code에 제공하는 MCP 도구는 2개다.

도구 설명
search_codebase 자연어 쿼리로 코드 검색. 프로젝트명을 넘기면 자동으로 컬렉션 전환 + 미인덱싱 시 자동 인덱싱
refresh_index 프로젝트 경로를 지정해서 수동 인덱싱. 증분 방식으로 변경된 파일만 처리

에이전트가 코드를 탐색할 때 search_codebase를 먼저 호출하도록 규칙을 강제하면, Read 도구로 파일을 순회하는 토큰 낭비를 막을 수 있다.

장점

  • 한 번 인덱싱하면 이후 검색은 즉시 — 인덱싱은 최초 1회만 느리고, 이후 증분 방식이라 변경된 파일만 처리. 검색 자체는 ~200ms
  • 토큰 소비 0 — Read로 파일을 열지 않으니 컨텍스트 윈도우를 검색에 쓰지 않는다
  • 자연어로 코드 탐색 — "인증 처리", "SQL 쿼리" 같은 질문으로 관련 코드를 바로 찾는다
  • 전체 코드베이스를 훑는 작업에 강함 — 보안 감사, 코드 리뷰처럼 넓게 패턴을 파악하는 용도에 적합

한계

"에러 핸들링이 제대로 되어 있는가?" 같은 정밀한 의미 검색은 벡터 유사도만으로 부족하다. 이런 경우에는 Rerank 모델을 붙이거나, 키워드 검색(BM25)과 벡터 검색을 조합하는 하이브리드 방식이 필요하다.

용도 현재 시스템 추가 필요
전체 코드 구조 파악 적합
보안 패턴 스캔 적합
특정 로직 정밀 검색 부족 Rerank, 하이브리드 검색
에러 핸들링 추적 부족 Rerank + AST 분석

7. 시작하기

필요한 것

  • Docker 환경 (Qdrant, TEI 실행용)
  • Rust (mcp-code-rag 빌드용)
  • Claude Code (Pro 플랜)

모두 설치하고 Claude Code에 MCP 서버를 등록하면, 토큰 낭비 없이 의미 기반으로 필요한 코드만 가져온다.

Log

  • 2026-01-29: create

Claude Code 관련 글