把可观测性数据送进 LLM 追踪平台

把可观测性数据送进 LLM 追踪平台

本文基于实际部署经验整理,实验环境为 Windows + WSL2 + Docker。

核心目标:让 OpenTelemetry Demo 采集 Github Copilot 的 traces,在不改动任何业务代码的前提下,额外转发一份到自托管的 Langfuse,实现 LLM 调用的全链路追踪。


背景

OpenTelemetry(OTel)是目前最主流的可观测性标准,覆盖 traces、metrics、logs 三类信号。很多团队已经用 OTel Demo 跑通了从应用到 Prometheus + Grafana 的链路。

这次的具体需求 :我想看看 GitHub Copilot 具体的行为模式:它在代码补全、对话、Edits 等场景下分别发起了哪些 LLM 调用、调用了什么模型、耗时多少、token 用量如何。OTel Demo 已经在采集这些 gen_ai.* 语义约定的 traces,但 Prometheus + Grafana 只能看聚合指标,看不到单次调用的输入输出细节,也做不了多次调用的关联分析。

我们需要的是一个能把每一次 LLM 调用都当成一个可检索、可回放的事件来存储和分析的平台。

Langfuse 是专为 LLM 应用设计的可观测平台,支持标准 OTLP 协议接入,这意味着:只需改一行 OTel Collector 配置,就能把现有 traces 同时打到 Langfuse,零业务代码改动。

采集 LLM 交互信息的意义

采集并保存每一次 LLM 调用的输入/输出、模型、耗时、token 用量、调用上下文等信息,对团队和产品有多方面的价值:

  • 可观测性与故障定位:将单次调用做为可检索事件,可以精确重现异常请求、定位模型返回错误或延迟的根因(如模型、网络、超参或输入质量问题)。
  • 成本与计费归因:通过记录每次调用的 token 与耗时,能按功能、用户、产品线精确核算成本,支持异常扣费警报与成本优化决策。
  • 性能优化与容量规划:按模型/接口统计延迟与吞吐趋势,识别瓶颈(带宽、显存、模型选择),指导量化、缓存或分层路由等优化策略。
  • 模型行为分析与质量监控:可进行误答率、鲁棒性、偏差检测与回归测试,帮助评估不同模型/版本在真实流量下的表现。
  • 产品与 UX 迭代:分析用户输入与模型输出的模式,发现常见失败场景或交互阻力,驱动提示词设计、候选排序或对话策略优化。
  • A/B 实验与模型选择:将调用视为事件可用于分组实验(模型 A/B/n),量化改动对业务指标与体验的影响。
  • 审计、合规与可回放:对敏感或合规场景,保留可回放记录支持审计、事后追踪与法律合规(需配合访问控制与保留策略)。
  • 训练数据与持续学习:筛选高价值的真实交互作为微调或强化学习的候选样本,帮助持续改进模型质量。

注意事项:采集 LLM 交互数据同时伴随隐私与合规风险,实践中应至少做到:

  • 最小化与脱敏:仅收集必要字段,对可能包含 PII 的文本做脱敏或加密;对高风险请求建立明确白名单/黑名单策略。
  • 访问与保留策略:制定细粒度访问控制、审计日志与数据留存期限,避免长期存储不必要的敏感数据。
  • 合规与告知:在需要的法律/监管场景(如金融、医疗)明确用户告知与同意,并与合规团队对接审查数据处理流程。

将这些实践与 Langfuse 的事件化 trace 能力结合,既能实现工程与业务层面的度量与改进,也能把可回放、审计与实验能力带入 LLM 产品化的常规流程。


整体架构

这里仅以我的验证环境为例,实际部署时需细致规划。

关键点:两套 Docker 栈运行在不同的 WSL 实例中,通过 WSL 的内部网络互通,OTel Collector 以 HTTP 协议将 traces 推送给 Langfuse 的 OTLP 入口。


部署概况

部署细节略,不是本文重点,仅简略说明。

  • OTel Demo:官方 Docker Compose 一键启动,包含 20+ 微服务 + otel-collector + prometheus + jaeger + grafana
  • Langfuse:官方 Docker Compose 一键启动,包含 web、worker、postgres、clickhouse、redis、minio

两套栈分别在不同 WSL 实例内运行,天然网络隔离。


排坑记录

实际操作中遇到了几个典型问题,记录在此供参考。

问题一:多 WSL 实例共享 Linux 内核导致 Docker 网络子网冲突

两个 WSL 实例(Ubuntu-24.04 和 langfuse)使用同一个 Linux 内核,Docker 默认都会尝试使用 172.18.0.0/16,产生路由冲突,导致容器间 DNS 解析正确但 TCP 不通。

解法:给 Langfuse 的 Docker Compose 指定独立子网:

yaml 复制代码
# docker-compose.override.yml(放在 langfuse 目录)
networks:
  default:
    driver: bridge
    ipam:
      config:
        - subnet: 172.25.0.0/16
          gateway: 172.25.0.1

问题二:iptables-legacy FORWARD 链默认 DROP

WSL 重启后,iptables-legacy 的 FORWARD chain policy 变成 DROP,导致同一 Docker 网络内的容器之间无法通信(ping 通但 TCP 不通)。

表现 :容器日志报 Can't reach database server,但 docker network inspect 显示 IP 分配完全正确。

解法:持久化修复规则:

bash 复制代码
# /etc/rc.local
#!/bin/bash
iptables-legacy -P FORWARD ACCEPT

问题三:WSL 内的 curl 走了系统代理返回 503

Langfuse 实际已正常启动(日志显示 ✓ Ready in 86.1s),但 curl 验证一直返回 503,因为环境变量中设置了 HTTP 代理,curl 把本地请求也转发给了代理服务器。

