mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-23 23:18:13 +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
|
import time
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
|
|
||||||
|
import httpx
|
||||||
from fastapi import APIRouter, HTTPException
|
from fastapi import APIRouter, HTTPException
|
||||||
from fastapi.responses import StreamingResponse
|
from fastapi.responses import StreamingResponse
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
@@ -28,6 +29,7 @@ from .. import router as msg_router
|
|||||||
from ..tools import check_html, _safe_path
|
from ..tools import check_html, _safe_path
|
||||||
from ..agent import run_agent
|
from ..agent import run_agent
|
||||||
from ..config import settings
|
from ..config import settings
|
||||||
|
from ..ollama_client import ollama
|
||||||
|
|
||||||
router = APIRouter(prefix="/api", tags=["chat"])
|
router = APIRouter(prefix="/api", tags=["chat"])
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -62,6 +64,37 @@ def _apply_mode(cfg: dict, mode: str) -> dict:
|
|||||||
return cfg
|
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:
|
def _loading_message(model: str, seconds: float) -> str:
|
||||||
"""Message d'attente avant le premier jeton (chargement du modèle)."""
|
"""Message d'attente avant le premier jeton (chargement du modèle)."""
|
||||||
waited = int(seconds)
|
waited = int(seconds)
|
||||||
@@ -421,6 +454,12 @@ async def chat(req: ChatRequest) -> StreamingResponse:
|
|||||||
for mcp_notice in mcp_manager.notices():
|
for mcp_notice in mcp_manager.notices():
|
||||||
yield _sse("notice", {"message": mcp_notice})
|
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 ──────────────────────────────
|
# ── Consignes additionnelles du tour ──────────────────────────────
|
||||||
# Elles sont COLLECTÉES ici puis fusionnées dans l'UNIQUE message
|
# Elles sont COLLECTÉES ici puis fusionnées dans l'UNIQUE message
|
||||||
# système (voir _merge_system plus bas). Beaucoup de templates
|
# système (voir _merge_system plus bas). Beaucoup de templates
|
||||||
|
|||||||
Reference in new issue
Block a user