Langfuse 的核心抽象只有一个:Trace。可观测是「看 Trace」,评估是「给 Trace 打 Score」,Prompt 管理是「让生成 Trace 的那段提示词可版本化」。三大能力不是三个独立产品,而是围绕同一份数据的三种视角——这正是它和「日志工具 + 评估工具 + 配置中心」拼盘方案的本质区别。

它到底解决什么问题

把一个 demo 级 LLM 应用推向生产时,你会连续撞上三堵墙:链路是黑盒,效果没法量化,成本不透明。Langfuse 的设计就是逐个拆掉这三堵墙。

黑盒链路

典型表现
一个 RAG / Agent 请求内部有检索、重排、多次 LLM 调用,线上偶发变慢或答非所问,但你只看得到最终输出,定位不到是哪一步、哪个 prompt、哪段输入出了问题。
判断标准
能在 UI 里点开任意一条线上请求,逐层展开它的 span 与 generation,看到每一步的输入/输出/耗时/模型。
解决方向
用 Tracing:@observe 装饰器或 langfuse.openai 自动把每次调用记成嵌套的 span / generation。

效果不可量化

典型表现
改了 prompt 或从 gpt-4o 换到别的模型,凭感觉觉得「好像好了一点」,但拿不出数字,也无法回归验证。
判断标准
同一批输入能跑出可对比的 score(如准确率、相关性、用户点赞率),并能在 Dataset 实验里横向对比两个版本。
解决方向
用 Scores + Datasets:手动打分 / LLM-as-judge / 用户反馈三种来源统一成 score,挂在 trace 上。

成本不透明

典型表现
月底拿到 provider 账单是一个总数,分不清是哪个功能、哪个用户、哪条链路烧掉的 token。
判断标准
能按 user / session / 功能维度看 token 与花费分布,定位高成本路径。
解决方向
Langfuse 对每个 generation 自动按模型定价计算 token 与 cost,在 Dashboard 聚合。

架构全景:从 SDK 到 Web UI

Langfuse 是典型的「客户端 SDK + 服务端摄入 + 双存储 + Web UI」架构。关键是要记住:SDK 到服务端是异步、批量、单向的上报,你的应用主链路不等待 Langfuse 的网络往返。

  1. Instrumentation 层(SDK):Python SDK(@observe 装饰器 / langfuse.openai 直替 / LangChain CallbackHandler)、JS/TS SDK。它们在你应用进程里把调用记录成 trace/span/generation,缓存进本地队列。
  2. Ingestion API:SDK 后台线程把队列里的事件 批量、异步 POST 到 /api/public/ingestion,失败自动重试,应用退出时 flush。
  3. 队列与 Worker:服务端把摄入事件入队(自托管用 Redis),由 Worker 异步消费、解析、计算 token 与 cost。
  4. 存储双写:分析型大表(traces / observations / scores)落 ClickHouse(列式,扛聚合查询);项目、用户、API key、prompt 等元数据落 Postgres。对象(如大 payload)走 S3 兼容存储。
  5. Web UI:Dashboard(用量/成本/延迟指标)、Tracing(链路下钻)、Prompts(版本与 label)、Evaluations(datasets 与 scores)从存储读取并展示。
一条请求如何变成一条 Trace(数据流)

  [你的应用进程]
        │  ① 调用被 SDK 拦截 / 装饰
        ▼
  ┌──────────────────────────┐
  │ Langfuse SDK              │
  │  trace → span → generation│  ② 记录输入/输出/耗时/模型
  │  写入本地内存队列          │
  └──────────────┬───────────┘
                 │ ③ 后台线程:批量 + 异步 + 重试(不阻塞主链路)
                 ▼  POST /api/public/ingestion
  ┌──────────────────────────┐
  │ Langfuse Server           │
  │  Ingestion API → 队列      │  ④ 入队
  │  Worker 消费               │  ⑤ 解析 + 按模型定价算 token/cost
  └───────┬───────────┬──────┘
          │           │
          ▼           ▼
     ClickHouse     Postgres        ⑥ 双写:分析大表 / 元数据
     (traces,        (projects,
      observations,   prompts,
      scores)         users, keys)
          │           │
          └─────┬─────┘
                ▼
        ┌───────────────┐
        │   Web UI       │  ⑦ Dashboard / Tracing / Prompts / Evals
        └───────────────┘

30 秒感受:一条 Trace 是怎么产生的

下面是能直接跑通的最小示例。把它当作「架构图里 ①②③ 步」的代码版——你会在第 4 章 quickstart-sdk 里展开细节,这里先建立体感。

