用 Langfuse 打造终极 LLMOps 体系——使用 Langfuse 指标提炼可执行洞察

0 阅读24分钟

引言

在本章中,我们将探索 Langfuse 的仪表盘和分析能力如何帮助团队把 LLM 应用生成的数据转化为可执行洞察。基于运行时收集到的 traces、observations 和 evaluation scores,metrics 提供了一种结构化方式,用来大规模分析系统行为。利用这些指标,团队可以识别优化机会,例如通过提示词优化降低成本,通过解决回答质量问题提升用户满意度,以及通过监控错误和性能趋势来缓解可靠性问题。我们还会看如何按照 model、prompt version 或 user group 等维度对 metrics 进行切分,从而对系统的不同切片进行更深入分析。这类切分有助于发现那些在单独查看 traces 或 evaluations 时很难看到的模式和取舍。

结构

本章将覆盖以下主题:

Score Analytics
Using Score Analytics
Application Setup
Dashboarding in Langfuse
Limitations of Custom Dashboards
Accessing Metrics Programmatically
Metrics API
Querying via SDK

Score Analytics

在上一章中,我们看到如何评估 LLM 应用,并为对象生成不同类型的 metrics 和 scores,这些对象包括 Traces、Observations 和 Sessions。这些 scores 可以通过三种技术生成:Human annotations、LLM-as-a-Judge evaluations,或者 Custom scores。通过 experiments 或 live traces 随时间积累这些数据后,自然而然就需要分析这些 scores,以便指导开发决策并解决应用中的问题。这正是 Langfuse Score Analytics 成为评估工作流关键部分的地方。它把 scores 转换成一个有组织、可交互的分析环境。

Score Analytics 为我们提供即用型分析能力,使我们能够:

快速探索 scores 的分布情况。
并排比较两种 evaluation methods。
评估不同 judges 之间的一致性。
识别异常值和不匹配的评估。
监控质量随时间的变化。
定位 evaluation coverage gaps,也就是评估覆盖缺口。

Score Analytics 可以从左侧导航中的 Scores -> Analytics 标签页进入。

image.png

图 8.1:Langfuse 的 Score Analytics 功能

这个界面可以用来查看单个 score 的分析,也可以比较同一对象类型上的两个 scores,例如 observations。该页面上的关键元素如下:

功能它告诉我们什么
Basic Stats数量、平均值、波动性、主导类别,适用于 categorical scores。
Distribution Chartscores 如何分布,包括聚类、偏斜、极端值。
Timeline Chartscores 随时间的趋势和漂移。
Comparison Panel当选择两个 scores 时,展示二者之间的对齐和一致性。
Heatmaps or Confusion Matrices两种 scoring methods 之间的交互关系。

表 8.1:Score Analytics 功能

其中最有价值的功能之一,是能够把两个 scoring sources 并排放在一起比较。它们可以是:

两个不同的 LLM judges,来自两个不同 LLM;
人工评估与自动化 score;
同一个 scoring rubric 的两个版本;以及
categorical score 与 numeric score。

比较可以跨任意类型对象进行:Traces、Sessions、Observations 或 Dataset Runs。

通过这样做,我们可以衡量一个 score 与另一个 score 的对齐程度。不一致通常指向以下问题:

judge 行为不一致。
rubrics 定义含糊。
某些边缘案例让特定 evaluators 感到困惑。
新模型或 prompt 发布后引入了偏差。
scoring methods 随时间发生漂移。

这种比较可以揭示若干洞察:

Correlation or Agreement Score:评估器之间关系的强度。
Error Metrics:两个 numeric systems 平均相差多远。
Confusion Matrix(用于 Categorical Scores) :评估器是否在某些类别上存在分歧。
Heatmap(用于 Numeric Pairings) :scores 在哪里聚集,以及不匹配在哪里发生。
Matched versus Full Distributions:一个 evaluator 是否覆盖了比另一个更多的数据。

Confusion matrices 和 heatmaps 只有在被比较的 metrics 属于同一类型时才可用,例如 categorical-categorical 或 numeric-numeric。

还需要注意的是,两个 evaluators 之间的高相关性并不能验证 evaluators 本身是正确的。它只能说明这两个 evaluators 彼此意见一致。

