mirror of
https://github.com/Alkatrazz24/Funk-lab.git
synced 2026-07-08 21:24:41 +02:00
Qwen3 est un modèle « thinking » : il dépensait tout le budget max_tokens en reasoning_content → content vide, ou partait en raisonnement long → timeout (502 "upstream LiteLLM : " avec message vide). Diagnostic : appel direct LiteLLM en 0.87s mais content="" et tout dans reasoning_content. - brain.py : ajoute le token de contrôle `/no_think` au system prompt (configurable STT_DISABLE_THINKING, défaut true ; inoffensif pour non-Qwen). - brain.py : filet de sécurité — si content vide, récupère reasoning_content au lieu de renvoyer "". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT
54 lines
2.2 KiB
Python
54 lines
2.2 KiB
Python
"""Orchestration AI : route les requêtes des clients vers LiteLLM (s01).
|
|
|
|
LiteLLM (:4000) est OpenAI-compatible et route lui-même vers Qwen3 (g01) ou Claude
|
|
selon l'alias `hermes-default` / `hermes-switch`. L'intégration des outils Hermes
|
|
(« agir sur Funk » via le gateway :8080) est une étape ultérieure.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import httpx
|
|
|
|
from stt_server.config import settings
|
|
|
|
|
|
async def ask(
|
|
text: str,
|
|
model: str | None = None,
|
|
history: list[dict] | None = None,
|
|
memories: list[str] | None = None,
|
|
) -> str:
|
|
system = settings.system_prompt
|
|
if settings.disable_thinking:
|
|
# Qwen3 est un modèle « thinking » : sans ça il dépense tout le budget max_tokens
|
|
# en raisonnement (`reasoning_content`) → `content` vide, ou part en réflexion longue
|
|
# → timeout (502). Le token de contrôle `/no_think` désactive le mode raisonnement.
|
|
# Inoffensif pour les modèles non-Qwen (simple texte ignoré).
|
|
system += "\n/no_think"
|
|
if memories:
|
|
souvenirs = "\n".join(f"- {m}" for m in memories)
|
|
system += (
|
|
"\n\nÉléments de mémoire long-terme (peuvent aider, ignore si hors-sujet) :\n"
|
|
+ souvenirs
|
|
)
|
|
messages = [{"role": "system", "content": system}]
|
|
if history:
|
|
messages += history
|
|
messages.append({"role": "user", "content": text})
|
|
payload = {
|
|
"model": model or settings.model,
|
|
"messages": messages,
|
|
"max_tokens": settings.max_tokens,
|
|
"temperature": settings.temperature,
|
|
}
|
|
headers = {"Authorization": f"Bearer {settings.litellm_key}"}
|
|
async with httpx.AsyncClient(timeout=settings.request_timeout) as client:
|
|
r = await client.post(settings.litellm_url, json=payload, headers=headers)
|
|
r.raise_for_status()
|
|
msg = r.json()["choices"][0]["message"]
|
|
# Filet de sécurité : si un modèle « thinking » renvoie un content vide (tout parti
|
|
# en reasoning_content), on récupère le raisonnement plutôt que de renvoyer "".
|
|
content = (msg.get("content") or "").strip()
|
|
if not content:
|
|
content = (msg.get("reasoning_content") or "").strip()
|
|
return content
|