fix(llm): request_id 条件透传贯通网关日志(CR-H4,守 §9.3)
This commit is contained in:
@@ -183,22 +183,26 @@ class Gateway:
|
||||
def _log_call(
|
||||
self, req: LlmRequest, usage: Usage, served_by: ServedBy, *, stream: bool
|
||||
) -> None:
|
||||
log.info(
|
||||
"llm_call",
|
||||
provider=usage.provider,
|
||||
model=usage.model,
|
||||
tier=req.tier,
|
||||
input_tokens=usage.input_tokens,
|
||||
output_tokens=usage.output_tokens,
|
||||
cache_read_tokens=usage.cache_read_tokens,
|
||||
cost_minor=usage.cost_minor,
|
||||
currency=usage.currency,
|
||||
stream=stream,
|
||||
fell_back=served_by.fell_back,
|
||||
degraded=served_by.degraded,
|
||||
input_chars=_input_len(req),
|
||||
project_id=str(req.scope.project_id) if req.scope.project_id else None,
|
||||
)
|
||||
fields: dict[str, object] = {
|
||||
"provider": usage.provider,
|
||||
"model": usage.model,
|
||||
"tier": req.tier,
|
||||
"input_tokens": usage.input_tokens,
|
||||
"output_tokens": usage.output_tokens,
|
||||
"cache_read_tokens": usage.cache_read_tokens,
|
||||
"cost_minor": usage.cost_minor,
|
||||
"currency": usage.currency,
|
||||
"stream": stream,
|
||||
"fell_back": served_by.fell_back,
|
||||
"degraded": served_by.degraded,
|
||||
"input_chars": _input_len(req),
|
||||
"project_id": str(req.scope.project_id) if req.scope.project_id else None,
|
||||
}
|
||||
# 仅在调用方显式设了 request_id 时才发——否则 None 会覆盖 merge_contextvars
|
||||
# 供的 id,反倒回退 sync/SSE 路径的追踪(§9.3)。
|
||||
if req.request_id is not None:
|
||||
fields["request_id"] = req.request_id
|
||||
log.info("llm_call", **fields)
|
||||
|
||||
def _retrying(self) -> AsyncRetrying:
|
||||
return AsyncRetrying(
|
||||
@@ -237,6 +241,7 @@ class Gateway:
|
||||
provider=route.provider,
|
||||
tier=req.tier,
|
||||
error=type(exc).__name__,
|
||||
**({"request_id": req.request_id} if req.request_id is not None else {}),
|
||||
)
|
||||
continue
|
||||
self._breaker.record_success(route.provider)
|
||||
@@ -297,6 +302,7 @@ class Gateway:
|
||||
tier=req.tier,
|
||||
error=type(exc).__name__,
|
||||
stream=True,
|
||||
**({"request_id": req.request_id} if req.request_id is not None else {}),
|
||||
)
|
||||
continue
|
||||
self._breaker.record_success(route.provider)
|
||||
|
||||
@@ -29,7 +29,11 @@ class Scope(BaseModel):
|
||||
|
||||
|
||||
class LlmRequest(BaseModel):
|
||||
"""统一请求。`system` 稳定块在前(断点前),`input` 易变内容在后。"""
|
||||
"""统一请求。`system` 稳定块在前(断点前),`input` 易变内容在后。
|
||||
|
||||
`request_id`(可选)贯通端到端追踪:调用方设置后,网关把它落到每条 LLM 调用日志,
|
||||
使一次「写一章」的 assemble→write→审→验收全链路可 grep(ARCH §9.3)。
|
||||
"""
|
||||
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
|
||||
@@ -40,6 +44,7 @@ class LlmRequest(BaseModel):
|
||||
output_schema: type[BaseModel] | None = None
|
||||
max_tokens: int | None = None
|
||||
scope: Scope
|
||||
request_id: str | None = None
|
||||
|
||||
|
||||
class Usage(BaseModel):
|
||||
|
||||
Reference in New Issue
Block a user