Score Analytics 还包括时间序列图,可以展示 scores 在天、周或月维度上的行为。这尤其适用于:

发现部署后的静默回归。
确认 prompt 变更后的质量提升。
识别 evaluator drift,例如 judge 变得更严格。
观察由流量峰值或异常输入导致的异常。
随时间追踪 A/B 测试效果。

趋势线突然变化通常意味着:

发布了新模型;
修改了 system prompts;
引入了新的 evaluation method;
用户行为发生变化;以及
数据流水线发生变化。

在写作时,Score Analytics 还是 Beta 功能,并有以下限制:

一次只能比较两个 scores。
两个 scores 必须具有相同的底层数据类型,即 numeric 或 categorical。
大型数据集可能会为了性能而被采样。

使用 Score Analytics

下面是几个真实场景,展示 Score Analytics 如何帮助我们做决策:

验证人工标注的 Ground Truths:如果一个自动 evaluator 应该模仿人工反馈,我们可以将其 scores 与人工标签进行比较。高对齐度说明我们可以较安全地依赖自动评分来处理大规模数据集。

评估两个 LLM Judges:有时我们会测试多个 LLM,以寻找最一致的 evaluator。比较图表可以揭示哪一个 judge 产生更稳定、更可解释的判断。

调查质量下降:如果近期 scores 下降,Score Analytics 可以帮助我们定位下降从什么时候开始,以及它是否与某次部署、prompt 更新或模型变更一致。

研究行为取舍:通过比较两个 scores,我们可以发现相关性,并由此产生可执行改进。

检测未评分或审查不足的案例:当某个 evaluator 的记录数量远少于另一个时,覆盖缺口会变得很明显。这有助于我们优化 scoring pipelines。

应用设置

为了充分利用本章内容,我们会创建一个小型 chatbot simulation application,设计用于回答关于 Langfuse 的问题。这是一个简单的基于 GPT 的应用,不使用 RAG,也不使用工具,因为目标只是生成足够多的 scores,用来展示 Langfuse 的分析功能。该应用还会使用另一个 LLM 来模拟 chatbot 与真实用户之间的对话。

为了让场景更真实,模拟器会随机向 chatbot 提出一个离题问题,观察 chatbot 如何回应。最终,我们将在 Langfuse 中生成大量 traces,并使用 LLM-as-a-Judge 为它们添加 scores。

我们先加载环境变量,并创建 Langfuse client 实例。同时定义两个全局参数:

MAX_TURNS:每次对话中的用户交流轮数。
N_CONVERSATIONS:要模拟的对话总数。

我们可以根据希望生成的 trace 数量调整这些数字。如果启用了 sampling,它会影响实际记录的 traces 数量。

from dotenv import load_dotenv
from langfuse.openai import openai
from langfuse import get_client
import random
import uuid

load_dotenv()

# 每次对话中的消息轮数
MAX_TURNS = 10
N_CONVERSATIONS = 10

langfuse_client = get_client()

所有 prompts 都直接从 Langfuse 中获取。

# System prompts
chatbot_system_prompt = langfuse_client.get_prompt("langfuse_chatbot_system_prompt")
simulator_system_prompt = langfuse_client.get_prompt("simulator_system_prompt")
random_question_generator_prompt = langfuse_client.get_prompt(
    "random_question_generator_prompt"
)

这些 prompts 也非常简单:

langfuse_chatbot_system_prompt:You are an expert assistant answering questions about Langfuse. Your goal is to give correct, structured, helpful, and concise answers. If a question is not about Langfuse, say so and don't answer.

simulator_system_prompt:You are simulating a curious user who wants to learn about Langfuse. You will ask questions, follow up naturally, refer to prior answers, and behave like a real human exploring a product. Do NOT answer questions—only ask them.

random_question_generator_prompt:You are a random question generator. Generate a random question not related to the conversation history Return only the question and nothing else.

def call_target_bot(conversation_history, session_id, user_id):
    chatbot_model = random.choice(["gpt-4.1-mini", "gpt-4.1"])
    response = openai.chat.completions.create(
        model=chatbot_model,
        messages=[
            {"role": "system", "content": chatbot_system_prompt.prompt},
            *conversation_history
        ],
        name="langfuse-chatbot",
        metadata={"langfuse_session_id": session_id, "langfuse_user_id": user_id},
        langfuse_prompt=chatbot_system_prompt,
    )
    return response.choices[0].message.content

