GitHub - tobi/qmd: mini cli search engine for your docs, knowledge bases, meeting notes, whatever. Tracking current sota approaches while being all local
Service

GitHub - tobi/qmd: mini cli search engine for your docs, knowledge bases, meeting notes, whatever. Tracking current sota approaches while being all local

tobi
2026.03.06
·GitHub·by 최세영
#CLI#LLM#Local AI#RAG#Search Engine

핵심 포인트

  • 1QMD는 BM25, Vector semantic search 및 LLM re-ranking을 결합한 온디바이스 검색 엔진으로, markdown 문서, 회의록, 지식 베이스를 색인하여 키워드 또는 자연어로 검색할 수 있습니다.
  • 2이 도구는 `qmd collection` 및 `qmd context`로 문서를 관리하고, `qmd query` 명령을 통해 Query Expansion, Parallel Retrieval, RRF Fusion, LLM Re-ranking 및 Position-Aware Blend 단계를 거치는 복합적인 하이브리드 검색 파이프라인을 제공합니다.
  • 3QMD는 Node.js 또는 Bun 환경에서 실행되며, GGUF 모델을 사용하여 로컬에서 임베딩, 쿼리 확장 및 재순위화를 수행하고, 에이전트 통합을 위한 MCP Server를 지원합니다.

QMD는 node-llama-cpp와 GGUF 모델을 활용하여 로컬에서 실행되는 온디바이스 검색 엔진입니다. 이는 Markdown 노트, 회의록, 문서 및 지식 베이스를 색인화하고 키워드 또는 자연어로 검색할 수 있게 합니다. 특히 에이전트(agent) 워크플로우에 최적화되어 있습니다. QMD는 BM25 전문 검색(full-text search), 벡터 임베딩을 이용한 시맨틱 검색(semantic search), 그리고 LLM 리랭킹(re-ranking)을 결합하여 고품질의 검색 결과를 제공합니다.

핵심 방법론 (Core Methodology):

QMD의 검색 파이프라인은 크게 색인화(Indexing)와 쿼리(Querying) 두 부분으로 나뉩니다.

  1. 색인화 흐름 (Indexing Flow):
    • 컬렉션 관리 (Collection Management): 사용자는 특정 디렉토리나 글로브 패턴(glob pattern)을 기반으로 컬렉션을 생성하고 이름을 지정하여 문서를 관리합니다.
    • 문서 처리 (Document Processing): Markdown 파일이 파싱되어 제목이 추출되고, 각 문서에는 6자리 해시(hash) 기반의 docid가 부여됩니다. 이 문서들은 SQLite 데이터베이스에 저장됩니다.
    • 전문 검색 색인 (Full-Text Search Index): 문서 내용은 SQLite FTS5를 사용하여 BM25 알고리즘 기반의 전문 검색을 위한 색인으로 변환됩니다.
    • 임베딩 흐름 (Embedding Flow):
      • 스마트 청킹 (Smart Chunking): 문서는 약 900토큰(token) 크기의 청크(chunk)로 분할되며, 15%의 오버랩(overlap)을 가집니다. 일반적인 하드 토큰 경계 대신, QMD는 Markdown의 자연스러운 분할점(예: 제목, 코드 블록, 빈 줄, 목록 항목)에 점수를 부여하여 의미 단위(semantic unit)가 유지되도록 합니다. 900토큰 목표에 도달하면, 커트오프(cutoff) 이전 200토큰 창 내에서 가장 높은 점수를 가진 분할점을 선택합니다. 이때 finalScore=baseScore×(1(distance/window)2×0.7)finalScore = baseScore \times (1 - (distance/window)^2 \times 0.7) 공식이 적용되어, 거리가 멀수록 점수 기여도가 감소합니다. 코드 블록 내부의 분할점은 무시되어 코드가 함께 유지됩니다.
      • 임베딩 생성 (Embedding Generation): 각 청크는 "title | text" 형식으로 포맷된 후 node-llama-cppembedBatch() 함수를 사용하여 embeddinggemma-300M-Q8_0 GGUF 모델로 벡터 임베딩(vector embedding)이 생성됩니다.
      • 벡터 저장 (Vector Storage): 생성된 벡터는 문서 해시, 청크 시퀀스 번호(seq), 그리고 원본 문서 내의 문자 위치(pos)와 함께 sqlite-vec 확장 기능을 통해 벡터 색인으로 저장됩니다.
  1. 쿼리 흐름 (Query Flow) - 하이브리드 검색 파이프라인:
