fix(llm): Anthropic 结构化输出记真实 usage——修计费记 0 成本(CR-H3)
This commit is contained in:
@@ -46,7 +46,9 @@ class AnthropicClient(Protocol):
|
||||
|
||||
|
||||
class StructuredAnthropic(Protocol):
|
||||
async def create(self, *, response_model: type[BaseModel], **kwargs: Any) -> BaseModel: ...
|
||||
async def create_with_completion(
|
||||
self, *, response_model: type[BaseModel], **kwargs: Any
|
||||
) -> tuple[BaseModel, Any]: ...
|
||||
|
||||
|
||||
def _is_transient(exc: Exception) -> bool:
|
||||
@@ -115,7 +117,7 @@ class AnthropicAdapter:
|
||||
# 注入客户端是 `AnthropicClient` Protocol(保留测试替身缝),
|
||||
# 但 instructor.from_anthropic 只重载真实 SDK 的具体类型;
|
||||
# 本适配器异步 → 转 `AsyncAnthropic` 选中 AsyncInstructor 重载,
|
||||
# 返回的 AsyncInstructor 鸭子匹配 StructuredAnthropic。
|
||||
# 返回的 AsyncInstructor 鸭子匹配 StructuredAnthropic(含 create_with_completion)。
|
||||
async_client = cast("AsyncAnthropic", self._client)
|
||||
self._structured_client = cast(
|
||||
"StructuredAnthropic", instructor.from_anthropic(async_client)
|
||||
@@ -156,9 +158,11 @@ class AnthropicAdapter:
|
||||
system = _system_blocks(req)
|
||||
if system:
|
||||
kwargs["system"] = system
|
||||
parsed = await self._structured().create(response_model=req.output_schema, **kwargs)
|
||||
# instructor.from_anthropic 默认不回 raw usage(按名隐藏);usage 经流/text 路径覆盖。
|
||||
usage = ProviderUsage(input_tokens=0, output_tokens=0)
|
||||
parsed, raw = await self._structured().create_with_completion(
|
||||
response_model=req.output_schema, **kwargs
|
||||
)
|
||||
# 从 raw completion 提取真实 usage(记账真源,§4.8);不再硬编码零(CR-H3)。
|
||||
usage = _usage_from(getattr(raw, "usage", None))
|
||||
return ProviderResult(text=parsed.model_dump_json(), usage=usage, parsed=parsed)
|
||||
|
||||
async def stream(self, req: LlmRequest, model: str) -> AsyncIterator[StreamChunk]:
|
||||
|
||||
Reference in New Issue
Block a user