Zettelkasten

QMD는 BM25, 벡터, LLM 리랭킹을 로컬 SQLite에서 결합한다

·수정 2026.05.06·수정 1

요약

  • Shopify CEO Tobi Lütke가 만든 로컬 마크다운 검색 엔진. SQLite 한 파일에 FTS5(BM25) + sqlite-vec(벡터) + GGUF 모델(임베딩/리랭킹/쿼리 확장)을 패키징해, 클라우드 RAG 없이 노트/위키를 의미 검색한다.
  • 실제 가치는 "에이전트가 MCP로 호출하는 retrieval 인프라" 포지션. CLI보다 Claude Code/Cursor가 호출하는 도구로 쓸 때 진가가 나온다.

본문

핵심 아이디어

"RAG의 retrieval 레이어만 뜯어서 로컬 마크다운에 특화 + 컨텍스트 트리 + 에이전트 인터페이스로 묶은 도구."

LLM이 grep만 쓰면 키워드 매칭에 갇히고 벡터만 쓰면 정확한 용어를 놓치는 문제를, 하이브리드 + 리랭킹 + 컨텍스트 주입으로 푼다.

아키텍처

~/.qmd/index.sqlite (단일 파일)
├── FTS5 (SQLite 내장)         → BM25 키워드 검색
├── sqlite-vec (확장)          → 벡터 유사도 검색
└── 일반 테이블                 → 메타데이터, context, collections

전부 로컬 — node-llama-cpp + GGUF 모델로 임베딩/리랭킹/쿼리 확장까지 외부 API 호출 없이 수행. 데이터가 디스크 밖으로 안 나간다.

검색 파이프라인

  1. Query Expansion — LLM이 사용자 쿼리를 3가지 sub-query 타입으로 확장
    • lex: BM25 키워드 (예: "connection pool" timeout -redis)
    • vec: 의미 검색용 자연어
    • hyde: Hypothetical Document Embeddings — 답이 들어있을 법한 가상 문서를 LLM이 생성한 뒤 임베딩해서 검색
  2. 병렬 검색 — FTS5와 sqlite-vec를 동시 실행
  3. RRF (Reciprocal Rank Fusion) — 점수 스케일이 다른 결과를 순위 기반으로 병합: score(d) = Σ 1 / (k + rank_i(d))
  4. LLM Reranking — 상위 N개를 cross-encoder 스타일로 재정렬

Context Tree (qmd만의 차별점)

qmd context add qmd://meetings/2024-q3 "Q3 플랫폼 팀 정기 미팅"

검색 결과를 반환할 때 조상 경로의 컨텍스트를 함께 줌 → LLM이 "어떤 맥락의 문서인지" 즉시 이해. 벡터 DB로는 이걸 깔끔하게 못 함(각 청크에 메타데이터 박아야). 디렉토리 트리를 1급 시민으로 다루는 게 차별점.

MCP 서버 (에이전트 통합)

  • stdio: 호출마다 모델 재로딩 1~2초. 단일 사용자용
  • HTTP daemon: 모델 메모리 상주, 여러 에이전트가 공유. qmd mcp --http --daemon --port 8181

Claude Agent SDK의 mcpServers 옵션에 URL만 꽂으면 query/get/multi_get/status 도구가 자동 등록됨.

해결하는 4가지 문제

  1. grep만으론 부족 — 동의어, 모호한 자연어 못 잡음 → 하이브리드로 해결
  2. RAG 직접 만들기 번거로움 — 임베딩 호스팅, 벡터 DB, 청킹, 리랭커 통합... → npm install로 끝
  3. 클라우드 RAG의 프라이버시/비용 — 사내 위키/일기를 OpenAI에 못 올림 → 100% 로컬
  4. 검색 결과만으론 LLM이 맥락 못 잡음 → Context Tree로 디렉토리 메타 주입

SQLite 선택의 이점과 한계

이점: zero-config, 단일 파일 백업/이동, FTS5 BM25 내장, sqlite-vec로 한 SQL에서 BM25+벡터 join 가능, 트랜잭션 안전성

한계:

  • 단일 작성자 (동시 쓰기에 약함)
  • 분산 불가 (수백만 문서 부적합)
  • sqlite-vec는 brute-force에 가까움 (수만 청크까지 OK, 수백만은 느림)
  • 팀 공유는 파일 sync 또는 HTTP daemon 필요

벤치마크 현실

공식 외부 벤치마크 0개. 내부 회귀 테스트(6개 합성 문서, 24개 쿼리, Hit@K 하한선)와 자체 finetune 모델 평가(31개 쿼리 92%)만 있음. BEIR/MSMARCO/MTEB 표준 벤치마크 측정 없고, ripgrep/LangChain 대비 비교도 없음.

도입할 거면 본인 코퍼스로 직접 측정해야 함. "표준 기법 조합(BM25+벡터+RRF+리랭킹)이라 별도 검증 불필요"라는 논리에 의존하는 도구.

한국어 사용 시

  • BM25 토크나이저 한글 약함 → qmd vsearch/qmd query 위주로
  • 임베딩 모델은 multilingual-e5나 bge-m3 GGUF로 교체 권장
  • Obsidian 한글 vault + qmd MCP + Claude Code가 한국 개발자 흔한 셋업

안 써도 되는 경우

  • 문서 100개 미만 → grep 충분
  • 클라우드 RAG 이미 운영 중 → 옮길 이유 없음
  • 코드 검색 목적 → ripgrep/LSP가 더 나음

참고