Skip to content

Commit 3ed5792

Browse files
committed
fix: streamline Jev diagnostics and request usage logs
Remove ineffective request classifiers and unused Jev transport configuration. Fix native usage extraction, distinguish absent confidence from zero, and simplify log payloads while retaining historical data. Align operational descriptions, admin views, API contracts and embedded assets with regression coverage.
1 parent 38a6f07 commit 3ed5792

68 files changed

Lines changed: 1602 additions & 820 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎README.md‎

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,22 @@ docker rm auto-router
5858

5959
Jev 不可用、未启用或推荐置信度低于 `routing.policy.low_confidence` 时,使用 `routing.auto.default_group`(默认 `medium`);所选组没有合格成员时明确失败,不自动切换任务等级。故障转移只尝试同组后续成员。`routing.auto.failover.max_attempts` 统计首次请求,范围为 1–8,默认 2;请求发送前可确认未送达的失败默认允许重试,超时与 HTTP 状态码默认不重试。启用超时或状态码重试可能导致重复计费或重复执行,状态码仅支持 408、425、429、500、502、503、504。以上设置可在管理台“系统设置 → 全局路由行为”调整。
6060

61+
### Jev 输入与字段口径
62+
63+
Jev 的任务是推荐任务组,模型仍按组内配置顺序选择。Jev 启用且只剩一个有合格成员的任务组时,直接使用该组并跳过推荐调用;未启用时仍使用默认组。`jev.input_mode` 控制哪些信息发往推荐服务:
64+
65+
| 模式 | 管理台名称 | 实际发送内容 |
66+
| --- | --- | --- |
67+
| `redacted`(默认) | 脱敏截取摘要 | 规则替换 URL、邮箱、疑似密钥和长载荷;每个保留文本块取脱敏后的前 512 字节,其他消息保留数量和字节数。规则脱敏不保证匿名化。 |
68+
| `content` | 原文截取摘要 | 系统文本最多 1 KiB;视图中最新用户文本最多 8 KiB;最多 3 条更早用户文本,每条 1 KiB。长文本保留约 2/3 开头和 1/3 结尾。 |
69+
| `features_only` | 仅请求结构特征 | 协议、长度估算、工具与媒体存在性、流式请求和分析完整性等,不发送用户或系统原文。没有任务原文时,推荐信息有限。 |
70+
71+
这里的“摘要”由本地 Go 代码截取、计数和拼接模板得出,不调用模型生成语义总结。文本模式下,每段用户消息之后的 assistant/工具消息按角色统计数量和文本字节数,并附该段最后一条 assistant 文本的截取(`content` 最多 256 字节,`redacted` 为脱敏后前 512 字节);工具结果内容不直接发送,工具定义只发送最多 32 个名称,不发送参数 schema。整体文本预算是 16 KiB,超出时删除最旧的用户段;该预算不包含完整 JSON 编码和固定推荐指令,也不是 Jev tokenizer 的上下文计量。
72+
73+
分析器最多读取请求前 4 MiB,供摘要使用的文本视图最多保留 256 条消息、共 1 MiB;旧消息可能在摘要前被逐出。解析范围、条目数或嵌套边界触发的不完整分析默认拒绝自动路由,而正常的摘要截取不触发这一拒绝。`input_tokens_estimate = ceil(已分析请求 JSON 字节数 / 4)`,包含 JSON 结构及内联载荷,是能力筛选用的粗估值,不是精确 tokenizer 结果或计费用量。
74+
75+
`has_code`、`reasoning_likely` 及正文关键词识别已移除,不再出现在 Jev 结构特征输入、诊断 API 或 `-analyze-check` 输出中。工具调用、文件检索、图片/文件/音频、输出上限等协议结构识别继续用于能力筛选;客户端的 reasoning 参数仍按原请求转发上游。传输客户端中未生效的 `jev.Config.InputMode` 字段也已移除,输入模式只由实际构建 Jev 请求的路由层管理。
76+
6177
`GET /v1/models` 始终首先列出虚拟模型 `auto`,默认声明:
6278

6379
- `context_window`: `1000000`
@@ -96,7 +112,31 @@ curl http://127.0.0.1:8080/v1/chat/completions \
96112

97113
Anthropic 和 Gemini 原生接口要求所选上游支持相同协议。OpenAI Chat 文本请求可转换后转发至 Anthropic 或 Gemini,但只支持有限的安全子集;不支持的参数或功能会在发送上游前被拒绝。
98114

