Kazeia-engine/dist/HANDOFF.md

73 lines
5.4 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.

# Kazeia-Engine — handoff intégration (MAJ 26/05/2026)
Point d'entrée unique. Remplace le LLM ExecuTorch/Genie par llama.cpp (fork ql) + Hexagon.
GGUF, pas de `.pte`. STT reste ORT-QAIRT (inchangé).
## Décisions figées cette session
- **Modèle Speaker = Qwen3.5-4B en variante `q35-lmq4.gguf`** (embeds en Q4 au lieu du Q6_K
par défaut → 2.38 GB, decode +5%, qualité ≈ Q4_0 mesurée). Choisi sur l'éval qualité
(`../eval/VERDICT.md`) : gagne le SAFETY (cite 3114/15) et la majorité du SUPPORT vs le dense.
- **9B écarté** (decode ~4-5 t/s réel, trop lent ; pas de gain qualité justifiant). Cascade
éventuelle = Guard-4B (thinker) + 4B (speaker), pas 9B.
- **Kernel GDN = chantier clos** : son calcul n'est PAS le goulot (cf RAPPORT_RD §7). Ne pas
y retoucher pour la perf. Decode au plafond BW CPU (~25 GB/s).
## État du bridge JNI (`jni/kazeia_engine_jni.cpp`) — OPTION C câblée (27/05)
Le JNI implémente **C** (prefill HTP / decode CPU), validé multi-tour (`jni/dual_ctx_mt.cpp` :
3 tours cohérents + mémoire conversationnelle OK, prefill HTP 103-144 t/s, decode CPU ~7-9).
- `load()` : pose `GGML_HEXAGON_GDN_PREFILL=1` + `GGML_HEXAGON_OPFILTER=SSM_CONV` (avant init backend),
charge le modèle **2×** : instance HTP (ngl99, device HTP0, t8) + instance CPU (ngl0, t4). ~4.7 GB.
- `generate()` : prefill du prompt sur HTP → `llama_state_seq_get/set_data` transfère le KV → decode sur CPU.
Sans état entre appels (l'app passe l'historique complet dans le prompt → re-prefill HTP, rapide).
- KV **f16**, flash_attn ON, thinking OFF (`<think></think>` vide), greedy. API inchangée : `load/generate/reset/free`.
-**Rebuild `libkazeia_engine.so` requis** (le .so livré est l'ancienne version CPU-only/q8_0).
`CMakeLists.txt` inchangé (linke llama+ggml+ggml-base+log) ; compile+linke vérifié (4 symboles JNI OK).
## Décisions (vérifiées 27/05, batterie 90%, device froid)
1. **KV = f16 (RÉSOLU, corrigé dans le JNI).** Mesuré : decode q35-lmq4 f16=**10.9** vs q8_0=**6.5**
(40%, idem à d=512). Le déquant KV en flash-attn coûte plus que le BW épargné. `type_k/v`
repassé en `GGML_TYPE_F16`. → **rebuild `libkazeia_engine.so` avant de shipper** (le .so livré
contient encore l'ancien q8_0). q8_0 seulement si OOM KV en très long contexte.
2. **Prefill HTP : RÉCUPÉRABLE via `GGML_HEXAGON_OPFILTER=SSM_CONV`.** Cause du charabia localisée :
**une seule op, SSM_CONV (conv1d), est cassée sur HTP en multi-token (prefill) pour d_inner=1024/2048**
(oracle FAIL ERR~1.3 ; decode n=1 OK ; bug côté backend hexagon, pas le calcul — les 2 chemins HTP
échouent, ggml-cpu est correct). En forçant cette op sur CPU (`OPFILTER=SSM_CONV`), le reste du prefill
tourne sur HTP et la **sortie redevient cohérente** : « Je comprends que cette rumination nocturne… ».
Mesuré : **prefill HTP 181 t/s** (×13 vs CPU 14) avec sortie correcte. Trois options d'intégration :
- **A (livrée) CPU-only** : prefill 14, decode 10.9, 2.4 GB. Simple.
- **B mono-contexte HTP + OPFILTER** : prefill **181**, decode HTP **6.4**, 2.4 GB (+ION). Gros gain prefill,
decode + lent, aucune RAM en plus, peu de code (ngl99 + env). **Recommandé** pour prompts longs/multi-tour.
- **C dual-contexte (prefill HTP+OPFILTER → transfert KV → decode CPU)** : prefill 181, decode **10.9**,
**+2.3 GB** RAM (2e instance). Optimal mais + complexe. Harness prouvé : `jni/dual_ctx.cpp`.
TODO propre : corriger SSM_CONV HTP (gate `test-backend-ops -o SSM_CONV` = 45/45) → enlèverait l'OPFILTER.
## Perf (sains, 27/05, device froid)
| | prefill | decode | RAM |
|---|--:|--:|--:|
| q35-lmq4 — **C: HTP-prefill / CPU-decode (CÂBLÉ JNI)** | **103-180** (HTP, monte avec ctx) | **~7-9** (CPU, profondeur) | 4.7 GB |
| q35-lmq4 — A: CPU-only | 14 | 10.9 (ctx court) | 2.4 GB |
| q35-lmq4 — B: HTP+OPFILTER mono-ctx | 181 | 6.4 (HTP) | 2.4 GB +ION |
| q35-lmq4 — HTP sans OPFILTER | 189 *(sortie CASSÉE: SSM_CONV)* | — | — |
Multi-tour mesuré (C) : tour1 63tok→prefill 103/decode 9 ; tour3 268tok→prefill 144/decode 6.7 ; mémoire OK.
Decode CPU baisse avec la profondeur de contexte (normal). Un tour ~80 tok ≈ prefill 1-3 s + decode 9-12 s.
Decode = ce que l'utilisateur ressent (10.9, OK). Prefill CPU 14 t/s → prompt 200 tok ≈ 14 s ;
garder le system prompt + l'historique courts. Le prefill HTP rapide existe mais sort du charabia (cf décision 2).
## Système (prompt) — `system_fr.txt` fourni
Inclut les garde-fous (3114, pas de prescription) + 2 correctifs issus de l'éval :
tutoiement constant, et « ne présume pas du pire, fais préciser » (le modèle lisait
« le départ de ma fille » comme un décès). À passer tel quel en `sys` de `generate()`.
## Paquet à intégrer
- `lib/*.so``app/src/main/jniLibs/arm64-v8a/` (libkazeia_engine.so **statique** + ggml/htp ;
htp-v79 = celui de cette session, fp16 derrière env `KZ_F16` OFF par défaut = comportement inchangé).
- `jni/kazeia_engine_jni.cpp` + `jni/EngineLlmEngine.kt` + `include/` → projet app.
- `q35-lmq4.gguf` → external storage (2.38 GB, hors git ; le pousser ou le reproduire, cf MODELS.md).
- `./package.sh` réassemble `lib/` depuis le build `ql/b` + recopie le prompt.
## Détails
INTEGRATION.md (build/CMake), MODELS.md (modèle + recette), PERF.md (mesures+leviers morts),
PITFALLS.md (pièges vécus), STATUS.md (limites). Verdict qualité : `../eval/VERDICT.md`.