feat(api): LLMClient.chat_json 加 want_usage 可选参返 (obj,usage)——漏斗 token 计量数据源, 默认调用零变化 [vps] [no-doc]

This commit is contained in:
2026-10-02 09:51:29 +08:00
parent eb6475b1d7
commit 7b489d1606
2 changed files with 29 additions and 4 deletions
+13 -4
View File
@@ -34,8 +34,16 @@ class LLMClient:
self._sleep = sleep or asyncio.sleep
async def chat_json(self, messages: list[dict], *, temperature: float = 0.2,
max_tokens: int = 2000) -> dict:
"""一轮对话→dict.传输层重试+参数自愈在 payload 级,解析失败 strict 重试一次."""
max_tokens: int = 2000,
want_usage: bool = False) -> dict | tuple[dict, dict]:
"""一轮对话→dict;want_usage=True 返 (dict, usage)(P4-3 漏斗 token 计量,
usage 含 prompt_tokens/completion_tokens)。默认调用形态零变化。"""
obj, usage = await self._chat_json(messages, temperature=temperature,
max_tokens=max_tokens)
return (obj, usage) if want_usage else obj
async def _chat_json(self, messages: list[dict], *, temperature: float,
max_tokens: int) -> tuple[dict, dict]:
payload: dict = {
"model": self._cfg.model,
"messages": messages,
@@ -62,7 +70,7 @@ class LLMClient:
usage.get("prompt_tokens"),
usage.get("completion_tokens"))
try:
return robust_json_parse(content)
return robust_json_parse(content), usage
except JSONParseError:
return await self._strict_retry(messages, payload)
if status in (401, 403, 404):
@@ -96,7 +104,8 @@ class LLMClient:
if status != 200:
raise LLMError(f"LLM strict 重试失败(HTTP {status}): {text[:200]}")
try:
return robust_json_parse(self._content(text))
usage = json.loads(text).get("usage") or {}
return robust_json_parse(self._content(text)), usage
except JSONParseError as e:
raise LLMError(f"LLM 返回非 JSON(两轮): {e}") from e