Files
awoooi/apps/api/src/models/nvidia.py
OG T 4f7282a97a fix(ai): Phase 20 P2 修復 - Protocol + 邊界測試 + model_registry
P2-1: 定義 INvidiaProvider Protocol (@runtime_checkable)
P2-2: 補充邊界測試 15 → 25 案例
P2-3: model_registry 新增 NVIDIA + tool_calling_fallback_order

首席架構師評分: 82 → 86 → 90/100

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-29 01:24:17 +08:00

120 lines
4.1 KiB
Python

"""
NVIDIA Nemotron API Models - ADR-036
====================================
2026-03-29 ogt: Nemotron Tool Calling 整合 (83.3% 精準度)
OpenAI 相容格式 - 用於 Tool Calling 任務
"""
from typing import Any
from pydantic import BaseModel, Field
class ToolFunction(BaseModel):
"""Tool Function 定義"""
name: str = Field(..., description="Tool 函數名稱")
arguments: str = Field(..., description="Tool 參數 (JSON 字串)")
class ToolCall(BaseModel):
"""Tool Call 結構"""
id: str = Field(..., description="Tool Call ID")
type: str = Field(default="function", description="Tool 類型")
function: ToolFunction = Field(..., description="Tool 函數")
class NvidiaMessage(BaseModel):
"""NVIDIA API Message 結構"""
role: str = Field(..., description="訊息角色 (assistant/user/system)")
content: str | None = Field(default=None, description="訊息內容")
tool_calls: list[ToolCall] | None = Field(
default=None, description="Tool Calls (僅 assistant)"
)
class NvidiaChoice(BaseModel):
"""NVIDIA API Choice 結構"""
index: int = Field(default=0, description="選項索引")
message: NvidiaMessage = Field(..., description="回應訊息")
finish_reason: str | None = Field(
default=None, description="結束原因 (stop/tool_calls)"
)
class NvidiaUsage(BaseModel):
"""NVIDIA API Token 使用統計"""
prompt_tokens: int = Field(default=0, description="輸入 Token 數")
completion_tokens: int = Field(default=0, description="輸出 Token 數")
total_tokens: int = Field(default=0, description="總 Token 數")
class NvidiaResponse(BaseModel):
"""NVIDIA Nemotron API 完整回應"""
id: str = Field(..., description="回應 ID")
object: str = Field(default="chat.completion", description="物件類型")
created: int = Field(..., description="建立時間戳")
model: str = Field(..., description="模型名稱")
choices: list[NvidiaChoice] = Field(..., description="回應選項")
usage: NvidiaUsage | None = Field(default=None, description="Token 使用統計")
# === Tool Calling 請求結構 ===
class ToolDefinition(BaseModel):
"""Tool 定義 (發送給 API)"""
type: str = Field(default="function", description="Tool 類型")
function: dict[str, Any] = Field(..., description="函數定義 (JSON Schema)")
class NvidiaToolCallRequest(BaseModel):
"""NVIDIA Tool Calling 請求"""
model: str = Field(
default="nvidia/nemotron-mini-4b-instruct",
description="模型名稱 (2026-03-29 ogt: 修正為可用的 mini 模型)",
)
messages: list[dict[str, Any]] = Field(..., description="對話訊息")
tools: list[ToolDefinition] = Field(..., description="可用 Tools")
tool_choice: str | dict[str, Any] = Field(
default="auto", description="Tool 選擇策略"
)
temperature: float = Field(default=0.0, description="溫度 (0.0 最確定性)")
max_tokens: int = Field(default=1024, description="最大輸出 Token")
# === 驗證結果結構 ===
class ToolCallValidationResult(BaseModel):
"""Tool Call 驗證結果"""
valid: bool = Field(..., description="是否有效")
tool_name: str | None = Field(default=None, description="Tool 名稱")
arguments: dict[str, Any] | None = Field(default=None, description="解析後參數")
error: str | None = Field(default=None, description="錯誤訊息")
raw_response: str | None = Field(default=None, description="原始回應 (debug)")
class NvidiaProviderResult(BaseModel):
"""NvidiaProvider 回傳結果"""
success: bool = Field(..., description="是否成功")
tool_calls: list[ToolCallValidationResult] = Field(
default_factory=list, description="驗證後的 Tool Calls"
)
usage: NvidiaUsage | None = Field(default=None, description="Token 使用統計")
latency_ms: float = Field(default=0.0, description="延遲 (毫秒)")
error: str | None = Field(default=None, description="錯誤訊息")
fallback_triggered: bool = Field(
default=False, description="是否觸發 Fallback"
)