# 安装 Python SDK(v3,基于 OpenTelemetry);带 openai 集成
pip install "langfuse>=3.0.0" openai

# 三个环境变量来自 Langfuse 项目设置页(云版 cloud.langfuse.com 或自托管实例)
export LANGFUSE_PUBLIC_KEY="pk-lf-xxxxxxxx"
export LANGFUSE_SECRET_KEY="sk-lf-xxxxxxxx"
export LANGFUSE_HOST="https://cloud.langfuse.com"   # 自托管换成你的地址
export OPENAI_API_KEY="sk-..."
# 方式 A:用 @observe 装饰器,把整段函数变成一个 trace,内嵌一个 generation
from langfuse import observe, get_client
# 关键:从 langfuse.openai 导入,而不是直接 import openai
# 这个 drop-in 替换会自动把每次 chat.completions 记成 generation(含 token/cost)
from langfuse.openai import openai


@observe()  # 装饰器把这个函数包成一个 trace 的根节点
def answer_question(question: str) -> str:
    completion = openai.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": "你是一个简洁的助手。"},
            {"role": "user", "content": question},
        ],
        # name 会成为这条 generation 在 UI 里的显示名,便于检索
        name="answer-llm-call",
    )
    return completion.choices[0].message.content


if __name__ == "__main__":
    print(answer_question("用一句话解释什么是可观测性"))

    # SDK 默认异步批量上报;脚本/短任务退出前必须 flush,否则事件可能没发出去
    langfuse = get_client()
    langfuse.flush()  # 阻塞直到本地队列清空(长驻服务里通常无需手动调用)
    # 运行后到 Web UI 的 Tracing 页,就能看到一条名为 answer_question 的 trace

Langfuse vs LangSmith vs Phoenix:怎么选

三者都做 LLM 可观测,但定位不同。一句话区分:Langfuse 是开源 + 可自托管 + 框架中立的全平台;LangSmith 是 LangChain 官方的托管闭源方案,和 LangChain/LangGraph 生态贴得最紧;Phoenix(Arize)是开源、强调本地探索与 OpenTelemetry 原生的可观测/评估工具。

维度LangfuseLangSmithPhoenix (Arize)
开源 / 自托管✅ 开源(MIT 核心),可完整 Docker 自托管❌ 闭源,主要托管 SaaS✅ 开源,可本地/自托管
能力范围可观测 + 评估 + Prompt 管理 一体可观测 + 评估 + Prompt + 数据集,生态最全可观测 + 评估为主,Prompt 管理较轻
框架绑定中立:原生 SDK + 集成 LangChain/LlamaIndex 等与 LangChain/LangGraph 深度耦合中立,OpenTelemetry 原生
数据主权自托管时数据完全在自己手里数据在 LangChain 托管(可申请自托管,企业版)自托管时数据在自己手里
典型选择理由要开源/数据合规/不想锁定生态已重度使用 LangChain,要官方一体化偏研究/调试,想要 OTel 原生与轻量本地
口诀开源全平台选 Langfuse,吃定 LangChain 选 LangSmith,OTel 原生轻探索选 Phoenix
推荐做法
  • 把 Tracing 当成 LLM 应用的「最低门槛基建」,在接入第一天就装上,而不是等出了线上事故再补
  • 短脚本结尾 flush,长驻服务依赖 SDK 后台自动上报
  • 选型时先确认是否有「数据必须自托管/可审计」的硬约束,这一条往往直接决定 Langfuse vs LangSmith
不推荐
  • 不要把 Langfuse 当成同步日志库——它是异步上报,别在主链路里阻塞等它返回
  • 不要因为现在只用 OpenAI 就觉得「框架中立」无所谓,半年后接入新框架时锁定的代价很高
  • 不要在没有 Score 和 Dataset 的情况下凭感觉评价 prompt 改动效果
常见误区
  • 误以为 HTTP 200 就代表数据已落库:摄入是异步队列,真正可见要等 Worker 消费完
  • 自托管时只起了 Postgres 忘了 ClickHouse/Redis,导致 Tracing 页空白或报错
  • 把 LANGFUSE_HOST 留成默认云地址,结果数据上报到了 cloud.langfuse.com 而不是自己的实例

接入后能在 Web UI 看到第一条带 token/cost 的 trace,且确认数据落在你预期的(云 or 自托管)实例上。

你无法改进你看不见、量不准、算不清成本的系统。Langfuse 做的就是先让 LLM 应用变得「可见、可量、可算」。

— 本 Wiki 编者按

下一章进入动手环节:搞清楚 云版 vs Docker 自托管 各自的取舍,并把一个可用的 Langfuse 实例跑起来——这是后续所有 SDK 接入和实验的前提。