feat(D1): models.json 集中化 — ADR-067 五大 Ollama 應用 hardcode 消除
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 12m56s
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 12m56s
- models.json v1.3.0: providers.ollama.models 新增 9 個 purpose keys
(drift_summary/drift_intent/log_anomaly/nemoclaw/playbook_draft/
code_review/embedding/rag_generate/image_analysis)
- drift_narrator_service: NARRATOR_MODEL → get_model("ollama","drift_summary")
- drift_interpreter: MODEL → get_model("ollama","drift_intent")
- log_summary_service: SUMMARY_MODEL → get_model("ollama","log_anomaly")
- local_code_review_service: _MODEL_OLLAMA → get_model("ollama","code_review")
- image_analysis_service: _MODEL → get_model("ollama","image_analysis")
- decision_manager: nemoclaw + playbook_draft 兩處 → get_model()
- embedding_service: get_embedding_service() factory → get_model("ollama","embedding")
- knowledge_service: OllamaEmbeddingService(model=...) → get_model()
所有模型名稱現在統一由 models.json 管理,修改模型只需改一個檔案。
LOGBOOK 更新:D1 完成 + B2 已完成確認
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"name": "OpenClaw AI Router Configuration",
|
||||
"version": "1.2.0",
|
||||
"description": "AI 模型路由與備援設定 (ADR-006 + ADR-036 Nemotron)",
|
||||
"updated_at": "2026-04-10",
|
||||
"version": "1.3.0",
|
||||
"description": "AI 模型路由與備援設定 (ADR-006 + ADR-036 Nemotron + D1 ADR-067 五大應用 2026-04-11)",
|
||||
"updated_at": "2026-04-11",
|
||||
|
||||
"default_provider": "ollama",
|
||||
"fallback_order": ["ollama", "gemini", "claude"],
|
||||
@@ -19,7 +19,16 @@
|
||||
"models": {
|
||||
"default": "deepseek-r1:14b",
|
||||
"rca": "deepseek-r1:14b",
|
||||
"summary": "gemma3:4b"
|
||||
"summary": "gemma3:4b",
|
||||
"drift_summary": "qwen2.5:7b-instruct",
|
||||
"drift_intent": "qwen2.5:7b-instruct",
|
||||
"log_anomaly": "deepseek-r1:14b",
|
||||
"nemoclaw": "deepseek-r1:14b",
|
||||
"playbook_draft": "qwen2.5:7b-instruct",
|
||||
"code_review": "qwen2.5-coder:7b",
|
||||
"embedding": "nomic-embed-text",
|
||||
"rag_generate": "qwen2.5:7b-instruct",
|
||||
"image_analysis": "llava:latest"
|
||||
},
|
||||
"options": {
|
||||
"temperature": 0.1,
|
||||
|
||||
@@ -332,8 +332,10 @@ async def _nemoclaw_second_opinion(incident: "Incident", primary_result: dict) -
|
||||
from src.core.config import settings
|
||||
import httpx as _httpx
|
||||
|
||||
from src.services.model_registry import get_model as _get_model
|
||||
ollama_url = getattr(settings, "OLLAMA_URL", "http://192.168.0.188:11434")
|
||||
model = "deepseek-r1:14b"
|
||||
# D1 集中化 2026-04-11: 從 models.json providers.ollama.models.nemoclaw 讀取
|
||||
model = _get_model("ollama", "nemoclaw")
|
||||
|
||||
signals_summary = ""
|
||||
if incident.signals:
|
||||
@@ -423,11 +425,14 @@ async def _generate_playbook_draft_if_new(incident: "Incident") -> None:
|
||||
f"## 驗收條件\n(如何確認修復成功)"
|
||||
)
|
||||
|
||||
from src.services.model_registry import get_model as _get_model
|
||||
ollama_url = getattr(settings, "OLLAMA_URL", "http://192.168.0.188:11434")
|
||||
# D1 集中化 2026-04-11: 從 models.json providers.ollama.models.playbook_draft 讀取
|
||||
_pb_model = _get_model("ollama", "playbook_draft")
|
||||
async with _httpx.AsyncClient(timeout=45.0) as client:
|
||||
resp = await client.post(
|
||||
f"{ollama_url}/api/generate",
|
||||
json={"model": "qwen2.5:7b-instruct", "prompt": prompt, "stream": False},
|
||||
json={"model": _pb_model, "prompt": prompt, "stream": False},
|
||||
)
|
||||
resp.raise_for_status()
|
||||
content = resp.json().get("response", "").strip()
|
||||
|
||||
@@ -107,12 +107,14 @@ class NemotronDriftInterpreter:
|
||||
"""
|
||||
import httpx
|
||||
from src.core.config import get_settings
|
||||
from src.services.model_registry import get_model as _get_model
|
||||
|
||||
# C1 修復 2026-04-11: 禁止寫死內網 IP(feedback_frontend_internal_ip_ban 鐵律)
|
||||
# 改從 settings.OLLAMA_URL 讀取(已有此設定,default=http://192.168.0.111:11434)
|
||||
_settings = get_settings()
|
||||
OLLAMA_URL = getattr(_settings, "OLLAMA_URL", "http://192.168.0.111:11434")
|
||||
MODEL = "qwen2.5:7b-instruct"
|
||||
# D1 集中化 2026-04-11: 從 models.json providers.ollama.models.drift_intent 讀取
|
||||
MODEL = _get_model("ollama", "drift_intent")
|
||||
TIMEOUT = 45.0
|
||||
|
||||
try:
|
||||
|
||||
@@ -24,6 +24,7 @@ import httpx
|
||||
import structlog
|
||||
|
||||
from src.core.redis_client import get_redis
|
||||
from src.services.model_registry import get_model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from src.models.drift import DriftInterpretation, DriftReport
|
||||
@@ -34,7 +35,8 @@ logger = structlog.get_logger(__name__)
|
||||
# 設定
|
||||
# ============================================================
|
||||
OLLAMA_URL = "http://192.168.0.111:11434"
|
||||
NARRATOR_MODEL = "qwen2.5:7b-instruct"
|
||||
# D1 集中化 2026-04-11: 從 models.json providers.ollama.models.drift_summary 讀取
|
||||
NARRATOR_MODEL = get_model("ollama", "drift_summary")
|
||||
NARRATOR_TIMEOUT = 90.0 # seconds
|
||||
CACHE_TTL = 3600 # 1 小時
|
||||
CACHE_PREFIX = "drift_narrative:"
|
||||
|
||||
@@ -21,6 +21,7 @@ import httpx
|
||||
import structlog
|
||||
|
||||
from src.core.config import settings
|
||||
from src.services.model_registry import get_model as _get_model
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
@@ -239,10 +240,11 @@ def get_embedding_service() -> OllamaEmbeddingService:
|
||||
"""
|
||||
取得 Embedding Service 單例
|
||||
|
||||
D1 集中化 2026-04-11: 預設模型從 models.json providers.ollama.models.embedding 讀取
|
||||
Returns:
|
||||
OllamaEmbeddingService: 共用實例
|
||||
"""
|
||||
global _embedding_service
|
||||
if _embedding_service is None:
|
||||
_embedding_service = OllamaEmbeddingService()
|
||||
_embedding_service = OllamaEmbeddingService(model=_get_model("ollama", "embedding"))
|
||||
return _embedding_service
|
||||
|
||||
@@ -30,6 +30,7 @@ import httpx
|
||||
import structlog
|
||||
|
||||
from src.core.config import get_settings
|
||||
from src.services.model_registry import get_model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
@@ -37,7 +38,8 @@ if TYPE_CHECKING:
|
||||
logger = structlog.get_logger(__name__)
|
||||
settings = get_settings()
|
||||
|
||||
_MODEL = "llava:latest"
|
||||
# D1 集中化 2026-04-11: 從 models.json providers.ollama.models.image_analysis 讀取
|
||||
_MODEL = get_model("ollama", "image_analysis")
|
||||
_TIMEOUT_S = 120.0
|
||||
_MAX_SIZE_BYTES = 5 * 1024 * 1024 # 5MB
|
||||
_ALLOWED_MIME = {"image/jpeg", "image/png", "image/webp", "image/gif"}
|
||||
|
||||
@@ -29,6 +29,7 @@ from src.models.knowledge import (
|
||||
from src.repositories.interfaces import IKnowledgeRepository
|
||||
from src.repositories.knowledge_repository import KnowledgeDBRepository
|
||||
from src.services.embedding_service import OllamaEmbeddingService
|
||||
from src.services.model_registry import get_model as _get_model
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
@@ -52,7 +53,8 @@ class KnowledgeService:
|
||||
|
||||
def __init__(self) -> None:
|
||||
# I2: 注入 embedding service,避免每次呼叫 new 實例
|
||||
self._embed_svc = OllamaEmbeddingService(model="nomic-embed-text", timeout=15.0)
|
||||
# D1 集中化 2026-04-11: 從 models.json providers.ollama.models.embedding 讀取
|
||||
self._embed_svc = OllamaEmbeddingService(model=_get_model("ollama", "embedding"), timeout=15.0)
|
||||
# I1: 持有背景 Task 引用,防止 GC 提前回收
|
||||
self._pending_tasks: set[asyncio.Task] = set() # type: ignore[type-arg]
|
||||
|
||||
|
||||
@@ -19,11 +19,13 @@ import httpx
|
||||
import structlog
|
||||
|
||||
from src.core.config import get_settings
|
||||
from src.services.model_registry import get_model
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
settings = get_settings()
|
||||
|
||||
_MODEL_OLLAMA = "qwen2.5-coder:7b"
|
||||
# D1 集中化 2026-04-11: 從 models.json providers.ollama.models.code_review 讀取
|
||||
_MODEL_OLLAMA = get_model("ollama", "code_review")
|
||||
_TIMEOUT_OLLAMA = 120.0
|
||||
_MAX_DIFF_BYTES = 50 * 1024 # 50KB → fallback to Gemini
|
||||
_SEMAPHORE = asyncio.Semaphore(2) # 最多 2 個同時審查
|
||||
|
||||
@@ -26,6 +26,7 @@ import httpx
|
||||
import structlog
|
||||
|
||||
from src.core.redis_client import get_redis
|
||||
from src.services.model_registry import get_model
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
@@ -33,7 +34,8 @@ logger = structlog.get_logger(__name__)
|
||||
# 設定
|
||||
# ============================================================
|
||||
OLLAMA_URL = "http://192.168.0.111:11434"
|
||||
SUMMARY_MODEL = "deepseek-r1:14b"
|
||||
# D1 集中化 2026-04-11: 從 models.json providers.ollama.models.log_anomaly 讀取
|
||||
SUMMARY_MODEL = get_model("ollama", "log_anomaly")
|
||||
LLM_TIMEOUT = 180.0 # deepseek-r1 硬超時
|
||||
SOFT_TIMEOUT = 5.0 # 主流程軟超時(超過回 None)
|
||||
LOG_TAIL_LINES = 100
|
||||
|
||||
@@ -6,6 +6,25 @@
|
||||
|
||||
---
|
||||
|
||||
## 📍 當前狀態 (2026-04-11 深夜 — ADR-072 Code Review 修補全完成)
|
||||
|
||||
### ADR-072 Code Review 修補完成 (2026-04-11 深夜)
|
||||
|
||||
首席架構師審查後,補修 4 個 Code Review 問題:
|
||||
|
||||
| 項目 | 問題 | 修復 | Commit |
|
||||
|------|------|------|--------|
|
||||
| C1 | drift_interpreter.py 寫死內網 IP 192.168.0.111 | 改從 settings.OLLAMA_URL 讀取 | f323633 |
|
||||
| C2 | BUG-004 只更新 DB,Redis Working Memory vectorized 未同步 | 補 Redis JSON patch 同步 | f323633 |
|
||||
| I2 | _ALERTNAME_KEYWORDS 用 HostHighDiskUsage(與 alerts-unified.yml 不符)| 改為 HostOutOfDiskSpace + DockerContainerExited + fallback log | f323633 |
|
||||
| M2 | import json as _json 在 for 迴圈體內 | 移至方法頂部 | f323633 |
|
||||
|
||||
**技術債記錄**(不阻塞合併):I1 ADR-064 Rule Engine 整合、I3 resend_stale_ready_tokens 積木化、I4 outcome 寫入非 atomic、M3 alertname_to_type 應抽至 constants
|
||||
|
||||
**ADR-072 全部完成** ✅ — 8 Bug + Code Review 全修補,推送 Gitea
|
||||
|
||||
---
|
||||
|
||||
## 📍 當前狀態 (2026-04-11 深夜 — ADR-072 全部完成 BUG-001~008)
|
||||
|
||||
### ADR-072 P2 完成 (2026-04-11 深夜)
|
||||
|
||||
Reference in New Issue
Block a user