Skip to content

QMD는 OpenClaw와 함께 동작하는 local-first 검색 사이드카입니다. 하나의 바이너리에서 BM25, 벡터 검색, reranking을 결합하며, 워크스페이스 memory 파일을 넘어선 콘텐츠도 인덱싱할 수 있습니다.

builtin 대비 추가 기능

  • Reranking과 query expansion -- 더 나은 recall 제공.
  • 추가 디렉토리 인덱싱 -- 프로젝트 문서, 팀 노트 등 디스크상의 무엇이든.
  • 세션 전사본 인덱싱 -- 이전 대화를 recall.
  • 완전 로컬 -- Bun + node-llama-cpp로 실행, GGUF 모델 자동 다운로드.
  • 자동 fallback -- QMD를 사용할 수 없으면 OpenClaw가 자연스럽게 builtin 엔진으로 fallback합니다.

시작하기

사전 요건

  • QMD 설치: npm install -g @tobilu/qmd 또는 bun install -g @tobilu/qmd
  • extension을 허용하는 SQLite 빌드(macOS에서는 brew install sqlite).
  • QMD가 gateway의 PATH에 있어야 합니다.
  • macOS와 Linux는 바로 동작합니다. Windows는 WSL2를 통해 가장 잘 지원됩니다.

활성화

json5
{
  memory: {
    backend: "qmd",
  },
}

OpenClaw는 ~/.openclaw/agents/<agentId>/qmd/ 아래에 자체 포함된 QMD 홈을 생성하고 사이드카 라이프사이클을 자동 관리합니다 -- 컬렉션, 업데이트, embedding 실행이 알아서 처리됩니다. 최신 QMD 컬렉션 및 MCP 쿼리 형태를 선호하지만, 필요 시 레거시 --mask 컬렉션 플래그와 구버전 MCP 도구 이름으로도 fallback합니다. 부팅 시 reconciliation은 이름이 같은 구버전 QMD 컬렉션이 남아있을 때, stale한 관리 컬렉션을 canonical 패턴으로 재생성합니다.

사이드카 동작 방식

  • OpenClaw는 워크스페이스 memory 파일과 memory.qmd.paths에 설정된 경로로부터 컬렉션을 생성한 뒤, 부팅 시 그리고 주기적으로(기본 5분마다) qmd update + qmd embed를 실행합니다.
  • 기본 워크스페이스 컬렉션은 MEMORY.mdmemory/ 트리를 추적합니다. 소문자 memory.md는 루트 memory 파일로 인덱싱되지 않습니다.
  • 부팅 갱신은 백그라운드에서 실행되어 채팅 시작을 지연시키지 않습니다.
  • 검색은 설정된 searchMode(기본값: search, vsearchquery도 지원)를 사용합니다. 모드 실패 시 OpenClaw는 qmd query로 재시도합니다.
  • QMD가 완전히 실패하면 OpenClaw는 builtin SQLite 엔진으로 fallback합니다.

INFO

첫 검색은 느릴 수 있습니다 -- QMD가 첫 qmd query 실행 시 reranking과 query expansion용 GGUF 모델(약 2 GB)을 자동 다운로드하기 때문입니다.

모델 오버라이드

QMD 모델 환경 변수는 gateway 프로세스에서 그대로 전달되므로, 새로운 OpenClaw 설정을 추가하지 않고도 QMD를 전역으로 튜닝할 수 있습니다.

bash
export QMD_EMBED_MODEL="hf:Qwen/Qwen3-Embedding-0.6B-GGUF/Qwen3-Embedding-0.6B-Q8_0.gguf"
export QMD_RERANK_MODEL="/absolute/path/to/reranker.gguf"
export QMD_GENERATE_MODEL="/absolute/path/to/generator.gguf"

embedding 모델을 변경한 뒤에는 인덱스가 새 벡터 공간과 일치하도록 embedding을 다시 실행하세요.

추가 경로 인덱싱

QMD를 추가 디렉토리로 향하게 하여 검색 가능하게 만들 수 있습니다.

json5
{
  memory: {
    backend: "qmd",
    qmd: {
      paths: [{ name: "docs", path: "~/notes", pattern: "**/*.md" }],
    },
  },
}

추가 경로에서 나온 snippet은 검색 결과에 qmd/<collection>/<relative-path> 형태로 나타납니다. memory_get은 이 접두어를 이해하고 올바른 컬렉션 루트에서 읽어들입니다.

세션 전사본 인덱싱

이전 대화를 recall하려면 세션 인덱싱을 활성화하세요.

json5
{
  memory: {
    backend: "qmd",
    qmd: {
      sessions: { enabled: true },
    },
  },
}

전사본은 정제된 User/Assistant 턴으로 ~/.openclaw/agents/<id>/qmd/sessions/ 아래의 전용 QMD 컬렉션으로 내보내집니다.

검색 범위(scope)

기본적으로 QMD 검색 결과는 direct 및 channel 세션에서만 노출됩니다(group은 제외). 이를 변경하려면 memory.qmd.scope를 설정하세요.

json5
{
  memory: {
    qmd: {
      scope: {
        default: "deny",
        rules: [{ action: "allow", match: { chatType: "direct" } }],
      },
    },
  },
}

scope가 검색을 거부하면, OpenClaw는 유도된 channel과 chat type을 로그로 남겨 빈 결과를 디버깅하기 쉽게 만듭니다.

Citation

memory.citationsauto 또는 on이면, 검색 snippet에 Source: <path#line> footer가 포함됩니다. memory.citations = "off"로 설정하면 footer는 생략되지만 경로는 여전히 에이전트에 내부적으로 전달됩니다.

사용 시점

다음이 필요할 때 QMD를 선택하세요.

  • 더 고품질의 결과를 위한 reranking.
  • 워크스페이스 바깥 프로젝트 문서나 노트를 검색.
  • 과거 세션 대화 recall.
  • API 키 없이 완전 로컬 검색.

더 단순한 설정으로 충분하다면, builtin 엔진이 추가 의존성 없이 잘 동작합니다.

문제 해결

QMD를 찾을 수 없나요? 바이너리가 gateway의 PATH에 있는지 확인하세요. OpenClaw가 서비스로 실행된다면 심링크를 만드세요: sudo ln -s ~/.bun/bin/qmd /usr/local/bin/qmd.

첫 검색이 매우 느린가요? QMD는 첫 사용 시 GGUF 모델을 다운로드합니다. OpenClaw가 사용하는 것과 동일한 XDG 디렉토리로 qmd query "test"를 실행해 미리 준비하세요.

검색이 타임아웃되나요? memory.qmd.limits.timeoutMs(기본값: 4000ms)를 늘리세요. 느린 하드웨어에서는 120000으로 설정하세요.

group chat에서 결과가 비어 있나요? memory.qmd.scope를 확인하세요 -- 기본값은 direct와 channel 세션만 허용합니다.

루트 memory 검색이 갑자기 너무 넓어졌나요? gateway를 재시작하거나 다음 시작 시 reconciliation을 기다리세요. OpenClaw는 이름이 같은 충돌이 감지되면 stale한 관리 컬렉션을 canonical MEMORY.mdmemory/ 패턴으로 재생성합니다.

워크스페이스에 노출된 임시 저장소 때문에 ENAMETOOLONG이 나거나 인덱싱이 깨지나요? QMD traversal은 현재 OpenClaw의 builtin 심링크 규칙이 아닌 QMD scanner 동작을 따릅니다. QMD가 cycle-safe traversal이나 명시적 제외 제어를 노출하기 전까지는 임시 monorepo 체크아웃을 .tmp/ 같은 숨김 디렉토리 아래나 인덱싱된 QMD 루트 바깥에 두세요.

설정

전체 설정 면(memory.qmd.*), 검색 모드, 업데이트 주기, scope 규칙을 비롯한 모든 옵션은 Memory 설정 레퍼런스를 참고하세요.

관련 문서