QMD의 query 명령어는 복합적인 하이브리드 검색 파이프라인을 구현합니다.
  • 쿼리 확장 (Query Expansion): 초기 사용자 쿼리는 qmd-query-expansion-1.7B GGUF 모델을 통해 2개의 변형된 쿼리로 확장됩니다. 원본 쿼리는 2배의 가중치를 가집니다.
  • 병렬 검색 (Parallel Retrieval): 원본 쿼리와 2개의 확장된 쿼리, 총 3개의 쿼리 각각에 대해 다음 두 가지 유형의 검색이 병렬로 수행됩니다.
    • BM25 (FTS5) 전문 검색.
    • 벡터 시맨틱 검색.
  • RRF 융합 (RRF Fusion): 생성된 총 6개(3개 쿼리 ×\times 2개 검색 유형)의 랭크(rank) 목록은 Reciprocal Rank Fusion (RRF)을 사용하여 결합됩니다. RRF 점수는 (1/(k+rank+1))\sum(1/(k+rank+1)) 공식으로 계산되며, 여기서 k=60k=60입니다.
    • 원본 쿼리에 대한 가중치 2배가 적용됩니다.
    • 어떤 단일 검색 목록에서든 1위를 차지한 문서에는 +0.05점, 2-3위에는 +0.02점의 추가 보너스가 부여됩니다.
  • 후보 선택 (Candidate Selection): RRF 융합을 거친 상위 30개의 문서가 리랭킹을 위한 후보로 선택됩니다.
  • LLM 리랭킹 (LLM Re-ranking): 후보 문서들은 qwen3-reranker-0.6b GGUF 모델을 사용하여 재평가됩니다. 이 LLM은 각 문서의 관련성을 "예/아니오"와 함께 로그 확률(logprobs) 신뢰도로 평가하여 0.0에서 1.0 사이의 점수를 부여합니다. node-llama-cppcreateRankingContext()rankAndSort() API를 활용합니다.
  • 위치 인지 블렌딩 (Position-Aware Blending): 최종 점수는 RRF 점수와 리랭커 점수를 혼합하여 산출됩니다. 이는 RRF 순위에 따라 혼합 비율이 달라집니다.
    • RRF 랭크 1-3위: 75% RRF, 25% 리랭커 (정확한 매치 보존)
    • RRF 랭크 4-10위: 60% RRF, 40% 리랭커
    • RRF 랭크 11위 이상: 40% RRF, 60% 리랭커 (리랭커 결과에 더 의존)
이 접근 방식은 순수 RRF가 쿼리 확장으로 인해 정확한 매치를 희석시킬 수 있는 문제를 방지하고, 리랭커가 초기 고신뢰도 검색 결과를 훼손하지 않도록 합니다.

시스템 요구사항 및 모델:
Node.js>=22Node.js >= 22 또는 Bun>=1.0.0Bun >= 1.0.0이 필요하며, macOS에서는 Homebrew SQLite가 요구됩니다. QMD는 embeddinggemma-300M-Q8_0 (임베딩), qwen3-reranker-0.6b-q8_0 (리랭킹), qmd-query-expansion-1.7B-q4_k_m (쿼리 확장)의 세 가지 로컬 GGUF 모델을 사용하며, 이들은 첫 사용 시 자동으로 다운로드되어 ~/.cache/qmd/models/에 캐시됩니다.

MCP 서버 (Model Context Protocol Server):
QMD는 CLI 도구 외에 MCP 서버를 제공하여 Claude와 같은 에이전트와 더 긴밀하게 통합될 수 있습니다. HTTP 전송을 지원하여 장시간 실행되는 서버를 통해 모델 로딩 비용을 줄일 수 있습니다.