fix(drift): drift_narrator 改用 OpenClaw AI Router — 修復「研判原因」空白

根因:drift_narrator_service.py 的 _generate_narrative() 直接呼叫
      Ollama httpx (192.168.0.111:11434),繞過 AI Router,無 fallback。
      192.168.0.111 為死亡 IP → httpx 連線失敗 → 降級 fallback_narrative()
      → fallback 中 interpretation.explanation 存在但顯示層截斷 → 空白

修復:改用 get_openclaw().call(prompt),統一走 AI Router
      同 drift_interpreter.py 的修法(d952435)
      移除 unused httpx import

2026-04-17 ogt + Claude Sonnet 4.6

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
OG T
2026-04-17 13:27:05 +08:00
parent 0247058d92
commit 58d9c0637a

View File

@@ -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))