refactor(ai): 模組化重構 - NVIDIA chat 移至 NvidiaProvider
符合 feedback_lewooogo_modular_enforcement.md 規範: - 移除 openclaw.py 中的 _call_nvidia() (重複邏輯) - 新增 NvidiaProvider.chat() 方法 - 更新 INvidiaProvider Protocol - openclaw.py 改用 get_nvidia_provider().chat() - 測試移至 test_nvidia_chat.py 架構層次: - Router → Service → Provider (正確) - 禁止 Service 層重複實作已存在的 Provider 功能 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -461,76 +461,8 @@ 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)
|
||||
2026-03-29 ogt: P1 修復 - 從 ModelRegistry 取得模型名稱
|
||||
|
||||
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()
|
||||
|
||||
# 從 ModelRegistry 取得模型 (P1-1 修復)
|
||||
registry = get_model_registry()
|
||||
model_name = registry.get_model("nvidia", "rca")
|
||||
options = registry.get_provider_options("nvidia")
|
||||
|
||||
logger.info(
|
||||
"nvidia_request_start",
|
||||
model=model_name,
|
||||
prompt_length=len(prompt),
|
||||
)
|
||||
|
||||
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": options.get("temperature", 0.1),
|
||||
"max_tokens": options.get("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",
|
||||
model=model_name,
|
||||
response_length=len(text),
|
||||
prompt_tokens=prompt_tokens,
|
||||
completion_tokens=completion_tokens,
|
||||
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), error_type=type(e).__name__)
|
||||
return str(e), False, 0, 0.0
|
||||
# 2026-03-29 ogt: _call_nvidia 已移至 nvidia_provider.py
|
||||
# 符合模組化規範 - 所有 NVIDIA API 呼叫統一由 NvidiaProvider 處理
|
||||
|
||||
# =========================================================================
|
||||
# Mock LLM - Intelligent Fallback with SignOz Data
|
||||
@@ -948,8 +880,10 @@ class OpenClawService:
|
||||
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)
|
||||
# 2026-03-29 ogt: 使用 NvidiaProvider.chat() (模組化規範)
|
||||
from src.services.nvidia_provider import get_nvidia_provider
|
||||
nvidia_provider = get_nvidia_provider()
|
||||
response, success, total_tokens, cost_usd = await nvidia_provider.chat(prompt)
|
||||
elif provider == "claude":
|
||||
response, success = await self._call_claude(prompt)
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user