mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-24 07:28:13 +02:00
Raisonnement : NUDGE_IN_TOOL décide sur le verdict de la forme de la requête
La sonde de gabarit gardait le verdict de la DERNIÈRE forme sondée (outils, chat_template_kwargs, reasoning_effort), quelle qu'elle soit. NUDGE_IN_TOOL pouvait donc glisser le rappel de budget dans un résultat d'outil sur la foi d'un « préfixe instable » conclu pour une autre forme — un autre jeu d'outils, la réflexion coupée, un autre niveau — dont le rendu n'a rien à voir. - Les verdicts sont aussi rangés par forme (empreinte tplShape, au plus 16, la plus ancienne cède) ; tplCapsFor rend celui de la forme demandée. - NUDGE_IN_TOOL calcule la forme de la requête courante (mêmes outils, kwargs et niveau que ceux envoyés) et ne place le rappel dans le résultat que si CETTE forme est « instable » pour ce modèle ; forme jamais sondée ou inconnue : message à part, comme sans la clé. Une relance outils coupés ou tool_choice « none » (forme que la sonde ne voit jamais) se replie aussi. - L'affichage (/api/perf/summary) et REASONING_ECHO gardent le dernier verdict, comme avant. Sans la clé, rien ne change. - Tests : verdict par forme dans la sonde, autre forme / autres kwargs / autre niveau refusés, bout à bout avec le verdict d'une autre forme (échouait sur l'ancien code). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ac40a2556a
commit
4b659ac186
6 files changed
+154
-20
No files matched your search
@@ -165,9 +165,14 @@ var (
|
||||
// Attente entre deux essais sur un 503 (modèle en chargement).
|
||||
tplProbeBackoff = time.Second
|
||||
|
||||
tplProbeMu sync.Mutex
|
||||
tplProbeCache = map[string]tplProbeResult{}
|
||||
tplProbeLast *tplProbeResult
|
||||
tplProbeMu sync.Mutex
|
||||
tplProbeCache = map[string]tplProbeResult{}
|
||||
tplProbeLast *tplProbeResult
|
||||
// tplProbeByShape : le dernier verdict de chaque forme de requête
|
||||
// (tplShape.hash). tplProbeLast est celui de la dernière forme sondée,
|
||||
// quelle qu'elle soit : bon pour l'affichage, pas pour décider d'une
|
||||
// requête d'une autre forme (tplCapsFor).
|
||||
tplProbeByShape = map[string]tplProbeResult{}
|
||||
tplProbeRunning bool
|
||||
tplProbeTried time.Time
|
||||
tplProbeLogged string
|
||||
@@ -215,6 +220,20 @@ func tplCapsCurrent() (tplProbeResult, bool) {
|
||||
return *tplProbeLast, true
|
||||
}
|
||||
|
||||
// tplCapsFor : le dernier verdict pour CETTE forme de requête (mêmes outils,
|
||||
// mêmes chat_template_kwargs, même reasoning_effort). Pas de verdict pour elle
|
||||
// — jamais sondée, ou sortie du cache — : rien, et l'appelant se replie comme
|
||||
// sur « inconnu ». Rien non plus pour un preset externe.
|
||||
func tplCapsFor(shape tplShape) (tplProbeResult, bool) {
|
||||
if externalActive() {
|
||||
return tplProbeResult{}, false
|
||||
}
|
||||
tplProbeMu.Lock()
|
||||
defer tplProbeMu.Unlock()
|
||||
r, ok := tplProbeByShape[shape.hash()]
|
||||
return r, ok
|
||||
}
|
||||
|
||||
// tplProbeEnsure : verdict pour la forme donnée, depuis le cache ou une sonde.
|
||||
func tplProbeEnsure(ctx context.Context, shape tplShape) tplProbeResult {
|
||||
if resolveChatEndpoint().External {
|
||||
@@ -232,7 +251,7 @@ func tplProbeEnsure(ctx context.Context, shape tplShape) tplProbeResult {
|
||||
props, err := p.props(ctx)
|
||||
if err != nil {
|
||||
r := tplUnknownResult("/props illisible : " + err.Error())
|
||||
tplProbeStore("", r)
|
||||
tplProbeStore("", shape.hash(), r)
|
||||
return r
|
||||
}
|
||||
h := fnv.New64a()
|
||||
@@ -245,6 +264,7 @@ func tplProbeEnsure(ctx context.Context, shape tplShape) tplProbeResult {
|
||||
tplProbeMu.Lock()
|
||||
if r, ok := tplProbeCache[key]; ok {
|
||||
tplProbeLast = &r
|
||||
tplProbeKeepShape(shape.hash(), r)
|
||||
tplProbeMu.Unlock()
|
||||
return r
|
||||
}
|
||||
@@ -265,14 +285,30 @@ func tplProbeEnsure(ctx context.Context, shape tplShape) tplProbeResult {
|
||||
if fresh {
|
||||
fmt.Fprintln(os.Stderr, line)
|
||||
}
|
||||
tplProbeStore(key, r)
|
||||
tplProbeStore(key, shape.hash(), r)
|
||||
return r
|
||||
}
|
||||
|
||||
func tplProbeStore(key string, r tplProbeResult) {
|
||||
// tplProbeKeepShape note le verdict d'une forme (tplProbeMu tenu). Au plus
|
||||
// tplProbeCacheMax formes : la plus ancienne cède sa place.
|
||||
func tplProbeKeepShape(shape string, r tplProbeResult) {
|
||||
if _, ok := tplProbeByShape[shape]; !ok && len(tplProbeByShape) >= tplProbeCacheMax {
|
||||
oldest := ""
|
||||
for k, v := range tplProbeByShape {
|
||||
if oldest == "" || v.At.Before(tplProbeByShape[oldest].At) {
|
||||
oldest = k
|
||||
}
|
||||
}
|
||||
delete(tplProbeByShape, oldest)
|
||||
}
|
||||
tplProbeByShape[shape] = r
|
||||
}
|
||||
|
||||
func tplProbeStore(key, shape string, r tplProbeResult) {
|
||||
tplProbeMu.Lock()
|
||||
defer tplProbeMu.Unlock()
|
||||
tplProbeLast = &r
|
||||
tplProbeKeepShape(shape, r)
|
||||
if key == "" || !r.cacheable {
|
||||
return
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user