Funk-lab/progress/2026-06-22.md
alkatrazz 19773a837a feat(stt): Asa agentique — boucle d'outils (function calling, Phase 1)
Asa ne répondait qu'à partir d'un contexte figé (RAG doc ou blocs live
pré-câblés, à présélectionner) → les questions à état live (« gpu-01 tourne
bien ? ») tombaient sur « la doc ne le précise pas ». Bascule vers une boucle
de function-calling : le modèle décide quels outils appeler puis répond à
partir de leurs résultats.

- Nouveau contexte `asa` (STT_DEFAULT_CONTEXT=asa, défaut prod) + tools.py
  (registre schémas OpenAI + exécuteurs) + brain.ask_with_tools (boucle bornée
  STT_TOOL_MAX_ITERS=4, réponse forcée au-delà ; _post factorisé + retry).
- Outils Phase 1, LECTURE SEULE : search_docs (RAG funk-docs), host_health
  (gpu-01|storage-01 : up/charge/RAM + llama-server), cluster_status,
  prometheus_query (PromQL arbitraire). Réutilisent sources.py / knowledge.py.
- Trace des outils renvoyée dans `context` → visualiseur HUD (un bloc par appel).
- 100 % local (Qwen3-8B) : tool-calling natif llama.cpp validé, survit au
  /no_think. LiteLLM transmet bien les tools. PromQL validés contre le vrai
  Prometheus in-cluster. 3 tests unitaires de la boucle (hors-ligne).

Web search (SearXNG in-cluster) = Phase 2 ; actions admin pilotées par le LLM
(hermes-exec comme outil) = Phase 3.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 21:45:44 +02:00

