把可观测性数据送进 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

相关推荐
时下握今1 小时前
战略数据分析完整流程:从桌面研究、调研取证到报告落地
大数据·人工智能
LuTshoes1 小时前
AI Agent 相关介绍
人工智能·ai
小饕1 小时前
Jetson TensorRT vs RK3588 RKNN:两块板子都跑通了 LLM 和 VLM 之后,我悟了
人工智能·机器人·大模型端侧部署
上海蓝色星球1 小时前
蓝色星球NG-AIOS新型AI工业操作系统重磅发布——以本体智能为内核,重构“AI+制造“新范式
大数据·数据库·人工智能·机器人
来让爷抱一个1 小时前
2026 视觉语言模型实战:八帧跳跃不许看走样,百智云精灵图把图文契约写进素材包
人工智能·机器学习
Joy T1 小时前
Spring AI 2.0 进阶入门:RAG、Structured Output 与 Agent 信息闭环
java·人工智能·spring·rag·springai·agent入门
skywalk81631 小时前
第 23 轮方向确定:保护表通用化替代轮。先深入探查剩余保护表依赖场景和任务 6 的四阶段路径,再写任务书。9.14
开发语言·人工智能·光明
程序员老赵1 小时前
Docker 部署 DeepSeek Harness:轻松搭建本地 AI Agent 运行时平台
docker·agent·deepseek
半糖程序员1 小时前
从零构建 Agent(5):让事件流同时提供过程和结果
typescript·agent