6.2 Langfuse:线上trace与evals


6.2 Langfuse:线上trace与evals

本节摘要:离线回归集再全,也照不到线上的真实长尾——观测平台补上这一端。Langfuse 是开源、可自托管的 LLM 工程平台(官方支持 Docker / Kubernetes / VM 自托管,另有托管云),核心是两件事:trace 采集在线 evals。trace 模型是三层嵌套树:一次用户请求记为一个 trace,内部每步操作是 span(检索、工具调用、业务逻辑),模型调用是更特殊的 generation(带 prompt、输出、token 用量与延迟)——session 与 user 字段把多次请求串成会话与用户画像。在线 evals 的分数挂在 trace 上,来源三路:用户反馈(界面上的 👍/👎 写成 score)、模型裁判评分器(对 trace 的输入输出按第 5 章 rubric 批量打分写回)、规则/统计(脚本对 trace 字段做计算,如"输出是否为空")。三路分数在同一个分析视图里随时间排布,就是第 8 章监控面板的数据底座;trace 分层抽样又反哺第 3.1 节的回归集——离线与在线从此闭环。本节代码均标注「写法示意,以官方文档为准」。

学习目标

阅读完本节,你应当能够:

  1. 说出 trace / span / generation 三层模型的各自职责与嵌套关系。
  2. 用装饰器把现有函数无侵入地接入 trace(写法示意)。
  3. 把三路在线评分(用户反馈 / 裁判 / 规则统计)挂到 trace 上。
  4. 设计"trace 抽样 → 回归集"与"离线调裁判 → 线上挂裁判"的双向闭环。

一、trace 模型:线上行为的数据结构

trace(一次用户请求:input = 用户问题,output = 最终回答) ├── span: 检索(query 改写 → 向量召回 → 重排) ← 业务步骤 │ └── span: 向量召回(top-k=5, 耗时 120ms) ├── span: 工具调用(查订单接口) ← 外部依赖 └── generation: LLM 调用 ← 模型调用(最特殊的 span) prompt 版本 = prompt-v12,模型 = xxx-snapshot token: 输入 1200 / 输出 350,延迟 1.8s session: 会话聚合(同一用户的多轮) user: 用户维度聚合(脱敏 ID)

三个字段是评测的眼睛:usage(token 与延迟——第 4.4 节成本三角的原始数据)、metadata(自定义标签:场景、路由分支——第 7.3 节 PSI 分桶的依据)、prompt 版本 / 模型标识(第 3.4 节版本化在线上的兑现:指标异动时可下钻到版本对比)。

二、接入:装饰器无侵入打点(写法示意)

# langfuse_instrument.py(写法示意,以官方文档为准) from langfuse import get_client, observe langfuse = get_client() # 凭环境变量读取 host / public key / secret key @observe() # 外层函数 → trace(自动捕获输入输出与耗时) def answer(question: str) -> str: docs = retrieve(question) return draft_answer(question, docs) @observe() # 内层函数 → span(调用层级即嵌套层级) def retrieve(question: str) -> list[str]: return ["退款政策:5 个工作日原路退回…"] # 示意 @observe(as_type="generation") # 模型调用 → generation(记录 prompt 版本与 usage) def draft_answer(question: str, docs: list[str]) -> str: return call_llm(question, docs) # 示意:换成厂商 SDK if __name__ == "__main__": print(answer("退款多久到账?")) langfuse.flush() # 短生命周期进程退出前冲刷缓冲

三条纪律:PII 脱敏在前(第 3.1 节同款——trace 是新的影子日志);采样控制成本(全量记 trace、按比例挂重评分器,示意:裁判只抽 1%~5%);版本字段必填(prompt 版本、模型快照写进 metadata,否则第 8 章的版本下钻无从谈起)。

三、在线 evals:三路评分挂上 trace

# langfuse_scores.py(写法示意,以官方文档为准) from langfuse import get_client langfuse = get_client() trace_id = "当前 trace 的 ID" # 第 1 路:用户反馈(前端 👍/👎 回调里调用) langfuse.create_score(trace_id=trace_id, name="user-feedback", value=1, data_type="NUMERIC") # 1 赞 / 0 踩 # 第 2 路:模型裁判评分器(离线调好的第 5 章裁判,对抽样的 trace 批量跑) verdict = judge(question, answer, reference) # 5.1 节六件套裁判 langfuse.create_score(trace_id=trace_id, name="judge-rubric", value=verdict["score"] / 2, data_type="NUMERIC", comment=verdict["reason"]) # 第 3 路:规则/统计(便宜且确定的先跑) score = 0.0 if answer.strip() == "" else 1.0 # 空输出检测(示意) langfuse.create_score(trace_id=trace_id, name="non-empty", value=score, data_type="NUMERIC")

三路的分工与第 2.3 节判定分流同构:规则最便宜跑全量,裁判贵跑抽样,"用户反馈"是人工的众包形态——每一路都是带时间的分数流,汇进同一张按日聚合的看板(第 8.2 节监控面板直接消费)。裁判评分器通常由定时任务驱动:拉取近期 trace → 抽样 → 跑第 5 章裁判 → 分数写回——官方把这类任务称为 evaluation 的模型裁判方式,平台侧也有托管配置。

四、离线—在线双向闭环

线上 trace ──分层抽样(3.1 影子日志配方)──▶ 回归集新样本(3.1/3.4 入库升版本) ▲ │ │ ▼ 在线评分器 ◀──离线调优(5 章裁判 + 4 章指标校准)──离线回归(6.1 Promptfoo)

两个方向的节奏(观点):

  1. 周向(离线→在线):回归集上确认新裁判 kappa 达标(5.3 门禁)后,才替换线上评分器——线上评分器换版与被测系统换版一样要走影子验证(第 8.1 节);
  2. 月向(在线→离线):从 trace 按分层配额抽样,经人工确认为 badcase 的进回归集——回归集长得像事故史(第 3.1 节),而 trace 是事故的第一现场。

五、自托管与数据合规

部署形态 适合 注意
自托管(Docker/K8s/VM,官方支持) 数据敏感、内网合规 运维成本自担:升级、备份、容量
托管云 快速起步、小团队 数据出境与 DPA 条款要先过法务

无论哪种形态,评测侧的红线不变:PII 进 trace 前脱敏;裁判评分器用到的样本同样遵守第 3.1 节三条纪律(旁路不改线、脱敏先行、元数据随行)。

本节要点回顾

  1. trace 三层:trace(请求)→ span(步骤)→ generation(模型调用);usage / metadata / 版本字段是评测的眼睛。
  2. 接入:装饰器按调用层级自动嵌套;flush 兜底;脱敏与采样先行。
  3. 三路评分:用户反馈(众包人工)、裁判(抽样语义分)、规则(全量硬标准)——判定分流的在线版。
  4. 双向闭环:离线调裁判→线上换版走影子;线上 trace 抽样→回归集入库。

到此,离线(Promptfoo)与在线(Langfuse)两端都装上了。但工具市场远不止这两家——pytest 风格的 DeepEval、RAG 专项的 RAGAS、LangChain 系的 LangSmith……下一节横向比较六家主流工具,给出选型决策树。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U