返回 AICAP-180
B17 · Day 164outcome 指标仪表盘 + A/B

M7 cost-per-case + p95

前两天落地了 outcome 四指标里的「准」(FPR,Day 162)和「好」(SAR 质量,Day 163)。

阶段: B17 · outcome 指标仪表盘 + A/B(Day 161-170) 标签: #cost-per-case #p95-latency #unit-economics #deepseek-v4

今日导引(由浅入深)

前两天落地了 outcome 四指标里的「准」(FPR,Day 162)和「好」(SAR 质量,Day 163)。

今天 Day 164 一次落地剩下两个硬数字——「贵」(cost-per-case)和「快」(p95)。

这两个合起来决定单位经济性:一套又准又好但每案件烧 $5、p95 要 60 秒的系统,在生产里没人用。

在 B1→B18 曲线上,这是把 AI 方案从「能跑」推到「算得清单位成本」的一步——AISA 面试 hiring manager 四问里的「成本」那一问,靠的就是这种可链接的真实成本数字。

最小可判定产出:把 cost+latency 采集接到 attributeMap,p95 复用 summarizeLatency,跑 20 案件出 cost-per-case 与 p95 两个数(需 key)。

1. 机理精读

cost-per-case 的公式与口径。

cost-per-case = (输入 token + 输出 token) × 单价 / 案件数

三个口径必须钉死:

  1. 输入输出 token 分开记——多数模型输入输出单价不同;
  2. 单价用当周 OpenRouter 真实价,不能用过时 id 的旧单价;
  3. 分母是「案件数」不是「请求数」——一个案件可能跨多次 LLM 调用(证据汇集 + 类型学比对 + SAR 草稿),要全部累加。

本仓真实跑过的成本基线是 DeepSeek V4-Flash $0.0139/run,这是已测真值。

p95 为什么比均值重要。

时延分布通常右偏长尾:大多数请求很快,少数请求(长 prompt、重试、限流)很慢。

  • 均值会被长尾轻微抬高但仍掩盖最坏体验;
  • p95(第 95 分位) 直接报「95% 的请求都比这快」,反映的是尾部体验。

生产 SLO 几乎都按 p95/p99 定,不按均值定——因为用户感知的是最慢的那批请求,不是平均请求。

为什么 cost 和 p95 要放一起看。

两者是单位经济性的两个轴:cost 是「每案件花多少钱」,p95 是「每案件最坏要等多久」。

  • 可以用更便宜的模型压 cost,但可能换来更高 p95(小模型重试多);
  • 也可以并行化压 p95,但可能抬高 cost(重复调用)。

把两者并排进仪表盘,才能看清这种权衡,而不是只优化一个指标把另一个搞坏。

与相邻概念的边界。

今天的 p95 实现(summarizeLatency)是已 built+tested 的纯函数,输入时延样本就能出 p50/p95/p99;cost 的单条 run 真值($0.0139)也是已测的。

但「20 案件聚合的 cost-per-case 与 p95」需要真实跑一遍 eval:agent(需 key),属于 key-gated 外部动作——今天接好线、备好真值锚点,不臆造聚合数。

2. 推导 / 手算 / 代码走读

p95 实现 src/agent/eval/stats.tssummarizeLatencybuilt + tested。走读:

  • summarizeLatency(samplesMs)

    • [...samplesMs].sort((a,b)=>a-b)
    • 返回 {n, p50, p95, p99, mean},p50/p95/p99 都走 percentile(sorted, p),mean 走 mean(samplesMs)
    • 注释点明设计意图:「p95/p99 surface the tail that the mean hides.」
  • percentile(sorted, p):线性插值分位——

    • idx = (p/100)×(len−1)lo=floor, hi=ceilw=idx−lo
    • 返回 sorted[lo]×(1−w) + sorted[hi]×w
    • 空数组返回 NaN,单元素直接返回该元素。
  • cost 采集挂点 src/aml/observability/attributeMap.ts

    • token 数走 semconv 属性 GEN_AI_ATTR.USAGE_INPUT_TOKENS / USAGE_OUTPUT_TOKENStoSemconvAttributesif (span.inputTokens !== undefined) attrs[...] = span.inputTokens);
    • 注意该文件当前不真正上报(注释明确「当前不真正上报——需后端 collector + 真实 LLM 调用元数据」),所以 cost 采集是把 token 字段接进来、乘单价,不是接 OTel collector。

p95 手算:

