mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-11 17:26:57 +02:00
Nomme la cause d'un débit anormal : placement du modèle hors GPU
Un modèle dont les couches partent en RAM tombe à quelques jetons par seconde. Loki subissait la lenteur sans jamais la nommer : l'utilisateur ne pouvait pas distinguer un blocage de l'application d'un modèle placé sur le CPU par Ollama. Au début de chaque réponse, si /api/ps indique que le modèle n'est pas entièrement en VRAM, une notice donne le pourcentage réellement en VRAM et le volume resté en RAM. Le placement appartient à Ollama — Loki le constate, il ne le corrige pas. Silencieux quand tout est sur GPU, quand le modèle n'est pas encore chargé, ou quand Ollama ne répond pas. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
This commit is contained in:
1 file changed
+39
@@ -17,6 +17,7 @@ import re
|
||||
import time
|
||||
from contextlib import suppress
|
||||
|
||||
import httpx
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from fastapi.responses import StreamingResponse
|
||||
from pydantic import BaseModel
|
||||
@@ -28,6 +29,7 @@ from .. import router as msg_router
|
||||
from ..tools import check_html, _safe_path
|
||||
from ..agent import run_agent
|
||||
from ..config import settings
|
||||
from ..ollama_client import ollama
|
||||
|
||||
router = APIRouter(prefix="/api", tags=["chat"])
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -62,6 +64,37 @@ def _apply_mode(cfg: dict, mode: str) -> dict:
|
||||
return cfg
|
||||
|
||||
|
||||
async def _placement_notice(model: str) -> str | None:
|
||||
"""Avertit si le modèle tourne (au moins en partie) hors du GPU.
|
||||
|
||||
C'est LA cause d'un débit ridicule (quelques jetons/s) : Ollama a placé
|
||||
tout ou partie des couches en RAM. Loki ne peut pas le corriger — le
|
||||
placement appartient à Ollama — mais il peut le NOMMER, au lieu de
|
||||
laisser croire à un blocage de l'application.
|
||||
"""
|
||||
try:
|
||||
loaded = await ollama.ps()
|
||||
except (httpx.HTTPError, OSError):
|
||||
return None
|
||||
|
||||
for m in loaded:
|
||||
if (m.get("name") or m.get("model")) != model:
|
||||
continue
|
||||
size = m.get("size", 0) or 0
|
||||
vram = m.get("size_vram", 0) or 0
|
||||
if size <= 0 or vram >= size * 0.99:
|
||||
return None
|
||||
pct = int(vram / size * 100)
|
||||
in_ram = (size - vram) / 1e9
|
||||
where = "entièrement en RAM" if pct == 0 else f"{pct} % en VRAM"
|
||||
return (
|
||||
f"⚠️ {model} tourne {where} ({in_ram:.1f} Go hors GPU) : "
|
||||
"le débit sera de quelques jetons par seconde. Réduis le contexte, "
|
||||
"prends un modèle plus petit, ou répartis sur tes GPU côté Ollama."
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
def _loading_message(model: str, seconds: float) -> str:
|
||||
"""Message d'attente avant le premier jeton (chargement du modèle)."""
|
||||
waited = int(seconds)
|
||||
@@ -421,6 +454,12 @@ async def chat(req: ChatRequest) -> StreamingResponse:
|
||||
for mcp_notice in mcp_manager.notices():
|
||||
yield _sse("notice", {"message": mcp_notice})
|
||||
|
||||
# Placement du modèle : dire tout de suite si l'inférence est hors GPU,
|
||||
# au lieu de laisser l'utilisateur attribuer la lenteur à Loki.
|
||||
placement = await _placement_notice(model)
|
||||
if placement:
|
||||
yield _sse("notice", {"message": placement})
|
||||
|
||||
# ── Consignes additionnelles du tour ──────────────────────────────
|
||||
# Elles sont COLLECTÉES ici puis fusionnées dans l'UNIQUE message
|
||||
# système (voir _merge_system plus bas). Beaucoup de templates
|
||||
|
||||
Reference in new issue
Block a user