LINGSHU · 报错定位方案 · v2 已拍板 · 2026-10-26
报错能看见,
钥匙放进错误体
入口定在账单详情(账单与请求 1:1),错误体带上请求 ID;不解请求原文,只存「完整增量消息 + 其他参数」。
本文只定落库字段、写入点、权限与工作量,不写代码。
1 个入口:账单详情(会话复用同一视图)
2 列新增落库:req_params / token_id
7.5人日,P0 两天能上线
PRODUCT SPEC · v2状态:已拍板 · 待开任务书变更:入口 / 错误体 / 存储策略
现状实测 · AS IS
记录八成都在,缺的是钱与路
AUDIT02/10
call_logs 已有的
0002 / 0011 / 0012
- 01
req_messages 请求消息增量(role / content / tool_calls)
- 02
decision 决策轨迹:候选渠道、跳过原因、协议转换与 lossy、成本
- 03
resp_body 上游返回体(错误体截断 4KB,落库前已清洗凭据)
- 04
upstream_usage 上游原始用量 + 归一化三段 token
- 05
error_message / duration_ms / first_token_ms 失败原因与耗时
索引 idx_call_logs_request 已就绪,按请求 ID 查不用加表。
缺的三样(本轮修)
拍板范围
- !
错误体没 ID:只有 message/type/code,request_id 藏在响应头,SDK 不回显
- !
其他参数没落库:temperature / max_tokens / top_p / tools / stream / response_format / 端点 / 协议 / 上游 URL 全无
- !
令牌标识没落库:只在 billing_records 有,失败无账单场景查不到是谁调的
另有权限漏点:开发者端能看到渠道密钥名 / 内部模型 / 成本。
2现有入口:账单详情 / 会话详情
1 : N一次请求多条日志(随候选数)
0 天现有保留期(永不清理)
0 个控制台断点适配
结论:不重建体系,只补三样——错误体给钥匙、参数补齐、权限收口。
诊断
断点 → 修法 · FIX MAP
四个断点,各有对应动作
FIX03/10
STEP 1
网关返回报错
加 ID 错误体带 request_id
→
→
→
→
| 断点 | 现状 | 修法 | 批次 |
| 手里没 ID | 错误体 {"error":{message,type,code}} | 顶层加 request_id,响应头保留 | P0 |
| 搜不到记录 | 只有按账单 ID / 会话 ID 查 | 账单列表加「请求 ID」关键字搜索 + 列 | P0 |
| 一次请求多行 | 每候选失败各写一条,账单出现多行 | 同 request_id 归并主行 + "另有 N 次尝试"角标 | P0 |
| 参数不全 | 只落 messages 增量 | 新增 req_params:messages 之外全部参数 + 端点/协议/上游 URL | P1 |
| 身份不明 | 令牌 ID 只在账单里 | call_logs 补 token_id,界面只给掩码 | P1 |
| 越权可见 | 开发者端能看到渠道/成本 | 后端按角色裁剪 + 前端开关默认关 | P1 |
顺序:先给钥匙(P0),再补货(P1),最后适配手机(P2)。
批次
入口定案 · ENTRY = BILLING DETAIL
不新开页面:账单详情就是报错详情
DECIDED04/10
入口
账单列表
搜索:请求 ID / 账单 ID / 会话 ID
→
主视图
账单详情
结论 + 请求 + 决策 + 上游 + 用量
→
为什么账单详情够用
1:1
每个账单 = 一次请求,`billing_id` 与 call_logs 一一对应;失败请求同样落一条失败账单,所以"报错"在账单列表里本来就有一条。
界面上只做三件事:加请求 ID 列、加搜索、把详情补全。不新增菜单、不新增页面。
一个必须说清的现实
处理
多候选失败时,每个候选会各写一条日志/账单,于是同一个请求在列表里有多行。
处理:按 request_id 归并成主行,角标「另有 N 次尝试」,点开看整条尝试链。不归并的话,用户会点进错误的那一行。
省下的:不做独立日志页与列表接口,约 1.5 人日。
代价:跨会话排查只能走会话详情;无账单的拒绝记录(令牌无效等)看不到。
兜底:详情组件只写一份,将来要加日志页可直接复用。
一句话:入口不新增,只把"账单详情"补成"能定责的详情"。
定案
详情页设计 · SIX ZONES
六区:先结论,再消息,再参数,再轨迹
LAYOUT05/10
01失败 · 上游 400 · 1.8s · 请求 ID ⧉
02a完整增量消息 JSON(气泡渲染 + 原始文本折叠)
02b其他参数:model · temperature · max_tokens · top_p · stream · tools(3) · 端点 · 协议 · 上游 URL
03决策轨迹:候选① 400 ▸ 候选② 跳过·限流 ▸ 候选③ 转换 lossy 2 项
04上游返回:400 · param=model · 原文折叠
05用量:上游原始 usage / 三段归一化 / 计费三步
06关联:同请求其余尝试 / 所属会话 / 关联账单
消息与参数分开看
核心
消息是"用户发了什么",参数是"我们用这些开关发了什么"。上游 400 多半在参数区,日志缺失也多在参数区。
决策轨迹用时间线
关键
一候选一行:渠道 / 密钥 / 内部模型 / 跳过原因(中文)/ 耗时 / 上游状态码 / 是否转换 + lossy 项。
首屏只说一件事
必做
哪一步失败、上游原话、请求 ID 一键复制。其余折叠,手机上一屏读完。
缺失要有话
体验
没收到上游响应 / 已过保留期 / 无权查看,三种文案分开写,别统一"暂无数据"。
层级原则:结论 → 我发了什么(消息+参数)→ 平台做了什么(轨迹)→ 上游回了什么。
IA
落库设计 · SCHEMA & WRITE POINT
加两列,不动表结构,不存请求原文
SCHEMA06/10
| 列 | 类型 | 内容 | 约束 |
| req_messages收紧 | JSONB | 完整增量消息数组:role / content / tool_calls / tool_call_id / name | 不裁剪、不二次摘要 |
| req_params新增 | JSONB | messages 之外全部:model / temperature / max_tokens / top_p / n / stop / stream / response_format / tools_summary{count,names,bytes,truncated} / endpoint / inbound_protocol / upstream_protocol / upstream_url | ≤8KB,超限截断并打标 |
| token_id新增 | BIGINT | 调用令牌(失败无账单时也能定位调用方) | 展示仅掩码 |
| schema_version建议 | INT | 字段演进标记,默认 1 | 便于后续解析兼容 |
写入点只有一个
handler 组包处
请求体解析完、算出增量消息的那一处,顺手组装 req_params;
调用日志写入函数(calllog)加两个参数,INSERT 与列常量同步;
失败路径复用同一组装函数,避免"成功有、失败没有"。
解析请求 → 算增量消息 + 组装 req_params → 候选循环 → 写日志(统一入口)
体积口径:单行新增 ≤8KB,异步批量写入,不阻塞热路径;读取走已有 billing_id / request_id 索引。
成本
权限 · ACCESS CONTROL
开发者看自己的请求,管理员看全链路
RBAC07/10
| 信息 | 管理员 | 开发者 |
| 增量消息 / 其他参数 / 上游返回 | 可看 | 仅本人记录 |
| 跳过原因 / 耗时 / 上游状态码 | 可看 | 可看 |
| 渠道名 / 渠道密钥 / 内部模型 | 可看 | 隐藏(现状泄漏) |
| 成本 / 时段系数 | 可看 | 隐藏(现状泄漏) |
| 令牌标识 | 可看 | 仅本人令牌,掩码 |
| 导出 / 分享 | 后续版本 | 不可 |
P1 泄漏:必须同批修
漏洞
详情组件的"显示内部字段"开关默认打开,账单详情页没关;开发者端因此能看到渠道名、渠道密钥名、内部模型、成本,与接口注释"不含内部模型/渠道名"矛盾。
原则:自己请求的全貌可看,平台内部结构不可看;渠道与成本属于平台资产。
权限
交互与移动端 · MOBILE FIRST
手机上先给结论,别让人横着拖
UX08/10
五条硬规则
对齐报告铁律
- 01
一屏一结论:首屏只有失败原因 + 请求 ID + 复制按钮
- 02
搜索置顶:请求 ID / 账单 ID / 会话 ID 自动识别,回车即查
- 03
表格转卡片:决策轨迹窄屏变时间线,不横向滚动
- 04
字号底线:正文 ≥14px、标题 ≥16px、表格 ≥13px
- 05
断点 640px:侧栏改抽屉、内容单列、卡片圆角加大
手机首屏 · 375px · 账单详情
400 · 上游拒绝
请求 ID req-8f2a… ⧉ 复制
模型 gpt-4o / 端点 /v1/chat/completions
参数 temperature 1.2 · max_tokens 8000 · tools 3
候选① 400 | 候选② 跳过·限流
增量消息 …(点击展开)
用量与计费 …(点击展开)
长文本:等宽 12–13px、独立滚动区、右上角复制,默认只展开 20 行。
空态三分:无记录 / 已过保留期 / 无权查看,文案分开。
跳转:详情底部给"所属会话""其余尝试",别让人回列表重找。
现状反差:控制台零断点适配,侧栏固定 160px,5 列决策表在手机上必然溢出。
现状
数据边界 · RETENTION & MASKING
正文 30 天,元数据长期;凭据永不见明文
POLICY09/10
存储成本对照
增量 vs 全文
长上下文请求里 tools / 历史消息重复率高,存全文的体积与重复成本不成比例。
一句话:够定位、够省、够安全——30 天正文 + 长期元数据 + 全程无明文凭据。
边界
工作量 · EFFORT & NEXT
三期 7.5 人日,P0 两天就能搜到
PLAN10/10
分期
后端 / 前端
错误体带请求 ID · 账单列表搜索与列 · 同请求归并 · 详情接统一视图
req_params / token_id 扩列与写入点 · 截断策略 · 开发者端裁剪(修泄漏)· 参数展示区
断点适配(列表 + 详情)· 保留期清理任务 · 导出(可选)
真正成本在两处
注意
后端口径扩列要动组包处并回归热路径;前端要把两套详情合并成一套。
验收口径
可判定
上游报错后,凭错误体里的请求 ID,在控制台 3 次点击内看到:完整增量消息 + 其他参数 + 走了哪些候选 + 上游原文;开发者端看不到渠道与成本。
开工前确认 3 条
不阻塞
① 保留期 30 天?② req_params 单行 8KB 上限?③ 上游 URL 只留 host+path(丢 query)?
下一步:写进任务书 P0(含验收口径),闲时开工;详版在 notes/calllog-detail-方案.md。
NEXT