feat(ai): 新增 NVIDIA Nemotron 到告警 Fallback Chain

- 新增 _call_nvidia() 一般告警支援 (非 Tool Calling)
- Fallback 順序: Gemini → Nvidia → Ollama → Claude
- Nvidia 免費 tier ($0),含 Token 追蹤

解決: Gemini 超限 (500/500) 後無法 fallback 問題

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
OG T
2026-03-29 20:28:24 +08:00
parent 6a8e1bfdd1
commit 79134fb019
2 changed files with 67 additions and 5 deletions

View File

@@ -461,6 +461,65 @@ class OpenClawService:
logger.warning("claude_call_failed", error=str(e))
return str(e), False
async def _call_nvidia(self, prompt: str) -> tuple[str, bool, int, float]:
"""
呼叫 NVIDIA Nemotron (OpenAI 相容格式)
2026-03-29 ogt: 新增 Nemotron 一般告警支援 (非 Tool Calling)
Returns:
tuple: (response_text, success, total_tokens, cost_usd)
"""
if not settings.NVIDIA_API_KEY:
return "NVIDIA_API_KEY not configured", False, 0, 0.0
try:
client = await self._get_client()
# Nemotron 模型
model_name = "nvidia/llama-3.1-nemotron-70b-instruct"
response = await client.post(
"https://integrate.api.nvidia.com/v1/chat/completions",
headers={
"Authorization": f"Bearer {settings.NVIDIA_API_KEY}",
"Content-Type": "application/json",
},
json={
"model": model_name,
"messages": [{"role": "user", "content": prompt}],
"temperature": 0.1,
"max_tokens": 2048,
"response_format": {"type": "json_object"}, # 強制 JSON
},
timeout=60.0,
)
response.raise_for_status()
data = response.json()
text = data["choices"][0]["message"]["content"]
# Token 用量
usage = data.get("usage", {})
prompt_tokens = usage.get("prompt_tokens", 0)
completion_tokens = usage.get("completion_tokens", 0)
total_tokens = usage.get("total_tokens", prompt_tokens + completion_tokens)
# NVIDIA NIM 免費 tier = $0
cost_usd = 0.0
logger.info(
"nvidia_response_received",
response_length=len(text),
total_tokens=total_tokens,
cost_usd=f"${cost_usd:.6f}",
)
return text, True, total_tokens, cost_usd
except Exception as e:
logger.warning("nvidia_call_failed", error=str(e))
return str(e), False, 0, 0.0
# =========================================================================
# Mock LLM - Intelligent Fallback with SignOz Data
# =========================================================================
@@ -876,6 +935,9 @@ class OpenClawService:
response, success = await self._call_ollama(prompt)
elif provider == "gemini":
response, success, total_tokens, cost_usd = await self._call_gemini(prompt)
elif provider == "nvidia":
# 2026-03-29 ogt: Nemotron 一般告警支援
response, success, total_tokens, cost_usd = await self._call_nvidia(prompt)
elif provider == "claude":
response, success = await self._call_claude(prompt)
else:

View File

@@ -1,8 +1,8 @@
# AWOOOI 正式環境 ConfigMap
# 負責人: CIO
# 版本: v1.1
# 日期: 2026-03-27 (台北時區)
# 變更: Gemini 優先 (臨時,待 Ollama CPU 問題修復後切回)
# 日期: 2026-03-29 (台北時區)
# 變更: Gemini 優先 + Token/Cost 追蹤
apiVersion: v1
kind: ConfigMap
@@ -34,10 +34,10 @@ data:
CORS_ORIGINS: '["https://awoooi.wooo.work","http://localhost:3000","http://localhost:3001"]'
# AI 配置 (JSON array 格式 for pydantic-settings)
# 2026-03-29 ogt: 切換 Gemini 優先 (確認 AI 仲裁運作正常)
# 備援順序: Gemini(~$0.001) → Ollama($0) → Claude(~$0.008)
# 2026-03-29 ogt: Gemini 優先 + Nvidia 備援 + Token/Cost 追蹤
# 備援順序: Gemini(~$0.001) → Nvidia($0 免費tier) → Ollama($0) → Claude(~$0.008)
# Rate Limiter: RPM=10, 每日 500 次, Token 100K
AI_FALLBACK_ORDER: '["gemini","ollama","claude"]'
AI_FALLBACK_ORDER: '["gemini","nvidia","ollama","claude"]'
AI_CACHE_TTL: "3600"
# 快取 TTL (秒)