99-
管理界面提供提供商与模型管理、模型组配置、推理密钥管理、请求日志和用量统计。系统设置页可配置全局路由行为(默认组、故障转移)、Jev 选组置信度阈值、截断证据处理、持久日志、Jev 输入模式、会话 TTL 与 models.dev 同步范围;每个区域只提交对应的设置 patch。旧版的路由偏好(`routing.default_preference` 与 `X-Routing-Preference` 请求头)、高置信度阈值、默认兜底模型和成本/延迟等级已移除:它们不影响分组路由。数据库中保存的旧值会在启动时被忽略,仍发送的 `X-Routing-Preference` 请求头会被忽略并在转发前剥离。
115+
管理界面提供提供商与模型管理、模型组配置、推理密钥管理、请求日志和用量统计。系统设置页可配置全局路由行为(默认组、故障转移)、Jev 选组置信度阈值、请求分析完整性策略、持久日志和 Jev 输入模式;每个区域只提交对应的设置 patch。会话 TTL 与 models.dev 同步范围可通过设置 API 调整。旧版的路由偏好(`routing.default_preference` 与 `X-Routing-Preference` 请求头)、高置信度阈值、默认兜底模型和成本/延迟等级已移除:它们不影响分组路由。数据库中保存的旧值会在启动时被忽略,仍发送的 `X-Routing-Preference` 请求头会被忽略并在转发前剥离。
116+
117+
请求日志中的用量状态 `oversized` 表示用量元数据超过提取边界,与 Jev 的提示词上下文限制无关,也不表示请求转发失败。OpenAI、Anthropic 和 Gemini 响应均支持增量提取用量,长响应或大流式事件不会仅因正文体积导致用量观测停止;增量扫描时单个用量值仍有 4 KiB 上限。流式事件中分开上报的输入、输出 token 数会合并保留,未上报的计数保持为空。
118+
119+
### 请求日志排查顺序
120+
121+
1. 看 `status`、`upstream_status`、`error_code` 和尝试明细,判断客户端请求及上游是否成功。
122+
2. 看 `jev_status`、`confidence`、`fallback_reason` 判断 Jev 推荐是否返回、是否被采用。`jev_status=ok` 与 `selection_mode=first_eligible` 可以同时成立:前者是组选取,后者是组内按配置顺序选模型。
123+
3. 单独查看 `usage_status`。Token 计数来自处理请求的上游模型,不包含 Jev 用量;未知字段会省略,界面的“—”及旧响应的 `null` 代表未知,合法的 0 会原样保留。`bytes_written` 是响应字节数,不是客户端输入或 Jev 提示词大小。管理台的 JSON 是结构化路由日志,不是原始请求/响应正文。
124+
125+
| 用量状态 | 含义与检查方向 |
126+
| --- | --- |
127+
| `observed` | 至少一个合法非负整数已提取;其余未上报的计数保持为空。 |
128+
| `absent` | 响应结束但未读取到用量;检查上游是否上报 usage,Chat Completions 流式请求是否需要 `stream_options.include_usage`。 |
129+
| `malformed` | 用量字段无法解析或计数类型无效;检查上游 usage 格式。 |
130+
| `oversized` | 用量提取触及边界;先核对运行版本,再检查用量值大小。旧版本会因未完成的 SSE 事件超过 16 KiB 或事件数超过 4096 停止统计,9 月 30 日提交 `e16c21d` 已改为增量扫描。 |
131+
| `interrupted` | 读取用量前响应中断;检查客户端连接、上游连接及超时。已读到的合法计数会保留。 |
132+
133+
部署更新后应核对运行镜像摘要或启动日志中的版本,管理台与服务端应来自同一构建。历史日志中的旧状态和空计数不会自动回填;旧版模型选择枚举保留用于读取历史记录,界面会标注“旧版”。
134+
135+
日志 API、服务日志与 `-logs-check` 统一省略未知或不适用的可选字段:未启用 IP 记录时无 `client_ip`,成功请求无空错误字段,未调用 Jev 时无 `jev_latency_ms`,未产生有效推荐时无 `confidence`。实际推荐置信度为 0 或调用耗时不足 1 ms 时仍输出 0。历史记录中失败/跳过 Jev 的占位置信度 0 只在读取时隐藏,不改写数据库;有效推荐优先展示历史追踪中的原始置信度。
136+
137+
`confidence_band` 不再生成或作为主日志字段输出:它不是当前选模型的依据。`evidence_hash` 移至 `diagnostics.evidence_hash`,用于核对决策元数据,不是提示词哈希,也不参与路由;有实际历史分档时保留为 `diagnostics.legacy_confidence_band` / `legacy_trace_confidence_band`。`confidence_band` 查询参数仅兼容筛选旧记录,新记录不再填充该列。管理台将诊断信息与 JSON 默认折叠,并直接展示上游逐次尝试、故障转移及脱敏失败摘录。
138+
139+
当前组路由的日志 API 与 `-logs-check` 不再输出空的旧版 `candidate_models`、`model_count`、`selected_model` 和 `probabilities`;旧记录有实际数据时仍可读取,CLI JSON 的旧 `selected` 改为与 API 一致的 `selected_model`,旧模型分布同时保留模型标识和概率。Jev 追踪不再重复主记录已有的状态、耗时、置信度、兜底原因和指纹;`group_count` 可由 `candidate_groups.length` 得出,不再输出。当前推荐使用 `candidate_groups`、`recommended_group`、`selected_group` 与 `group_probabilities`。这些是日志输出契约变更,直接解析上述字段的脚本需要同步调整;没有删除历史数据库字段,也没有回填未知用量。
100140

101141
模型管理页可查看 models.dev 最近同步结果并显式触发全局同步;仪表盘分开显示服务健康/依赖状态与路由、Jev 窗口汇总。设置页的“重置所有运行时覆盖”会恢复代码默认值并清除运行时保存的 Jev 密钥,但不会删除 Provider、模型、绑定或入站凭据。
102142

‎cmd/auto-router/analyze_check.go‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,6 @@ func writeAnalyzeReport(output io.Writer, protocol providers.Protocol, source st
145145
fmt.Fprintf(output, "tools: %d (truncated=%t forced=%t file_search=%t)\n",
146146
features.ToolCount, features.ToolsTruncated, features.ForcedToolChoice, features.FileSearchUsed)
147147
fmt.Fprintf(output, "tool_names: %s\n", formatStrings(features.ToolNames))
148-
fmt.Fprintf(output, "has_code: %t\n", features.HasCode)
149-
fmt.Fprintf(output, "reasoning_likely: %t\n", features.ReasoningLikely)
150148
fmt.Fprintf(output, "chained_tool_use: %t\n", features.ChainedToolUse)
151149
fmt.Fprintf(output, "stream_requested: %t\n", features.StreamRequested)
152150
fmt.Fprintf(output, "max_output_tokens: %s\n", formatOptionalInt(features.MaxOutputTokensRequested))

0 commit comments

Comments
 (0)