ByteFisher AI 工程化深度实战(十一):LLM 应用可观测性与评测

前 10 篇我们做了一堆优化:重试、缓存、上下文压缩、混合检索、评测集、本地兜底、多 Agent 流水线。但这些优化有没有效果、哪天生效哪天回归,目前全是”感觉”。第 01 篇诊断时就说了:成本不可见、无埋点。本篇用 Langfuse 给整个系统装上仪表盘,让每一条请求可回放、每个指标可度量、每次回归可告警。

一、为什么传统监控不够用

传统后端监控(Prometheus、Sentry)衡量的是”HTTP 200 还是 500、响应几毫秒”。但 LLM 应用的失败往往是”HTTP 200,回答却是错的“——模型幻觉、检索跑偏、Prompt 改坏了。这种失败只能靠内容级可观测性发现:你要能看到”这条请求发给了哪个模型、喂了什么 Prompt、检索到哪些 chunk、模型怎么回答、花了几块钱”。

这就是 LLMOps 的核心:把每一次 LLM 调用、每一步 Agent 决策、每一份注入的上下文,都变成可检索、可回放、可评分的 trace。

二、Langfuse 的核心概念

Langfuse 是主流的开源 LLMOps 平台(可自托管,也兼容 OpenTelemetry)。它围绕两个概念组织:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Trace(一次完整会话/任务)
└── Span(trace 里的一个步骤)
├── LLM 调用:模型、输入token、输出token、费用、延迟
├── 检索调用:query、召回结果、分数
├── 工具调用:工具名、参数、结果
└── Agent 步骤:节点、状态、分支决策

一个 trace 示例(ByteBot 回答"Unity 有哪些入门文章"):
trace: chat_id=8f3a
├── span: intent_classify duration=2ms
├── span: hybrid_search query="unity 入门文章" top5=5 cost=0.001元
├── span: build_prompt version=prompt_v2.3
├── span: llm_call deepseek-chat prompt_tokens=1200 completion_tokens=400
│ cost=0.002元 latency=1.8s
└── span: render_validate links_fixed=1

trace 能回答所有”感觉”问题:这条回答花了多少钱?检索召回对不对?用的是哪个版本的 Prompt?模型是不是降级到本地了?

三、给 ByteBot 接入 Langfuse

3.1 埋点的最小集合

api/chat.js 是 serverless 函数,埋点不能喧宾夺主。最小方案:在关键边界打 span,异步上报。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const { Langfuse } = require('langfuse');
const langfuse = new Langfuse({
publicKey: process.env.LANGFUSE_PUBLIC_KEY,
secretKey: process.env.LANGFUSE_SECRET_KEY,
baseUrl: process.env.LANGFUSE_BASE_URL // 自托管地址
});

module.exports = async (req, res) => {
const trace = langfuse.trace({
name: 'bytebot-chat',
userId: anonymizeIp(req.headers['x-forwarded-for'] || req.ip), // 脱敏
input: lastUserMessage
});

const searchSpan = trace.span({ name: 'hybrid_search', input: question });
const articles = await hybridSearch(question);
searchSpan.end({ output: articleSummaries, metadata: { scores, engine: 'hybrid-v1' } });

const llmSpan = trace.span({ name: 'llm_call', model: 'deepseek-chat' });
// ... 流式转发,结束后用 usage 补齐 token 与 cost
llmSpan.end({
output: reply,
usage: { input: usage.prompt_tokens, output: usage.completion_tokens },
metadata: { cost: computeCost(usage), model: 'deepseek-chat' }
});
trace.update({ output: reply });
};

3.2 关键埋点清单

埋点 位置 采集内容
意图分类结果 buildBlogMessages intent=blog/casual
检索调用 rankArticles / hybridSearch query、Top 结果、分数、引擎版本
检索降级 缓存/重试命中 是否命中缓存、重试了几次
LLM 调用 fetch DeepSeek 模型、token、费用、延迟、是否降级本地
Prompt 版本 生成 system prompt 处 version 标签(见下一节)
前端渲染修正 validateLinks 修正了几个链接(反映输出质量)

