kazeia/kazeia-android/docs/SAMPLING_ENGINE_SPEC.md

94 lines
4.1 KiB
Markdown

# Spec — API d'échantillonnage natif (kazeia-engine) pour les presets Kazeia
**Date** : 2026-06-18
**Demandeur** : app Kazeia (refonte presets admin)
**Cible** : `kazeia-engine` (lib `libkazeia_engine`, JNI `EngineJni`)
## Contexte
L'app admin permet désormais de régler, par modèle (Speaker / Thinker) et via des
**presets** nommés, les paramètres d'échantillonnage : `temperature`, `top_p`,
`top_k`, `repeat_penalty`, `presence_penalty`, `frequency_penalty`, `max_tokens`.
Côté app, ces valeurs sont **persistées et transmises** jusqu'au pont JNI
(`UnifiedLlmAdapter` → `EngineLlmEngine`/`LlmSession`). **MAIS le JNI actuel
n'expose que `maxTok`** :
```kotlin
external fun generate(h: Long, sys: String, usr: String, maxTok: Int): String
external fun sessionAsk(h: Long, usr: String, maxTok: Int, cb: TokenCallback)
external fun generateStream(h: Long, sys: String, usr: String, maxTok: Int, cb: TokenCallback)
```
Donc aujourd'hui **seul `max_tokens` agit** ; température/top-p/k/pénalités sont
inertes (l'app l'indique honnêtement dans l'UI : « effectif après MAJ moteur »).
## Demande — exposer le sampling au JNI
Ajouter une **variante échantillonnée** des entrées de génération (sans casser les
signatures existantes), qui prend une struct de sampling et la câble sur la chaîne
de samplers llama.cpp. Le GGUF Qwen3.5-4B (Speaker par défaut) est la cible
prioritaire.
### Signatures proposées
```kotlin
// Struct portée côté natif (ou 7 args primitifs si plus simple en JNI) :
// temperature: Float, topP: Float, topK: Int,
// repeatPenalty: Float, presencePenalty: Float, frequencyPenalty: Float, maxTokens: Int
external fun generateSampled(
h: Long, sys: String, usr: String,
maxTokens: Int, temperature: Float, topP: Float, topK: Int,
repeatPenalty: Float, presencePenalty: Float, frequencyPenalty: Float,
cb: TokenCallback
)
external fun sessionAskSampled(
h: Long, usr: String,
maxTokens: Int, temperature: Float, topP: Float, topK: Int,
repeatPenalty: Float, presencePenalty: Float, frequencyPenalty: Float,
cb: TokenCallback
)
```
### Mapping llama.cpp (sampler chain)
Construire la chaîne par requête (ou réutiliser un `llama_sampler` reconfiguré) :
```c
auto * chain = llama_sampler_chain_init(llama_sampler_chain_default_params());
llama_sampler_chain_add(chain, llama_sampler_init_top_k(top_k));
llama_sampler_chain_add(chain, llama_sampler_init_top_p(top_p, 1));
llama_sampler_chain_add(chain, llama_sampler_init_penalties(
/*penalty_last_n*/ 64, repeat_penalty, frequency_penalty, presence_penalty));
llama_sampler_chain_add(chain, llama_sampler_init_temp(temperature));
llama_sampler_chain_add(chain, llama_sampler_init_dist(/*seed*/ LLAMA_DEFAULT_SEED));
```
- `temperature <= 0` ⇒ greedy (`llama_sampler_init_greedy`), ignorer les autres.
- Conserver le **thinking-off** et le template ChatML actuels inchangés.
- `presence/frequency_penalty = 0` ⇒ no-op (comportement neutre).
### Comportement attendu
- Valeurs de référence (preset « Kaz chaleureux ») : temp 0.4, top_p 0.85, top_k 40,
repeat 1.05, presence 0.2, frequency 0.2, max 256 — doit produire des sorties
visiblement moins répétitives / plus chaleureuses que le greedy actuel.
- Déterminisme : exposer un `seed` optionnel plus tard si besoin (pas requis v1).
### `.pte` (NPU) — hors scope v1
Le runner ExecuTorch `.pte` décode **greedy**. Le sampling y est une évolution
distincte (échantillonnage post-logits côté runner). Pour l'instant les presets
n'affectent que le chemin GGUF ; documenter la limite suffit.
## Côté app — déjà prêt
- `SamplingParams` (com.kazeia.core) porte les 7 knobs.
- `UnifiedLlmAdapter.generateWithSystem` reçoit les params ; il suffira de router
vers `*Sampled` au lieu de `ask(max)` / `generateStream(max)` quand le JNI existe.
- `ConfigStore.ModelConfig` + presets persistent les valeurs ; l'admin les édite.
Quand le JNI échantillonné est livré : ~10 lignes à changer côté `UnifiedLlmAdapter`
(brancher `sessionAskSampled` / `generateSampled`) et retirer la mention
« effectif après MAJ moteur » de l'UI admin.