max retries eingeführt
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 4s
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 4s
This commit is contained in:
parent
cbaf664123
commit
6ac1f318d0
|
|
@ -6,9 +6,12 @@ DESCRIPTION: Hybrid-Client für Ollama, Google GenAI (Gemini) und OpenRouter.
|
|||
WP-20 Fix: Bulletproof Prompt-Auflösung für format() Aufrufe.
|
||||
WP-22/JSON: Optionales JSON-Schema + strict (für OpenRouter structured outputs).
|
||||
FIX: Intelligente Rate-Limit Erkennung (429 Handling), v1-API Sync & Timeouts.
|
||||
VERSION: 3.3.6
|
||||
VERSION: 3.3.7
|
||||
STATUS: Active
|
||||
DEPENDENCIES: httpx, yaml, logging, asyncio, json, google-genai, openai, app.config
|
||||
FIX:
|
||||
- Implementiert striktes max_retries Handling für alle Provider (v.a. für Chat-Stabilität).
|
||||
- Synchronisiert Rate-Limit Retries mit dem max_retries Parameter.
|
||||
- Optimiert Logging für sofortige Fehlererkennung.
|
||||
"""
|
||||
import httpx
|
||||
import yaml
|
||||
|
|
@ -84,8 +87,6 @@ class LLMService:
|
|||
Hole provider-spezifisches Template mit intelligenter Text-Kaskade.
|
||||
HINWEIS: Dies ist nur ein Text-Lookup und verbraucht kein API-Kontingent.
|
||||
Kaskade: Gewählter Provider -> Gemini (Cloud-Stil) -> Ollama (Basis-Stil).
|
||||
|
||||
WP-20 Fix: Garantiert die Rückgabe eines Strings, um AttributeError zu vermeiden.
|
||||
"""
|
||||
active_provider = provider or self.settings.MINDNET_LLM_PROVIDER
|
||||
data = self.prompts.get(key, "")
|
||||
|
|
@ -118,11 +119,6 @@ class LLMService:
|
|||
) -> str:
|
||||
"""
|
||||
Haupteinstiegspunkt für LLM-Anfragen mit Priorisierung.
|
||||
|
||||
force_json:
|
||||
- Ollama: nutzt payload["format"]="json"
|
||||
- Gemini: nutzt response_mime_type="application/json"
|
||||
- OpenRouter: nutzt response_format=json_object (Fallback) oder json_schema
|
||||
"""
|
||||
target_provider = provider or self.settings.MINDNET_LLM_PROVIDER
|
||||
|
||||
|
|
@ -154,11 +150,12 @@ class LLMService:
|
|||
strict_json_schema: bool
|
||||
) -> str:
|
||||
"""
|
||||
Routet die Anfrage mit intelligenter Rate-Limit Erkennung (WP-20 + WP-76).
|
||||
Schleife läuft über MINDNET_LLM_RATE_LIMIT_RETRIES.
|
||||
Routet die Anfrage mit intelligenter Rate-Limit Erkennung.
|
||||
Nutzt max_retries um die Rate-Limit Schleife zu begrenzen.
|
||||
"""
|
||||
rate_limit_attempts = 0
|
||||
max_rate_retries = getattr(self.settings, "LLM_RATE_LIMIT_RETRIES", 3)
|
||||
# FIX: Wir nutzen max_retries als Limit für Rate-Limit Versuche, wenn explizit klein gewählt (z.B. Chat)
|
||||
max_rate_retries = min(max_retries, getattr(self.settings, "LLM_RATE_LIMIT_RETRIES", 3))
|
||||
wait_time = getattr(self.settings, "LLM_RATE_LIMIT_WAIT", 60.0)
|
||||
|
||||
while rate_limit_attempts <= max_rate_retries:
|
||||
|
|
@ -182,18 +179,17 @@ class LLMService:
|
|||
|
||||
except Exception as e:
|
||||
err_str = str(e)
|
||||
# Intelligente 429 Erkennung für alle Cloud-Provider
|
||||
# Intelligente 429 Erkennung
|
||||
is_rate_limit = any(x in err_str for x in ["429", "RESOURCE_EXHAUSTED", "rate_limited", "Too Many Requests"])
|
||||
|
||||
if is_rate_limit and rate_limit_attempts < max_rate_retries:
|
||||
rate_limit_attempts += 1
|
||||
logger.warning(
|
||||
f"⏳ [LLMService] Rate Limit (429) detected from {provider}. "
|
||||
f"Attempt {rate_limit_attempts}/{max_rate_retries}. "
|
||||
f"Waiting {wait_time}s before cloud retry..."
|
||||
f"⏳ [LLMService] Rate Limit detected from {provider}. "
|
||||
f"Attempt {rate_limit_attempts}/{max_rate_retries}. Waiting {wait_time}s..."
|
||||
)
|
||||
await asyncio.sleep(wait_time)
|
||||
continue # Nächster Versuch in der Cloud-Schleife
|
||||
continue
|
||||
|
||||
# Wenn kein Rate-Limit oder Retries erschöpft -> Fallback zu Ollama (falls aktiviert)
|
||||
if self.settings.LLM_FALLBACK_ENABLED and provider != "ollama":
|
||||
|
|
@ -206,14 +202,12 @@ class LLMService:
|
|||
async def _execute_google(self, prompt, system, force_json, model_override):
|
||||
"""Native Google SDK Integration (Gemini) mit v1 Fix."""
|
||||
model = model_override or self.settings.GEMINI_MODEL
|
||||
# Fix: Bereinige Modellnamen (Entfernung von 'models/' Präfix)
|
||||
clean_model = model.replace("models/", "")
|
||||
|
||||
config = types.GenerateContentConfig(
|
||||
system_instruction=system,
|
||||
response_mime_type="application/json" if force_json else "text/plain"
|
||||
)
|
||||
# Thread-Offloading mit striktem Timeout gegen "Hangs"
|
||||
response = await asyncio.wait_for(
|
||||
asyncio.to_thread(
|
||||
self.google_client.models.generate_content,
|
||||
|
|
@ -233,7 +227,7 @@ class LLMService:
|
|||
json_schema_name: str = "mindnet_json",
|
||||
strict_json_schema: bool = True
|
||||
) -> str:
|
||||
"""OpenRouter API Integration (OpenAI-kompatibel) mit Schema-Support."""
|
||||
"""OpenRouter API Integration (OpenAI-kompatibel)."""
|
||||
model = model_override or self.settings.OPENROUTER_MODEL
|
||||
messages = []
|
||||
if system:
|
||||
|
|
@ -262,14 +256,14 @@ class LLMService:
|
|||
return response.choices[0].message.content.strip()
|
||||
|
||||
async def _execute_ollama(self, prompt, system, force_json, max_retries, base_delay):
|
||||
"""Lokaler Ollama Call mit exponentiellem Backoff."""
|
||||
"""Lokaler Ollama Call mit striktem Retry-Limit."""
|
||||
payload = {
|
||||
"model": self.settings.LLM_MODEL,
|
||||
"prompt": prompt,
|
||||
"stream": False,
|
||||
"options": {
|
||||
"temperature": 0.1 if force_json else 0.7,
|
||||
"num_ctx": 8192
|
||||
"num_ctx": 8192 # Begrenzung für Stabilität (WP-20)
|
||||
}
|
||||
}
|
||||
if force_json:
|
||||
|
|
@ -285,9 +279,11 @@ class LLMService:
|
|||
return res.json().get("response", "").strip()
|
||||
except Exception as e:
|
||||
attempt += 1
|
||||
# WICHTIG: Wenn max_retries=0 (Chat), bricht dies nach dem 1. Versuch (attempt=1) sofort ab.
|
||||
if attempt > max_retries:
|
||||
logger.error(f"❌ Ollama Error after {attempt} retries: {e}")
|
||||
logger.error(f"❌ Ollama request failed after {attempt} attempt(s): {e}")
|
||||
raise e
|
||||
|
||||
wait_time = base_delay * (2 ** (attempt - 1))
|
||||
logger.warning(f"⚠️ Ollama attempt {attempt} failed. Retrying in {wait_time}s...")
|
||||
await asyncio.sleep(wait_time)
|
||||
|
|
@ -300,6 +296,7 @@ class LLMService:
|
|||
|
||||
final_prompt = rag_template.format(context_str=context_str, query=query)
|
||||
|
||||
# RAG Aufrufe im Chat nutzen nun standardmäßig max_retries=2 (überschreibbar)
|
||||
return await self.generate_raw_response(
|
||||
final_prompt,
|
||||
system=system_prompt,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user