这里,我们把每一轮对话发送给 chatbot。这是我们希望评估其性能的模型。chatbot 会在 gpt-4.1-minigpt-4.1 之间交替选择。这有助于测试不同模型规模在相同 evaluation metrics 下的表现。我们发送完整的逐轮对话历史,以保留上下文。langfuse_session_id 会把同一次模拟对话中的所有消息绑定在一起。langfuse_user_id 允许我们测试多用户场景。Prompts 也会通过 langfuse_prompt= 链接到 traces。

def get_user_question(conversation_history):
    simulator_prompt = random.choice([
        random_question_generator_prompt,
        simulator_system_prompt
    ])
    response = openai.chat.completions.create(
        model="gpt-4.1-mini",
        messages=[
            {"role": "system", "content": simulator_prompt.prompt},
            *conversation_history
        ],
        name="question-generator",
        langfuse_prompt=simulator_prompt
    )
    return response.choices[0].message.content

用户消息由 LLM 创建。我们会在 Langfuse 相关问题和离题问题之间随机选择。最后,我们循环生成对话:

def simulate_conversation(conv_id):
    print(f"\n=== Conversation {conv_id} ===")
    conversation_history = []

    # 生成随机 session_id
    session_id = str(uuid.uuid4())

    # 随机选择 user_id
    user_id = random.choice(["user_1", "user_2", "user_3"])

    # 继续对话
    for turn in range(MAX_TURNS):
        # 模拟用户查询
        user_msg = get_user_question(conversation_history)
        conversation_history.append({"role": "user", "content": user_msg})
        print(f"{user_id}:", user_msg)

        # chatbot 回复
        bot_reply = call_target_bot(conversation_history, session_id, user_id)
        conversation_history.append({"role": "assistant", "content": bot_reply})
        print("Bot:", bot_reply)

if __name__ == "__main__":
    for i in range(N_CONVERSATIONS):
        simulate_conversation(i + 1)
        print("\n--- End Conversation ---\n")

每次对话都是逐步生成的:

创建新的 session ID。
随机选择 user ID。
模拟器基于前面轮次生成用户消息。
chatbot 作出回应。这条消息会被 Langfuse trace 并评分。
两条消息都会加入 history,确保上下文随时间自然增长。

我们还会设置以下 LLM-as-a-Judge Evaluators:

基于内置 Conciseness evaluator 的 Chatbot Conciseness。
基于内置 Helpfulness evaluator 的 Chatbot Helpfulness。
内置 Chatbot Hallucination evaluator。
一个自定义指标,名为 Chatbot was off-topic,用于评估 chatbot 是否回答了与 Langfuse 无关的问题。

下面是 Chatbot was off topic evaluator 使用的 evaluation prompt:

You are a strict evaluator. Your job is to decide whether a chatbot made a mistake by answering an off-topic question.
You will receive:
- A user message
- A chatbot message
Your task:
1. Decide if the user message is about Langfuse (the LLM engineering platform).
- If it mentions Langfuse features, tracing, prompts, evaluation, metrics, dashboards, SDKs, or anything clearly related → it IS on-topic.
- Everything else (general questions, unrelated tech, personal topics, random topics) → off-topic.
2. If the user message is OFF-TOPIC:
- If the chatbot ANSWERED the question → return "1" (incorrect behavior)
- If the chatbot REFUSED because it is off-topic → return "0" (correct behavior)
3. If the user message is ON-TOPIC (about Langfuse):
- Always return "0" (answering is correct)
Very important rules:
- A refusal must clearly say it cannot answer or that the question is outside its domain.
- Ignore answer quality. Judge only topicality.
- Output MUST be exactly one character: "1" or "0". No words. No punctuation.
Return only: 1 or 0.
User: {{user_message}}
Chatbot: {{assistant_message}}

运行前面的程序应该会生成足够多的 traces,LLM-as-Judge evaluators 会自动计算 metrics。现在,我们重新回到 Score Analytics 部分。

image.png

图 8.2:Helpfulness 统计