解法 :验证时加 --noproxy '*' 参数。


核心配置:OTel Collector → Langfuse

这是本文的核心,只需修改一个文件 :otelcol-config-extras.yml。

OTel Demo 的 Collector 支持通过 extras 文件叠加配置,不用动主配置文件。

第一步:生成 Langfuse API Key

登录 Langfuse 控制台,创建项目后在 Settings → API Keys 中获取:

  • Public Key:pk-lf-xxxxxxxx
  • Secret Key:sk-lf-xxxxxxxx

将两者拼接后做 Base64 编码,作为 Basic Auth 凭证:

bash 复制代码
echo -n "pk-lf-xxxxxxxx:sk-lf-xxxxxxxx" | base64
# 输出类似:cGstbGYteHh4eHh4eHg6c2stbGYteHh4eHh4eHg=


第二步:编写 extras 配置

编辑 src/otel-collector/otelcol-config-extras.yml:

yaml 复制代码
# otelcol-config-extras.yml
# 将 traces 额外转发到自托管 Langfuse

exporters:
  otlp_http/langfuse:
    endpoint: http://<LANGFUSE_HOST_IP>:3000/api/public/otel
    headers:
      Authorization: "Basic <上一步生成的Base64字符串>"
    tls:
      insecure: true

service:
  pipelines:
    traces:
      # 在现有导出器基础上追加 langfuse,保留原有 jaeger 和 span_metrics
      exporters: [debug, otlp_grpc/jaeger, span_metrics, otlp_http/langfuse]

注意 :OTel Collector 合并多个配置文件时,exporters 是合并的,但 pipeline.exporters 数组是替换而非追加,所以必须把原有的导出器名称也写进去。

第三步:重启 OTel Collector

配置文件是以 volume mount 方式挂载的,修改后直接重启容器即可:

bash 复制代码
docker restart otel-collector

查看日志确认 Langfuse 导出器已加载:

bash 复制代码
docker logs otel-collector 2>&1 | grep -i langfuse

正常输出(只有 deprecation 提示,无 error):

复制代码
warn  "otlphttp" alias is deprecated; use "otlp_http" instead  
      {"otelcol.component.id": "otlphttp/langfuse", "otelcol.signal": "traces"}

验证效果

Langfuse 收到 traces

通过 API 查询确认数据已入库:

bash 复制代码
curl --noproxy '*' \
  -u 'pk-lf-xxxxxxxx:sk-lf-xxxxxxxx' \
  'http://<LANGFUSE_HOST_IP>:3000/api/public/traces?limit=5'

成功返回 trace 列表,说明链路已打通:

json 复制代码
{
  "data": [
    {
      "id": "c6d44c1d...",
      "name": "chat gpt-4o-mini-2024-07-18",
      "timestamp": "2026-05-29T02:43:05.639Z",
      "projectId": "my-project",
      ...
    }
  ]
}

截图演示

Trace 全景:


Langfuse Traces 列表:


Trace 详情:


与 Jaeger 并行工作

Langfuse 接入后,原有的 Jaeger、Prometheus、Grafana 完全不受影响,traces 只是"多发了一份"。


两种平台的定位对比

维度 Prometheus + Grafana Langfuse
擅长信号 Metrics(时序) Traces(LLM 调用链)
适合场景 服务健康、资源监控 LLM 输入输出、token 消耗、对话链路
接入方式 OTel metrics pipeline OTel traces pipeline(OTLP HTTP)
数据存储 TSDB ClickHouse + PostgreSQL
配置改动 已有 新增 extras 约 15 行

两者互补关系。


小结

整个接入过程的核心就是 15 行 YAML:

  1. 在 extras 配置里声明一个新的 otlp_http/langfuse exporter
  2. 在 traces pipeline 的 exporters 列表里追加它
  3. 重启 OTel Collector

Langfuse 对 OTLP 协议的原生支持是这一切能够顺滑实现的基础------不需要 SDK、不需要改业务代码、不需要额外的 agent,已有的 OTel instrumentation 产生的数据直接复用。

对于正在用 OTel 做可观测性、同时有 LLM 应用需要追踪的团队,这是成本最低的接入路径。


环境:Windows 11 + WSL2 + Docker Desktop / Docker Engine,OTel Demo v0.151.0,Langfuse v3.104.0

相关推荐
老金带你玩AI10 小时前
这几天,我都是拿手机让dot帮我干活
人工智能
怕浪猫12 小时前
GEO 优化到底是什么?AI时代内容创作者必须懂的新技能
算法·面试·github
7yewh13 小时前
SLAM 三维空间刚体运动(2)
数据结构·人工智能·机器人·嵌入式·slam
miofly13 小时前
Aleph Alpha 开源 78B 参数 MoE 模型 Kolibri
开源·github
小虎AI生活13 小时前
WorkBuddy 模型选型实操:0.03 倍的 Space-Bunny 怎么用、派什么活、避什么坑
人工智能·超级个体·一人公司·青玥ai
ai小陈13 小时前
GPU服务器租用存储验收:检查点写入与磁盘吞吐实战
运维·服务器·人工智能·ai·ssh·gpu算力
微三云马玮均—GEO源码系统 私有化部署14 小时前
消费返物业费:消费+服务趋势的必然产物!
大数据·人工智能·物联网·区块链·生活
明月_清风14 小时前
Muse 登顶 App Store 第一,SDK 直接开源:AI Agent 开始进入下一个阶段
人工智能·后端
JackSparrow41414 小时前
和AI一起将全部CSDN博文迁移到个人博客站
人工智能·程序人生·ai·github·cloudflare·astro·静态博客