"""Startup model connectivity probe helpers.""" from __future__ import annotations import asyncio import os import time from .core.logging import get_logger logger = get_logger(__name__) def startup_log(message: str, **fields) -> None: logger.info(f"[后端] {message}", **fields) async def probe_model_connectivity_on_startup() -> None: from .services.llm import llm_service low_provider = str(os.getenv("LLM_ROUTING_LOW_PROVIDER", os.getenv("LLM_PROVIDER", "glm")) or "").strip() or "glm" low_model = str(os.getenv("LLM_ROUTING_LOW_MODEL", os.getenv("GLM_MODEL", "GLM-4.7")) or "").strip() or "GLM-4.7" high_provider = str(os.getenv("LLM_ROUTING_HIGH_PROVIDER", os.getenv("LLM_PROVIDER", "openai")) or "").strip() or "openai" high_model = str(os.getenv("LLM_ROUTING_HIGH_MODEL", os.getenv("OPENAI_MODEL", "GLM-5")) or "").strip() or "GLM-5" probe_targets: list[tuple[str, str, str]] = [ ("LOW", low_provider, low_model), ("HIGH", high_provider, high_model), ] deduped_targets: list[tuple[str, str, str]] = [] seen: set[tuple[str, str]] = set() for level, provider, model in probe_targets: key = (provider.lower(), model) if key in seen: continue seen.add(key) deduped_targets.append((level, provider, model)) lines: list[str] = [ "┌──────────────────────────────┐", "│ 模型连通性检测 │", ] for level, provider, model in deduped_targets: try: runtime = llm_service._env_provider_runtime(provider) runtime["model"] = model except Exception as exc: logger.error( "startup_model_probe_runtime_invalid", level=level, provider=provider, model=model, error=str(exc), ) lines.append(f"│ {model:<12} ✗ 失败 (0.0s) │") continue started_at = time.perf_counter() ok = False error_text = "" try: result = await asyncio.wait_for( llm_service._chat_completion( provider=str(runtime.get("provider") or provider), prompt="ping", system_prompt="你是连通性检测助手,只回复 OK。", api_key=str(runtime.get("api_key") or ""), base_url=str(runtime.get("base_url") or ""), model=str(runtime.get("model") or model), temperature=0.0, max_tokens=1, function_name="startup_model_probe", response_mode="fast", ), timeout=8.0, ) ok = bool(str(result or "").strip()) if not ok: error_text = "empty_response" except Exception as exc: error_text = str(exc) logger.error( "startup_model_probe_failed", level=level, provider=provider, model=model, error=error_text, ) elapsed = time.perf_counter() - started_at if ok: lines.append(f"│ {model:<12} ✓ 正常 ({elapsed:.1f}s) │") else: lines.append(f"│ {model:<12} ✗ 失败 ({elapsed:.1f}s) │") if error_text: startup_log("模型连通性失败(不阻断启动)", model=model, provider=provider, error=error_text) lines.append("└──────────────────────────────┘") for line in lines: logger.info(line)