我们可以单独查看每个 score 的统计信息,也可以比较两个 scores 之间的关系。这里可以看到,我们的 chatbot 平均 Helpfulness 只有 60%,这可能需要进一步分析 evaluator 的 reasoning,才能找到根因。

image.png

图 8.3:Helpfulness 与 Chatbot off-Topic 的关系

比较 Helpfulness 和 off-topic metrics 时,我们看到二者只是松散相关,Pearson r 值为 0.4。这意味着当 chatbot 收到离题问题时,它的 helpfulness 会下降。这是符合预期的,因为它本来就不应该回答离题问题。

image.png

图 8.4:Helpfulness 与 Conciseness 的关系

同时,我们可以看到 Conciseness 和 Helpfulness 高度相关,这意味着简洁回答也很可能更有帮助。

这些只是 Score Analytics 如何帮助我们揭示应用关键洞察的一些示例。提取洞察的另一个更强大功能是 Dashboard,下一节会介绍。

Langfuse 中的 Dashboarding

Langfuse 中的 Custom dashboards 允许我们组织和可视化与 LLM 应用最相关的 metrics。这些 dashboards 建立在 Langfuse 的 query system 之上,支持跨 tracing data 的分组聚合和过滤。这使我们能够检查随时间变化的趋势、比较不同用户细分下的行为,或者把运营指标和质量指标放在同一个地方。无论我们是在监控应用表现,还是审查变更对用户行为的影响,dashboards 都提供了一种结构化方式来解释系统产生的数据。这些 dashboards 允许我们:

集中关键指标:把所有重要 KPI、evaluation scores、latency、costs 和 error types 放到一个连贯视图中。
按角色定制监控:产品经理可能关注用户体验 scores,而工程师关注模型性能或错误峰值。Dashboards 帮助我们清晰分离这些视角。
快速识别模式:可以发现 helpfulness 下降、off-topic responses 突增,或者 reasoning quality 随时间回归。
支持可重复分析:Dashboards 作为保存好的配置存在。我们不用每次都重新构建 filters 或 charts,而是可以一眼获得一致洞察。

每个 dashboard 都由 widgets 构成,例如 charts、tables 和 summary cards。我们可以配置这些 widgets,让它们精确展示所需内容。Dashboards 可以从左侧导航的 Dashboards 菜单进入。

image.png

图 8.5:Langfuse 中的 Dashboards

默认情况下,Langfuse 云版本和 self-hosted 版本都已经预先创建了三个 dashboards:

Langfuse Cost Dashboard:成本相关可视化。
Langfuse Usage Management:使用量 metrics。
Langfuse Latency Dashboard:延迟 metrics。

这些 dashboards 无法自定义,但包含许多有用的可视组件,可以让我们快速查看项目最重要的信息。这些 curated dashboards 可以被克隆并定制,用来添加我们自己的 metrics。

image.png

图 8.6:Langfuse 中的 Cost Dashboards

要创建新的 Dashboard,可以使用 + New dashboard 按钮。

image.png

图 8.7:创建新的 Dashboard

为了充分发挥 dashboards 的价值,应该创建自己的 Widgets,也就是 dashboard 中的单个可视元素。可以点击 Widgets 标签页,再点击 + New widget 按钮来完成。

image.png

图 8.8:创建新的 Widget

在 Langfuse 中,widget 是一个可以添加到 dashboard 的单个可视化或数据视图组件。每个 widget 都是 dashboard 上的一个“tile”,可以是 chart、table、pivot 或任何其他数据展示。Widgets 高度可配置,因为我们可以控制数据源、要展示的 metric、分组/维度、filters 和可视化样式。每个 widget 有两个主要部分:Data 和 Visualization。

在 Data 部分,我们可以选择要展示 metric 的主要对象,或者 View。它可以是 Traces、Observations 或 Scores。此外,我们可以展示哪些 metrics 取决于所选 View。

可选地,我们可以对所选 View 的任意属性应用 filters,例如 Environment、Release version、Trace name 等。

如果想进一步切分视图,可以使用 Breakdown Dimension 选项。例如,可以按 model name、tags、prompt version 等切分 traces。

Visualization 部分用于自定义可视元素。在这里,可以为 dashboard 设置 Name 和 Description,并选择 chart type。截至最新 Langfuse 版本,可以创建的主要 widget 类型包括:

