mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-22 06:28:11 +02:00
Contexte : le raisonnement jamais renvoyé ne compte plus, et la compaction ne part plus trop tôt
CtxUsed valait usage.prompt_tokens + généré, raisonnement compris. Or Loki ne renvoie jamais ce raisonnement au modèle (Message n'a pas de champ pour lui) : la requête suivante pesait 1 à 8 k jetons de moins que le compte, et la compaction, qui perd de l'information, partait vers 44-47 k au lieu de 49 k sur une fenêtre de 65 k. Rien ne change dans les requêtes : seul le compte qui décide de compacter. - Comptage : seulement les morceaux reasoning_content séparés par le llama-server local, remis à zéro à chaque tentative. Le <think> découpé chez nous reste dans le message renvoyé pendant le tour, il n'est pas retiré ; l'API externe garde l'ancien calcul. Un morceau vaut au plus un jeton : on ne peut que sous-estimer, le sens sans danger. - Début de tour : le message utilisateur (et la file) arrivé depuis la dernière mesure s'ajoute en estimation, comme en cours de tour. - Vérificateur : sa trace isolée écrasait CtxUsed avec sa petite taille, et la fin de tour décidait sur ce chiffre-là. Plus maintenant ; la jauge de l'UI ne bouge pas non plus et suit le même calcul que le serveur. - Marge de génération : le compte gonflé offrait une marge par accident. Elle est remplacée par une vraie garde — compacter si 1,2 × la plus longue génération récente ne tient plus dans la fenêtre. Plancher et marge seuls ne devancent jamais le seuil de 75 %. - Fenêtre pleine en plein raisonnement (finish « length » au-delà du seuil) : compaction puis étape rejouée, au lieu du nudge « arrête de raisonner ». - Journal [ctx] : estimation contre compte réel au-delà de 2 % d'écart, chaque « length » et chaque nudge, pour vérifier qu'ils n'augmentent pas. - Le seuil reste à 75 % : la réserve fixe proposée (toolResultMax/3 + 6 k) laissait trop peu de place sans budget de raisonnement ni max_tokens. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
18a723a671
commit
d6023ef8a0
7 files changed
+514
-25
No files matched your search
@@ -215,6 +215,63 @@ func compactWouldTrigger(msgs []Message, knownTokens int) bool {
|
||||
return used >= int(float64(ctxWindow())*compactTriggerFrac)
|
||||
}
|
||||
|
||||
// compactNeeded = compactWouldTrigger, plus une garde de MARGE DE GÉNÉRATION.
|
||||
// Tant que le raisonnement de la dernière étape était compté dans le contexte
|
||||
// (à tort : il n'est jamais renvoyé), il offrait par accident une marge à peu
|
||||
// près proportionnelle à la longueur des étapes. Ce compte est désormais juste,
|
||||
// et sans max_tokens ni budget de raisonnement, une étape aussi longue que la
|
||||
// plus longue récente doit encore tenir : sinon le moteur coupe en plein
|
||||
// raisonnement (« length »). peakGen = 0 (inconnu, API externe) : seuil seul.
|
||||
func compactNeeded(msgs []Message, used, peakGen int) bool {
|
||||
if compactWouldTrigger(msgs, used) {
|
||||
return true
|
||||
}
|
||||
return compactEnabled() && genHeadroomShort(used, peakGen, ctxWindow())
|
||||
}
|
||||
|
||||
// genHeadroomShort : la fenêtre ne laisse plus la place d'une génération de
|
||||
// 1,2 × la plus longue récente (plancher de 8 k jetons, ramené à 1/8 de la
|
||||
// fenêtre pour les petites), plus une petite marge. Fonction pure, testable.
|
||||
// Plancher et marge sont choisis pour ne JAMAIS devancer le seuil de 75 % à eux
|
||||
// seuls : seule une génération longue avance la compaction.
|
||||
func genHeadroomShort(used, peakGen, window int) bool {
|
||||
if used <= 0 || peakGen <= 0 || window <= 0 {
|
||||
return false
|
||||
}
|
||||
need := max(peakGen*6/5, min(8192, window/8)) + min(1024, window/32)
|
||||
return used+need > window
|
||||
}
|
||||
|
||||
// logCtx trace un fait du comptage de contexte (fenêtre pleine, relance après
|
||||
// un raisonnement sans action) : de quoi vérifier, journal en main, qu'ils ne
|
||||
// deviennent pas plus fréquents.
|
||||
func logCtx(format string, args ...any) {
|
||||
fmt.Fprintf(os.Stderr, "[ctx] "+format+"\n", args...)
|
||||
}
|
||||
|
||||
// logCtxEstimate compare le contexte ESTIMÉ avant une requête au compte réel
|
||||
// du moteur (usage.prompt_tokens), et ne parle qu'au-delà de 2 % d'écart.
|
||||
func logCtxEstimate(phase string, est, actual int) {
|
||||
if actual <= 0 {
|
||||
return
|
||||
}
|
||||
if d := est - actual; d*50 > actual || -d*50 > actual {
|
||||
logCtx("%s estimé=%d réel=%d écart=%+d", phase, est, actual, d)
|
||||
}
|
||||
}
|
||||
|
||||
// ctxPending ajoute au dernier contexte mesuré (used, valable pour les
|
||||
// measured premiers messages) l'estimation des messages arrivés depuis : le
|
||||
// nouveau message utilisateur, ceux de la file. Le compte du moteur ne les a
|
||||
// pas vus. measured = 0 (inconnu, discussion rechargée) ou plus grand que
|
||||
// l'historique (réécrit entre-temps) : on s'en tient au compte mesuré.
|
||||
func ctxPending(used, measured int, msgs []Message) int {
|
||||
if used <= 0 || measured <= 0 || measured > len(msgs) {
|
||||
return used
|
||||
}
|
||||
return used + estimateTokens(msgs[measured:])
|
||||
}
|
||||
|
||||
// logCompact trace UNE ligne par décision de compaction sur la sortie d'erreur
|
||||
// (donc dans `journalctl -u loki-ui`). Sans ça, une compaction qui ne se
|
||||
// déclenche pas — ou qui se déclenche et n'enlève rien — est invisible : côté
|
||||
|
||||
Reference in new issue
Block a user