LLM 调用日志可观测性 (LLM Invocation Observability)
核心设计
LLM 调用日志可观测性 (LLM Invocation Observability) 的目标不是只保存一段原始响应,而是同时提供:
- 原始 JSON:保证协议字段和异常数据可追溯。
- 解析行:按
messages_before → events → messages_after保留消息、Thinking、工具调用、工具结果、usage 和错误事件顺序。 - 聚合摘要:为列表和详情快速提供 token、流速、成本、价格快照和上游调用信息。
原始数据与解析结果必须分离。解析失败或协议字段未知时保留 raw_fragment,不能为了 UI 方便破坏原始日志。
工具调用聚合规则
同一轮日志中,事件流和消息历史可能同时描述同一个工具调用。以 tool_call_id 作为聚合键,只在 tool_calls 摘要中保留一条记录:
recorded → running → completedparsed_rows 仍保留每一个原始事件和消息行,方便审计与 CSV 分析。聚合时只补全缺失字段;结构化工具结果已经存在时,不被消息历史中的文本结果覆盖。这样可以同时满足“事件不丢失”和“详情卡片不重复”。
SQLite 幂等迁移
SQLite 的 CREATE TABLE IF NOT EXISTS 不会为已有表增加新列。新增字段时,启动流程应:
- 通过
PRAGMA table_info(<table>)检查列是否存在。 - 缺列时执行
ALTER TABLE ... ADD COLUMN ...。 - 迁移函数可重复执行;多进程同时通过检查时,重复列错误应视为竞争中的成功结果,其他错误继续返回。
价格快照 (Price Snapshot) 字段应允许旧记录为 NULL。旧日志没有历史价格时不能用当前 Profile 价格反推,否则修改配置后历史金额会失去可解释性。新调用在开始时写入输入价、缓存输入价和输出价,结束时用调用记录中的快照计费。
接口一致性
日志列表、统计和批量导出必须复用同一组筛选条件,例如时间、模型、Profile、分组、协议、调用类型、用户和 Session。否则页面指标与下载文件会出现范围不一致。
详情接口同时返回原始内容、解析结果和同一轮的上游调用明细;前端默认展示摘要,原始 JSON 放入独立 tab,避免首屏被大字段淹没。
验证方法
- 启动两次旧数据库,确认迁移不会报 duplicate column。
- 用旧 schema 的日志确认三个价格快照返回
null。 - 用事件流和
messages_after同时包含同一tool_call_id的样例,确认聚合数量为 1、结构化结果优先。 - 检查 CSV 的 UTF-8 BOM、标准引号转义和稀疏列结构。
- 对列表、统计和批量导出使用同一筛选条件,确认条数与范围一致。
关联项目
- 校园导航 POI 功能化标注 (Campus Navigation POI Functional Annotation)
- Agent 工具结果文本化 (Tool Result Text Formatting for LLM Agents)
- OpenAI 兼容反代的协议兼容与语义保真 (Protocol Compatibility and Semantic Fidelity)
本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/AI apps