Widget 类型用例 / 何时使用
Line Chart / Time Series追踪某个 metric 如何随时间演变,例如平均延迟、质量 score 趋势。
Bar Chart(Vertical 或 Horizontal)跨类别组比较 metrics,例如不同 models、users、features。
Histogram检查连续 metric 的分布,例如响应延迟、token counts、score values,有助于发现异常值或分布形状。
Pie Chart展示类别之间的比例或相对频率,例如每个 model 的响应占比、用户类型分布、off-topic violations 比例。
Pivot Table多维汇总:同时交叉分析两个或更多维度,例如按 model 和 user 分析质量 score,或者按 feature 和 time period 分析 cost。

表 8.2:Langfuse 中的图表类型

下面是一个 Custom Dashboard 示例,展示 Chatbot 应用的 metrics。

image.png

图 8.9:Chatbot 应用的 Custom Dashboard

它包含以下 Widgets:

Chatbot Latency(99th Percentile),展示 traces 的模型延迟。
Random versus On-topic questions 的比例,以 Pie Chart 展示。
按 Model Name 切分的 usage metrics。
按 User ID 切分的 total cost。
Conciseness、Helpfulness 和 Off-Topic responses 的平均 score values。

可以看到,创建 widgets 的可能性几乎无限,我们可以根据自己的监控需求定制这些 dashboards。

除了已经看到的功能外,也可以把单个 Widgets 的结果下载为 CSV。只需要把鼠标悬停在 Widget 上,然后点击 Download 按钮。

Custom Dashboards 的限制

虽然 Langfuse 的 Custom Dashboards 功能非常方便,可以快速创建一些可视化,但它并不是完整规模的 Business Intelligence(BI)工具。对于高级分析,可能需要更多自定义能力和数据处理选项。在写作时,Langfuse 的 Custom Dashboards 不支持以下功能:

Data Connectivity and Sources

只能可视化 Langfuse 中的数据,没有连接外部数据库、API、CSV 或其他应用数据的 connectors。

Data Modeling

Langfuse Dashboards 不支持自定义数据模型、维度或关系。

不能定义 calculated fields、custom measures 或 transformations。

Querying and Transformations

聚合数量受限于 Langfuse 暴露的内容,例如 counts、average、sum 等。

不能进行数据清洗、整理或复杂 query 逻辑。

Visualization and Widget Options

Widget 类型限制为 time series、bar/line charts、counters/KPIs 和 tables。

不能进行 conditional formatting,也不能添加自定义 colors/themes。

Interactivity

交互性较少,例如 date filters、environment filters、tag filters。

没有参数化 inputs 或动态 selectors。

Dashboard Customization and Layout

只有基础布局能力;固定网格,灵活性有限。

不能创建多页 dashboards 或 dashboard navigation flows。

Collaboration and Governance

不能对 dashboards 进行版本管理。

没有细粒度基于角色的权限控制,例如按行/列区分 view 和 edit。

Exporting and Distribution

导出选项有限,例如 table 的 CSV。

没有 PDF/Image 导出选项。

Limited Alerting / Automation

Custom dashboards 不支持基于阈值的 alerts,例如当 latency > X 时通知。

它们不集成 on-call 或 incident management systems。

由于这些限制,有些情况下我们可能希望直接从 Langfuse 检索 metrics data,并在自己的 BI 应用或已有内部分析栈中使用它。这让团队可以把 Langfuse 洞察与更广泛的业务数据结合,应用更高级的数据建模或可视化技术,并构建具备专用 BI 工具灵活性和交互性的 dashboards。

Langfuse 允许我们以编程方式访问 metrics/scores data,从而实现这种数据抽取。下一节会介绍这一点。

以编程方式访问 Metrics

如前所述,Langfuse 当前 dashboard 选项存在一些不足,这就需要通过其他方式派生 metrics。Langfuse 通过 Metrics API 实现这一点。Langfuse Metrics API 提供了一种编程方式,用于查询 LLM 应用数据的聚合分析结果,这些数据来自 traces、model calls、evaluations 以及相关 metadata。我们不需要手动浏览 dashboards,而是可以直接通过 API 调用拉取 metrics results,并将其集成到自己的 reporting tools 或 data pipelines 中。

