runbook : contournement direct NVIDIA NIM/OpenRouter pour onedrive_vec
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
# nyora-notes-tt -- contournement direct NVIDIA NIM/OpenRouter pour onedrive_vec
|
||||
|
||||
**Instance auteur** : hermes-tt (Claude, session nyora-notes-tt)
|
||||
**Date** : 2026-08-05
|
||||
**Tags** : nyora-notes-tt, bifrost, embeddings, nvidia-nim, openrouter
|
||||
**Statut** : valide, backfill en cours
|
||||
|
||||
---
|
||||
|
||||
## Probleme
|
||||
|
||||
Le quota gratuit Google (`embed_content_free_tier_requests`, 1000/j sur
|
||||
`gemini-embedding-001`) etait epuise, cassant a la fois le backfill embeddings
|
||||
et la recherche vectorielle en temps reel de `search_onedrive_archive`. Le fix
|
||||
de rotation multi-cles Bifrost (voir `common/bifrost-google-provider-key-rotation.md`)
|
||||
ne resout rien : les 3 cles Google partagent le meme pool de quota.
|
||||
|
||||
Tentative de bascule vers NVIDIA NIM et OpenRouter (tous deux gratuits, comptes
|
||||
crees le 05/08) **via Bifrost** : echec dans les deux cas, en 404. Confirme comme
|
||||
bugs Bifrost upstream, pas une erreur de config :
|
||||
- NVIDIA NIM : issue GitHub maximhq/bifrost#2356 (ouverte) -- Bifrost ne transmet
|
||||
pas le header `Authorization` a l'API amont quand le provider est en
|
||||
`custom_provider_config.base_provider_type: openai`.
|
||||
- OpenRouter : erreur cote client HTTP Bifrost ("small read buffer" en lisant
|
||||
les headers de reponse), cause exacte non confirmee dans les issues connues.
|
||||
|
||||
Les deux providers fonctionnent parfaitement en appel DIRECT (sans Bifrost),
|
||||
verifie avec les memes cles.
|
||||
|
||||
---
|
||||
|
||||
## Solution validee : contournement direct, scope isole a onedrive_vec
|
||||
|
||||
`notes_vec` (mail, alimentee par `pipeline_processor.py`) et `onedrive_vec`
|
||||
(OneDrive, alimentee par `embed_onedrive_docs.py`) sont deux tables
|
||||
**separees**, toutes deux 768d/Google avant ce fix. Decision : ne toucher QUE
|
||||
`onedrive_vec` -- `notes_vec` reste sur Google/Bifrost (768d), fonctionne deja,
|
||||
aucune raison de la casser aujourd'hui.
|
||||
|
||||
**Modele choisi** : `nvidia/llama-nemotron-embed-vl-1b-v2` (2048d), disponible
|
||||
IDENTIQUE (memes poids) sur NVIDIA NIM et sur OpenRouter (OpenRouter route ce
|
||||
modele gratuit directement vers l'infra NVIDIA -- "hosted by one provider").
|
||||
Consequence utile : les deux sources produisent le MEME espace vectoriel, donc
|
||||
un vrai repli (pas deux embeddings incompatibles a ne jamais mixer).
|
||||
|
||||
**Code** (`embed_onedrive_docs.py` et nouvelle fonction `generate_onedrive_embedding`
|
||||
dans `mcp_server.py`, strictement separee de `generate_gemini_embedding` qui
|
||||
reste utilisee par `search_mail_memory`) :
|
||||
|
||||
```python
|
||||
NVIDIA_NIM_API_KEY = os.getenv("NVIDIA_NIM_API_KEY", "")
|
||||
OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY", "")
|
||||
EMBEDDING_MODEL = "nvidia/llama-nemotron-embed-vl-1b-v2"
|
||||
EMBEDDING_DIMENSIONS = 2048
|
||||
|
||||
def get_embedding(text):
|
||||
text = text[:8000]
|
||||
if NVIDIA_NIM_API_KEY:
|
||||
try:
|
||||
resp = httpx.post(
|
||||
"https://integrate.api.nvidia.com/v1/embeddings",
|
||||
headers={"Authorization": f"Bearer {NVIDIA_NIM_API_KEY}"},
|
||||
json={"model": EMBEDDING_MODEL, "input": [text], "input_type": "passage"},
|
||||
timeout=30,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
vec = resp.json()["data"][0]["embedding"]
|
||||
if len(vec) == EMBEDDING_DIMENSIONS:
|
||||
return vec
|
||||
except Exception:
|
||||
pass # repli OpenRouter
|
||||
if OPENROUTER_API_KEY:
|
||||
resp = httpx.post(
|
||||
"https://openrouter.ai/api/v1/embeddings",
|
||||
headers={"Authorization": f"Bearer {OPENROUTER_API_KEY}"},
|
||||
json={"model": EMBEDDING_MODEL, "input": text},
|
||||
timeout=30,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
return resp.json()["data"][0]["embedding"]
|
||||
```
|
||||
|
||||
**Piege NVIDIA NIM specifique** : le parametre `input_type` (`"query"` ou
|
||||
`"passage"`) est requis par leurs modeles NV-Embed*, absent chez OpenRouter --
|
||||
mis uniquement sur l'appel NVIDIA direct.
|
||||
|
||||
**Migration schema** : `onedrive_vec` (`vec0`, dimension figee a la creation)
|
||||
recree en 2048d, perte des 1781 vecteurs 768d existants (non recuperables,
|
||||
mauvais espace vectoriel de toute facon) -- backfill relance depuis zero sur
|
||||
6648 documents processed, rythme observe ~1/s (~2h estimees), aucune erreur
|
||||
constatee sur le premier lot.
|
||||
|
||||
**Secrets** : cles dans `/volume1/docker/nyora-notes-tt/.env`
|
||||
(`NVIDIA_NIM_API_KEY`, `OPENROUTER_API_KEY`) -- PAS via Bifrost pour cet usage
|
||||
precis, contournement volontaire tant que #2356 n'est pas corrige upstream.
|
||||
|
||||
---
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
docker exec nyora-notes-tt python3 -c "
|
||||
import sqlean as sqlite3, sqlite_vec
|
||||
c = sqlite3.connect('/app/nyora-notes-tt.db')
|
||||
c.enable_load_extension(True); sqlite_vec.load(c); c.enable_load_extension(False)
|
||||
print(c.execute('SELECT COUNT(*) FROM onedrive_vec').fetchone()[0])
|
||||
"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Reste a faire
|
||||
|
||||
- Laisser le backfill se terminer (~2h, tourne en arriere-plan via
|
||||
`docker exec -d`, resumable si interrompu -- rescanner simplement au
|
||||
redemarrage, la logique "deja embedde" se base sur les rowid presents).
|
||||
- Reevaluer le retour a Bifrost si/quand #2356 est corrige upstream (verifier
|
||||
changelog maximhq/bifrost).
|
||||
- Auto-actualisation OneDrive (point 1) et ingestion mail continue (point 2) :
|
||||
design discute mais pas implemente -- voir prompt de reprise en session
|
||||
suivante.
|
||||
|
||||
## References
|
||||
|
||||
- Issue Bifrost NVIDIA NIM : https://github.com/maximhq/bifrost/issues/2356
|
||||
- Runbook associe : `common/bifrost-google-provider-key-rotation.md`,
|
||||
`hermes-tt/nyora-notes-tt-3-bugs-05-08-2026.md`
|
||||
Reference in New Issue
Block a user