mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-11 17:26:57 +02:00
Version 0.15.0
Version consacrée à la vitesse sans dénaturer le modèle : les lots 1, 2 et 3 de performance. Ce qui est sans perte est actif d'office ; tout ce qui change ce que voit le modèle, le placement ou les slots attend une clé. - Version passée à 0.15.0 (run.go, versioninfo.json, ressources Windows régénérées par goversioninfo seul — icônes inchangées). - Notes de release réécrites : actif d'office, opt-in et leurs clés, ordre de test conseillé, ce qui a été écarté (cache-reuse, context-shift, KV quantifié par défaut) et pourquoi. - README : une section « Performance » rassemble toutes les clés (défaut, effet, prix ou zone grise), les outils sans clé, l'ordre de test et les pistes écartées ; le détail de chaque clé y est déplacé depuis « Fonctionnalités », qui n'y renvoie plus que par un lien. - NOTICE inchangé : rien de ces lots ne reprend OpenFox ni AJEAN. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5d37bef0ce
commit
5dd14c9de5
6 files changed
+368
-180
No files matched your search
@@ -356,6 +356,242 @@ Ajoutées par ce fork :
|
||||
→ maximale) et rejoue le message sans rien perdre de l'historique — une fois,
|
||||
puis la traduction est retenue pour ce modèle. La liste est grisée quand le
|
||||
raisonnement est coupé pour ce modèle.
|
||||
- **Performance** : cache de prompts, slots, décodage spéculatif, placement
|
||||
MoE et multi-GPU, optimiseur — tout est rassemblé dans la section
|
||||
[Performance](#performance), avec la table des clés et leur défaut.
|
||||
- **Discussions multiples** : historique complet dans la barre latérale, titre
|
||||
repris du premier message (renommable), suppression. **Chaque discussion a son
|
||||
dossier de fichiers** (`workspace/discussions/<id>/`) : les pièces jointes
|
||||
déposées, les captures et ce que l'agent écrit y atterrissent, le shell et les
|
||||
chemins relatifs du modèle y sont résolus. Changer de discussion change donc
|
||||
les fichiers ; supprimer (ou vider) une discussion emporte les siens, pour que
|
||||
le disque ne se remplisse pas en silence.
|
||||
- **Recherche Hugging Face** intégrée avec verdict mémoire et installation liée
|
||||
du projecteur vision (voir [Installer un modèle](#installer-un-modèle)).
|
||||
- **Captures de pages web** : l'agent dispose de l'outil `web_screenshot`
|
||||
(Chromium via Playwright, inclus dans l'image). Les captures partent en JPEG
|
||||
et sont plafonnées à 20 fichiers / 40 Mo par discussion. La description de
|
||||
l'outil suit la capacité **réelle** du moteur, sondée sur `/props` : sans
|
||||
vision effective, elle dit au modèle « tu ne vois pas l'image » plutôt que de
|
||||
lui promettre des yeux qu'il n'a pas — il peut toujours prendre la capture et
|
||||
la montrer, sans prétendre la décrire. L'image relayée au moteur reste
|
||||
éphémère : la persister gonflait le contexte jusqu'à le faire déborder.
|
||||
- **Panneau Fichiers** (bouton dossier de la barre de saisie) : les fichiers de la
|
||||
discussion ouverte — dépôts, captures, ce que l'agent y a écrit — avec
|
||||
navigation dans les sous-dossiers, téléchargement et suppression. Un dossier
|
||||
affiche la taille de **tout** son contenu, c'est ce qu'on libère en le
|
||||
supprimant, et le pied donne l'occupation disque de la discussion. Les chemins
|
||||
sont bornés à son dossier, liens symboliques résolus des deux côtés : ni le
|
||||
reste du disque ni les autres discussions ne sont atteignables. Les fichiers
|
||||
d'avant ce rangement que la migration n'a pas su rattacher restent joignables
|
||||
par le bouton **hors discussion**, qui disparaît une fois le ménage fait.
|
||||
- **Interface « Sober Tech »** : ardoise et sauge, typographie Inter (interface)
|
||||
et JetBrains Mono (code, chiffres, chemins) — embarquées dans le binaire, donc
|
||||
aucune requête vers un service de polices. Deux variantes : claire par défaut,
|
||||
**Deep Dark** (fond `#0F172A`, cartes `#1E293B`) d'un clic depuis l'en-tête.
|
||||
L'en-tête porte le titre de la discussion et le **sélecteur de modèle** (le
|
||||
changement de preset ne demande plus d'ouvrir les réglages) ; la barre
|
||||
latérale s'escamote pour rendre toute la largeur au fil ; les discussions s'y
|
||||
cherchent au clavier et les jauges **GPU / VRAM / mémoire vive** restent
|
||||
visibles en pied de colonne.
|
||||
- **Libérer la VRAM d'un clic** : sur les jauges du moniteur, un bouton décharge
|
||||
le modèle et arrête le moteur (ainsi que le serveur de dictée, qui occupe la
|
||||
carte lui aussi) pour rendre la mémoire vidéo à une autre application — jeu,
|
||||
encodage, autre serveur d'inférence. Le bilan est annoncé en Gio réellement
|
||||
rendus, et le même bouton devient **Recharger le modèle** pour reprendre la
|
||||
main. Routes : `POST /api/vram/unload` et `POST /api/vram/reload`.
|
||||
- **API OpenAI servie par Loki** : `/v1/*` est exposé **sur le port de
|
||||
l'interface** (8090) et relayé vers llama-server, au lieu d'annoncer l'adresse
|
||||
du moteur. Conséquence directe : l'API est joignable partout où l'interface
|
||||
l'est — par l'IP du réseau local comme par un nom de domaine — sans publier de
|
||||
second port ni ouvrir le moteur. L'amont annonçait `http://<ip>:8080/v1`, une
|
||||
adresse injoignable en conteneur (le port 8080 n'y est pas publié, et l'IP
|
||||
détectée est celle du bridge Docker).
|
||||
- Authentification par la **clé API** du panneau (`Authorization: Bearer …`),
|
||||
vérifiée par Loki **et** par le moteur. Sans clé, l'endpoint est ouvert et
|
||||
l'interface le dit en rouge.
|
||||
- **Adresse publique** : un champ où saisir son domaine, pour le cas du
|
||||
reverse proxy où Loki ne voit qu'un appel interne. Laissé vide, l'adresse
|
||||
affichée suit celle du navigateur.
|
||||
- **TLS** : mettre un reverse proxy devant (Caddy, Nginx, Traefik). Loki
|
||||
honore `X-Forwarded-Proto` pour annoncer une adresse en `https`.
|
||||
- L'ancienne exposition publique via le relais de l'amont
|
||||
(`<machine>.oai.ajean.link`) est retirée de l'interface : elle exigeait un
|
||||
jeton de relais que ce fork ne permet plus d'obtenir, l'interrupteur ne
|
||||
pouvait donc qu'échouer.
|
||||
- **Budget d'appels d'outils** : un tour d'agent n'a aucun plafond — couper une
|
||||
recherche légitime est pire que la laisser durer — mais au-delà de 24 appels
|
||||
sur un même tour, Loki rappelle au modèle combien il en a déjà faits et lui
|
||||
demande de conclure. Le rappel revient tous les 24 appels, en durcissant le
|
||||
ton ; il ne coupe jamais le tour, c'est de la pression, pas une barrière.
|
||||
Sans lui, un petit modèle qui tourne en rond n'avait rien en face de lui sauf
|
||||
le bouton stop (vu en production : 50 appels, 55 minutes, à relire cinq fois
|
||||
les mêmes fichiers). Réglable par `AGENT_BUDGET` dans `config.env` —
|
||||
`AGENT_BUDGET=off` le désactive complètement.
|
||||
- **Identité** : ton prénom et un avatar emoji pour toi et pour Loki, affichés
|
||||
dans le fil.
|
||||
- **Réglages en modale** : tous les réglages vivent dans une fenêtre à deux
|
||||
volets — la nav des sections à gauche (IA, moteur, application), le panneau
|
||||
choisi à droite. La barre latérale ne garde que les discussions (les plus
|
||||
récentes en tête) et le moniteur machine.
|
||||
- **Nom du modèle sur chaque réponse** : une pastille à côté de « Loki » dit
|
||||
quel modèle a produit la réponse. Elle est journalisée avec le tour : elle
|
||||
survit au rechargement, et un vieux tour garde le modèle de l'époque.
|
||||
- **Dictée vocale** : un bouton micro dans la carte de saisie enregistre,
|
||||
transcrit **en local** (whisper.cpp, compilé dans l'image ; modèle
|
||||
`small-q5_1` multilingue ~190 Mo téléchargé au premier usage dans
|
||||
`/data/whisper/`) et pose le texte dans le champ. ⚠️ le navigateur n'autorise
|
||||
le micro qu'en **HTTPS** (ou sur `localhost`) — derrière un reverse proxy
|
||||
TLS, rien à faire ; en `http://IP:8090`, le bouton l'explique.
|
||||
- **Cartes raisonnement/outils à hauteur bornée** : un long raisonnement ne
|
||||
fait plus grandir la page de plusieurs écrans — la carte reste à taille fixe
|
||||
et défile toute seule pendant la génération. Sur un raisonnement géant, seul
|
||||
le bas du bloc est re-rendu en direct (le texte complet est posé à la fin) :
|
||||
l'affichage ne se fige plus.
|
||||
|
||||
Retirées par ce fork :
|
||||
|
||||
- **Accès distant via [ajean.link](https://ajean.link)** : la section de
|
||||
l'interface et son module JS sont supprimés — un conteneur derrière son
|
||||
propre réseau n'en a pas l'usage. Le code serveur du relais reste en place
|
||||
mais **inerte** (aucun jeton, aucune section pour en fournir un) : le retirer
|
||||
créerait un conflit à chaque reprise de l'amont.
|
||||
- **Postes distants** (faire agir l'agent sur un autre PC appairé) : bouton du
|
||||
composeur, modales d'appairage et module JS supprimés. Même traitement que
|
||||
ci-dessus — les routes `/api/node/*` subsistent mais plus rien ne peut
|
||||
générer de code d'appairage, donc aucun poste ne peut se connecter.
|
||||
- **Catalogue de modèles distant** : il interrogeait `ajean.link/models.json`,
|
||||
sa route n'avait aucun consommateur et son repli embarqué datait de 2024. La
|
||||
recherche Hugging Face le remplace.
|
||||
|
||||
## Performance
|
||||
|
||||
Le but : des tours plus courts **sans dénaturer le modèle**. Rien ici ne
|
||||
touche à la quantification des poids, à l'échantillonnage, à la température, au
|
||||
budget de raisonnement ni au contenu du contexte. Tout ce qui changerait ce
|
||||
qu'envoie Loki au modèle, le placement des poids ou les slots du moteur est
|
||||
**désactivé par défaut**, derrière une clé ; sans clé, la requête et la ligne de
|
||||
commande restent celles d'avant. Les clés se posent dans le preset (éditeur) ou
|
||||
par `loki config set CLÉ valeur` ; celles marquées « moteur relancé » demandent
|
||||
un redémarrage du moteur.
|
||||
|
||||
### Actif par défaut, sans perte
|
||||
|
||||
- **Cache de prompts dimensionné** (`--cache-ram`) : agrandi pour un modèle
|
||||
tout-GPU d'après l'état mesuré dans le GGUF, jamais sous le défaut du moteur ;
|
||||
et le slot est effacé après un sous-agent, une vérification, une tâche ou un
|
||||
bench, pour que la conversation revienne du cache RAM au lieu d'être
|
||||
recalculée.
|
||||
- **Préfixe stable** : rappels de Loki gardés dans l'historique tels
|
||||
qu'envoyés, relance après un 500 sans toucher aux outils ni au système, ligne
|
||||
MCP présente dès le premier tour, ordre des trackers fixe.
|
||||
- **Comptage du contexte** sans le raisonnement jamais renvoyé : la compaction
|
||||
(avec perte) part moins tôt, et son résumé n'est plus amputé de l'état
|
||||
d'avancement.
|
||||
- **Threads CPU** : sans `THREADS`, le moteur prend ses cœurs physiques (plus
|
||||
tous les threads logiques) ; conteneur à l'étroit (cpuset, quota) borné.
|
||||
- **Deux GPU** : `CUDA_SCALE_LAUNCH_QUEUES=4x` quand le pipeline entre cartes
|
||||
est possible (même calcul, seul le prompt peut gagner).
|
||||
- **Points de reprise des hybrides** sur un moteur officiel antérieur à
|
||||
`b10864` : `--checkpoint-min-step 2048` d'office si la RAM le permet, et un
|
||||
avis « moteur trop ancien » ; l'encart « version recommandée » propose la mise
|
||||
à jour (sur clic seulement, voir [Mettre à jour llama.cpp](#mettre-à-jour-llamacpp-sans-reconstruire-limage)).
|
||||
- **Côté Go** : écriture d'un gros fichier en temps linéaire, persistance de la
|
||||
discussion hors du chemin du premier jeton, un seul `nvidia-smi` partagé
|
||||
(moniteur et éditeur de preset), stockage Unraid servi par FUSE signalé.
|
||||
- **Mesure** : télémétrie par complétion (cache repris, recalculé, brouillon
|
||||
accepté) dans l'interface et `GET /api/perf/summary`, sonde du gabarit de
|
||||
chat (lecture seule, `/apply-template`), bench honnête en tâche de fond.
|
||||
- **Garde-fous** : un cache KV quantifié, `--context-shift` ou `--cache-reuse`
|
||||
posés à la main sont signalés ; un mode de chargement résident voué à
|
||||
l'échec est refusé (`LOAD_GUARD`) ; avis de placement MoE dans l'éditeur.
|
||||
|
||||
### Les clés
|
||||
|
||||
| Clé | Défaut | Effet | Prix, zone grise |
|
||||
|---|---|---|---|
|
||||
| `CACHE_RAM` | auto | cache de prompts en RAM hôte (`--cache-ram`, Mio), copie exacte des conversations quittées | `-1` = RAM non bornée (déconseillé avec un MoE mmappé), `0` = coupé |
|
||||
| `CACHE_ISOLATE` | actif | efface le slot après un travail annexe (sous-agent, vérification, tâche, bench) | `off` pour couper ; sans objet avec `SIDE_SLOT` |
|
||||
| `THREADS` / `THREADS_BATCH` | vide = cœurs physiques | `-t` / `-tb` | — |
|
||||
| `CUDA_LAUNCH_QUEUES` | auto (4x sur ≥ 2 GPU si pipeline) | file de lancements CUDA | `off`, ou `0.25x`…`4x` imposé ; réglage de machine |
|
||||
| `CTX_CHECKPOINTS` | moteur (32) | points de reprise par slot d'un hybride | 70 à 200 Mio de RAM hôte chacun |
|
||||
| `CKPT_MIN_STEP` | moteur (2048 d'office : hybride, moteur officiel < `b10864`) | espacement minimal des points de reprise | — |
|
||||
| `LOAD_GUARD` | actif | refuse un `--load-mode` résident qui ne tient pas en RAM | `off` = lancer quand même |
|
||||
| `REASONING_ECHO` | off | renvoie au moteur local la réflexion du modèle, au format entraîné | plus de contexte par tour, compaction plus tôt |
|
||||
| `REASONING_PRESERVE` | vide = défaut du moteur | `--reasoning-preserve` / `--no-reasoning-preserve` | change le rendu : `off` rend l'ancien historique à Qwen3.6, mais change celui de Qwen3.8 |
|
||||
| `PROJ_SNAPSHOT` | off | bloc projet figé par discussion, changements en `<context_update>` ; date et dossier sortent du système | le modèle lit les changements en tête du message suivant |
|
||||
| `PREWARM` | off | `on` : prépare le prochain tour pendant que tu lis ; `full` : aussi la discussion qu'on ouvre | une requête de plus au moteur au repos (1 jeton, jeté) |
|
||||
| `COMPACT_CONTINUATION` | off | le résumé de compaction prolonge le prompt en cache au lieu d'une transcription à froid | repli sur l'ancien chemin au moindre écart |
|
||||
| `KEEP_TURN_IMAGES` | off | garde dans l'historique les images montrées par les outils | **zone grise** : plus de contexte, compaction plus tôt ; une API externe refacture les images |
|
||||
| `NUDGE_IN_TOOL` | off | le rappel de budget d'outils part au bout du dernier résultat d'outil | **zone grise** : un modèle peut moins bien suivre une consigne lue dans un outil |
|
||||
| `SIDE_SLOT` | off (moteur relancé) | second slot pour les travaux annexes, la discussion garde le sien | cache KV et état récurrent en double en VRAM |
|
||||
| `SLOT_PERSIST` | off | état du slot gardé sur disque à la bascule de preset, rechargé au retour | 2 fichiers de 8 Gio au plus ; refusé avec `SPEC` |
|
||||
| `SPEC` | off (moteur relancé) | décodage spéculatif : `auto`, `mtp`, `ngram`, `mtp+ngram` | même distribution, pas le même texte au bit près ; MTP : 1 à 2 Go de VRAM |
|
||||
| `MODEL_DRAFT` | — | tête MTP publiée à part ou petit modèle brouillon | VRAM |
|
||||
| `SPEC_N_MAX` | moteur (3) | jetons anticipés par étape | — |
|
||||
| `SPEC_SAMPLING` | greedy (exact) | `probabilistic` seulement avec `SPEC=mtp` ou `mtp+ngram` | — |
|
||||
| `SPLIT_MODE` | couches | `tensor` : parallélisme de tenseurs entre cartes CUDA | expérimental : décodage plus rapide, prefill plus lent |
|
||||
| `FIT_TARGET` | 1024 Mio par carte | marge laissée libre par le placement auto (`--fit-target`) | — |
|
||||
| `OP_OFFLOAD_MIN_BATCH` | moteur (32) | lot à partir duquel les experts MoE sur CPU sont recopiés vers le GPU | à mesurer |
|
||||
| `CUDA_GRAPH_OPT` | off | branches Q/K/V en parallèle au décodage | expérimental ; `off` puis redémarrage s'il plante |
|
||||
| `KV_TYPE` (`_K`, `_V`) | f16 | quantification du cache KV | **zone grise** : `q8_0` modifie légèrement les sorties, `q4_0` perte mesurable — jamais posé par Loki |
|
||||
| `BATCH` / `UBATCH` | 2048 / 512 | lots du prefill | MoE aux experts en RAM : `UBATCH` 2048+ |
|
||||
| `LOKI_PERF_LOG` (environnement) | absent | une ligne `[perf]` par complétion sur stderr | — |
|
||||
|
||||
Outils sans clé, qui ne font rien d'eux-mêmes :
|
||||
|
||||
| Outil | Ce qu'il fait |
|
||||
|---|---|
|
||||
| **Bench** (bouton, `loki bench`, `--full`) | mesure en tâche de fond, à profondeur réelle avec le mode complet (prefill à froid, tours qui reprennent le cache, decode) |
|
||||
| **Optimiseur** (`loki tune`, bouton « Optimiser… ») | cherche lots, threads, marges, placement (`--placement`) et options opt-in (`--opt-in`) sur un moteur d'essai ; rien n'est écrit sans un clic |
|
||||
| **Dupliquer en placement auto…** (éditeur, MoE) | copie du preset où `--fit` place les experts au lieu de `-ot` / `--n-cpu-moe` |
|
||||
| **Version recommandée** (panneau Moteur) | met à jour llama.cpp vers un build ≥ `b10864`, sur clic, avec retour à la version précédente |
|
||||
|
||||
### Ordre de test conseillé
|
||||
|
||||
Une étape à la fois, mesurée avant la suivante :
|
||||
|
||||
1. **Bench complet** du preset tel quel : la référence.
|
||||
2. **`PREWARM=on` et `COMPACT_CONTINUATION=on`**, puis une vraie session de
|
||||
travail ; `GET /api/perf/summary` dit, par nature de requête
|
||||
(`kinds.main`…), combien de fois et de jetons le cache a été perdu
|
||||
(`lost_events`, `lost_tokens`) et le prefill par tour.
|
||||
3. **Optimiseur** (« Optimiser… ») sur le preset en service : lots, threads,
|
||||
marges.
|
||||
4. **MoE aux experts en RAM** : « Dupliquer en placement auto… », bascule sur
|
||||
la copie, `successfully fit params` au journal, bench complet des deux.
|
||||
5. **Mise à jour du moteur** vers la version recommandée si l'encart s'affiche
|
||||
(points de reprise des hybrides, MTP rapide) ; vérifier le rendu du gabarit
|
||||
dans le panneau.
|
||||
6. **`SPEC=auto`** (ou `mtp`) si le modèle a une tête MTP : bench, puis
|
||||
`draft_rate` dans `/api/perf/summary`.
|
||||
|
||||
### Ce qui a été écarté, et pourquoi
|
||||
|
||||
- **`--cache-reuse`** : réutilise des morceaux de cache calculés sous un autre
|
||||
contexte, donc change les sorties ; llama.cpp le coupe d'ailleurs pour les
|
||||
hybrides et le multimodal. Signalé s'il est posé à la main.
|
||||
- **`--context-shift`** à la place de la compaction : retire des jetons du
|
||||
contexte (perte), et ne marche pas sur les hybrides. Signalé lui aussi.
|
||||
- **Cache KV quantifié par défaut** : `q8_0` n'est pas exact, `q4_0` perd
|
||||
mesurablement, pour un gain d'environ 2 Gio sur un 27B hybride (16 couches
|
||||
sur 64 portent du KV). Reste un choix explicite et étiqueté (`KV_TYPE`).
|
||||
- Aussi : `-sm tensor` par défaut (prefill plus lent, expérimental), plus de
|
||||
slots par défaut (OOM : états récurrents par slot), `--cache-ram -1` (RAM
|
||||
non bornée), et tout réglage d'échantillonnage ou de quantification « pour
|
||||
aller plus vite ».
|
||||
|
||||
### Détail des clés et des outils
|
||||
|
||||
- **Bench** (bouton du preset, `loki bench`, `--full` pour le mode complet) :
|
||||
en tâche de fond (`POST /api/bench`, progression et annulation), chat,
|
||||
tâches et compaction refusés le temps de la mesure. Le mode rapide mesure une
|
||||
ligne courte avec le gabarit, le raisonnement et l'échantillonnage du preset ;
|
||||
le mode complet ajoute un prefill à froid à profondeur réelle (jusqu'à 32 k
|
||||
jetons, 16 k si des poids tournent sur CPU) et trois tours qui reprennent le
|
||||
cache — reprise lue dans `cache_n`, jamais supposée. Rien n'est enregistré
|
||||
sans réponses valides et timings réels ; l'empreinte du preset accompagne
|
||||
chaque mesure.
|
||||
- **Raisonnement renvoyé au modèle** (clé `REASONING_ECHO`, **off** par défaut,
|
||||
`loki config set REASONING_ECHO on`) : le raisonnement que le moteur local a
|
||||
séparé (`reasoning_content`) est gardé avec chaque message et renvoyé au même
|
||||
@@ -747,110 +983,6 @@ Ajoutées par ce fork :
|
||||
decode) — sinon l'ancienne version est rétablie et le moteur relancé. Pendant
|
||||
la mesure, le chat est indisponible : prévoir 10 à 40 minutes selon la taille
|
||||
du modèle (un modèle relu depuis un disque lent recharge à chaque essai).
|
||||
- **Discussions multiples** : historique complet dans la barre latérale, titre
|
||||
repris du premier message (renommable), suppression. **Chaque discussion a son
|
||||
dossier de fichiers** (`workspace/discussions/<id>/`) : les pièces jointes
|
||||
déposées, les captures et ce que l'agent écrit y atterrissent, le shell et les
|
||||
chemins relatifs du modèle y sont résolus. Changer de discussion change donc
|
||||
les fichiers ; supprimer (ou vider) une discussion emporte les siens, pour que
|
||||
le disque ne se remplisse pas en silence.
|
||||
- **Recherche Hugging Face** intégrée avec verdict mémoire et installation liée
|
||||
du projecteur vision (voir [Installer un modèle](#installer-un-modèle)).
|
||||
- **Captures de pages web** : l'agent dispose de l'outil `web_screenshot`
|
||||
(Chromium via Playwright, inclus dans l'image). Les captures partent en JPEG
|
||||
et sont plafonnées à 20 fichiers / 40 Mo par discussion. La description de
|
||||
l'outil suit la capacité **réelle** du moteur, sondée sur `/props` : sans
|
||||
vision effective, elle dit au modèle « tu ne vois pas l'image » plutôt que de
|
||||
lui promettre des yeux qu'il n'a pas — il peut toujours prendre la capture et
|
||||
la montrer, sans prétendre la décrire. L'image relayée au moteur reste
|
||||
éphémère : la persister gonflait le contexte jusqu'à le faire déborder.
|
||||
- **Panneau Fichiers** (bouton dossier de la barre de saisie) : les fichiers de la
|
||||
discussion ouverte — dépôts, captures, ce que l'agent y a écrit — avec
|
||||
navigation dans les sous-dossiers, téléchargement et suppression. Un dossier
|
||||
affiche la taille de **tout** son contenu, c'est ce qu'on libère en le
|
||||
supprimant, et le pied donne l'occupation disque de la discussion. Les chemins
|
||||
sont bornés à son dossier, liens symboliques résolus des deux côtés : ni le
|
||||
reste du disque ni les autres discussions ne sont atteignables. Les fichiers
|
||||
d'avant ce rangement que la migration n'a pas su rattacher restent joignables
|
||||
par le bouton **hors discussion**, qui disparaît une fois le ménage fait.
|
||||
- **Interface « Sober Tech »** : ardoise et sauge, typographie Inter (interface)
|
||||
et JetBrains Mono (code, chiffres, chemins) — embarquées dans le binaire, donc
|
||||
aucune requête vers un service de polices. Deux variantes : claire par défaut,
|
||||
**Deep Dark** (fond `#0F172A`, cartes `#1E293B`) d'un clic depuis l'en-tête.
|
||||
L'en-tête porte le titre de la discussion et le **sélecteur de modèle** (le
|
||||
changement de preset ne demande plus d'ouvrir les réglages) ; la barre
|
||||
latérale s'escamote pour rendre toute la largeur au fil ; les discussions s'y
|
||||
cherchent au clavier et les jauges **GPU / VRAM / mémoire vive** restent
|
||||
visibles en pied de colonne.
|
||||
- **Libérer la VRAM d'un clic** : sur les jauges du moniteur, un bouton décharge
|
||||
le modèle et arrête le moteur (ainsi que le serveur de dictée, qui occupe la
|
||||
carte lui aussi) pour rendre la mémoire vidéo à une autre application — jeu,
|
||||
encodage, autre serveur d'inférence. Le bilan est annoncé en Gio réellement
|
||||
rendus, et le même bouton devient **Recharger le modèle** pour reprendre la
|
||||
main. Routes : `POST /api/vram/unload` et `POST /api/vram/reload`.
|
||||
- **API OpenAI servie par Loki** : `/v1/*` est exposé **sur le port de
|
||||
l'interface** (8090) et relayé vers llama-server, au lieu d'annoncer l'adresse
|
||||
du moteur. Conséquence directe : l'API est joignable partout où l'interface
|
||||
l'est — par l'IP du réseau local comme par un nom de domaine — sans publier de
|
||||
second port ni ouvrir le moteur. L'amont annonçait `http://<ip>:8080/v1`, une
|
||||
adresse injoignable en conteneur (le port 8080 n'y est pas publié, et l'IP
|
||||
détectée est celle du bridge Docker).
|
||||
- Authentification par la **clé API** du panneau (`Authorization: Bearer …`),
|
||||
vérifiée par Loki **et** par le moteur. Sans clé, l'endpoint est ouvert et
|
||||
l'interface le dit en rouge.
|
||||
- **Adresse publique** : un champ où saisir son domaine, pour le cas du
|
||||
reverse proxy où Loki ne voit qu'un appel interne. Laissé vide, l'adresse
|
||||
affichée suit celle du navigateur.
|
||||
- **TLS** : mettre un reverse proxy devant (Caddy, Nginx, Traefik). Loki
|
||||
honore `X-Forwarded-Proto` pour annoncer une adresse en `https`.
|
||||
- L'ancienne exposition publique via le relais de l'amont
|
||||
(`<machine>.oai.ajean.link`) est retirée de l'interface : elle exigeait un
|
||||
jeton de relais que ce fork ne permet plus d'obtenir, l'interrupteur ne
|
||||
pouvait donc qu'échouer.
|
||||
- **Budget d'appels d'outils** : un tour d'agent n'a aucun plafond — couper une
|
||||
recherche légitime est pire que la laisser durer — mais au-delà de 24 appels
|
||||
sur un même tour, Loki rappelle au modèle combien il en a déjà faits et lui
|
||||
demande de conclure. Le rappel revient tous les 24 appels, en durcissant le
|
||||
ton ; il ne coupe jamais le tour, c'est de la pression, pas une barrière.
|
||||
Sans lui, un petit modèle qui tourne en rond n'avait rien en face de lui sauf
|
||||
le bouton stop (vu en production : 50 appels, 55 minutes, à relire cinq fois
|
||||
les mêmes fichiers). Réglable par `AGENT_BUDGET` dans `config.env` —
|
||||
`AGENT_BUDGET=off` le désactive complètement.
|
||||
- **Identité** : ton prénom et un avatar emoji pour toi et pour Loki, affichés
|
||||
dans le fil.
|
||||
- **Réglages en modale** : tous les réglages vivent dans une fenêtre à deux
|
||||
volets — la nav des sections à gauche (IA, moteur, application), le panneau
|
||||
choisi à droite. La barre latérale ne garde que les discussions (les plus
|
||||
récentes en tête) et le moniteur machine.
|
||||
- **Nom du modèle sur chaque réponse** : une pastille à côté de « Loki » dit
|
||||
quel modèle a produit la réponse. Elle est journalisée avec le tour : elle
|
||||
survit au rechargement, et un vieux tour garde le modèle de l'époque.
|
||||
- **Dictée vocale** : un bouton micro dans la carte de saisie enregistre,
|
||||
transcrit **en local** (whisper.cpp, compilé dans l'image ; modèle
|
||||
`small-q5_1` multilingue ~190 Mo téléchargé au premier usage dans
|
||||
`/data/whisper/`) et pose le texte dans le champ. ⚠️ le navigateur n'autorise
|
||||
le micro qu'en **HTTPS** (ou sur `localhost`) — derrière un reverse proxy
|
||||
TLS, rien à faire ; en `http://IP:8090`, le bouton l'explique.
|
||||
- **Cartes raisonnement/outils à hauteur bornée** : un long raisonnement ne
|
||||
fait plus grandir la page de plusieurs écrans — la carte reste à taille fixe
|
||||
et défile toute seule pendant la génération. Sur un raisonnement géant, seul
|
||||
le bas du bloc est re-rendu en direct (le texte complet est posé à la fin) :
|
||||
l'affichage ne se fige plus.
|
||||
|
||||
Retirées par ce fork :
|
||||
|
||||
- **Accès distant via [ajean.link](https://ajean.link)** : la section de
|
||||
l'interface et son module JS sont supprimés — un conteneur derrière son
|
||||
propre réseau n'en a pas l'usage. Le code serveur du relais reste en place
|
||||
mais **inerte** (aucun jeton, aucune section pour en fournir un) : le retirer
|
||||
créerait un conflit à chaque reprise de l'amont.
|
||||
- **Postes distants** (faire agir l'agent sur un autre PC appairé) : bouton du
|
||||
composeur, modales d'appairage et module JS supprimés. Même traitement que
|
||||
ci-dessus — les routes `/api/node/*` subsistent mais plus rien ne peut
|
||||
générer de code d'appairage, donc aucun poste ne peut se connecter.
|
||||
- **Catalogue de modèles distant** : il interrogeait `ajean.link/models.json`,
|
||||
sa route n'avait aucun consommateur et son repli embarqué datait de 2024. La
|
||||
recherche Hugging Face le remplace.
|
||||
|
||||
## Différences avec l'amont
|
||||
|
||||
|
||||
+128
-72
@@ -1,93 +1,149 @@
|
||||
# Loki 0.14.0
|
||||
# Loki 0.15.0
|
||||
|
||||
Loki rattrape AJEAN jusqu'à la 0.17.6 et reprend une série d'idées d'OpenFox
|
||||
pour le mode Code. Le gros du travail est invisible : des discussions qui ne se
|
||||
bloquent plus sur un contexte plein, des réponses qui survivent à une coupure
|
||||
réseau, un agent de code qui gaspille moins de tours.
|
||||
Une version entièrement consacrée à la vitesse, avec une règle tenue de bout en
|
||||
bout : **ne jamais dénaturer le modèle**. Rien ne touche à la quantification
|
||||
des poids, à l'échantillonnage, à la température, au budget de raisonnement ni
|
||||
au contenu du contexte. Ce qui est sans perte est actif d'office ; tout ce qui
|
||||
changerait ce que voit le modèle, le placement des poids ou les slots du moteur
|
||||
attend une clé. Sans clé, la requête et la ligne de commande restent celles
|
||||
d'avant.
|
||||
|
||||
## Le contexte ne bloque plus la discussion
|
||||
La section **Performance** du README rassemble toutes les clés, leur défaut et
|
||||
leur prix.
|
||||
|
||||
Sur une fenêtre de 65k, un tour qui lisait plusieurs gros fichiers d'un coup
|
||||
passait de 60 % à plus de 130 % sans jamais compacter, et le moteur répondait
|
||||
par un 400 qui figeait la discussion.
|
||||
## Actif d'office, sans perte
|
||||
|
||||
- Le compactage en cours de tour compte aussi les résultats d'outils que le
|
||||
moteur n'a pas encore vus.
|
||||
- Tout résultat d'outil est borné à 30 000 caractères **pour le modèle** ;
|
||||
l'interface garde le résultat complet (« voir plus »).
|
||||
- En dernier recours, les gros résultats sont tronqués puis les plus vieux
|
||||
échanges retirés, au lieu de laisser remonter l'erreur.
|
||||
- Le compactage ne fait plus répondre deux fois à une vieille question, et le
|
||||
texte écrit avant un appel d'outil n'est plus rangé en double.
|
||||
**La conversation n'est plus recalculée pour rien.**
|
||||
|
||||
## Presets : API compatible OpenAI
|
||||
- **Cache de prompts dimensionné** : le moteur garde en RAM une copie exacte des
|
||||
conversations qu'il quitte. Son défaut ne tenait pas une conversation de 30 à
|
||||
65 k jetons à côté d'un vérificateur ou d'un sous-agent : il l'évinçait, et
|
||||
tout était recalculé (30 à 80 s sur un 27B). Il est maintenant agrandi pour un
|
||||
modèle tout-GPU, et le slot est effacé après chaque travail annexe pour que la
|
||||
conversation revienne du cache.
|
||||
- **Préfixe stable** : les rappels de Loki entrent dans l'historique tels
|
||||
qu'envoyés, la relance après un 500 ne change plus les outils, la ligne MCP ne
|
||||
manque plus au premier tour après un démarrage, l'ordre des trackers ne bouge
|
||||
plus. Chacun de ces écarts faisait recalculer toute la boucle d'outils.
|
||||
- **Compaction moins tôt** : le raisonnement que Loki ne renvoie jamais ne
|
||||
compte plus dans le contexte. La compaction (qui perd de l'information)
|
||||
partait vers 44-47 k au lieu de 49 k sur une fenêtre de 65 k. Son résumé n'est
|
||||
plus amputé de l'état d'avancement.
|
||||
- **Hybrides (Qwen3.5/3.6) sur un moteur ancien** : `--checkpoint-min-step 2048`
|
||||
d'office quand la RAM le permet, pour ne plus retomber jusqu'à ~8 k jetons en
|
||||
arrière à chaque reprise.
|
||||
|
||||
Les presets d'API externe gagnent ce qui leur manquait :
|
||||
**Le matériel est mieux employé.**
|
||||
|
||||
- une case **« le modèle accepte les images »** pour un modèle distant
|
||||
multimodal ;
|
||||
- plus de `chat_template_kwargs` (propre à llama.cpp) envoyé à l'API : une API
|
||||
stricte répondait 400 et **chaque compactage échouait** ;
|
||||
- **reprise automatique** quand le flux se coupe en pleine réponse (Wi-Fi, VPN,
|
||||
proxy) : jusqu'à 5 fois, le modèle reprend là où il s'était arrêté ;
|
||||
- un 401, 429 ou 502 n'est plus pris pour un appel d'outil mal formé ;
|
||||
- le débit est mesuré même quand l'API ne le donne pas ; le benchmark refuse de
|
||||
mesurer un moteur local qui n'est pas celui du preset ; le badge des réponses
|
||||
porte le nom du modèle distant.
|
||||
- **Threads CPU** : « auto » veut dire les cœurs physiques, plus tous les
|
||||
threads logiques — c'est le décodage des experts MoE sur CPU qui payait.
|
||||
- **Deux GPU** : file de lancements CUDA élargie quand le pipeline entre cartes
|
||||
est possible (même calcul ; seul le prompt peut gagner).
|
||||
|
||||
## Mode Code
|
||||
**Loki lui-même pèse moins.**
|
||||
|
||||
- **La vérification attend que le builder ait fini.** Il marque chaque critère
|
||||
`completed` une fois fait ; tant qu'il en reste d'ouverts, il est relancé au
|
||||
lieu de payer une passe de vérification sur un travail inachevé. Plus aucune
|
||||
vérification ne part quand il vient de poser une question.
|
||||
- **Écriture refusée dès son chemin** : un `write` sur un fichier jamais lu
|
||||
était refusé après tout le fichier généré. Le chemin passe maintenant en
|
||||
premier et le refus coupe la génération aussitôt.
|
||||
- **Appel d'outil écrit en texte** (`<tool_call>`, format XML de Qwen3-Coder) :
|
||||
repéré pendant le flux, coupé, et la relance cite l'extrait fautif.
|
||||
- `read_file`, `str_replace`, `old_string`… appris d'autres agents sont
|
||||
traduits vers les vrais outils.
|
||||
- Les consignes du dépôt (**AGENTS.md**, CLAUDE.md) font partie du contexte.
|
||||
- Terminal : `cmd | tail -N` rend le **vrai** code de sortie, la sortie déjà
|
||||
produite est gardée au délai dépassé, les couleurs ANSI sont retirées.
|
||||
- `git_status` / `git_diff` trouvent le dépôt cloné dans un sous-dossier.
|
||||
- Le compactage garde les fichiers touchés, les erreurs résolues et l'état des
|
||||
critères.
|
||||
- Écrire un gros fichier ne coûte plus un temps quadratique côté Go (jusqu'à
|
||||
8 s de CPU volées au décodage sur un MoE).
|
||||
- L'enregistrement de la discussion ne retarde plus le premier jeton.
|
||||
- Un seul `nvidia-smi` pour tous les onglets, aucun pour un onglet caché, un
|
||||
seul à l'ouverture de l'éditeur de preset.
|
||||
- Unraid : un `/data` ou `/models` servi par la couche FUSE est signalé, avec
|
||||
le remède.
|
||||
|
||||
## Tâches et chat
|
||||
**On peut enfin mesurer.**
|
||||
|
||||
- **« Rappelle-moi dans 20 minutes »** : `task_create` accepte `in_minutes` ou
|
||||
`at`, à l'heure du navigateur (le conteneur tourne en UTC).
|
||||
- **Écrire pendant que l'IA répond** : le message part en file et le modèle en
|
||||
tient compte dans la suite de sa réponse ; deux appareils qui envoient en
|
||||
même temps ne se refusent plus.
|
||||
- Longues discussions : au chargement, les 20 derniers échanges, le début d'un
|
||||
clic ; la liste des discussions se dessine par pages et montre la nouvelle
|
||||
dès le premier message.
|
||||
- Mémoire : un mode par projet, et un quatrième, « recherche ».
|
||||
- Appels d'outils parallèles séparés selon leur index ; bascule de preset par
|
||||
identifiant ; un raisonnement qui reprend après la réponse a sa propre bulle.
|
||||
- Chaque réponse dit ce qu'elle a repris du cache, recalculé et accepté du
|
||||
brouillon ; `GET /api/perf/summary` en fait la synthèse par nature de requête
|
||||
(`lost_events`, `lost_tokens` : le cache perdu, et après quoi).
|
||||
- **Bench** honnête, en tâche de fond : mode complet à profondeur réelle, tours
|
||||
qui reprennent le cache, rien d'enregistré sans timings réels.
|
||||
- Une sonde du gabarit de chat dit, sans rien envoyer au modèle, si le rendu
|
||||
reste stable d'un message à l'autre.
|
||||
|
||||
## Sécurité et données
|
||||
**Garde-fous.** Un cache KV quantifié, `--context-shift` ou `--cache-reuse`
|
||||
posés à la main sont signalés. Un mode de chargement résident voué à l'échec
|
||||
(poids restés en RAM au-delà de 90 %) est refusé avec la raison en clair —
|
||||
`LOAD_GUARD=off` pour passer outre ; le refus n'est plus relancé en boucle par
|
||||
systemd, et un moteur Vulkan sur cartes mixtes n'est plus refusé à tort.
|
||||
|
||||
- **Un site tiers ne peut plus piloter Loki** depuis le navigateur (Origin /
|
||||
Sec-Fetch-Site, DNS rebinding). ⚠️ Derrière un reverse proxy par nom de
|
||||
domaine, définis une clé de pilotage ou `LOKI_TRUSTED_HOSTS` **avant** la mise
|
||||
à jour, et vérifie que le proxy transmet l'en-tête `Host` d'origine.
|
||||
- **Chiffrement de la mémoire** : l'activer rendait illisibles la discussion
|
||||
active et le mode Code. Corrigé ; une base déjà touchée est réparée au
|
||||
déverrouillage. Les résultats d'outils (« voir plus ») et les images du fil
|
||||
sont désormais chiffrés eux aussi, et les images effacées après 24 h.
|
||||
## En opt-in : à essayer, à mesurer
|
||||
|
||||
## Moteur
|
||||
| Clé | Ce qu'elle fait |
|
||||
|---|---|
|
||||
| `PREWARM=on` | prépare le prochain tour pendant que tu lis (`full` : aussi la discussion qu'on ouvre) |
|
||||
| `COMPACT_CONTINUATION=on` | le résumé de compaction prolonge le prompt en cache au lieu d'être calculé à froid |
|
||||
| `PROJ_SNAPSHOT=on` | bloc projet figé par discussion, changements livrés à part ; date et dossier sortent du système |
|
||||
| `REASONING_ECHO=on` | renvoie au moteur local la réflexion du modèle, au format entraîné |
|
||||
| `SPEC=auto` / `mtp` | décodage spéculatif MTP (tête détectée dans le fichier, garde-fous VRAM) |
|
||||
| `SPEC=ngram` / `mtp+ngram` | n-grammes du contexte, utiles en mode Code |
|
||||
| `SIDE_SLOT=on` | second slot pour les travaux annexes (VRAM en double) |
|
||||
| `SLOT_PERSIST=on` | état du slot gardé à la bascule de preset |
|
||||
| `SPLIT_MODE=tensor` | parallélisme de tenseurs entre cartes (expérimental) |
|
||||
| `FIT_TARGET`, `OP_OFFLOAD_MIN_BATCH`, `CUDA_GRAPH_OPT` | réglages d'expert pour cartes inégales et MoE |
|
||||
| `KEEP_TURN_IMAGES=on` | **zone grise** : garde les images des outils dans l'historique |
|
||||
| `NUDGE_IN_TOOL=on` | **zone grise** : rappel de budget dans le résultat d'outil |
|
||||
|
||||
- `--mlock` seul ne coupe plus le mmap (OOM au chargement).
|
||||
- Port déjà occupé refusé avec un message clair ; cache KV lent signalé.
|
||||
- Réponses web compressées en gzip.
|
||||
Et deux outils qui ne font rien d'eux-mêmes :
|
||||
|
||||
- **Optimiseur** (`loki tune`, bouton « Optimiser… ») : cherche lots, threads,
|
||||
marges et placement sur un moteur d'essai isolé ; rien n'est écrit sans un
|
||||
clic, et l'application est vérifiée puis défaite si le moteur ne tient pas.
|
||||
- **« Dupliquer en placement auto… »** pour un MoE aux experts placés à la
|
||||
main : une copie du preset où `--fit` les répartit.
|
||||
|
||||
## Ordre de test conseillé
|
||||
|
||||
Une étape à la fois, mesurée avant la suivante :
|
||||
|
||||
1. **Bench complet** du preset tel quel : la référence.
|
||||
2. **`PREWARM` + `COMPACT_CONTINUATION`**, une vraie session de travail, puis
|
||||
`/api/perf/summary` : le cache perdu (`lost`) doit baisser.
|
||||
3. **Optimiseur** sur le preset en service.
|
||||
4. **MoE** : « Dupliquer en placement auto… », bench complet des deux.
|
||||
5. **Mise à jour du moteur** vers la version recommandée (encart du panneau
|
||||
Moteur).
|
||||
6. **`SPEC=auto`** (ou `mtp`) si le modèle a une tête MTP.
|
||||
|
||||
## Moteur : version recommandée et retour arrière
|
||||
|
||||
Quand le moteur officiel est antérieur à `b10864`, le panneau Moteur dit ce
|
||||
qu'une mise à jour apporte (points de reprise des hybrides, MTP rapide) et la
|
||||
propose — sur clic seulement, version vérifiée sur le registre. La version
|
||||
quittée est gardée : **Revenir à la version précédente** y ramène sans réseau.
|
||||
|
||||
Depuis `b10763`, llama-server garde par défaut la réflexion des tours passés :
|
||||
un gabarit comme Qwen3.6 la rendrait vide. Avant de basculer, Loki le détecte et
|
||||
propose `REASONING_PRESERVE=off` ; après, il compare le rendu de l'ancien et du
|
||||
nouveau moteur et signale le premier écart.
|
||||
|
||||
## Ce qui a été écarté
|
||||
|
||||
- **`--cache-reuse`** : réutilise du cache calculé sous un autre contexte, donc
|
||||
change les sorties.
|
||||
- **`--context-shift`** : retire des jetons du contexte, et ne marche pas sur
|
||||
les hybrides.
|
||||
- **Cache KV quantifié par défaut** : `q8_0` n'est pas exact, `q4_0` perd
|
||||
mesurablement, pour ~2 Gio gagnés sur un 27B hybride. Reste un choix
|
||||
explicite (`KV_TYPE`).
|
||||
|
||||
## Autres corrections
|
||||
|
||||
- Une compaction en plein tour ne fait plus disparaître le rappel des pages
|
||||
mémoire lues.
|
||||
- Un `loki tune` tué net ne laisse plus le moteur arrêté ; lancé avec un autre
|
||||
`LOKI_HOME` que l'interface (`sudo`), il refuse au lieu de charger un essai à
|
||||
côté d'un moteur vivant.
|
||||
- L'ancienne option « n-grammes (mod) » de l'éditeur rejoint `SPEC=ngram`, avec
|
||||
une migration proposée (jamais faite d'office).
|
||||
- Accès refusé : l'interface dit pourquoi et comment le lever.
|
||||
|
||||
## Mise à jour
|
||||
|
||||
```
|
||||
docker compose pull && docker compose up -d
|
||||
```
|
||||
|
||||
Installation systemd (`loki install`) : l'unité du moteur gagne
|
||||
`RestartPreventExitStatus=78`. `loki update` ne réécrit pas les unités ;
|
||||
`sudo loki install`, ou `sudo systemctl edit loki-engine` avec cette ligne dans
|
||||
`[Service]`, la met à jour.
|
||||
Binary file not shown.
Binary file not shown.
@@ -2,13 +2,13 @@
|
||||
"FixedFileInfo": {
|
||||
"FileVersion": {
|
||||
"Major": 0,
|
||||
"Minor": 14,
|
||||
"Minor": 15,
|
||||
"Patch": 0,
|
||||
"Build": 0
|
||||
},
|
||||
"ProductVersion": {
|
||||
"Major": 0,
|
||||
"Minor": 14,
|
||||
"Minor": 15,
|
||||
"Patch": 0,
|
||||
"Build": 0
|
||||
},
|
||||
@@ -25,7 +25,7 @@
|
||||
"LegalCopyright": "Copyright (c) 2026 Loki contributors. MIT License.",
|
||||
"OriginalFilename": "loki.exe",
|
||||
"ProductName": "Loki",
|
||||
"ProductVersion": "0.14.0",
|
||||
"ProductVersion": "0.15.0",
|
||||
"Comments": "https://github.com/R0m1k3/Loki — projet open source (MIT)"
|
||||
},
|
||||
"VarFileInfo": {
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const Version = "0.14.0"
|
||||
const Version = "0.15.0"
|
||||
|
||||
// Main est le vrai main() du binaire (cmd/loki ne fait que l'appeler).
|
||||
func Main() {
|
||||
|
||||
Reference in new issue
Block a user