Metrics API

通过这个 API,我们可以沿着许多维度对数据进行分组和过滤,包括 model name、user ID、session、prompt version 和 environment,并检索各种 measurements:traces 或 observations 的数量、latencies、token 或 cost usage,以及 evaluation score distributions。因为它支持 traces、observations、numeric scores 和 categorical scores 等多个 views,Metrics API 提供了足够灵活性,让我们可以构建 custom dashboards、为外部 BI 工具导出数据,或基于真实使用数据驱动自动化报告工作流。

下面是一个简单代码示例,用于检索两个日期之间的 traces,并按 name 聚合,展示每个 name 的总数:

from dotenv import load_dotenv
from langfuse import get_client

# 安装 pandas 可运行 pip install pandas
import pandas as pd

load_dotenv()
langfuse_client = get_client()

query = """
{
"view": "traces",
"metrics": [{"measure": "count", "aggregation": "count"}],
"dimensions": [{"field": "name"}],
"fromTimestamp": "2025-11-01T00:00:00Z",
"toTimestamp": "2025-11-30T00:00:00Z"
}
"""

response = langfuse_client.api.metrics.metrics(query=query)
table = pd.DataFrame(response.dict()['data'])
print(table)

这会打印一个表格结构,其中包含结果。Metrics API 提供了我们在 Custom Dashboard 中看到的所有可用选项来派生数据。API 的数据模型非常广泛,能够轻松覆盖高级分析需求。我们会深入到 API 的每个对象,但这里只覆盖最重要的部分。

前面看到的 Query object 结构具有以下字段:

字段类型是否必需目的 / 含义
viewstring指定要查询的数据视图。可能值包括 "traces""observations""scores-numeric""scores-categorical"。它决定查询是在 trace-level、observation-level 还是 score-level。
metricsmetric objects 数组定义要计算哪些 metrics。每个 metric object 包含 measure,即衡量什么,例如 "latency""count""totalCost" 等;以及 aggregation,即如何聚合,例如 "sum""avg""p95" 等。
fromTimestampstring(ISO timestamp)要查询时间范围的起点,包含该时刻。
toTimestampstring(ISO timestamp)要查询时间范围的终点,包含该时刻。
dimensionsdimension objects 数组允许按照某些字段对结果分组,例如按 "name""model""userId""environment" 等分组。如果省略,结果会在所有 items 上全局聚合。
filtersfilter objects 数组提供过滤规则,限制纳入哪些数据。Filters 可应用于 metadata、字符串字段、数值字段等。例如按 userId、environment、tags 和 custom metadata keys 过滤。
timeDimensionobject如果提供,表示结果应按时间桶分组,例如每小时、每天、每周。示例:{ "granularity": "day" }。适用于时间序列分析。
orderByordering objects 数组允许指定返回行的排序顺序。每个 ordering object 通常引用一个字段和方向,例如 ascending 或 descending。

表 8.3:Metrics API 的 Query Object 结构

Metric Object:示例:{ "measure": "latency", "aggregation": "p95" }measure 选择基础 metric;aggregation 选择如何汇总,例如 mean、percentile、count、sum 等。

Dimension Object:最简单形式:{ "field": "name" }。多个 dimensions 支持多级分组。

Filter Object:用于缩小数据范围,例如对 metadata、numeric ranges、string matches 等进行过滤。示例模式包含 column、operator、value 等字段;当过滤嵌套 metadata 时,也可以包含 key。

Time Dimension:当你希望得到随时间变化的 metrics,例如每日平均、小时级数量,而不是单一聚合值时非常有用。

下面是另一个 query,用于获取两个日期之间所有 traces 的每日聚合 metrics:

query = """
{
"view": "traces",
"metrics": [
{ "measure": "count", "aggregation": "count" },
{ "measure": "latency", "aggregation": "avg" },
{ "measure": "totalTokens", "aggregation": "sum"},
{ "measure": "totalCost", "aggregation": "sum" }
],
"dimensions": [],
"timeDimension": {
"granularity": "day"
},
"filters": [],
"fromTimestamp": "2025-11-01T00:00:00Z",
"toTimestamp": "2025-11-30T00:00:00Z"
}
"""

