PMFlow/backend/app/main_model_probe.py

103 lines
3.7 KiB
Python

"""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)