时延样本 [120, 150, 180, 220, 300, 350, 400, 900](n=8,已排序)。

p95:

  1. idx = 0.95 × 7 = 6.65
  2. lo=6, hi=7, w=0.65
  3. p95 = sorted[6]×0.35 + sorted[7]×0.65 = 400×0.35 + 900×0.65 = 140 + 585 = 725 ms

对比 mean = (120+150+180+220+300+350+400+900)/8 = 2620/8 = 327.5 ms。

可见那个 900ms 的长尾把 p95 拉到 725,而均值 327 完全掩盖了 725 的尾部体验。这正是 p95 存在的理由。

cost-per-case 手算(口径示范,非真值):

若一个案件累计 input=1500、output=600 token,input 单价 $X/M、output 单价 $Y/M,则:

  • 单案件 cost = 1500/1e6×X + 600/1e6×Y
  • 20 案件的 cost-per-case = 20 案件总 cost / 20

本仓已测的单条 run 真值是 $0.0139(V4-Flash)——可作为锚点校验聚合数量级是否合理。

3. 今日实战

  1. 把 cost + latency 采集加到 src/aml/observability/attributeMap.ts(接 token 字段 + 记录每步时延样本)。
  2. p95 直接复用 src/agent/eval/stats.tssummarizeLatency(p50/p95/p99 已 built),不另写分位实现。
  3. cost 项用 token×当周 OpenRouter 单价(V4-Flash/Pro)/ 案件数算 cost-per-case。
  4. 跑 20 案件 pnpm eval:agent(需 key)出 cost-per-case 与 p95 两个数;用 $0.0139/run 校验数量级。

4. 今日实测 / 产出

  • stats.tssummarizeLatency 已 built + tested,可直接出 p50/p95/p99。
  • 真实成本已测:V4-Flash $0.0139/run
  • 20 案件聚合的 cost-per-case 与 p95(ms) = 待跑(需 key 跑 eval:agent),将产出 cost-per-case=$X.XX、p95=Yms;单条 run 成本 $0.0139 是已测真值
  • 不臆造 20 案件聚合数——仅有的真实成本数字是 $0.0139/run。

5. 常见误区 / 陷阱

  • 用均值代替 p95 报时延:均值掩盖长尾(手算里 327 vs 725),生产 SLO 必须按 p95/p99。
  • cost 分母用「请求数」而非「案件数」:一个案件多次 LLM 调用,必须全部累加再除以案件数。
  • input/output 单价混用:两者单价通常不同,要分开乘。
  • 把 $0.0139/run 当 cost-per-case:$0.0139 是单条 run 真值,cost-per-case 是跨多次调用的案件级聚合,二者不是一回事;后者需跑 eval 才有。
  • 引旧模型 id 单价:legacy deepseek-chat/-reasoner 单价不能再用(见 SOTA 检查)。

6. 学习资源(每条带 YYYY-MM)

  • OpenRouter pricing(2026-06)——DeepSeek V4-Pro / V4-Flash 当周单价,价格波动快需复查。
  • OTel GenAI semantic conventions(2026-03)——gen_ai.usage.input_tokens / output_tokens 指标命名(仓内 attributeMap.ts 沿用)。
  • 本仓代码:src/agent/eval/stats.tssummarizeLatency/percentile(p95 实现)、src/aml/observability/attributeMap.ts(token/cost 采集挂点)。
  • DeepSeek-V4 模型卡 / 定价页(2026-06)——确认 deepseek-v4-pro / deepseek-v4-flash id 与单价。

SOTA检查 (2026-06 更新)

  • 当前主流:DeepSeek V4 模型 id 为 deepseek-v4-pro / deepseek-v4-flash;p95/p99 + cost-per-case 是单位经济性的标准 outcome 度量,仍 SOTA。
  • 过时黑名单:legacy deepseek-chat / deepseek-reasoner2026-07-24 退役——成本模型里禁止再引旧 id 单价
  • 下次复查点:OpenRouter 2026-06 单价需执行当周复查(价格波动快);临近 2026-07-24 复查所有成本配置已切到 V4 id。

衔接

  • 昨天:Day 163 — M7 SAR 质量量化(rubric 四维加权聚合)。
  • 今天:cost-per-case(token×单价/案件数)+ p95(时延尾部),单条 run 真值 $0.0139,聚合数待 key 跑。
  • 明天:Day 165 — 活仪表盘聚合(把 4 指标合成带 delta 的 snapshot JSON)。