---
tags: [OpenCode]
description: "QMD 2.8.3 : recherche hybride BM25 + vecteurs 100 % locale, 0 token API, 874 notes indexées."
nature: documentation
projects:
  - [[03_PROJETS/VPS-IA]]
type: note
---
# RAG local QMD pour l'espace SilverBullet shizendo

**Date :** 2026-10-28 · **Statut :** opérationnel (Phase 0 + 1 + 2)

## Objectif

Recherche sémantique/hybride locale sur le PKM (~1000 notes, 2000-3000 prévues) : le MCP `silverbullet-ai` n'a pas de recherche plein-texte/sémantique ; SLIQ = structuré uniquement. QMD (https://github.com/tobi/qmd, MIT) complète le dispositif avec BM25 + vecteurs, **100 % local, 0 token API, 0 service résident**.

## Phase 0 — accès lecture (fait 28/10)

- `sudo usermod -aG silverbullet opencode` + `systemctl restart opencode` (exécuté par Guillaume).
- `grep -r` direct sur tout l'espace : ~0,2 s / 874 .md. Lecture seule — écriture toujours via MCP//.fs.
- ⚠️ Perms à re-vérifier après chaque upgrade YunoHost SilverBullet.
- Doc : [[04_NOTES/VPS-IA_Acces-Lecture-Notes-OpenCode]]

## Phase 1 — POC (fait 28/10)

- QMD 2.8.3 installé `npm i -g @tobilu/qmd --prefix ~/.local` (préfixe utilisateur, **pas de root** ; `--allow-scripts=node-llama-cpp,...` requis pour compiler les bindings natifs).
- Collection `shizendo` → `/home/yunohost.app/silverbullet/notes/shizendo`, pattern `**/*.md`.
- Config `~/.config/qmd/index.yml` : `ignore: "**/.chrome-data/**"` (profil Chrome de la Runtime API, inaccessible → crash sinon).
- Index : 868 fichiers / 2525 chunks vectorisés / index SQLite 22 Mo (`~/.cache/qmd/index.sqlite`) ; modèles GGUF 2,2 Go (`~/.cache/qmd/models` : EmbeddingGemma-300M-Q8, Qwen3-Reranker-0.6B, qmd-query-expansion-1.7B).
- Premier embedding complet : 30 min CPU (multithread). Leçons :
  - Pression mémoire → erreurs "LLM session expired" (swap déjà chargé) → `QMD_EMBED_PARALLELISM=2` résout (passe de rattrapage : 115 chunks en 2 min).
  - **Ollama bge-m3 écarté** : ~1,2-1,5 Go RAM vs ~300 Mo pour QMD, et QMD n'accepte pas d'endpoint d'embedding externe. Alternative si besoin de qualité : `QMD_EMBED_MODEL` → Qwen3-Embedding-0.6B-Q8.

## Benchmark (28/10)

| Requête | Mode | Résultat | Temps |
|---|---|---|---|
| « usermod groupe silverbullet » | search (BM25) | ✅ pertinent | 0,37 s |
| « historique des sessions opencode » | vsearch | ✅ bonne note en 1er | 5-27 s |
| « optimiser l'usage des tokens » | query --no-rerank | ✅ pertinent | ~6 s |
| idem avec rerank | query (rerank) | ✅ mais | **5+ min** (inacceptable) |

**Verdict :** `qmd query --no-rerank` = mode par défaut (RRF BM25+vecteurs). Rerank ponctuel seulement.

## Phase 2 — industrialisation (fait 28/10)

- **Cron nocturne** : `cron-qmd-update.sh` (02:30 UTC) = `qmd update` + `QMD_EMBED_PARALLELISM=2 qmd embed`, incrémental (2 s si rien de neuf), log `~/.local/state/qmd/cron-qmd.log` (rotation > 1 Mo), alerte ntfy `vps-admin` sur échec ou chunks en attente.
- **Skill** [[80_CONFIG/IA_SKILLS/Qmd-Search]] : routage structuré→SLIQ / texte exact→grep / flou-sémantique→qmd.
- **Pas de MCP QMD** : les schémas d'outils MCP surchargeraient toutes les sessions ; le CLI suffit (agents ont le shell).

## Architecture d'accès finale (3 canaux cloisonnés)

| Besoin | Outil | Écriture |
|---|---|---|
| Structuré (tags, tasks, frontmatter) | SLIQ via MCP | oui |
| Lecture/écriture ciblée | MCP silverbullet-ai + API /.fs | oui |
| Recherche floue/sémantique | qmd (CLI, lecture seule) | **non** |

## Suivi

- À ~2000-3000 notes : index < 100 Mo prévu ; embedding incrémental sans douleur.
- Détail du crontab : [[03_PROJETS/VPS-IA]] (log 2026-10-28), skill [[80_CONFIG/IA_SKILLS/Qmd-Search]], script `/var/lib/opencode/.opencode/bin/cron-qmd-update.sh`.