From 58d9c0637ae25259033dff209a23da06ab63c94a Mon Sep 17 00:00:00 2001 From: OG T Date: Fri, 17 Apr 2026 13:27:05 +0800 Subject: [PATCH] =?UTF-8?q?fix(drift):=20drift=5Fnarrator=20=E6=94=B9?= =?UTF-8?q?=E7=94=A8=20OpenClaw=20AI=20Router=20=E2=80=94=20=E4=BF=AE?= =?UTF-8?q?=E5=BE=A9=E3=80=8C=E7=A0=94=E5=88=A4=E5=8E=9F=E5=9B=A0=E3=80=8D?= =?UTF-8?q?=E7=A9=BA=E7=99=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因: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 --- .../src/services/drift_narrator_service.py | 30 ++++++++----------- 1 file changed, 12 insertions(+), 18 deletions(-) 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))