面试知识库

M15 · 评测分数回注 trace 与工具 RT 告警#

简历 Bullet Point: 补齐可观测性两处缺口——Rubric 评测分数回注 Langfuse trace(三条 score + 失败维度 comment,支持按低分筛 bad case trace),工具 RT 告警(P95 滑动时间窗 + 三态状态机防抖 + hard_ms 兜底低 QPS),refdocs 示例代码四处真错全部更正


开场钩子#

评测跑完有分数,Langfuse 有 trace,但两套数据割裂——看到一条低分不知道对应哪条 trace,看到一条 trace 不知道它的评测分是多少。做不到”按低分筛 bad case trace”这个最基本的调试 SOP。

更隐蔽的问题:run_agenttrace_id 最初用 ContextVar 传给下游。但 run_agent 跑在 asyncio.create_task 里——子 task 的 ContextVar.set 不回传父上下文。结果 trace_idrun_rubric.py 主进程里永远是 None,分数挂不到 trace 上。


一、模块运作流程#

1.1 分数回注 trace#

run_agent() → 返回 {final_text, trace_id, ...}
  │                    ↑ 显式返回值,不用 ContextVar

run_rubric.py → judge 打分 → record_rubric_scores(trace_id, scores)

  ├─ rubric_total(归一 0-1,UI 按它筛低分)
  ├─ rubric_pass(BOOLEAN)
  ├─ rubric_p2_avg
  └─ comment:失败维度 + judge 判词(不是无信息量的计数)


finally: flush_traces()  ← 短命进程不 flush,score 随进程蒸发
plaintext

评测报告新增 trace_id 字段;evolution/ 全链路串起”证据 trace”。

1.2 工具 RT 告警#

refdocs 示例代码四处真错(全部更正):

  1. window_minutes 是死字段(deque(maxlen) 按条数截断)→ 改滑动时间
  2. min_samples=10 配 P99 = “max 值告警” → 改 min_samples=20 + P95
  3. check_alerts() 没有调用者(抄下来即死代码)→ lifespan 起后台轮询
  4. 没配 webhook 直接 return(告警凭空消失)→ 落 logger.error

三态状态机breached / cleared / 滞回带静默。两态会发出自相矛盾告警(P95=760ms > 阈值 800ms 但报 breached)。

只有 status=ok 进 RT 窗口:熔断 OPEN 时快速失败 ~0ms,计入会在故障最重时报”已恢复”。

hard_ms 绝对阈值兜底:低 QPS 工具 P95 无统计意义,用绝对阈值兜。

告警消息带最慢调用的 trace 链接(把 SOP 四步压成一次点击)。

1.3 告警规则#

三条:工具 RT P95 / 断路器非 CLOSED / 安全事件增量。一致性测试:规则的 tool 名必须真在 FULL_TOOL_SET 里(名字对不上 = 死规则)。


二、踩坑实录#

坑 1:trace_id 用 ContextVar 传,子 task set 不回传父#

  • run_agent 跑在 create_task 里,ContextVar.set 不回传。改成返回值显式带 trace_id。

坑 2:短命进程不 flush#

  • run_rubric.py 是短命脚本。Langfuse SDK 的 score 在后台队列里,进程退出前不 flush 就蒸发。加 finally: flush_traces()

坑 3:scores_v3.get_many_v3() 不返回 comment#

  • Langfuse 列表接口不返回 comment 字段。需要用 api.trace.get() 单条读取。

三、面试问答#

Q1: 为什么不直接用 Langfuse Dataset/Experiment?#

“score 挂 trace” 是更轻的方案——不需要创建 Dataset 和 Run,直接把分数打到已有 trace 上。按 rubric_total 降序排就能找到所有 bad case trace。

Q2: 三态状态机为什么比两态好?#

两态(breached/cleared)在边界抖动时会频繁翻转:P95=800ms → breached → P95=799ms → cleared → P95=801ms → breached。三态加滞回带——breached 后必须降到 threshold × 0.8 才 cleared,消除毛刺。


四、诚实边界#

维度做了没做
分数回注三条 score + commentLangfuse Dataset/Experiment
告警P95 + hard_ms + 三态告警分级与静默窗口
告警状态进程内存多 worker Redis 共享
分位数低频工具 hard_ms 兜底自适应阈值