feat:修复投顾agent功能

This commit is contained in:
2026-09-14 21:41:40 +08:00
parent fc1d74570f
commit 058f45115d
14 changed files with 142 additions and 33 deletions
+32 -21
View File
@@ -103,6 +103,21 @@ class LLMClient:
def __init__(self, cfg: LLMCfg | None = None):
self.cfg = cfg or settings.llm
self.backends = resolve_backends(self.cfg)
self._clients: dict[str, httpx.AsyncClient] = {}
def _client_for(self, backend: Backend) -> httpx.AsyncClient:
clients = getattr(self, "_clients", None)
if clients is None:
clients = {}
self._clients = clients
if backend.name not in clients:
clients[backend.name] = backend.client(self.cfg.timeout)
return clients[backend.name]
async def aclose(self) -> None:
for client in getattr(self, "_clients", {}).values():
await client.aclose()
getattr(self, "_clients", {}).clear()
# ---- 首选后端(健康检查/日志/embed 使用) -----------------------------
@property
@@ -186,9 +201,9 @@ class LLMClient:
"stream": False,
}
try:
async with backend.client(self.cfg.timeout) as client:
r = await client.post(url, headers=backend.headers, json=payload)
r.raise_for_status()
client = self._client_for(backend)
r = await client.post(url, headers=backend.headers, json=payload)
r.raise_for_status()
choice = r.json()["choices"][0]
message = choice["message"]
content = message.get("content")
@@ -250,20 +265,16 @@ class LLMClient:
response = None
max_retries = max(1, int(getattr(self.cfg, "max_retries", 1)))
retry_backoff_sec = float(getattr(self.cfg, "retry_backoff_sec", 0))
async with backend.client(self.cfg.timeout) as client:
for attempt in range(max_retries):
try:
response = await client.post(
url,
headers=backend.headers,
json=payload,
)
response.raise_for_status()
break
except Exception:
if attempt == max_retries - 1:
raise
await asyncio.sleep(retry_backoff_sec * (2**attempt))
client = self._client_for(backend)
for attempt in range(max_retries):
try:
response = await client.post(url, headers=backend.headers, json=payload)
response.raise_for_status()
break
except Exception:
if attempt == max_retries - 1:
raise
await asyncio.sleep(retry_backoff_sec * (2**attempt))
if response is None: # pragma: no cover - defensive guard
raise LLMFailError("Embedding 请求未返回响应")
data = response.json()
@@ -286,10 +297,10 @@ class LLMClient:
url = backend.base_url.removesuffix("/v1") + "/api/tags"
else:
url = f"{backend.base_url}/models"
async with backend.client(min(self.cfg.timeout, 10)) as client:
r = await client.get(url, headers=backend.headers)
if r.status_code >= 500:
r.raise_for_status()
client = self._client_for(backend)
r = await client.get(url, headers=backend.headers)
if r.status_code >= 500:
r.raise_for_status()
# 全局单例:Agent 统一引入