另一个高级示例,用于获取 chatbot 应用的平均 scores:

query = """
{
"view": "scores-numeric",
"metrics": [{"measure": "value", "aggregation": "avg"}],
"dimensions": [{"field": "name"}],
"filters": [
{
"column": "traceName",
"operator": "contains",
"key": "",
"value": "langfuse-chatbot",
"type": "string",
}
],
"fromTimestamp": "2025-11-01T00:00:00Z",
"toTimestamp": "2025-11-30T00:00:00Z"
}
"""

虽然 Metrics API 提供了一种灵活方式来处理 Langfuse analytics,但主要不便之处在于,要构建有效 queries,需要熟悉 Langfuse 的底层数据模型,包括 views、dimensions、measures 和 filter types,这需要一些时间理解。不过,queries 是在服务端执行的,以提升性能,因此它是延迟敏感用例的理想选择。接下来,我们会看看如何使用 SDK 以编程方式获取 metrics 或 scores。

通过 SDK 查询

虽然 Metrics API 提供了一种结构化方式来检索聚合分析数据,但它并不是以编程方式访问 Langfuse 数据的唯一方法。通过 SDK 查询提供了一种更灵活、更直接的替代方式,尤其适合那些更喜欢使用原始 trace-level 或 observation-level 数据,而不是预聚合 metrics 的团队。

访问原始数据,而不是聚合数据

Metrics API 围绕聚合查询设计:counts、averages、percentiles、grouped breakdowns 和 time-series rollups。当你已经明确知道要计算什么 metric 时,这非常理想。

然而,SDK 允许你直接拉取底层 trace、span、event、attachment 或 score records,而不需要定义 metrics query 结构。这在以下情况下很有用:

想构建自己的 custom aggregations。
需要把 Langfuse 数据与自己系统中的数据 join。
想检查单个 traces 或 evaluations,用于调试或研究。

换句话说,SDK 允许你在任何汇总发生之前处理数据。

支持自定义过滤和分页

Metrics API 要求用 columns、operators 和 types 表达 filters,而 SDK 通常提供更简单的过滤方法:

按 traceId、userId、environment、name 过滤。
按 timestamp ranges 搜索。
对大量 traces 或 observations 分页。
应用更容易直接表达的 metadata conditions。

这意味着你不需要理解 Metrics API 使用的完整 query object 结构,就能通过更直接的函数调用获取所需内容。

访问更多对象类型

Metrics API 只暴露某些 views:traces、observations、scores-numeric 和 scores-categorical。通过 SDK 查询则覆盖更广:

Traces
Observations
Scores
Prompts
Datasets
Sessions

当我们的用例超出 metrics 时,SDK 更合适,例如检索完整 traces 用于 labeling、导出 evaluation dataset,或检查 prompt versions。

通常在以下情况下,SDK 查询是更好选择:

需要原始 trace 或 score data,而不是 metrics。
正在自己的代码或 BI 系统中构建 custom aggregations。
需要通过检查完整 request/response logs 进行调试。
想创建数据导出 pipeline。
偏好一种更可预测、面向对象的数据交互方式。

下面是如何检索两个日期之间 traces 的示例:

from dotenv import load_dotenv
from langfuse import get_client
from datetime import datetime

# 安装 pandas 可运行 pip install pandas
import pandas as pd

load_dotenv()
langfuse_client = get_client()

traces = langfuse_client.api.trace.list(
    limit=100,
    from_timestamp=datetime(2025, 11, 1),
    to_timestamp=datetime(2025, 11, 30)
)

records = [t.dict() for t in traces.data]
traces_df = pd.DataFrame(records)

这会返回 traces 的以下所有字段:

描述
idTrace ID
timestampTrace 创建时间戳
nameTrace 名称
inputTrace 输入
outputTrace 输出
metadataTrace metadata
tagsTrace tags
public表示 Trace 是否有 public link 的标记
environmentLangfuse environment
htmlPathtrace 的 URL path
latencytrace 总延迟
totalCosttrace 总成本
observations关联的 Observation Ids 列表
scores关联的 Score Ids 列表
projectIdtrace 所属 Project Id
bookmarked表示 Trace 是否被 bookmark 的标记
createdAttrace 创建时间戳
updatedAttrace 更新时间戳
sessionId如果 trace 关联到 session,则为 Session ID
releaseRelease name
version应用版本
userId如果 trace 关联了用户,则为 User ID
externalIdExternal ID,如果存在

