Langfuse深度解析:ClickHouse加持的开源LLM可观测性平台——从Trace追踪到Prompt管理的AI工程化完整实战指南
一、前言:当你的AI Agent在生产环境"翻车"时
你有没有经历过这样的场景?
凌晨三点,你的AI客服系统突然开始给客户回复完全不相关的内容。用户投诉如潮水般涌来,你打开日志系统,看到的只有一堆零散的API调用记录——哪个Prompt版本出了问题?是检索模块返回了错误的上下文,还是LLM本身产生了幻觉?Token消耗为什么突然翻了三倍?
传统的软件监控工具(Prometheus、Grafana、Datadog)对这类问题几乎无能为力。因为LLM应用的本质是非确定性的——同样的输入可能产生不同的输出,一个Agent的执行链路可能涉及多次LLM调用、外部工具调用、RAG检索、记忆读写等复杂交互。你需要的不是"CPU使用率80%"这样的指标,而是完整的推理链路追踪。
这就是LLM可观测性(LLM Observability)要解决的问题。而在2026年的今天,这个领域最引人注目的开源项目,非Langfuse莫属。
Langfuse是一个开源的AI工程平台,由YC W23孵化,2026年1月被ClickHouse收购。它提供Trace追踪、Prompt管理、评估系统三大核心能力,基于ClickHouse构建高性能存储引擎,支持自部署,已成为LLM可观测性领域事实上的开源标准。
本文将从架构原理到代码实战,从自部署到生产最佳实践,全面拆解Langfuse如何帮助你驯服LLM应用的可观测性难题。
二、为什么需要LLM可观测性?
2.1 传统监控的盲区
在传统Web应用中,一个请求的生命周期是确定性的:接收请求 → 查询数据库 → 业务逻辑 → 返回响应。你可以用APM工具(如New Relic、Datadog)轻松追踪每一步的延迟和错误。
但LLM应用完全不同:
用户输入 → Prompt模板组装 → RAG检索(向量数据库查询)→ LLM调用 → 输出解析 → 工具调用 → 再次LLM调用 → 最终响应
一个Agent的执行链路可能包含:
- 多次LLM调用:不同的模型(GPT-4o、Claude Sonnet、本地模型),不同的参数
- 外部工具调用:搜索API、数据库查询、代码执行
- RAG检索:向量搜索 + 重排序 + 上下文拼装
- 记忆读写:短期记忆、长期记忆、对话历史
- 多Agent协作:Agent A调用Agent B,Agent B再调用Agent C
传统监控工具看到的只是一堆HTTP请求,完全无法回答以下问题:
- 这次响应质量差,是Prompt的问题还是模型的问题?
- Token消耗异常,是哪个环节在浪费?
- 用户反馈答案不准确,当时的检索结果是什么?
- Agent执行超时,卡在了哪一步?
2.2 LLM可观测性的核心需求
一个完整的LLM可观测性平台需要覆盖:
追踪(Tracing):记录每次LLM调用的完整上下文——输入Prompt、输出结果、Token用量、延迟、模型参数、检索结果等。这不是简单的日志,而是结构化的执行链路图。
评估(Evaluation):自动化地判断LLM输出的质量。包括LLM-as-Judge(用另一个LLM评分)、用户反馈收集、人工标注、代码规则校验等。
Prompt管理(Prompt Management):版本控制你的Prompt模板,支持A/B测试、灰度发布、回滚。这在传统软件中叫"配置管理",但在LLM应用中,Prompt就是代码。
成本分析(Cost Analytics):追踪每个用户、每个功能、每个模型的Token消耗和成本,帮助你做出"用GPT-4o还是Claude Sonnet"这样的技术选型决策。
2.3 Langfuse的市场定位
在LLM可观测性赛道,主要玩家包括:
| 平台 | 类型 | 核心特点 |
|---|---|---|
| Langfuse | 开源,可自部署 | ClickHouse后端,OTel兼容,全栈平台 |
| LangSmith | 闭源SaaS | LangChain官方出品,深度绑定LangChain |
| Helicone | 开源,可自部署 | 代理模式,轻量级,专注Gateway |
| Arize Phoenix | 开源 | 专注评估和嵌入分析 |
| Braintrust | 闭源SaaS | 专注评估和数据集管理 |
Langfuse的核心优势在于:它是唯一一个同时满足"开源+可自部署+全栈平台+高性能存储"的方案。ClickHouse的列式存储引擎让它在处理海量Trace数据时游刃有余,而OpenTelemetry兼容性则避免了厂商锁定。
三、Langfuse核心架构解析
3.1 整体架构
Langfuse的技术栈可以用一句话概括:Next.js前端 + Node.js Worker + ClickHouse存储 + PostgreSQL元数据 + Redis队列。
┌─────────────────────────────────────────────────────────┐
│ Langfuse Architecture │
├─────────────┬───────────────┬───────────────────────────┤
│ Web UI │ REST API │ SDK (Python/JS/OTel) │
│ (Next.js) │ (tRPC+REST) │ │
└──────┬──────┴───────┬───────┴───────────────────────────┘
│ │
▼ ▼
┌──────────────────────────────────────────────────────────┐
│ Processing Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────────┐ │
│ │ Ingestion│ │ Worker │ │ Evaluation Engine │ │
│ │ Queue │ │ (BullMQ) │ │ (LLM-as-Judge) │ │
│ └──────────┘ └──────────┘ └──────────────────────┘ │
└──────────────────────────┬───────────────────────────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
┌──────────────┐ ┌─────────┐ ┌─────────┐
│ ClickHouse │ │Postgres │ │ Redis │
│ (Traces) │ │(Config) │ │ (Queue) │
│ 列式存储 │ │ 元数据 │ │ 消息队列│
└──────────────┘ └─────────┘ └─────────┘
3.2 ClickHouse:为什么是它?
Langfuse选择ClickHouse作为Trace存储引擎,是一个深思熟虑的架构决策。
为什么不用PostgreSQL存Trace?
PostgreSQL是行式存储,适合OLTP(事务处理)。但LLM Trace数据有一个显著特点:写入量大,查询主要是聚合分析。你不会频繁修改某一条Trace记录,但你会经常做这样的查询:
-- 过去7天,每个模型的平均延迟和Token消耗
SELECT
model,
avg(latency_ms) as avg_latency,
sum(total_tokens) as total_tokens,
count() as trace_count
FROM traces
WHERE timestamp > now() - INTERVAL 7 DAY
GROUP BY model
ORDER BY total_tokens DESC
这种典型的OLAP查询,在ClickHouse上可以在毫秒级完成,而在PostgreSQL上可能需要数秒甚至更久。
ClickHouse的核心优势:
- 列式存储:只读取查询涉及的列,大幅减少I/O
- 向量化执行:利用SIMD指令批量处理数据
- 高效压缩:列式数据天然适合压缩,压缩比可达10:1甚至更高
- 分区和索引:按时间分区,支持跳数索引,查询时快速定位数据块
Langfuse的ClickHouse Schema设计中,traces表按天分区,observations(LLM调用记录)通过trace_id关联。这种设计让"查看某条Trace的完整链路"和"统计过去一周的Token消耗"这两个场景都能高效支持。
3.3 数据模型:Trace → Span → Generation
Langfuse的追踪数据模型借鉴了OpenTelemetry的概念:
Trace(一次完整的用户请求)
├── Span(一个操作步骤,如"检索")
│ ├── Generation(一次LLM调用)
│ │ ├── input: Prompt内容
│ │ ├── output: LLM响应
│ │ ├── model: "gpt-4o"
│ │ ├── usage: {promptTokens: 150, completionTokens: 300}
│ │ └── metadata: {temperature: 0.7}
│ └── Event(一个事件标记)
├── Span(另一个操作步骤,如"工具调用")
│ └── Tool Call记录
└── Score(评估分数,如用户反馈)
- Trace:顶层实体,代表一次完整的用户交互。可以关联
userId、sessionId、tags。 - Span:一个操作步骤的耗时记录。可以嵌套,形成树状结构。
- Generation:一种特殊的Span,专门记录LLM调用。包含模型名、输入输出、Token用量等LLM特有的元数据。
- Score:附加在Trace或Span上的评估分数。可以是数值型(0-1)、布尔型(正确/错误)或分类型(好/中/差)。
这种层次化的数据模型,让你既能看到宏观的调用链路,也能深入到每一次LLM调用的细节。
3.4 OpenTelemetry兼容
Langfuse的一个重要架构决策是基于OpenTelemetry(OTel)构建。这意味着:
- 标准协议:Trace数据遵循OTel的Trace/Span模型,可以与Jaeger、Zipkin等传统APM工具互操作
- 无厂商锁定:如果你想从Langfuse迁移到其他平台,OTel格式的数据可以直接迁移
- 生态丰富:OTel的自动注入(auto-instrumentation)可以让你几乎零代码地接入追踪
Langfuse提供了OTel Collector的导出器(exporter),你可以用标准的OTel SDK生成Trace,然后通过OTel Collector发送到Langfuse。
四、核心模块深度拆解
4.1 Observability:从Trace到洞察
4.1.1 追踪采集
Langfuse提供了多种追踪采集方式:
方式一:原生SDK(推荐)
Python SDK和JS/TS SDK是最直接的接入方式。以Python为例:
from langfuse import Langfuse
from langfuse.decorators import observe, langfuse_context
# 初始化客户端
langfuse = Langfuse(
public_key="pk-lf-...",
secret_key="sk-lf-...",
host="https://cloud.langfuse.com" # 或自部署地址
)
# 方式一:装饰器模式(推荐)
@observe(as_type="generation")
def call_llm(prompt: str) -> str:
"""被@observe装饰的函数自动创建Span/Generation"""
response = openai_client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}]
)
# 更新当前Generation的元数据
langfuse_context.update_current_observation(
model="gpt-4o",
usage={
"input": response.usage.prompt_tokens,
"output": response.usage.completion_tokens,
"total": response.usage.total_tokens
}
)
return response.choices[0].message.content
@observe() # 自动创建Trace
def rag_query(question: str) -> str:
"""RAG流程:检索 → 构建Prompt → LLM生成"""
# 检索步骤
docs = vector_store.similarity_search(question, k=5)
# 构建Prompt
context = "\n".join([doc.page_content for doc in docs])
prompt = f"根据以下参考资料回答问题:\n\n{context}\n\n问题:{question}"
# LLM生成
answer = call_llm(prompt)
return answer
# 执行并自动上报Trace
result = rag_query("什么是向量数据库?")
langfuse.flush() # 确保数据发送完成
装饰器@observe()会自动:
- 创建Trace(顶层调用)或Span(嵌套调用)
- 记录函数的输入参数和返回值
- 测量执行时间
- 支持嵌套调用,自动构建父子关系
方式二:OpenTelemetry
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
# 配置OTel导出到Langfuse
provider = TracerProvider()
exporter = OTLPSpanExporter(
endpoint="https://cloud.langfuse.com/api/public/otel",
headers={
"Authorization": "Basic " + base64.b64encode(
f"pk-lf-...:sk-lf-...".encode()
).decode()
}
)
provider.add_span_processor(BatchSpanProcessor(exporter))
trace.set_tracer_provider(provider)
# 使用标准OTel API
tracer = trace.get_tracer("my-app")
with tracer.start_as_current_span("my-operation") as span:
span.set_attribute("llm.model", "gpt-4o")
span.set_attribute("llm.tokens.prompt", 150)
# ... 你的LLM调用逻辑
方式三:LLM Gateway代理
如果你使用LiteLLM作为LLM Gateway,可以零代码接入Langfuse:
# litellm_config.yaml
model_list:
- model_name: gpt-4o
litellm_params:
model: gpt-4o
api_key: os.environ/OPENAI_API_KEY
litellm_settings:
success_callback: ["langfuse"]
failure_callback: ["langfuse"]
LiteLLM会自动将所有LLM调用的Trace数据发送到Langfuse,你的业务代码完全不需要修改。
4.1.2 Trace可视化
Langfuse的Web UI提供了丰富的Trace可视化能力:
- Trace详情页:以瀑布图(Waterfall)展示整个调用链路,每个Span的耗时、输入输出一目了然
- Session视图:将同一会话的多次Trace聚合在一起,方便调试多轮对话
- Agent Graph:将Agent的执行流程可视化为有向图,节点是工具调用或LLM调用,边是控制流
- Timeline视图:时间线视图,精确到毫秒的延迟分析
4.1.3 成本分析
Langfuse内置了Token成本计算。你可以在项目设置中配置每个模型的价格:
{
"models": {
"gpt-4o": {
"inputPrice": 0.0025,
"outputPrice": 0.01,
"unit": "per 1K tokens"
},
"claude-sonnet-4-20250514": {
"inputPrice": 0.003,
"outputPrice": 0.015,
"unit": "per 1K tokens"
}
}
}
Dashboard会自动展示:
- 按模型、用户、功能、时间段的成本分布
- Token消耗趋势
- 异常检测(如某用户Token消耗突增)
4.2 Prompt Management:Prompt即代码
4.2.1 版本控制
在Langfuse中,Prompt不再是硬编码在代码里的字符串,而是有版本管理的可部署资产。
from langfuse import Langfuse
langfuse = Langfuse()
# 获取Production环境的Prompt
prompt = langfuse.get_prompt(
name="customer-support",
label="production" # 环境标签
)
# 使用Prompt
response = openai_client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": prompt.compile(customer_name="张三")},
{"role": "user", "content": user_message}
]
)
Prompt的版本管理支持:
- 标签系统:
production、staging、development,通过标签控制哪个版本在哪个环境生效 - 变量模板:Prompt支持
{{variable}}语法,编译时替换为实际值 - 变更历史:每次修改都有完整的diff记录
- 回滚:一键回滚到任意历史版本
4.2.2 Playground
Langfuse内置了一个LLM Playground,你可以在Web UI中直接测试Prompt:
- 选择Prompt版本
- 填写变量值
- 选择模型和参数
- 点击运行,实时查看结果
这比在代码里改来改去效率高得多。尤其是当你需要快速迭代Prompt时,Playground可以让你在几分钟内测试十几个变体。
4.2.3 Prompt Experiments
Langfuse支持将Prompt与数据集结合,运行系统化的实验:
from langfuse import Langfuse
langfuse = Langfuse()
# 创建实验
experiment = langfuse.create_experiment(
name="support-prompt-v3-test",
dataset_name="support-questions",
prompt_name="customer-support",
prompt_label="staging"
)
# 对数据集中的每条测试用例运行实验
for item in experiment.dataset.items:
result = run_agent(item.input)
experiment.log_result(
item_id=item.id,
output=result,
scores={
"relevance": evaluate_relevance(result, item.expected_output),
"helpfulness": evaluate_helpfulness(result)
}
)
这种方式让你可以在部署新Prompt版本之前,系统化地验证其质量。
4.3 Evaluation:自动化的质量保障
4.3.1 LLM-as-Judge
这是目前最流行的自动化评估方式:用一个"裁判LLM"来评判"工作LLM"的输出质量。
from langfuse import Langfuse
langfuse = Langfuse()
# 配置LLM-as-Judge评估器
langfuse.create_evaluation(
name="answer-relevance",
trace_id="trace-123",
model="gpt-4o-mini",
judge_prompt="""
请评估以下回答与问题的相关性,给出0-10的分数。
问题:{question}
回答:{answer}
评分标准:
- 10分:完全相关,直接回答了问题
- 7-9分:大部分相关,有一些无关内容
- 4-6分:部分相关,但没有直接回答
- 1-3分:基本不相关
- 0分:完全不相关
""",
variables={
"question": "什么是向量数据库?",
"answer": "向量数据库是一种专门存储和检索高维向量的数据库..."
}
)
Langfuse支持在生产环境中自动运行评估——每一条新的Trace都可以触发LLM-as-Judge评估,让你在用户反馈之前就发现问题。
4.3.2 用户反馈收集
最直接的评估方式是收集用户反馈。Langfuse提供了简单的API:
# 在Trace上添加用户反馈分数
langfuse.score(
trace_id="trace-123",
name="user-feedback",
value=1, # 1 = 点赞, 0 = 点踩
comment="回答很准确"
)
在前端,你可以用Langfuse的JS SDK收集反馈:
import { Langfuse } from "langfuse";
const langfuse = new Langfuse();
// 用户点击"有帮助"按钮
function onHelpfulClick(traceId) {
langfuse.score({
traceId: traceId,
name: "user-feedback",
value: 1
});
}
// 用户点击"没帮助"按钮
function onNotHelpfulClick(traceId) {
langfuse.score({
traceId: traceId,
name: "user-feedback",
value: 0
});
}
4.3.3 数据集与离线评估
Langfuse支持创建数据集(Dataset),用于系统化的离线评估:
# 创建数据集
langfuse.create_dataset(
name="rag-evaluation",
description="RAG系统的评估数据集"
)
# 添加测试用例
langfuse.create_dataset_item(
dataset_name="rag-evaluation",
input={"question": "Go语言的垃圾回收机制是什么?"},
expected_output={"answer": "Go使用三色标记清除算法..."}
)
# 运行评估实验
for item in langfuse.get_dataset("rag-evaluation").items:
result = my_rag_system(item.input["question"])
# 记录这次运行
trace = langfuse.trace(
name="dataset-evaluation",
input=item.input,
output={"answer": result}
)
# 与期望输出对比
score = compute_similarity(result, item.expected_output["answer"])
langfuse.score(
trace_id=trace.id,
name="answer-similarity",
value=score
)
五、代码实战:从零搭建完整的LLM可观测性系统
5.1 场景:构建一个带可观测性的RAG问答系统
假设我们要构建一个技术文档问答系统,用户输入问题,系统检索相关文档,然后用LLM生成回答。我们要为这个系统添加完整的可观测性。
5.2 项目结构
rag-with-langfuse/
├── app.py # 主应用
├── retriever.py # 检索模块
├── llm_client.py # LLM调用模块
├── evaluator.py # 评估模块
├── docker-compose.yml # Langfuse自部署
├── requirements.txt
└── .env
5.3 Langfuse自部署
使用Docker Compose一键部署Langfuse:
# docker-compose.yml
version: '3.8'
services:
langfuse-server:
image: langfuse/langfuse:latest
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://postgres:postgres@db:5432/langfuse
- CLICKHOUSE_URL=http://clickhouse:8123
- CLICKHOUSE_USER=default
- CLICKHOUSE_PASSWORD=
- REDIS_URL=redis://redis:6379
- NEXTAUTH_SECRET=your-secret-key-here
- NEXTAUTH_URL=http://localhost:3000
- SALT=your-salt-here
depends_on:
- db
- clickhouse
- redis
db:
image: postgres:15
environment:
- POSTGRES_DB=langfuse
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
volumes:
- postgres_data:/var/lib/postgresql/data
clickhouse:
image: clickhouse/clickhouse-server:latest
environment:
- CLICKHOUSE_DB=langfuse
- CLICKHOUSE_USER=default
- CLICKHOUSE_PASSWORD=
volumes:
- clickhouse_data:/var/lib/clickhouse
ports:
- "8123:8123"
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
volumes:
postgres_data:
clickhouse_data:
redis_data:
启动:
docker compose up -d
访问 http://localhost:3000,注册账号,创建项目,获取API Key。
5.4 完整的RAG应用代码
# app.py
import os
from openai import OpenAI
from langfuse import Langfuse
from langfuse.decorators import observe, langfuse_context
from retriever import DocumentRetriever
from evaluator import RAGEvaluator
# 初始化客户端
langfuse = Langfuse()
openai_client = OpenAI()
retriever = DocumentRetriever()
evaluator = RAGEvaluator()
@observe(as_type="generation")
def generate_answer(question: str, context: str) -> str:
"""LLM生成回答"""
prompt = langfuse.get_prompt("rag-answer")
response = openai_client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": prompt.compile(context=context)},
{"role": "user", "content": question}
],
temperature=0.3,
max_tokens=1000
)
# 更新Generation元数据
langfuse_context.update_current_observation(
model="gpt-4o",
usage={
"input": response.usage.prompt_tokens,
"output": response.usage.completion_tokens,
"total": response.usage.total_tokens
},
metadata={"temperature": 0.3}
)
return response.choices[0].message.content
@observe()
def retrieve_documents(question: str) -> list:
"""检索相关文档"""
docs = retriever.search(question, top_k=5)
# 记录检索结果到当前Span
langfuse_context.update_current_observation(
metadata={
"retrieved_docs": [
{"content": doc[:200], "score": score}
for doc, score in docs
],
"top_k": 5
}
)
return docs
@observe() # 顶层函数自动创建Trace
def rag_query(question: str, user_id: str = None) -> dict:
"""完整的RAG流程"""
# 关联用户
if user_id:
langfuse_context.update_current_trace(
user_id=user_id,
tags=["rag", "production"],
metadata={"source": "api"}
)
# Step 1: 检索
docs = retrieve_documents(question)
context = "\n\n".join([doc for doc, _ in docs])
# Step 2: 生成
answer = generate_answer(question, context)
# Step 3: 自动评估
relevance_score = evaluator.evaluate_relevance(question, answer)
langfuse_context.score_current_trace(
name="relevance",
value=relevance_score
)
return {
"answer": answer,
"sources": [doc for doc, _ in docs],
"relevance": relevance_score
}
# API接口
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI()
class QueryRequest(BaseModel):
question: str
user_id: str = None
class QueryResponse(BaseModel):
answer: str
sources: list
relevance: float
@app.post("/query", response_model=QueryResponse)
async def query_endpoint(request: QueryRequest):
try:
result = rag_query(request.question, request.user_id)
langfuse.flush()
return QueryResponse(**result)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/feedback")
async def feedback_endpoint(trace_id: str, score: int):
"""用户反馈接口"""
langfuse.score(
trace_id=trace_id,
name="user-feedback",
value=score
)
langfuse.flush()
return {"status": "ok"}
5.5 检索模块
# retriever.py
from langfuse.decorators import observe
import numpy as np
from typing import List, Tuple
class DocumentRetriever:
def __init__(self):
# 假设使用FAISS作为向量索引
self.index = None
self.documents = []
self._load_index()
def _load_index(self):
"""加载向量索引"""
import faiss
self.index = faiss.read_index("docs.index")
with open("documents.txt", "r") as f:
self.documents = f.readlines()
@observe(as_type="span")
def search(self, query: str, top_k: int = 5) -> List[Tuple[str, float]]:
"""语义搜索"""
# 查询向量化
query_embedding = self._embed(query)
# FAISS检索
scores, indices = self.index.search(
np.array([query_embedding]).astype('float32'),
top_k
)
results = []
for score, idx in zip(scores[0], indices[0]):
if idx < len(self.documents):
results.append((self.documents[idx], float(score)))
return results
def _embed(self, text: str) -> list:
"""文本向量化"""
from openai import OpenAI
client = OpenAI()
response = client.embeddings.create(
model="text-embedding-3-small",
input=text
)
return response.data[0].embedding
5.6 评估模块
# evaluator.py
from openai import OpenAI
from langfuse.decorators import observe
class RAGEvaluator:
def __init__(self):
self.client = OpenAI()
@observe(as_type="generation")
def evaluate_relevance(self, question: str, answer: str) -> float:
"""用LLM评估回答与问题的相关性"""
response = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{
"role": "system",
"content": "你是一个评估专家。请评估回答与问题的相关性,只输出0到1之间的数字。"
},
{
"role": "user",
"content": f"问题:{question}\n\n回答:{answer}\n\n相关性分数(0-1):"
}
],
temperature=0,
max_tokens=10
)
try:
score = float(response.choices[0].message.content.strip())
return max(0.0, min(1.0, score))
except ValueError:
return 0.5
六、高级特性与生产最佳实践
6.1 异步处理与性能优化
在高并发场景下,同步发送Trace数据会影响应用性能。Langfuse的Python SDK支持异步模式:
from langfuse import Langfuse
# 使用异步模式
langfuse = Langfuse(
flush_at=15, # 批量发送,每15条Trace发送一次
flush_interval=10, # 或每10秒发送一次
max_retries=3, # 失败重试次数
timeout=10 # HTTP超时时间(秒)
)
# 在应用退出时确保数据发送完成
import atexit
atexit.register(langfuse.flush)
对于极致性能要求的场景,可以使用后台线程发送:
import threading
from langfuse import Langfuse
class AsyncLangfuse:
def __init__(self):
self.langfuse = Langfuse()
self._buffer = []
self._lock = threading.Lock()
self._start_flush_thread()
def _start_flush_thread(self):
def flush_loop():
while True:
time.sleep(5)
self._do_flush()
thread = threading.Thread(target=flush_loop, daemon=True)
thread.start()
def _do_flush(self):
with self._lock:
if self._buffer:
self.langfuse.flush()
self._buffer.clear()
6.2 多租户与权限管理
Langfuse支持多项目和多成员管理:
- 项目隔离:每个项目有独立的API Key和数据空间
- 角色权限:Admin、Member、Viewer三种角色
- API Key管理:支持创建多个API Key,便于轮换和撤销
6.3 数据保留与归档
生产环境中,Trace数据量增长很快。建议:
ClickHouse TTL:设置数据自动过期策略
ALTER TABLE traces MODIFY TTL timestamp + INTERVAL 90 DAY;冷热分离:近期数据保留完整详情,历史数据只保留聚合指标
定期导出:将重要Trace导出到S3/GCS进行长期归档
6.4 与CI/CD集成
将Langfuse评估集成到CI/CD流水线中:
# .github/workflows/llm-eval.yml
name: LLM Evaluation
on:
pull_request:
paths:
- 'prompts/**'
- 'src/llm/**'
jobs:
evaluate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run evaluation
env:
LANGFUSE_PUBLIC_KEY: ${{ secrets.LANGFUSE_PUBLIC_KEY }}
LANGFUSE_SECRET_KEY: ${{ secrets.LANGFUSE_SECRET_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: python scripts/run_evaluation.py
- name: Check results
run: python scripts/check_eval_thresholds.py
七、竞品深度对比
7.1 Langfuse vs LangSmith
| 维度 | Langfuse | LangSmith |
|---|---|---|
| 开源 | ✅ MIT/Apache 2.0 | ❌ 闭源 |
| 自部署 | ✅ Docker Compose | ❌ 仅SaaS |
| 存储引擎 | ClickHouse | 未知(闭源) |
| OTel兼容 | ✅ 原生支持 | ⚠️ 部分支持 |
| LangChain集成 | ✅ 深度集成 | ✅ 官方出品 |
| Prompt管理 | ✅ 完整功能 | ⚠️ 基础功能 |
| 评估系统 | ✅ LLM-as-Judge + 自定义 | ✅ 类似功能 |
| 价格 | 免费自部署/云版有免费额度 | 按Trace量收费 |
核心差异:LangSmith是LangChain生态的"官方"可观测性工具,如果你重度使用LangChain,LangSmith的集成体验更无缝。但Langfuse是厂商中立的,不绑定任何特定框架,且支持自部署,这对企业用户来说是决定性优势。
7.2 Langfuse vs Helicone
| 维度 | Langfuse | Helicone |
|---|---|---|
| 架构模式 | SDK注入 | 代理(Proxy) |
| 接入方式 | SDK/OTel/Gateway | 修改API endpoint |
| 性能影响 | 异步,几乎零影响 | 多一跳网络延迟 |
| 功能范围 | 全栈平台 | 偏Gateway和成本分析 |
| 自部署 | ✅ | ✅ |
核心差异:Helicone采用代理模式,你只需要把API endpoint从api.openai.com改成Helicone的地址,零代码接入。但这意味着所有LLM请求都要经过Helicone的服务器(即使自部署也多一跳),且功能范围比Langfuse窄。
7.3 选型建议
- 初创团队/个人开发者:Langfuse Cloud免费额度足够,快速上手
- 企业用户:Langfuse自部署,数据不出内网
- 纯LangChain项目:可以考虑LangSmith,但Langfuse的LangChain集成也很好
- 只需成本监控:Helicone更轻量
- 需要深度评估:Langfuse或Braintrust
八、ClickHouse收购的战略意义
2026年1月,ClickHouse宣布收购Langfuse。这不是一次简单的"大厂买买买",而是有着清晰的战略逻辑。
8.1 ClickHouse的AI基础设施版图
ClickHouse在2026年1月同时完成了:
- D轮融资4亿美元
- 收购Langfuse
- 推出原生Postgres服务
这三件事指向同一个战略方向:ClickHouse要成为AI时代的基础设施层。
LLM可观测性的数据特征(高写入量、列式分析、时序查询)与ClickHouse的核心能力完美匹配。收购Langfuse让ClickHouse从"你用我来存数据"升级为"你用我来管理整个LLM生命周期"。
8.2 开源策略的延续
ClickHouse本身就是从开源起家的,收购Langfuse后继续保持开源策略,这是一个明智的决定:
- 社区驱动:Langfuse的GitHub Star数和社区活跃度在收购后不降反升
- 生态扩展:开源让Langfuse更容易与各种AI框架集成
- 企业信任:开源+自部署消除了企业用户对数据安全的顾虑
8.3 对开发者的影响
作为开发者,这次收购意味着:
- 更稳定的资金支持:Langfuse不会因为资金问题停止维护
- ClickHouse深度优化:Trace存储和查询性能会持续提升
- 产品整合:未来可能出现ClickHouse原生的LLM分析能力
九、总结与展望
9.1 核心价值回顾
Langfuse解决了一个真实且紧迫的问题:LLM应用的可观测性。它的核心价值在于:
- 开源+自部署:数据主权在你手里,不依赖第三方
- ClickHouse后端:高性能的Trace存储和分析
- 全栈平台:追踪+Prompt管理+评估,一站式解决
- OTel兼容:标准协议,避免厂商锁定
- 丰富的集成:OpenAI、LangChain、LlamaIndex、LiteLLM等100+集成
9.2 未来趋势
LLM可观测性领域正在快速发展,几个值得关注的趋势:
Agent可观测性:随着AI Agent的普及,可观测性需要从"单次LLM调用"扩展到"多步骤Agent执行"。Langfuse的Agent Graph可视化已经迈出了第一步。
实时评估:从"事后评估"走向"实时拦截"。在LLM输出返回给用户之前,实时运行质量检查,不合格的输出自动触发重试或降级。
成本优化自动化:基于历史Trace数据,自动推荐最优的模型和参数组合。比如发现某个场景用GPT-4o-mini的效果与GPT-4o相当,但成本只有1/10。
合规审计:在金融、医疗等强监管行业,LLM的每一次调用都需要可审计。Langfuse的完整Trace记录天然满足这个需求。
9.3 给读者的建议
如果你正在构建LLM应用,我的建议是:
- 尽早接入可观测性:不要等到出了问题才想起来加监控。从第一个PoC开始就接入Langfuse
- 从追踪开始:先用SDK接入Trace追踪,了解你的LLM应用在做什么
- 逐步添加评估:先收集用户反馈,再配置LLM-as-Judge,最后建立数据集做离线评估
- Prompt版本化:把Prompt当作代码来管理,有版本、有测试、有灰度
- 关注成本:Token消耗是真金白银,定期查看Langfuse的Dashboard,优化你的模型选择
LLM应用的复杂性只会越来越高,可观测性不是"锦上添花",而是"生产必备"。Langfuse作为这个赛道的开源领跑者,值得每一个AI工程师认真了解和使用。