diff --git a/apps/api/src/services/drift_narrator_service.py b/apps/api/src/services/drift_narrator_service.py index de6d0ab8..8bfc6634 100644 --- a/apps/api/src/services/drift_narrator_service.py +++ b/apps/api/src/services/drift_narrator_service.py @@ -19,11 +19,11 @@ from __future__ import annotations from typing import TYPE_CHECKING -import httpx import structlog from src.core.redis_client import get_redis from src.services.model_registry import get_model +from src.services.openclaw import get_openclaw if TYPE_CHECKING: from src.models.drift import DriftInterpretation, DriftReport @@ -156,25 +156,19 @@ class DriftNarratorService: intent_summary=intent_summary, ) + # 2026-04-17 ogt + Claude Sonnet 4.6: 改用 OpenClaw AI Router 取代直接 Ollama httpx + # 根因:直接呼叫 192.168.0.111:11434 繞過 AI Router,無 fallback → "All connection attempts failed" + # 修復:統一走 openclaw.call(),自動享有 Provider 降級與 fallback 機制 + # 同 drift_interpreter.py 的修法(d952435) try: - async with httpx.AsyncClient(timeout=NARRATOR_TIMEOUT) as client: - resp = await client.post( - f"{OLLAMA_URL}/api/generate", - json={ - "model": NARRATOR_MODEL, - "prompt": prompt, - "stream": False, - "options": {"temperature": 0.3, "num_predict": 300}, - }, - ) - resp.raise_for_status() - data = resp.json() - text = data.get("response", "").strip() - if text: - return text + openclaw = get_openclaw() + text, _provider, success = await openclaw.call(prompt) + + if success and text and text.strip(): + return text.strip() + + logger.warning("drift_narrator_openclaw_failed", provider=_provider) - except httpx.TimeoutException: - logger.warning("drift_narrator_timeout", model=NARRATOR_MODEL) except Exception as e: logger.warning("drift_narrator_llm_error", error=str(e))