refactor: drop the now-unused source parameter from usage resolvers
三态兜底不再读源配置,_resolve_usage / _resolve_stream_usage / _resolve_embedding_usage 的 source 形参已成死参数;保留它等于在签名上继续 宣称用量口径依赖源配置,与本次改动切断该依赖的意图相悖。同步三个调用点 与测试的直接调用;SourceConfig 仍被文件内错误翻译等函数使用,import 保留。
This commit is contained in:
@@ -138,12 +138,13 @@ def _strip_think(content: str) -> tuple[str, str]:
|
|||||||
return _THINK_PATTERN.sub("", content).strip(), match.group(1).strip()
|
return _THINK_PATTERN.sub("", content).strip(), match.group(1).strip()
|
||||||
|
|
||||||
|
|
||||||
def _resolve_usage(usage: dict[str, Any], source: SourceConfig) -> tuple[int, int, str]:
|
def _resolve_usage(usage: dict[str, Any]) -> tuple[int, int, str]:
|
||||||
"""usage 帧读取;缺失/非法记 0/0 并标 unavailable(est_tokens 解耦设计 §3.2 #3)。
|
"""usage 帧读取;缺失/非法记 0/0 并标 unavailable(est_tokens 解耦设计 §3.2 #3)。
|
||||||
|
|
||||||
不再拿 `est_tokens` 兜底: 它按 CHS 定义是"最坏情形上界",拿上界当实测值
|
不再拿 `est_tokens` 兜底: 它按 CHS 定义是"最坏情形上界",拿上界当实测值
|
||||||
只会系统性高估账单;宁可把用量记成显式的"不可得"(cost 随之为 NULL),
|
只会系统性高估账单;宁可把用量记成显式的"不可得"(cost 随之为 NULL),
|
||||||
让缺口可被统计,也不编一个看似有效的数字。
|
让缺口可被统计,也不编一个看似有效的数字。用量口径自此不依赖源配置,
|
||||||
|
故不再收 `SourceConfig`。
|
||||||
"""
|
"""
|
||||||
prompt, completion = usage.get("prompt_tokens"), usage.get("completion_tokens")
|
prompt, completion = usage.get("prompt_tokens"), usage.get("completion_tokens")
|
||||||
if isinstance(prompt, int) and isinstance(completion, int) and prompt + completion > 0:
|
if isinstance(prompt, int) and isinstance(completion, int) and prompt + completion > 0:
|
||||||
@@ -151,15 +152,13 @@ def _resolve_usage(usage: dict[str, Any], source: SourceConfig) -> tuple[int, in
|
|||||||
return 0, 0, "unavailable"
|
return 0, 0, "unavailable"
|
||||||
|
|
||||||
|
|
||||||
def _resolve_stream_usage(
|
def _resolve_stream_usage(sink: dict[str, Any], salvaged: bool) -> tuple[int, int, str]:
|
||||||
sink: dict[str, Any], salvaged: bool, source: SourceConfig
|
|
||||||
) -> tuple[int, int, str]:
|
|
||||||
"""流式用量口径: 打捞路径把 measured 降级为 estimated,unavailable 原样保留。
|
"""流式用量口径: 打捞路径把 measured 降级为 estimated,unavailable 原样保留。
|
||||||
|
|
||||||
前置条件不可省(解耦设计 §3.2 #4): usage 帧本就缺失时 `0/0` 会被洗成
|
前置条件不可省(解耦设计 §3.2 #4): usage 帧本就缺失时 `0/0` 会被洗成
|
||||||
`estimated`,进而按 token 换算出一个假的 `0.0` 成本。
|
`estimated`,进而按 token 换算出一个假的 `0.0` 成本。
|
||||||
"""
|
"""
|
||||||
prompt, completion, usage_source = _resolve_usage(sink.get("usage") or {}, source)
|
prompt, completion, usage_source = _resolve_usage(sink.get("usage") or {})
|
||||||
if salvaged and usage_source == "measured":
|
if salvaged and usage_source == "measured":
|
||||||
# 收到 usage 帧但流被截断: 数字真实、可信度降级(M1 设计 §6)
|
# 收到 usage 帧但流被截断: 数字真实、可信度降级(M1 设计 §6)
|
||||||
usage_source = "estimated"
|
usage_source = "estimated"
|
||||||
@@ -188,7 +187,7 @@ def _extract_vectors(
|
|||||||
return vectors
|
return vectors
|
||||||
|
|
||||||
|
|
||||||
def _resolve_embedding_usage(data: dict[str, Any], source: SourceConfig) -> tuple[int, str]:
|
def _resolve_embedding_usage(data: dict[str, Any]) -> tuple[int, str]:
|
||||||
"""usage 读取;缺失/非法记 0 并标 unavailable(与 chat 同口径,设计 §3.2 #3)。"""
|
"""usage 读取;缺失/非法记 0 并标 unavailable(与 chat 同口径,设计 §3.2 #3)。"""
|
||||||
prompt = (data.get("usage") or {}).get("prompt_tokens")
|
prompt = (data.get("usage") or {}).get("prompt_tokens")
|
||||||
if isinstance(prompt, int) and prompt > 0:
|
if isinstance(prompt, int) and prompt > 0:
|
||||||
@@ -206,7 +205,7 @@ def _parse_embedding_payload(
|
|||||||
except json.JSONDecodeError as exc:
|
except json.JSONDecodeError as exc:
|
||||||
raise ResultInvalidError(f"{source.name} embedding 响应非 JSON: {exc}", **ctx) from exc
|
raise ResultInvalidError(f"{source.name} embedding 响应非 JSON: {exc}", **ctx) from exc
|
||||||
vectors = _extract_vectors(data, source, expected_count, ctx)
|
vectors = _extract_vectors(data, source, expected_count, ctx)
|
||||||
prompt_tokens, usage_source = _resolve_embedding_usage(data, source)
|
prompt_tokens, usage_source = _resolve_embedding_usage(data)
|
||||||
return EmbeddingTransportResult(
|
return EmbeddingTransportResult(
|
||||||
vectors=vectors,
|
vectors=vectors,
|
||||||
dim=len(vectors[0]),
|
dim=len(vectors[0]),
|
||||||
@@ -351,7 +350,7 @@ class OpenAICompatTransport:
|
|||||||
salvaged = self._check_done(sink, content_parts, thinking_parts, source)
|
salvaged = self._check_done(sink, content_parts, thinking_parts, source)
|
||||||
content, thinking = self._finalize_text(content_parts, thinking_parts, profile)
|
content, thinking = self._finalize_text(content_parts, thinking_parts, profile)
|
||||||
self._reject_empty_completion(content, source)
|
self._reject_empty_completion(content, source)
|
||||||
prompt, completion, usage_source = _resolve_stream_usage(sink, salvaged, source)
|
prompt, completion, usage_source = _resolve_stream_usage(sink, salvaged)
|
||||||
return TransportResult(
|
return TransportResult(
|
||||||
content=content,
|
content=content,
|
||||||
thinking=thinking,
|
thinking=thinking,
|
||||||
@@ -433,7 +432,7 @@ class OpenAICompatTransport:
|
|||||||
[message.get("content") or ""], [message.get("reasoning_content") or ""], profile
|
[message.get("content") or ""], [message.get("reasoning_content") or ""], profile
|
||||||
)
|
)
|
||||||
self._reject_empty_completion(content, source)
|
self._reject_empty_completion(content, source)
|
||||||
prompt, completion, usage_source = _resolve_usage(body.get("usage") or {}, source)
|
prompt, completion, usage_source = _resolve_usage(body.get("usage") or {})
|
||||||
return TransportResult(
|
return TransportResult(
|
||||||
content=content,
|
content=content,
|
||||||
thinking=thinking,
|
thinking=thinking,
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ class _MemoryRecorder:
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_resolve_usage_stays_in_domain(usage):
|
def test_resolve_usage_stays_in_domain(usage):
|
||||||
assert _resolve_usage(usage, _src())[2] in USAGE_SOURCES
|
assert _resolve_usage(usage)[2] in USAGE_SOURCES
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@@ -95,7 +95,7 @@ def test_resolve_usage_stays_in_domain(usage):
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_resolve_embedding_usage_stays_in_domain(data):
|
def test_resolve_embedding_usage_stays_in_domain(data):
|
||||||
assert _resolve_embedding_usage(data, _src())[1] in USAGE_SOURCES
|
assert _resolve_embedding_usage(data)[1] in USAGE_SOURCES
|
||||||
|
|
||||||
|
|
||||||
def _sse(*frames, done):
|
def _sse(*frames, done):
|
||||||
|
|||||||
Reference in New Issue
Block a user