93 lines
6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 2026-06-22 — STT : transcription live + veille/réveil vocal ; relevé cluster (la veille)
## STT — streaming partiel & contrôle vocal veille/réveil (client 0.13.0 → 0.14.0)
Deux fonctionnalités demandées sur l'assistant vocal Asa.
### Transcription partielle live dans le HUD
En éveil, pendant qu'on parle, le buffer audio en cours est **re-transcrit périodiquement**
(`partial_interval_sec`, défaut 0,5 s) et poussé au HUD via un événement `partial` → le texte
**se forme en direct** dans une bulle dédiée (italique + curseur clignotant), puis la bulle
« user » finale la remplace.
- Auto-activée seulement avec l'ASR **onnx** (Parakeet ~11× temps réel en CPU) ; whisper large-v3
CPU est trop lent → laissé off (forçable via `[voice].partial_transcription`).
- Bornée : `partial_min_sec` (anti-bruit) … `partial_max_sec` (coût ; au-delà, seul le final suit).
- Transcription inline dans la boucle audio (thread unique → pas d'accès concurrent au modèle ASR).
### Veille / réveil vocal (« Asa stop » / « Asa »)
Refonte de la boucle en **machine à états** explicite veille (`asleep`) ↔ éveil :
- **Veille** : Asa transcrit chaque énoncé **uniquement** pour repérer le wake word ; ne répond à
rien d'autre. HUD : portrait atténué/désaturé, label « SOMMEIL ».
- **« Asa »** (mot entier, alias ASR tolérés) → réveil. « Asa, <question> » exécute la question.
- **« Asa stop »** (ou `stop`/`dors`/`au revoir`… = `sleep_words`) → retour veille (+ « Je me mets
en veille »). Timeout d'inactivité aussi.
- Wake word par défaut **`asa`** (était `hermes`) ; `wake_word`/`wake_aliases`/`sleep_words` config.
- Détection wake durcie : **mot entier** (plus de sous-chaîne — « asa » est court et matchait
« casa », « phrase »…).
Validé : tests unitaires (wake/sleep/alias) + Playwright (rendu `asleep`, bulle partielle mise à
jour en place puis remplacée par le final, nettoyage du partiel au changement d'état).
Bump client **0.14.0**. Doc : `admin/ia/stt.md` (section « Interaction vocale »).
> 🐛 **Trouvaille ASR (test sur poste)** : Parakeet FR ne transcrit **pas** « Asa » comme un mot
> — il l'entend **« a so » / « à ça » / « ah ça »** (deux tokens). La détection mot-entier ne
> matchait donc jamais → « rien ne se passe ». **Corrigé** : on **joint les 1-2 premiers mots**
> (déaccentués, sans espace) et on compare en égalité exacte à des alias compacts (`aso`, `aca`,
> `ahca`…). Faux positifs évités (« à cause » → `acause` ≠ alias). Ajout d'un log diagnostic
> `[stt.voice]` (journalctl, `STT_VOICE_LOG=0` pour couper) qui montre la transcription réelle.
> Validé en live : « Asa » réveille, « Asa stop » endort.
---
## (Rappel) Relevé d'état réel + RAG re-ingéré — fait la veille (2026-06-21, PR #44)
Pour mémoire, cette même journée de travail a aussi produit (PR #44, mergée) : alignement de la
doc sur l'état réel du cluster (`admin/ops/etat-cluster.md`), re-ingestion du RAG **436/436 chunks**
et le **fix du batch embed** (`llama-embed` ubatch 512 → 2048). Détail : `progress/2026-06-21.md`.
---
## Réconciliation `make apply-gpu` + durcissement IaC (soir)
-**Drop-in `llama-embed` réconcilié.** Apply ciblé `--tags llama_server` (commit llama.cpp pinné
→ zéro rebuild, seul `llama-embed` redémarre) : l'unit rendu par le rôle porte maintenant
`--batch-size/--ubatch-size 2048`. Drop-in temporaire `batch.conf` **supprimé**. `ubatch 2048`
effectif sur le process, `rag-query` OK → RAG intact.
- 🐛 **Repo `amdgpu` cassé sur gpu-01** (cause du blocage `make apply-gpu` complet) : le `dnf upgrade`
du rôle `common` avait bumpé l'hôte en AlmaLinux **9.8**, mais radeon.com ne publie pas de
`rhel/9.8` (ni 9.5) — seulement 9.4/9.6/**9.7**. Le repo package-shipped (`$amdgpudistro`) tombait
en 404. **Soigné en live** (`/etc/dnf/vars/amdgpudistro=9.7``dnf repolist` propre) et **durci en
IaC** : `rocm_rhel_version` 9.4 → 9.7, `llama_server_commit` pinné, pièges documentés dans les
README de rôle. (PR `fix/gpu-apply-amdgpu-repo-and-commit-pin`.)
## Asa agentique — boucle d'outils / function calling (Phase 1)
Asa ne répondait qu'à partir d'un contexte **figé** (RAG doc ou blocs live pré-câblés, à
présélectionner) → « gpu-01 tourne bien ? » tombait sur « la doc ne le précise pas » (état live
absent de la doc). Bascule vers une **boucle de function-calling** : le modèle décide quels outils
appeler, puis répond à partir des résultats.
- **Validé empiriquement avant de coder** : Qwen3-8B via llama.cpp fait du tool-calling natif
(pas besoin de `--jinja`), LiteLLM transmet bien les `tools`, et le tool-calling **survit au
`/no_think`**. → 100 % local, pas d'escalade Claude (choix utilisateur).
- **Nouveau contexte `asa`** (`STT_DEFAULT_CONTEXT=asa`, défaut prod) + `tools.py` (registre
schémas + exécuteurs) + `brain.ask_with_tools` (boucle bornée `STT_TOOL_MAX_ITERS=4`, réponse
forcée au-delà). Outils **Phase 1, lecture seule** : `search_docs`, `host_health`,
`cluster_status`, `prometheus_query`. Trace des outils → visualiseur HUD.
- **PromQL validés** contre le vrai Prometheus in-cluster (labels `gpu-01-node`/`storage-01`/
`llama-server-gpu` confirmés ; up/load/mem renvoient des données réelles). 3 tests unitaires de
la boucle (hors-ligne). (PR `feat/asa-tool-loop`.)
- **Choix** : web search = **SearXNG in-cluster** (Phase 2) ; modèle = **local uniquement**.
## Prochaines étapes
- **Phase 2** — outil `web_search` (SearXNG self-host in-cluster, namespace `ai`, ArgoCD).
- **Phase 3** — outil `admin_action` (écriture) : brancher `hermes-exec` comme outil piloté par le
LLM, avec le handshake de confirmation vocale existant.
- Enrichir `host_health`/`cluster_status` (GPU via `rocm_scraper`, fs, températures) si utile.
- Si le wake word « asa » génère des faux positifs/négatifs, ajuster `wake_aliases`.
- **1er test d'action vocale** (#43, contexte 🤖 Agent → `hermes-exec`).