fix: normalize LLM provider key lookup and skip disabled HyDE ping (final review)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
wangwei
2026-07-02 21:24:22 +08:00
co-authored by Copilot
parent 6a7fe48c4c
commit e3afb8a07a
2 changed files with 120 additions and 4 deletions
+34 -4
View File
@@ -8,7 +8,7 @@ from fastapi import APIRouter
from app.config.settings import settings
from app.domain.retrieval import RetrievedChunk
from app.services.llm.llm_factory import get_llm_client
from app.services.llm.llm_factory import get_llm_client, get_llm_factory
from app.shared.bootstrap import (
get_bm25_retriever,
get_binary_store,
@@ -129,6 +129,27 @@ async def get_health():
}
def _normalize_llm_provider(raw_provider: str) -> str:
"""Normalize a raw LLM_PROVIDER/HYDE_LLM_PROVIDER settings string to the
canonical LLMProvider enum value, the SAME way LLMFactory.create() does.
TrackedLLMClient.chat() (tracked_client.py) always records usage under
`self._inner.config.provider.value` — the NORMALIZED enum value produced by
LLMFactory._parse_provider() — never the raw string a caller passed to
get_llm_client(). Reusing that same normalization here (instead of
duplicating the alias table) guarantees the tracker key this route reads
always agrees with the key TrackedLLMClient wrote, even when the raw
settings value is a non-canonical alias (e.g. "deepseek-v3") or different
casing. Falls back to the raw string, unchanged, if it does not match any
known provider/alias, so this passive status endpoint still renders
(as "never_called") instead of raising on a misconfigured provider string.
"""
try:
return get_llm_factory()._parse_provider(raw_provider).value
except ValueError:
return raw_provider
def _resolve_role_provider_model(role: str) -> tuple[str, str]:
"""Return the (provider, model) pair currently configured for one AI model role.
@@ -138,10 +159,10 @@ def _resolve_role_provider_model(role: str) -> tuple[str, str]:
recorded when HyDE actually ran.
"""
if role == "main_llm":
return settings.llm_provider, settings.llm_model
return _normalize_llm_provider(settings.llm_provider), settings.llm_model
if role == "hyde_llm":
return (
settings.hyde_llm_provider or settings.llm_provider,
_normalize_llm_provider(settings.hyde_llm_provider or settings.llm_provider),
settings.hyde_llm_model or settings.llm_model,
)
if role == "embedding":
@@ -204,7 +225,16 @@ async def get_model_statuses():
async def _ping_main_or_hyde(role: str) -> None:
"""Send one minimal chat completion to the LLM configured for `role`."""
"""Send one minimal chat completion to the LLM configured for `role`.
Skipped entirely for "hyde_llm" when settings.hyde_enabled is False,
mirroring _ping_reranker()'s disabled-skip pattern: when HyDE is turned
off (or reuses the main LLM, the default), issuing this ping would just be
a redundant duplicate chat call against the same model for no benefit.
"main_llm" is always pinged regardless of this check.
"""
if role == "hyde_llm" and not settings.hyde_enabled:
return
provider, model = _resolve_role_provider_model(role)
try:
client = get_llm_client(provider=provider, model=model)