From 7ed2a6668a11abf864d07cc462377670ca3ee58d Mon Sep 17 00:00:00 2001 From: zyycn Date: Sun, 2 Aug 2026 00:13:29 +0800 Subject: [PATCH] feat(usage): mark attempt list as best-effort observations Decide attempt facts are best-effort (adr-002), not authoritative history: - Usage detail response exposes attemptsComplete: false - frontend labels the attempt chain as best-effort - architecture.md documents the semantics Co-Authored-By: Claude Fable 5 --- .../crates/gateway-api/src/admin/observability.rs | 3 +++ docs/architecture.md | 5 +++-- frontend/src/api/modules/usage.ts | 2 ++ .../usage/components/UsageRecordDetailModal.vue | 14 +++++++++++--- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/backend/crates/gateway-api/src/admin/observability.rs b/backend/crates/gateway-api/src/admin/observability.rs index f441d36e6..1ac8b4936 100644 --- a/backend/crates/gateway-api/src/admin/observability.rs +++ b/backend/crates/gateway-api/src/admin/observability.rs @@ -718,6 +718,8 @@ pub struct UsageRecordDetailView { #[serde(flatten)] pub request: UsageRecordView, pub attempts: Vec, + /// 尝试列表是否完整;best-effort 下恒为 false。 + pub attempts_complete: bool, } /// Dashboard 趋势数据。 @@ -1842,6 +1844,7 @@ fn usage_detail_view(detail: domain::UsageDetail) -> UsageRecordDetailView { .into_iter() .map(usage_attempt_view) .collect(), + attempts_complete: false, } } diff --git a/docs/architecture.md b/docs/architecture.md index b6dc92186..045336ee3 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -66,8 +66,7 @@ API decode/auth 1. 每个客户端请求只有一条 `model_requests`;attempt 明细保存在其 JSON 事实中,不另建 attempt 表。 2. 任何可能到达上游的调用都必须先按序提交 request/attempt 观测到有界队列;PostgreSQL 投影是可恢复 - 观测,不是数据面发送的同步前置条件。 -3. `not_sent`、`sent`、`ambiguous` 是不同的上游发送边界;发送状态是请求级单调水位(`sent` > `ambiguous` > `not_sent`),跨 attempt 只升不降,终态写回不得低于水位;`ambiguous` 不自动重放。 + 观测,不是数据面发送的同步前置条件。3. `not_sent`、`sent`、`ambiguous` 是不同的上游发送边界;发送状态是请求级单调水位(`sent` > `ambiguous` > `not_sent`),跨 attempt 只升不降,终态写回不得低于水位;`ambiguous` 不自动重放。 4. 内存中的 downstream commit 表示网关已作出不可撤回的交付承诺,从该时刻禁止 retry/fallback; 它在实际首字节写出前越过并按序入队。`downstream_committed_at` 是该事实的 PostgreSQL 观测投影, 不宣称字节已经到达客户端,也不反向决定协议交付。 @@ -75,6 +74,8 @@ API decode/auth 6. 下游 commit 前,Core 可按冻结策略处理同一 Provider 内的账号 fallback;禁止跨 Provider fallback。 7. 本架构不通过隐式连接复用承载业务身份。HTTP client 可安全复用 transport 连接,但账号、credential revision、cookie/session binding 必须显式绑定到本次调用。 +管理端 Usage 详情中的 attempt 列表是 best-effort 观测(见 adr-002):中间失败来自 `ops_events`,最终尝试由 `model_requests` 合成,二者都不承诺完整(队列丢弃、写入失败、非失败观测不落库会造成缺口)。API 通过 `attemptsComplete: false` 显式标注这一语义,不再声称「全部尝试」。 + ## 4. 路由、fallback 与错误处理 RuntimeSnapshot 冻结 Provider 集合、模型能力、运行时策略和全局 `config_revision`。一次请求始终使用同一快照,不在执行中拼接新旧配置。 diff --git a/frontend/src/api/modules/usage.ts b/frontend/src/api/modules/usage.ts index 459fdafb8..fb444d291 100644 --- a/frontend/src/api/modules/usage.ts +++ b/frontend/src/api/modules/usage.ts @@ -175,6 +175,8 @@ export interface UsageAttempt { export type UsageRecordDetail = UsageRecord & { attempts: UsageAttempt[] + /** 尝试列表是否完整;best-effort 下恒为 false。 */ + attemptsComplete: boolean } export interface UsageRecordsResponse { diff --git a/frontend/src/views/usage/components/UsageRecordDetailModal.vue b/frontend/src/views/usage/components/UsageRecordDetailModal.vue index 2d3c5e7f6..ed445c923 100644 --- a/frontend/src/views/usage/components/UsageRecordDetailModal.vue +++ b/frontend/src/views/usage/components/UsageRecordDetailModal.vue @@ -402,9 +402,17 @@ const tokenDonutOption = computed(() => {
-

- 尝试链路 -

+
+

+ 尝试链路 +

+ + 尽力观测 + +