浅谈Langfuse 生产级全链路观测与排坑指南
前言
Langfuse 作为目前开源界最出色的 LLM 可观测工具,支持全链路 Trace 追踪、Prompt 管理和成本分析。
我今天在本地 Docker 私有化部署了Langfuse及结合到之前的 LangChain/LangGraph项目 ,下面记录总结一些重要的节点和注意事项。
一、 私有化部署:Docker 环境搭建
Langfuse 官方提供了非常完善的 Docker Compose 部署方案,内部集成了以下核心组件:
Web 服务 (
langfuse-web):提供前端 UI 及 API 服务。Worker (
langfuse-worker):处理后台异步任务与数据上报。Postgres:存储用户、项目配置与关系元数据。
ClickHouse:高性能列式数据库,专门存储海量 Trace 日志。
Redis:充当后台任务队列与缓存。
1. 启动 Docker 服务
在 docker-compose.yml 目录下执行:
Bash
docker compose up -d
启动后,可以通过 http://localhost:3000 访问 Langfuse 控制台并注册管理员账号。
二、 工程接入:LangChain / LangGraph 整合
在 LangChain 及 LangGraph (v2) 中接入 Langfuse 非常简洁,核心在于利用其提供的 CallbackHandler 机制。
1. 环境变量配置 (.env)
代码段
LANGFUSE_PUBLIC_KEY="pk-lf-***"
LANGFUSE_SECRET_KEY="sk-lf-***"
#这里最好不要用localhost,就用127.0.0.1
LANGFUSE_HOST="http://127.0.0.1:3000"
2. LangGraph 状态图绑定示例
在异步流式输出或图执行时,将 CallbackHandler 传入 config 中:
Python
from langfuse.langchain import CallbackHandler
from langfuse import Langfuse
async def get_stream_response(self, question: str, session_id: str):
# 1. 实例化CallbackHandler(自动读取 .env 环境变量)
langfuse_handler = CallbackHandler()
config = {
"recursion_limit": 100,
"callbacks": [langfuse_handler],
"metadata": {
# 绑定 session_id 实现会话级别的 Trace 归类
"langfuse_session_id": session_id
}
}
try:
# 执行 LangGraph 图链
async for event in self.graph.astream_events(initial_state, config=config, version="v2"):
# 处理流式事件
pass
finally:
# 手动刷新
try:
Langfuse().flush()
except Exception as e:
logger.warning(f"Langfuse flush 提醒: {e}")
三、 实战避坑指南
在实际部署与调试过程中,笔者遇到过几个非常具有代表性的工程问题,特此总结记录:
1. 报错 HTTPConnectionPool Read timed out
现象:测试脚本运行结束,控制台抛出
Failed to export span batch ... Read timed out,Langfuse 后台找不到任何 Trace。排查与原因:
IPv6 解析延迟:Windows/WSL2 环境下,
localhost会优先尝试 IPv6 地址 (::1),导致通信卡死超时。将LANGFUSE_HOST改为[http://127.0.0.1:3000](http://127.0.0.1:3000)可解决此问题。组件依赖缺失:因误将 Docker 容器中的 Redis 停止并卸载,导致
langfuse-web内部报Error: getaddrinfo ENOTFOUND redis异常。
这里简单说一下,langfuse集群内部使用的Redis和我本地跑的Redis是两码事,我本地之前在做LangChain\LangGraph流式输出的时候,有用到过,就是在agent_service里调用过这句(redis://localhost:6379/0),在docker安装好Langfuse的时候,在本地运行redis会报错,端口占用,这个时候如果去把docker里的redis暂停或删除,就可以了。然后启动本地Redis后,因为langfuse工作是离不开redis的时候,这个时候切记要去在docker里把他的redis给跑起来,要不就会卡在推送不到Tracing。
2. LLM 未能正确触发 Tool Calling
现象:前台询问“青岛天气”,模型回复“请提供您所在的城市名称”,且 Langfuse 中显示未调用
get_weather工具。原因分析:
Tool Docstring 不够直接:小模型(如 Qwen2.5 3B/Llama3)无法精准从“青岛天气”中提取
city="青岛"参数。System Prompt 约束模糊:提示词中写有“非汽车问题可以不调用工具”,导致模型倾向于直接回答而非触发 Tool Call。
Redis 历史会话污染:先前回答过的“请提供城市”被记录在
RedisChatMessageHistory中,引发模型上下文模仿。
解决方法:
优化 Tool Docstring,明确告知提取规则(如:“当用户输入中包含城市时,直接提取城市名并调用”)。
强化
SYSTEM_PROMPT中关于工具调用的硬性规则。清理 Redis 旧 Session 历史或更换新的
session_id进行测试
这里也简单说明一下,跟LangFuse关系不是很大,纯粹顺手升级了一下 原先的weather_tool类。
四、 运维与数据占用分析
本地存储占用空间不大,Langfuse 的 Trace 主要是文本,存放在 ClickHouse 列式数据库中,压缩比通常可达 10:1 以上。数千条 Trace 数据实际占用的磁盘空间仅数十兆。如果希望清理测试环境的脏数据,只需进入 Docker 目录执行:
docker compose down -v && docker compose up -d