先埋再优化:埋点本身不能引入延迟(异步上报、失败静默),且敏感信息必须脱敏——用户输入只存前 50 字符 + IP 匿名化,绝不存密钥。

四、Prompt 版本管理

第 01 篇诊断过:ByteBot 的 system prompt 是”打补丁”式演进,改坏了无法回滚。Langfuse 的 Prompt 管理功能解决这个问题:

1
2
3
4
prompt_name: bytebot-system-v2
├── version: v2.3 (当前线上)
├── version: v2.2 (改坏了,随时回滚)
└── version: v2.1

接入方式:

1
2
3
const prompt = langfuse.getPrompt('bytebot-system-v2');
const systemMessage = prompt.getLangchainMessage(); // 或用 prompt.prompt 取字符串
// trace 自动带上 prompt.version,报表里能对比 v2.2 与 v2.3 的指标

工程收益:

  • 线上回答质量突然下降 → 打开 Langfuse 报表,按 prompt 版本分组看 Faithfulness/成本 → 一秒定位”是 v2.3 引入的回归” → 一键回滚到 v2.2。
  • 第 03 篇的 system prompt 重构(滚动摘要、结构化输出)全部走版本管理,每次改动可 A/B 对比。

五、效果回归测试与告警

5.1 离线评测入 CI

第 05 篇的 eval 脚本现在接入 CI(deploy.yml 的测试步骤):

1
2
3
步骤:node --test + pytest
新增:python tools/rag-eval/eval.py --eval-set eval-set-v1.json --regression
断言:Faithfulness >= 0.85 且 >= 基线 - 0.02,否则 CI 失败

这样任何改动(改 Prompt、改检索、改 chunk)如果让评测指标劣化,push 直接失败,问题在合入前就被拦住——这是”评测不劣化”红线,也是第 05 篇承诺的回归检查。

5.2 线上指标与告警

Langfuse 的自定义指标(metrics)可以定义”异常区间”:

指标 告警阈值 含义
成本/天 > ¥10 成本异常(可能被刷或 prompt 膨胀)
降级率 > 5% DeepSeek 故障或密钥失效
检索空结果率 > 10% 索引过期或检索坏了
首 token 延迟 > 5s 模型或网络异常
429 率 > 5% 限流,需要降速

第 02 篇的 usage 埋点、第 06 篇的”降级打标”、第 09 篇的工具日志,所有埋点在这里汇合——这就是为什么全系列反复强调”先埋点再优化”。

六、落地清单与小结

优先级 改造 收益
P0 Langfuse 接入 + 5 个核心 span 埋点 每次请求可回放、成本可见
P0 Prompt 版本管理(v2.1→v2.3) 回归可定位、可回滚
P1 CI 评测回归门禁 改动劣化即失败
P1 成本/降级率/429 告警 线上异常主动发现
P2 前端渲染修正率埋点 度量模型输出质量
P2 线上问题回流评估集 评测集滚动进化

核心结论:

  • 传统监控看”HTTP 200”,LLMOps 看”回答对不对”;内容级可观测性才能发现模型层的失败。
  • Langfuse 的 trace/span 模型正好映射 ByteBot 的调用链:意图→检索→Prompt→LLM→渲染。
  • 埋点要脱敏、要异步、要静默失败;serverless 里埋点不能喧宾夺主。
  • Prompt 版本管理让”改坏了回滚”从 git 层面下沉到应用层面,还能按版本对比指标。
  • 离线评测进 CI + 线上指标告警,双闸门兜住质量与成本。

下一篇是系列收官:ByteBot v2 综合实战。把第 01~11 篇的改造全部收口,给出 ByteBot v2 的完整架构图、改造前后对比数据(质量/成本/延迟)和未来演进方向。


本系列持续更新中,每周一篇。

ByteFisher
分享编程技术 · 记录钓鱼乐趣
扫码关注
▸ 扫码关注 ◂
分享: