
Intro
노트 관리가 단순히 읽고 쓰고 잘 찾기만 하면 된다지만, 사실 각 과정은 단순하다고 할 수 없을 만큼 복잡하다. 특히 읽기와 쓰기는 교육 과정에서 중점적으로 배우기에 그 중요성을 알고 어느 정도 익숙하다고 말할 수 있지만 찾는 것은 그렇지 않다. 이 글에서는 노트를 의미 기반으로 찾게 해주는 도구인 QMD 를 소개한다. 개인적으로 옵시디언과 함께 잘 활용 중인 툴이다.
참고로 QMD 는 로컬 기반으로 동작하는데 컴퓨터 사양이 어느 정도는 뒷받침되어야 한다.
검색의 종류와 Semantic Search
파일 검색 방식은 크게 두 가지로 나눌 수 있다.
graph TD
A[파일 검색 방식] --> B[Lexical Search<br/>#40;Keyword search#41;]
A --> C[Semantic Search]Lexical search검색어가 포함된 것을 검색한다. 우리에게 직관적으로 떠오르는 바로 그 검색 방식. BM25 가 대표적이다.Semantic search검색어와 의미가 비슷한 것을 검색한다. 의미로 검색한다는 것엔 여러 방식이 있겠지만 Personal Knowledge Management 에서 주로 다루는 방식은 embedding model 을 사용한 방식이라고 보면 된다.
Embedding model 을 사용한다는 것은 다음과 같다.
graph LR
A[📄📄📄<br/>노트들] --> B[🧠<br/>Embedding Model]
C[🔍<br/>검색어] --> B
B --> D["[0.2, -0.5, ...] × N<br/>벡터 집합"]
B --> E["[0.3, -0.4, ...]<br/>쿼리 벡터"]
D --> M(( ))
E --> M
M -- cosine similarity --> F[📄<br/>유사한 노트]
classDef plain fill:none,stroke:none
class A,B,C,F,M plain노트를 임베딩하면 벡터로 바뀐다. 좋은 임베딩 모델은 의미가 비슷한 것은 비슷한 벡터로, 다른 것은 다른 벡터로 바꾼다. 그 후 검색어가 들어오면 검색어 역시 벡터로 바꿔서 코사인 유사도로 가장 유사한 노트를 찾아낸다.
QMD
QMD 란
옵시디언 노트를 의미 기반으로 찾고 싶다는 생각은 예전부터 있었고, 사실 이는 Smart Connections 커뮤니티 플러그인으로 가능했다. 그러나 어느 시점부터 embedding model 지정이 유료화되면서, 유료 사용이 아닌 한 Smart Connections 는 엉망이 되었다. 무료로 쓸 수 있게 지정된 embedding model 의 한국어 성능이 매우 떨어지기 때문이다. 대안을 찾던 중 마침 QMD 가 등장했다.
QMD 는 Shopify 창업자 Tobi Lütke 가 만든 로컬 마크다운 검색 도구다. CLI 형태로 동작하며, 마크다운 노트를 로컬에서 인덱싱 (토큰화나 임베딩) 하여 검색 가능하게 한다. 검색 방식도 다양하다. BM25, 벡터 검색, 그리고 LLM 과 BM25 + 벡터 검색을 조합한 하이브리드 검색까지 지원한다. 이 모든 과정이 로컬 모델을 기반으로 이루어진다.
사실 임베딩 정도야 openai 나 voyage ai 의 embedding model 을 사용하고 싶긴 했다. 비용이 들긴 하지만 임베딩은 비용이 그리 많이 들지도 않고 로컬 PC 성능도 타지 않으니까. 어찌되었든 로컬에서만 작동한다는 것은 보안이 중요한 회사 등에서 사용시 장점이 될 수 있다.
또한 QMD 는 마크다운에 특화되어 있기에 마크다운 친화적으로 청킹을 한다. 그러니까 문서 내용이 길어지면 쪼개가면서 임베딩을 진행한다. 그런데 정 없이 (?) 딱 정해진 토큰 수에서 문서를 자르면 문장 중간에 내용이 분리되는 문제가 있을 수 있다. 따라서 헤딩 등의 마크다운 요소들을 사용하여 마크다운 구조 내에서 청킹을 진행한다.
QMD 로는 Semantic Search 만 사용할 것
참고로 QMD 의 Lexical search 방식인 BM25 를 그대로 쓰면 한글의 경우 잘 맞지 않는다. 예를 들어서 안보위기 라는 이름의 노트가 있으면, 안보 로는 찾아지는데 위기 로는 찾아지지 않는다. 한국어의 경우 영어와 달리 띄어쓰기 없이 쓰는 경우가 있기 때문이다. 토큰화 과정 중 발생하는 문제인데 이를 해결하기 위한 kQMD 같은 프로젝트도 있다. (참고로 이 문제는 obsidian 플러그인인 omnisearch 에서도 발생한다.) 어쩌면 앞으로 QMD 에서 이 부분을 해결한 방식으로 지원할 수도 있겠지만.
상황이 이렇기에 나의 경우 lexical search 는 QMD 가 아닌 AI Agent 가 알아서 파일을 검색하도록 맡긴다. 즉 이 경우, claude code 가 Grep 이나 Glob 을 사용하게 된다. 의미 기반 검색이 필요할 경우에만 QMD 의 semantic search 를 사용한다. 이런 식의 하이브리드 검색이 어쩌면 비효율적으로 보일 수도 있겠으나, 당장은 동작하기에 그대로 사용한다. 사실 PKM 에서 노트는 정말 많아봐야 1 만개다.
QMD 사용하기
설치
qmd 설치는 https://github.com/tobi/qmd 를 참고하면 된다. Windows 사용자의 경우 조금 골치 아플 수도 있다.
Collection 추가하기
QMD 는 collection 이라는 단위로 마크다운 노트 모음을 관리한다. 따라서 QMD 에 옵시디언 볼트를 사용하려면 볼트 폴더를 collection 으로 추가할 필요가 있다. 터미널에서 옵시디언 볼트 폴더로 접근해서 qmd collection add . --name pkm 을 입력하여 볼트 폴더를 pkm 이란 이름의 콜렉션으로 추가한다.
임베딩 모델을 변경할 것
기본적으로 지정된 임베딩 모델은 embeddinggemma-300M-Q8_0 인데 이는 한국어 성능이 떨어지는 문제가 있다. 따라서 임베딩 모델을 바꿀 필요가 있다. Qwen3 임베딩 모델을 사용하면 되는데 다음과 같이 하면 된다.
export QMD_EMBED_MODEL="hf:Qwen/Qwen3-Embedding-0.6B-GGUF/Qwen3-Embedding-0.6B-Q8_0.gguf"
qmd embed -f
export 로 환경 변수를 변경하기 때문에 ~/.zshrc 등 사용하는 쉘이 실행될 때 자동으로 임베딩 모델을 지정하게 등록할 필요가 있다. 또한 embedding model 이 변경되었기 때문에 기존에 embeddinggemma 로 임베딩을 했다면 강제로 qmd embed -f 로 임베딩을 다시 진행할 필요가 있다. (무슨 말인지 모르겠다면 AI Agent 에게 요청하면 해준다.)
또한 추가된 collection 에 파일들이 변경되었다고 자동으로 임베딩이 업데이트되는 건 아니다. 따라서 cronjob 으로 collection 업데이트 후 임베딩을 해줄 필요가 있다. 내 경우 다음 명령어를 새벽 2 시 정도에 돌도록 설정했다. 파일 변경 시마다 임베딩까지 굳이 할 필요는 없어 보인다.
qmd update && qmd embed
잘 되었는지는 qmd status 로 확인할 수 있다.
로컬 임베딩 모델이므로 아무래도 성능이 의심될 수 있다. 관련 해서는 Qwen3-Embedding 0.6B 임베딩 성능 에서 다룬다.
Openclaw 의 메모리 엔진으로 QMD 사용하기
또한 openclaw 사용자의 경우 memory engine 을 qmd 로 사용할 수 있다. openclaw 는 대화 시에 몇 가지 대화 맥락을 memory 에 저장한다. 이는 마크다운 파일로 기록된다.
그런데 이를 의미 검색을 통해서 갖고 올 필요가 있다. 솔직히 대화 내용이 아직 적을 때는 필요 없다. 극단적으로 이 파일들을 통째로 AI 에게 넘길 수 있으니까. 그런데 내용 개수가 많아지면 필요한 것만 갖고 올 필요가 있고, 그럴 경우 의미를 바탕으로 갖고 올 필요가 있다. 이때 qmd 를 사용하면 되고 그 방법은 https://docs.openclaw.ai/concepts/memory-qmd 에 작성되어 있다. 성공적으로 연동한다면
qmd status 명령 시에 콜렉션으로 memory-root-main memory-alt-main memory-dir-main 이 추가된 것을 확인할 수 있다.
AI Agent 가 옵시디언 볼트의 QMD 사용하게 하기
QMD 는 MCP 를 지원한다. 따라서 QMD 로 임베딩한 내 노트를 claude code 등이 사용하게끔 하려면 이를 MCP 로 연동시켜줄 수 있다. 예컨대, 클로드 데스크탑의 경우 다음 설정으로 MCP 연동이 가능하다.
{
"mcpServers": {
"qmd": {
"command": "qmd",
"args": ["mcp"]
}
}
}
마무리
본격적인 로컬 LLM 의 시대가 오기는 좀 멀어도 임베딩 모델에 한해서는 빠른 시일 내로 로컬 PC 에서 동작시켜도 만족스러운 수준에 도달하지 않을까 싶다. QMD 는 과금이나 귀찮은 API 설정 필요 없이 내 옵시디언 볼트를 AI Agent 가 의미 기반으로 검색하게 해주는 좋은 도구다. 한 번 사용해보는 것을 추천한다.