表 8.4:使用 SDK 返回的 Trace 字段

可以看到,每个 trace record 都有指向底层 observations 和 scores 的链接,我们也可以用 SDK 获取它们。

作为一个高级用例,让我们尝试获取两个日期之间 chatbot 的所有 scores,包括模型名称和 score values。

chatbot_traces = langfuse_client.api.trace.list(
    limit=100,
    from_timestamp=datetime(2025, 11, 1),
    to_timestamp=datetime(2025, 11, 30),
    name="langfuse-chatbot",
)

print(f"Fetched {len(chatbot_traces.data)} chatbot traces")

records = []

for t in chatbot_traces.data:
    # 遍历 observations
    for to in t.observations:
        observation_data = langfuse_client.api.observations.get(to)

        # 获取 trace 的所有 scores
        score_data = langfuse_client.api.score_v_2.get(trace_id=t.id).data

        # 每个 score 创建一条 record
        for s in score_data:
            record = {
                "trace_id": t.id,
                "model": observation_data.model,
                "score_name": s.name,
                "score_value": s.value,
            }
            records.append(record)

traces_df = pd.DataFrame(records)

当你需要精确的、按 trace 和按 score 的细节时,基于 SDK 的方法很有帮助,包括每个 observation 使用的具体模型。然而,它也会变得非常低效,因为你必须先获取 traces,再获取每个 observation,再获取每个 score——这通常会导致每条 trace 需要几十次 API 调用。它还要求处理 100 条 trace 的分页限制,因此对于大型时间范围而言会很慢,也不实用。

相比之下,Metrics API 执行服务端聚合,可以在一次请求中查询大型数据集,但它不提供原始行级数据。

SDK 与 Metrics API 对比:

方面SDKMetrics API
Data Access可以完整访问原始 traces、observations、scores 和 metadata。仅访问聚合 metrics,例如 counts、averages、percentiles、breakdowns。
Granularity行级、按 trace、按 score。按 dimensions、time intervals 或 filters 聚合。
Flexibility高度灵活:可以实现 custom joins、filtering 和 transformations。限于预定义 measures、aggregations 和 dimensions。
Performance大数据集较慢,因为每条 trace/observation 需要多次 API 调用。大数据集较快,服务端聚合减少开销。
Pagination每次请求限制 100 条 traces,需要手动分页。没有逐 trace 限制;一个 query 可以覆盖大范围。
Ease of Use需要处理嵌套循环、join 和数据拉平。Query 结构需要理解 metrics、dimensions 和 filters。
Best Use Case调试、导出原始数据、构建 custom pipelines,或分析特定 traces。趋势分析、BI dashboards、成本/延迟监控和高层报告。
Limitations大规模低效,维护复杂,如果循环结构不正确,可能产生重复行。无法访问原始 trace-level data 或自定义 observation 细节。

表 8.5:SDK 与 Metrics API 对比

结论

本章介绍了 Langfuse 如何帮助团队从 LLM 应用中获得可执行洞察。我们覆盖了用于检查模型表现的 Score Analytics,讨论了 dashboards 如何让监控变得更容易,并比较了通过 Metrics API 或 SDK 访问数据的方式。每种方法都有自己的优势——无论你需要详细的 trace-level 数据,还是大局趋势。对于规模化场景,应优先使用 Metrics API;而 SDK 访问则更适合检查和数据丰富工作流。Langfuse 为团队提供了灵活工具,用于监控、排障和改进应用。下一章中,我们会查看 Langfuse 的 Administration 功能,用来添加访问级别安全,并介绍 Guardrails 概念以及 Langfuse 如何帮助我们把它们集成进应用中。

参考资料

Metrics in Langfuse –
langfuse.com/docs/metric…

Score Analytics in Langfuse –
langfuse.com/docs/evalua…

Custom Dashboards in Langfuse –
langfuse.com/docs/metric…

Langfuse metrics API –
langfuse.com/docs/metric…

Query via SDK –
langfuse.com/docs/api-an…