Fix: garder l'inférence sur GPU et réparer l'erreur 400 de template

- agent_config: num_gpu auto (-1) par défaut au lieu de forcer un nombre
  de couches codé en dur (RTX 3060), qui faisait basculer Ollama sur CPU
  quand la config ne tenait pas en VRAM. num_gpu/main_gpu ne sont transmis
  que si l'utilisateur force explicitement une valeur (>= 0).
- agent_config: migration v4 remettant a -1 les profils deja enregistres
  avec un num_gpu fige.
- agent: la boucle de reparation d'appel d'outil reinjecte son rappel en
  role "user" au lieu de "system" (les templates Gemma/Mistral refusent un
  message system hors tete -> 400 "System message must be at the beginning").

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MichaelandClaude Opus 4.8 committed 2026-06-30 12:26:49 +02:00
1 parent e24d397d31
commit aed5f8148c
2 files changed
+23 -5

No files matched your search

+6 -1
View File
@@ -122,9 +122,14 @@ async def run_agent(
int(request_options.get("num_predict", 0)), 4096
)
thinking_buf = ""
# NB : on réinjecte ce rappel en `user`, pas en `system`.
# Beaucoup de templates (Gemma, Mistral…) lèvent
# « System message must be at the beginning » dès qu'un
# message system apparaît ailleurs qu'en tête, ce qui
# ferait échouer toute la requête en 400.
convo.append(
{
"role": "system",
"role": "user",
"content": (
"L'appel d'outil précédent contenait un JSON "
"tronqué. Réessaie immédiatement avec des arguments "
+17 -4
View File
@@ -10,7 +10,7 @@ from . import db
CONFIG_KEY = "agent"
MODEL_PROFILES_KEY = "model_profiles"
PROFILE_STATE_KEY = "model_profiles_state"
PROFILE_VERSION = 3
PROFILE_VERSION = 4
DEFAULT_SYSTEM_PROMPT = (
"Tu es Loki, un assistant de développement local agentique. Tu disposes "
@@ -57,7 +57,10 @@ RTX_3060_GEMMA4_PROFILE: dict = {
**DEFAULT_GENERATION,
"max_tokens": 4096,
"num_ctx": 8192,
"num_gpu": 49,
# num_gpu = -1 : laisse Ollama placer le plus de couches possible sur le GPU
# (auto-fit, comme `ollama run`). Forcer un nombre de couches qui ne tient pas
# en VRAM fait basculer toute l'inférence sur le CPU.
"num_gpu": -1,
}
DEFAULT_CONFIG: dict = {
@@ -87,6 +90,12 @@ def _migrate_profiles() -> None:
if gemma_profile.get("max_tokens", 0) <= 2048:
gemma_profile["max_tokens"] = 4096
profiles["gemma4:12b"] = gemma_profile
# v4 : un ancien profil pouvait forcer num_gpu sur un nombre de couches codé
# en dur (ex. 49), ce qui basculait l'inférence sur le CPU quand ça ne tenait
# pas en VRAM. On repasse en auto (-1) pour laisser Ollama placer les couches.
for prof in profiles.values():
if prof.get("num_gpu", -1) is not None and prof.get("num_gpu", -1) > 0:
prof["num_gpu"] = -1
db.set_config_value(MODEL_PROFILES_KEY, profiles)
db.set_config_value(PROFILE_STATE_KEY, {"version": PROFILE_VERSION})
@@ -137,10 +146,14 @@ def ollama_options(cfg: dict) -> dict:
"top_p": cfg["top_p"],
"top_k": cfg["top_k"],
"num_predict": cfg["max_tokens"],
"num_gpu": cfg["num_gpu"],
"main_gpu": 0,
"num_batch": cfg["num_batch"],
}
# num_gpu n'est transmis que si l'utilisateur force explicitement un nombre
# de couches (≥ 0). En -1 (défaut), on laisse Ollama auto-ajuster l'offload
# GPU comme `ollama run` ; lui imposer une valeur peut le forcer sur le CPU.
if cfg.get("num_gpu", -1) >= 0:
opts["num_gpu"] = cfg["num_gpu"]
opts["main_gpu"] = 0
# num_ctx n'est envoyé que s'il est défini (> 0), sinon défaut du modèle.
if cfg.get("num_ctx"):
opts["num_ctx"] = cfg["num_ctx"]