À l'ouverture, l'éditeur demande en parallèle la taille du cache de prompts
(et celle du second slot) et les avis MoE. Chaque aperçu lançait son
nvidia-smi pour lire les mémoires totales — trois processus pour une réponse
identique, la mémoire d'une carte ne bougeant pas.
- La lecture brute des mémoires totales est partagée dix secondes ; le verrou
tenu pendant la lecture fait attendre les demandes simultanées sur la
même. La sélection des cartes (CUDA_VISIBLE_DEVICES) s'applique ensuite,
comme avant.
- Un échec est gardé le même délai : une salve ne relance pas trois lectures
vouées à échouer. « loki serve » ne lit qu'une fois : rien n'y change.
- Test : trois demandes simultanées, une lecture, chaque sélection juste ;
échec non relancé dans la salve.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
La garde du mode de chargement est le seul refus actif par défaut du lot 2 :
il ne doit tomber que sur un échec certain, et se dire là où l'on regarde.
- Serveurs --rpc (ou LLAMA_ARG_RPC) : une part des poids part ailleurs, la
VRAM locale ne borne plus rien — avertissement, jamais de refus.
- Mac Intel : la mémoire n'est unifiée que sur Apple Silicon ; ailleurs la
VRAM est inconnue, donc jamais de refus (l'agrandissement du cache RAM
reste coupé sur tout macOS, comme avant).
- LLAMA_ARG_NO_MMAP / LLAMA_ARG_MLOCK restées dans l'environnement ne
comptent plus sur un moteur à --load-mode, qui les ignore : un lancement en
mmap n'est plus refusé pour elles.
- Le refus sortait de « loki serve » avant tout chargement : l'interface
affichait un chargement sans fin. modelLoadError le reconnaît et dit quoi
faire (--load-mode mmap ou LOAD_GUARD=off).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Un MoE aux experts sur CPU se règle aujourd'hui à la main (-ot, --n-cpu-moe
40, UBATCH 512) sans que Loki dise ce que --fit ferait mieux, ni qu'un
--load-mode none/mlock trop gros pour la RAM mène au swap ou à l'OOM
(llama.cpp #26110). Rien n'est réécrit en douce : des avis, une copie sur
demande, un refus seulement quand l'échec est certain.
- moeNotes (pure, comme nglArgs) : experts placés à la main → --fit ne les
place pas, et ne pas monter UBATCH seul (tampon plus gros sur chaque carte) ;
placement auto, MoE plus gros que la VRAM, UBATCH ≤ 512 → « UBATCH 2048+ » ;
moteur sans --fit → « garde --n-cpu-moe » ; --fit coupé par un autre -ot.
Le détecteur cpuExperts ne compte un -ot que s'il vise les experts (exps)
vers le CPU : celui de per_layer_token_embd n'en est pas.
- « Dupliquer en placement auto… » (éditeur, /api/preset/autoplace) : COPIE du
preset affiché, sans -ot des experts, --n-cpu-moe, --cpu-moe, -ngl,
--tensor-split, --fit off, -b/-ub ni drapeaux de chargement ; NGL retiré,
UBATCH 2048, BATCH 4096, --load-mode mmap ; CTX, cache KV, échantillonnage
intacts. Refusée si --fit resterait inactif ou si CTX vaut 0. L'original
n'est pas touché, la copie n'est pas activée.
- loadModeRisk : none, mlock, dio, mmap+mlock (et --no-mmap, --mlock,
LLAMA_ARG_*) face à la RAM effective (limite cgroup comprise), en comptant
modèle moins VRAM (tout le modèle sur macOS) : avertissement au-delà de
80 %, refus au lancement au-delà de 90 % de la borne basse seulement ;
LOAD_GUARD=off le lève. VRAM inconnue : jamais de refus.
- Éditeur : avis sous « Experts MoE sur CPU » et sous « Chargement ».
Ligne de commande et environnement du moteur inchangés (test de
non-régression) ; presets externes ignorés.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Passer de A à B puis revenir à A relance llama-server deux fois, et la
conversation de A est recalculée en entier au retour. Avec SLOT_PERSIST=on
(off par défaut), Loki demande au moteur d'écrire l'état du slot 0 juste
avant la bascule, et le recharge au retour avant le premier message de la
discussion — seulement si tout concorde, sinon calcul normal, en silence.
llama.cpp ne vérifie à la relecture que types et tailles : rien ne dit quel
build ni quels réglages ont calculé ce cache. La clé de validité est donc
l'empreinte de tout ce qui touche au calcul, prise par « loki serve » au
lancement : ligne de commande complète (modèle, CTX, types KV, NGL, lots,
gabarit, SPEC, EXTRA_ARGS…), LLAMA_ARG_*/GGML_*/CUDA_*, taille et date du
modèle et de ses tranches, du projecteur, du brouillon, du binaire et de
ses bibliothèques. Pas de cas « mise à jour du moteur » : elle change la clé.
- --slot-save-path posé aussi pour SLOT_PERSIST accepté, sous les mêmes
conditions de sécurité que l'isolation du lot 1 (boucle locale ou clé
d'API) ; refusé avec le décodage spéculatif (le save ne garde pas le
brouillon ; /slots speculative revérifié à chaque fois), des poids sur
CPU, un --slot-save-path à la main ; la ligne reste alors celle d'avant
- sauvegarde depuis l'interface ou une tâche, avant l'arrêt : le slot doit
porter un tour de la discussion (tampon d'engineMarkMain), ≥ 4096 jetons,
≤ 8 Gio estimés, double de place libre ; nom provisoire, renommé
seulement si aucune requête n'est partie pendant l'écriture
- rechargement avant la première requête de la discussion (ou son
préchauffage) : même clé de moteur, même discussion, slot 0 vierge (/slots
sans id_task) ; une seule tentative, fichier retiré ; toute erreur =
calcul normal
- deux fichiers au plus ; clé retirée = tout effacé au lancement suivant ;
SLOT_PERSIST préservé à la bascule comme HOST (sinon B effaçait l'état de A)
- README : SIDE_SLOT, le cache KV plein ne déclenche jamais de compaction
- tests : plan et refus, ligne inchangée, empreinte (clé d'API exclue,
fichiers et réglages inclus), rotation, séquence save puis restore sur un
faux moteur, refus à la sauvegarde et au rechargement, autre clé, défaut
sans aucun appel
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
llama-server garde en RAM hôte une copie exacte des états de slot qu'il quitte
(KV, état récurrent, points de reprise, brouillon MTP) et la recharge octet pour
octet. Mais son défaut de 8 Gio ne tient pas une conversation de 30 à 65 k
jetons à côté de l'état d'un vérificateur, d'un sous-agent, d'une tâche ou d'un
bench : à la requête suivante il évince la conversation pour sauver l'annexe, et
tout est recalculé (30 à 80 s sur un 27B). Rien de ce que voit le modèle ne
change ici : seul le bruit de découpage des lots, comme le cache_prompt actuel.
- CACHE_RAM (Mio ; vide/auto, nombre passé tel quel, -1, 0) → --cache-ram,
seulement si l'aide du moteur le connaît. Loki se tait devant -cram
d'EXTRA_ARGS et LLAMA_ARG_CACHE_RAM. L'auto ne descend JAMAIS sous le défaut :
il agrandit seulement un modèle tout-GPU (VRAM NVIDIA connue, aucun poids ni
KV sur CPU, NGL complet), d'après l'état mesuré dans le GGUF (2,5 × KV à CTX
+ état récurrent et points de reprise des hybrides), plafonné à 30 % de la RAM
(limite cgroup comprise) et à la moitié de la RAM libre.
- --slot-save-path LOKI_HOME/slots (0700, purgé au lancement) uniquement si le
moteur est en boucle locale ou protégé par clé, et si le dossier existe. Les
proxys /v1 et du relais refusent désormais toute action /slots (405).
- engineSideJob efface le slot 0 APRÈS le sous-agent, la passe de vérification,
la tâche planifiée et le bench (pas après la compaction : rien à y gagner).
Synchrone, borné à 2 s, et seulement si : moteur local, build ≥ 8660 lu dans
/props, total_slots == 1, slot 0 au repos, aucune requête de Loki en vol
(compteur tenu par le chat, les résumés, le bench et les proxys).
CACHE_ISOLATE=off le coupe.
- usage.prompt_tokens_details.cached_tokens : si la conversation revient avec
moins de la moitié en cache, conseil (une fois) de relever CACHE_RAM.
- Éditeur de preset : champ « Cache de prompts » à côté d'UBATCH, avec la
valeur auto calculée par le serveur (/api/preset/cacheram).
- Lecteur GGUF : embedding_length, head_count et dimensions ssm.*.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>