Files
ewoooc/services/llm_caller_registry.py
OoO 875810620f
All checks were successful
CD Pipeline / deploy (push) Successful in 1m28s
[V10.327] 補 OpenClaw 備援可觀測性
2026-05-20 13:00:39 +08:00

151 lines
6.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
services/llm_caller_registry.py
Operation Ollama-First v5.0 / Phase 16 — caller 名稱集中註冊critic-A11 L4 修補)
問題caller 命名分散在 ai_call_logger 註解 / migrations/024 SQL 註解 /
各 service hardcode三層不一致時報表會看到鬼影gemini / Gemini / gemini-flash
修補:本檔為 single source of truthai_call_logger 啟動時驗證;
service 寫死 caller 字串若不在 registry → log warning不 raise保留擴展彈性
依 ADR-028 caller 白名單30+ 個 caller
"""
from __future__ import annotations
import logging
logger = logging.getLogger(__name__)
# ─────────────────────────────────────────────────────────────────────────────
# Caller 白名單(按服務分組,與 ai_call_logger 註解 + migration 024 對齊)
# ─────────────────────────────────────────────────────────────────────────────
CALLER_REGISTRY: frozenset = frozenset({
# Hermes 競價分析hermes_analyst_service
'hermes_analyst', # _call_hermes_batch
'hermes_intent', # intent_classify (L1 NLP)
'hermes_ea_prefetch', # EA HITL pre-fetch (ADR-021)
# KM Embeddingopenclaw_learning_service
'km_embedding_worker', # 60s retry queue worker
'km_embedding_realtime', # _build_semantic_rag_context
# AiderHealaider_heal_executor
'aider_heal', # SSH CLI 跑 Aider暫不接 logger
# MCP Collectormcp_collector_service
'mcp_l1_grounding', # Gemini 2.0 Flash Grounding
'mcp_l2_grounding', # Gemini 1.5 Flash Grounding
'mcp_l3_ollama', # Ollama 知識庫兜底
'mcp_collector', # Phase 10.5 omnisearch 入口
# OpenClaw 戰略openclaw_strategist_service
'openclaw_daily', # 每日報告
'openclaw_daily_gemini_fallback',
'openclaw_daily_nim',
'openclaw_weekly', # 週一 06:00
'openclaw_weekly_gemini_fallback',
'openclaw_weekly_nim',
'openclaw_monthly', # 每月 1 日
'openclaw_monthly_gemini_fallback',
'openclaw_monthly_nim',
'openclaw_meta', # Meta 自審 12:00
'openclaw_meta_gemini_fallback',
'openclaw_meta_nim',
'openclaw_qa', # Telegram Q&A
'openclaw_qa_gemini_fallback', # Telegram Q&A Gemini fallback
'openclaw_qa_nim', # Telegram Q&A NIM fallback
'openclaw_daily_insight', # Phase 3 A8 拆分後的 200 字 Ollama-first 洞察
'openclaw_daily_insight_gemini_fallback',
'openclaw_daily_insight_nim',
'openclaw_strategist', # Phase 10.5 mcp_router caller
# NemoTron 派遣nemoton_dispatcher_service
'nemotron_dispatch', # NIM 8B 主路徑 / qwen3 主路徑
# Code Reviewcode_review_pipeline_service
'code_review_hermes', # Step 2 Hermes 掃描
'code_review_openclaw', # Step 3 OpenClaw 評估Ollama-firstClaude optional fallback
'code_review_elephant', # Step 4 ElephantAlpha 49B
'code_review_openclaw_gemini', # Ollama/Claude 失敗後的 Gemini fallback
# ElephantAlphaelephant_alpha_*
'ea_engine', # _execute_autonomous_decision (Gemini orchestrate)
# PPT 簡報routes/openclaw_bot_routes
'ppt_gemini', # Gemini Flash 主分析
'ppt_ollama', # Ollama 失敗 fallback
'ppt_nim', # NIM deepseek-v3.2 主分析
'ppt_vision', # Phase 14 PPT 視覺檢查qwen2-vl
# Sales / Trendroutes/ai_routes + routes/trend_routes
'sales_copy', # 文案生成
'trend_match', # 商品比對
'trend_qa', # Web Search Q&A
'product_insights', # 商品洞察
'trend_keywords', # 趨勢關鍵字
# Telegram Bot
'tg_bot_copy', # /copy 文案
'tg_bot_copy_v2', # second copy entrance
'openclaw_bot_main', # OpenClaw Bot 主鏈 Ollama
'openclaw_bot_gemini', # Bot Gemini fallback
'openclaw_bot_image', # Bot 圖片商品辨識 Ollama-first
'openclaw_bot_image_gemini', # Bot 圖片商品辨識 Gemini fallback
'openclaw_bot_nim', # Bot NIM fallback
# 其他
'bot_api_copy', # bot_api_routes
'trend_crawler', # trend_crawler_service
'ai_provider_generic', # ai_provider 抽象層
})
def is_known_caller(caller: str) -> bool:
"""檢查 caller 是否在白名單"""
return caller in CALLER_REGISTRY
def assert_known_caller(caller: str, strict: bool = False) -> None:
"""ai_call_logger 啟動時或寫入時驗證。
Args:
caller: 待驗證的 caller 名
strict: True → 不在 registry 時 raiseFalse預設→ 只 log warning
依 ADR-028新增 caller 必須先入 ADR + registry再上 commit。
"""
if not is_known_caller(caller):
msg = f"unknown caller: {caller!r} not in CALLER_REGISTRY (ADR-028)"
if strict:
raise ValueError(msg)
logger.warning(f"[CallerRegistry] {msg} — see services/llm_caller_registry.py")
def list_callers_by_service() -> dict:
"""除錯/文件用:分組列出所有合法 caller"""
return {
'hermes': [c for c in CALLER_REGISTRY if c.startswith('hermes_')],
'openclaw': [c for c in CALLER_REGISTRY if c.startswith('openclaw_') and not c.startswith('openclaw_bot_')],
'openclaw_bot': [c for c in CALLER_REGISTRY if c.startswith('openclaw_bot_')],
'mcp': [c for c in CALLER_REGISTRY if c.startswith('mcp_')],
'code_review': [c for c in CALLER_REGISTRY if c.startswith('code_review_')],
'ppt': [c for c in CALLER_REGISTRY if c.startswith('ppt_')],
'tg_bot': [c for c in CALLER_REGISTRY if c.startswith('tg_bot_')],
'km_embedding': [c for c in CALLER_REGISTRY if c.startswith('km_embedding_')],
'sales_trend': ['sales_copy', 'trend_match', 'trend_qa',
'product_insights', 'trend_keywords'],
'misc': ['ea_engine', 'aider_heal', 'nemotron_dispatch',
'bot_api_copy', 'trend_crawler', 'ai_provider_generic'],
}
__all__ = [
'CALLER_REGISTRY',
'is_known_caller',
'assert_known_caller',
'list_callers_by_service',
]