fix(mcp): P1 修復 - DI 一致性 + 測試補充 + 配置優化
首席架構師審查 P1 修復清單: P1-1 RAG Provider DI 模式一致性: - 支援 rag_service 參數注入 - 新增 close() 方法 - TYPE_CHECKING 延遲導入 P1-3 RAG 測試補充: - test_rag_provider.py (9 tests) - DI 注入/Lazy Load/Tool Schema/驗證/Close P1-4 Grafana Config 快取優化: - URL/Key 首次查詢後快取 - 減少重複 settings 存取 P1-5 Embedding 維度配置化: - MODEL_DIMENSIONS 字典 (qwen/llama/nomic) - default_dimension 參數 - 支援更多模型 測試: 9/9 PASSED Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -17,8 +17,9 @@ Grafana MCP Tool Provider - Phase 13.2 #83
|
||||
|
||||
@see docs/adr/ADR-015-mcp-modular-architecture.md
|
||||
@author Claude Code
|
||||
@version 1.0
|
||||
@version 1.1
|
||||
@created 2026-03-26 (台北時區)
|
||||
@updated 2026-03-29 (台北時區) - P1 修復: URL/Key 快取優化
|
||||
@issue #83
|
||||
"""
|
||||
|
||||
@@ -80,9 +81,13 @@ class GrafanaProvider(MCPToolProvider):
|
||||
Args:
|
||||
grafana_url: Grafana URL (default: from settings)
|
||||
api_key: Grafana API Key (default: from settings)
|
||||
|
||||
P1 修復 (2026-03-29): 快取 URL/Key 避免重複 settings 查詢
|
||||
"""
|
||||
self._grafana_url = grafana_url
|
||||
self._api_key = api_key
|
||||
self._grafana_url_input = grafana_url
|
||||
self._api_key_input = api_key
|
||||
self._grafana_url: str | None = None # 快取解析後的 URL
|
||||
self._api_key: str | None = None # 快取解析後的 Key
|
||||
self._client: httpx.AsyncClient | None = None
|
||||
|
||||
logger.info(
|
||||
@@ -91,28 +96,48 @@ class GrafanaProvider(MCPToolProvider):
|
||||
)
|
||||
|
||||
def _get_grafana_url(self) -> str:
|
||||
"""取得 Grafana URL (lazy load from settings)"""
|
||||
if self._grafana_url:
|
||||
"""
|
||||
取得 Grafana URL (快取 + lazy load from settings)
|
||||
|
||||
P1 修復: 首次查詢後快取結果
|
||||
"""
|
||||
if self._grafana_url is not None:
|
||||
return self._grafana_url
|
||||
|
||||
if self._grafana_url_input:
|
||||
self._grafana_url = self._grafana_url_input
|
||||
return self._grafana_url
|
||||
|
||||
try:
|
||||
from src.core.config import get_settings
|
||||
settings = get_settings()
|
||||
return getattr(settings, "GRAFANA_URL", DEFAULT_GRAFANA_URL)
|
||||
self._grafana_url = getattr(settings, "GRAFANA_URL", DEFAULT_GRAFANA_URL)
|
||||
except Exception:
|
||||
return DEFAULT_GRAFANA_URL
|
||||
self._grafana_url = DEFAULT_GRAFANA_URL
|
||||
|
||||
return self._grafana_url
|
||||
|
||||
def _get_api_key(self) -> str | None:
|
||||
"""取得 API Key (lazy load from settings)"""
|
||||
if self._api_key:
|
||||
"""
|
||||
取得 API Key (快取 + lazy load from settings)
|
||||
|
||||
P1 修復: 首次查詢後快取結果
|
||||
"""
|
||||
if self._api_key is not None:
|
||||
return self._api_key
|
||||
|
||||
if self._api_key_input:
|
||||
self._api_key = self._api_key_input
|
||||
return self._api_key
|
||||
|
||||
try:
|
||||
from src.core.config import get_settings
|
||||
settings = get_settings()
|
||||
return getattr(settings, "GRAFANA_API_KEY", None)
|
||||
self._api_key = getattr(settings, "GRAFANA_API_KEY", None)
|
||||
except Exception:
|
||||
return None
|
||||
self._api_key = None
|
||||
|
||||
return self._api_key
|
||||
|
||||
def _get_headers(self) -> dict[str, str]:
|
||||
"""取得 HTTP Headers (含認證)"""
|
||||
|
||||
@@ -9,20 +9,25 @@ RAG MCP Tool Provider - ADR-015 模組化架構
|
||||
|
||||
Phase 13.2 #84 - Runbook RAG Tool
|
||||
|
||||
版本: v1.0
|
||||
版本: v1.1
|
||||
建立日期: 2026-03-27 00:00 (台北時區)
|
||||
更新日期: 2026-03-29 20:40 (台北時區)
|
||||
建立者: Claude Code
|
||||
更新者: Claude Code (P1 修復: DI 模式一致性)
|
||||
"""
|
||||
|
||||
import time
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
import structlog
|
||||
|
||||
from src.plugins.mcp.interfaces import MCPTool, MCPToolProvider, MCPToolResult
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from src.services.rag_service import IRAGService
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
|
||||
@@ -32,17 +37,35 @@ class RAGProvider(MCPToolProvider):
|
||||
|
||||
提供維運手冊的語義搜尋功能。
|
||||
使用 Redis Vector Search + Ollama Embedding。
|
||||
|
||||
支援 DI 注入或 Lazy Load (向後相容):
|
||||
# DI 注入 (推薦)
|
||||
provider = RAGProvider(rag_service=my_rag_service)
|
||||
|
||||
# Lazy Load (向後相容)
|
||||
provider = RAGProvider()
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._rag_service = None
|
||||
def __init__(self, rag_service: "IRAGService | None" = None) -> None:
|
||||
"""
|
||||
初始化 Provider
|
||||
|
||||
Args:
|
||||
rag_service: RAG Service 實例 (可選,不提供則 lazy load)
|
||||
"""
|
||||
self._rag_service = rag_service
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return "runbooks"
|
||||
|
||||
def _get_rag_service(self):
|
||||
"""Lazy load RAG service"""
|
||||
def _get_rag_service(self) -> "IRAGService":
|
||||
"""
|
||||
取得 RAG Service (支援 DI 或 Lazy Load)
|
||||
|
||||
Returns:
|
||||
IRAGService: RAG Service 實例
|
||||
"""
|
||||
if self._rag_service is None:
|
||||
from src.services.rag_service import get_rag_service
|
||||
self._rag_service = get_rag_service()
|
||||
@@ -232,4 +255,9 @@ class RAGProvider(MCPToolProvider):
|
||||
except Exception as e:
|
||||
logger.warning("rag_health_check_failed", error=str(e))
|
||||
return False
|
||||
# Trigger CD build
|
||||
|
||||
async def close(self) -> None:
|
||||
"""關閉 Provider (清理資源)"""
|
||||
# RAG Service 使用共享 Redis client,不在此關閉
|
||||
self._rag_service = None
|
||||
logger.debug("rag_provider_closed")
|
||||
|
||||
Reference in New Issue
Block a user