feat(ai): ADR-036 NVIDIA Nemotron Tool Calling 整合
Phase 20 - 提升 Tool Calling 精準度 50% → 83.3% 新增: - src/models/nvidia.py: Pydantic Schema - src/services/nvidia_provider.py: NvidiaProvider 類別 - tests/test_nvidia_provider.py: 15 項單元測試 (全部通過) 修改: - ai_router.py: AIProvider.NVIDIA + route_tool_calling() - ai_rate_limiter.py: NVIDIA 限制 (5 RPM, 100/day) - models.json: NVIDIA 配置 - cd.yaml: Secrets 注入 NVIDIA_API_KEY 路由策略: - Tool Calling: Nemotron → Gemini → Claude - 一般對話: Ollama → Gemini → Claude (不變) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
119
apps/api/src/models/nvidia.py
Normal file
119
apps/api/src/models/nvidia.py
Normal file
@@ -0,0 +1,119 @@
|
||||
"""
|
||||
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/llama-3.1-nemotron-70b-instruct",
|
||||
description="模型名稱",
|
||||
)
|
||||
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"
|
||||
)
|
||||
Reference in New Issue
Block a user