fix: make the sampling invariant test actually enforce the constraint
The test passed overlay and sampling as separate objects while production aliases them, so an in-place mutation slipped through it. Also syncs the telemetry schema page and adds the missing postgres round-trip assertion.
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
---
|
||||
type: schema
|
||||
node_id: schema:llm-calls
|
||||
title: "表结构: llm_calls(遥测 20 字段)"
|
||||
title: "表结构: llm_calls(遥测 21 字段)"
|
||||
date: 2026-07-20
|
||||
---
|
||||
|
||||
# 表结构: llm_calls(遥测 20 字段)
|
||||
# 表结构: llm_calls(遥测 21 字段)
|
||||
|
||||
|
||||
## 列定义(冻结,M1 设计 §4.4 / ARCH §7.8)
|
||||
@@ -26,6 +26,7 @@ date: 2026-07-20
|
||||
| created_at | TEXT NOT NULL DEFAULT (datetime('now')) | 落库时刻 |
|
||||
| cached_prompt_tokens | INTEGER | 供应商 prompt cache 命中的输入 token(2026-07-31,issue #3);NULL = 该源未上报,`0` = 上报了真实零命中,两者不可混同 |
|
||||
| model_reported | TEXT | API 响应体实际返回的 model;NULL = 未上报。与 `model`(配置别名)可能分叉 |
|
||||
| sampling | TEXT | 本次调用的采样参数 canonical JSON(2026-07-31,issue #4);NULL = 未传。见下方口径 |
|
||||
|
||||
## usage/成本口径(2026-07-30,est_tokens 解耦)
|
||||
|
||||
@@ -50,6 +51,29 @@ FROM llm_calls WHERE cache_hit = false AND cached_prompt_tokens IS NOT NULL;
|
||||
|
||||
`WHERE cache_hit = false` 不可省,理由与上面 cost 缺口口径同源:回放行计入即重复计数。
|
||||
|
||||
## 采样参数口径(2026-07-31,issue #4)
|
||||
|
||||
`sampling` 列 = 「调用方采样意图 ⊎ 生效源 `extra_body`」的 canonical JSON,空则 NULL。**不含**结构化输出注入的 `response_format`——列名是采样参数,schema 不是,且数 KB schema 逐行落库会让审计表无谓膨胀。补列纪律与 issue #3 两列逐字相同(排在末尾、先探测再 ALTER、失败只逐行降级)。
|
||||
|
||||
三个 emit 入口的取值必须各自定死,否则同一列在不同行含义不同:
|
||||
|
||||
| 入口 | 调用者 | 有生效源? | 记什么 |
|
||||
|---|---|---|---|
|
||||
| `emit_attempt` | RetryMW(最内) | 有 | `merge(source.extra_body, request.sampling)` |
|
||||
| `emit_cache_hit` | TelemetryMW(最外) | 无 | 仅 `request.sampling` |
|
||||
| `emit_terminal_failure` | TelemetryMW | 无 | 仅 `request.sampling` |
|
||||
|
||||
后两行缺 `extra_body` 是客观事实而非口径瑕疵——它们没有"生效源"可言,与 `model`/`source_name` 在终态行置空是同一先例;缓存命中行亦无损:`sampling` 已进缓存 key,能命中即意味调用级参数与历史那次逐字相同。三者统一读 `request.sampling` 而非 `request.overlay`(后者在 RetryMW 处已被结构化注入污染、在 TelemetryMW 处未被污染,直接用必然三行分叉)。
|
||||
|
||||
OCR / embedding 路径的该列**恒为 NULL**:两条路径的 transport 不发 `extra_body`(embed payload 硬编码 `{model, input}`、MonkeyOCR 只发 multipart),故其源在构造期就被剥离——不剥离则该列会记录一个从未发出的参数,那是数据造假而非参数失效。
|
||||
|
||||
复现某批实验的解码条件:
|
||||
|
||||
```sql
|
||||
SELECT DISTINCT sampling FROM llm_calls
|
||||
WHERE session_id = $1 AND cache_hit = false AND error IS NULL;
|
||||
```
|
||||
|
||||
## 埋点位置(单一 helper 铁律)
|
||||
|
||||
- `middleware/telemetry.py::TelemetryEmitter` 是全库**唯一** `record_llm_call` 调用点;
|
||||
|
||||
Reference in New Issue
Block a user