classifier: Add fallback model for transient LLM failures
The 26b model occasionally hangs or fails outright on the local Ollama box, which used to drop every such update into 'manual' for no good reason. Retry the same prompt with a smaller model before giving up, and surface both errors when even the fallback fails. OLLAMA_FALLBACK_MODEL is new config, see .env.sample.
This commit is contained in:
parent
2df588b957
commit
86268107fa
2 changed files with 19 additions and 2 deletions
|
|
@ -23,3 +23,4 @@ UPTIME_KUMA_PASSWORD=your-password
|
|||
# Ollama for AI-driven auto-update classification
|
||||
OLLAMA_BASE_URL=http://192.168.1.20:11434
|
||||
OLLAMA_MODEL=gemma4:26b
|
||||
OLLAMA_FALLBACK_MODEL=gemma4:12b
|
||||
|
|
|
|||
|
|
@ -29,9 +29,11 @@ class Classifier:
|
|||
self,
|
||||
base_url: str = "",
|
||||
model: str = "",
|
||||
fallback_model: str = "",
|
||||
) -> None:
|
||||
self.base_url = base_url or os.getenv("OLLAMA_BASE_URL", "http://192.168.1.20:11434")
|
||||
self.model = model or os.getenv("OLLAMA_MODEL", "gemma4:26b")
|
||||
self.fallback_model = fallback_model or os.getenv("OLLAMA_FALLBACK_MODEL", "gemma4:12b")
|
||||
|
||||
def classify(
|
||||
self,
|
||||
|
|
@ -54,9 +56,23 @@ class Classifier:
|
|||
context = context_file.read_text(encoding="utf-8").strip() if context_file.is_file() else None
|
||||
messages = self._build_messages(service_dir.name, examples, release_notes, current, latest, context)
|
||||
|
||||
try:
|
||||
return self._classify_with_model(self.model, messages, timeout)
|
||||
except Exception as primary_exc:
|
||||
if not self.fallback_model or self.fallback_model == self.model:
|
||||
return {"action": "manual", "reason": f"Classification error: {primary_exc}"}
|
||||
try:
|
||||
return self._classify_with_model(self.fallback_model, messages, timeout)
|
||||
except Exception as fallback_exc:
|
||||
return {
|
||||
"action": "manual",
|
||||
"reason": f"Classification error: {primary_exc}; fallback ({self.fallback_model}) also failed: {fallback_exc}",
|
||||
}
|
||||
|
||||
def _classify_with_model(self, model: str, messages: List[Dict[str, str]], timeout: float) -> Dict[str, str]:
|
||||
try:
|
||||
payload = json.dumps({
|
||||
"model": self.model,
|
||||
"model": model,
|
||||
"messages": messages,
|
||||
"stream": False,
|
||||
"options": {"temperature": 0},
|
||||
|
|
@ -79,7 +95,7 @@ class Classifier:
|
|||
raise ValueError(f"Unexpected action value: {action!r}")
|
||||
return {"action": action, "reason": result.get("reason", "")}
|
||||
except Exception as exc:
|
||||
return {"action": "manual", "reason": f"Classification error: {exc}"}
|
||||
raise RuntimeError(f"model {model}: {exc}") from exc
|
||||
|
||||
def _build_messages(
|
||||
self,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue