Langfuse 实战:用开源平台追踪和评估大模型应用

摘要

传统 Web 服务可以通过日志、指标和链路追踪定位问题,但大模型应用还需要回答更细的问题:一次回答使用了哪个 Prompt、调用了几次模型、检索了哪些文档、为什么触发工具、消耗了多少 Token、用户是否满意。

Langfuse 是一个开源的 LLM 可观测性平台,提供 Tracing、Prompt 管理、评估、成本统计和数据集能力。它可以通过 SDK、OpenTelemetry 或框架集成记录大模型应用中的 Trace、Generation、Span、Prompt、Token 和用户反馈。

本文以 RAG 客服应用为例,介绍:

  • Langfuse 的 Trace、Span、Generation 和 Score;
  • 如何通过 Docker Compose 自托管;
  • 如何在 Java 或 OpenAI-compatible 应用中接入追踪;
  • 如何记录 Prompt、检索、模型调用和工具调用;
  • 如何统计 Token、延迟和成本;
  • 如何构造数据集和评估集;
  • 如何处理敏感 Prompt、租户隔离和数据保留。

一、背景与问题

1. 普通日志无法解释模型质量

一条普通日志可能只有:

text 复制代码
request_id=req-001 answer=已为你查询

但排查回答质量时还需要知道:

  • 用户原始问题;
  • 最终 Prompt;
  • Prompt 版本;
  • 检索候选和分数;
  • 实际模型;
  • 输入和输出 Token;
  • 首 Token 延迟;
  • 工具调用;
  • 错误和重试;
  • 用户反馈。

2. AI 应用的调用链更长

text 复制代码
用户请求
    ↓
问题改写
    ↓
向量召回
    ↓
重排序
    ↓
Prompt 组装
    ↓
模型调用
    ↓
工具调用
    ↓
最终回答

如果没有统一 Trace,这些记录会散落在多个服务和日志文件中。

3. Langfuse 的定位

Langfuse 将一次用户请求组织为 Trace,再把内部步骤记录为 Span、Generation、Event 和 Score:

text 复制代码
Trace
  ├─ Span:检索
  ├─ Generation:模型调用
  ├─ Span:工具执行
  ├─ Generation:最终回答
  └─ Score:相关性、满意度或人工评价

它关注的是 AI 应用的运行过程和质量反馈,不替代业务数据库、日志平台和权限系统。

二、核心概念

1. Trace

Trace 表示一次完整用户请求或 Agent Run,通常包含:

  • traceId;
  • userId;
  • sessionId;
  • input;
  • output;
  • metadata;
  • tags;
  • 开始和结束时间。

2. Span

Span 表示一个普通处理步骤:

  • 查询会话;
  • 文档解析;
  • 向量召回;
  • 重排序;
  • 工具执行;
  • 内容过滤。

3. Generation

Generation 表示一次 LLM 调用,应记录:

  • 模型名称;
  • Provider;
  • Prompt;
  • 输出;
  • Token usage;
  • 延迟;
  • 参数;
  • 成本。

4. Score

Score 表示对 Trace 或 Generation 的评价:

text 复制代码
自动评分:答案是否包含引用
模型评分:相关性和忠实度
人工评分:用户是否满意
业务评分:是否解决工单

5. Prompt Management

Prompt 管理需要关注:

  • Prompt Key;
  • 版本;
  • 标签;
  • 变量;
  • 发布状态;
  • 回滚;
  • 与 Trace 的关联。

6. Dataset 与 Evaluation

Dataset 是固定的输入、期望输出或参考答案集合。修改模型或 Prompt 后,可以重新运行同一批数据比较结果。

三、工作原理

1. RAG Trace

text 复制代码
Trace: customer-question
    ├─ Span: load-conversation
    ├─ Span: retrieve-documents
    ├─ Span: rerank
    ├─ Generation: answer
    └─ Score: answer-relevance

2. Agent Trace

text 复制代码
Trace: ticket-agent-run
    ├─ Generation: planning
    ├─ Span: query-ticket
    ├─ Span: search-knowledge
    ├─ Generation: final-answer
    └─ Score: task-completion

3. 成本计算

成本通常由以下字段决定:

text 复制代码
输入 Token × 输入单价
    +
输出 Token × 输出单价
    +
缓存、批处理或工具相关费用

Provider 返回的 usage 可能不完整,因此成本系统要标识估算值和实际值。

4. OpenTelemetry

如果业务系统已经使用 OpenTelemetry,可以将模型调用的 Trace 与普通 HTTP、数据库和消息队列 Span 关联起来:

text 复制代码
HTTP Trace
  ├─ SQL Span
  ├─ Retrieval Span
  └─ LLM Generation

这样可以观察整个请求,而不是只在 AI 平台中看到模型部分。

四、实战示例

1. 使用 Docker Compose 自托管

Langfuse 的自托管部署通常需要数据库和应用服务。开发环境可以先参考官方 Compose:

powershell 复制代码
git clone https://github.com/langfuse/langfuse.git
Set-Location langfuse
docker compose up -d

官方部署文档会随版本更新 Compose、环境变量和数据库依赖,生产环境应直接使用官方仓库当前版本的示例,不要长期复制旧文章中的配置。

2. 配置环境变量

dotenv 复制代码
DATABASE_URL=postgresql://langfuse:change-me@postgres:5432/langfuse
NEXTAUTH_SECRET=replace-with-random-secret
SALT=replace-with-random-salt
ENCRYPTION_KEY=replace-with-32-byte-key
NEXTAUTH_URL=http://localhost:3000

生产环境还需要:

  • 使用 Secret Manager;
  • 启用 HTTPS;
  • 配置外部访问 URL;
  • 备份 PostgreSQL;
  • 限制管理入口;
  • 规划数据保留和删除。

3. Java 初始化 SDK

Java 应用可以使用 OpenTelemetry、HTTP API 或团队封装的 Langfuse Client。建议将追踪能力封装成自己的接口:

java 复制代码
public interface AiObservability {

    AiTrace startTrace(AiTraceRequest request);

    AiSpan startSpan(AiTrace trace, String name);

    AiGeneration recordGeneration(
            AiTrace trace,
            GenerationRequest request);

    void score(AiTrace trace, String name, double value);
}

业务代码不应该到处直接拼 Langfuse HTTP 请求。

4. 追踪一次 RAG 请求

java 复制代码
public KnowledgeAnswer answer(
        CurrentUser user,
        String question) {

    AiTrace trace = observability.startTrace(
            new AiTraceRequest(
                    "knowledge-answer",
                    user.userId().toString(),
                    question
            )
    );

    try {
        AiSpan retrieval = observability.startSpan(
                trace,
                "retrieve-documents"
        );
        List<Document> documents =
                retrievalService.search(
                        user.tenantId(),
                        question
                );
        retrieval.end(Map.of(
                "count", documents.size()
        ));

        AiGeneration generation =
                observability.startGeneration(
                        trace,
                        "answer",
                        promptVersion
                );
        String answer = chatClient.prompt()
                .system(systemPrompt)
                .user(question)
                .call()
                .content();
        generation.end(answer, usage);

        trace.end(answer);
        return new KnowledgeAnswer(answer, documents);
    } catch (Exception error) {
        trace.fail(error);
        throw error;
    }
}

5. 记录模型调用

java 复制代码
public record GenerationRequest(
        String provider,
        String model,
        String promptVersion,
        Object input,
        Map<String, Object> parameters) {
}

public record TokenUsage(
        Integer inputTokens,
        Integer outputTokens,
        Integer totalTokens) {
}

至少记录:

  • Provider 和模型;
  • Prompt 版本;
  • 输入输出 Token;
  • 延迟;
  • 是否流式;
  • 重试和 Fallback;
  • 错误类型;
  • requestId。

6. 记录工具调用

java 复制代码
AiSpan toolSpan = observability.startSpan(
        trace,
        "query-ticket"
);

try {
    TicketSummary result =
            ticketTool.query(context, ticketId);
    toolSpan.end(Map.of(
            "status", "COMPLETED",
            "ticketStatus", result.status()
    ));
} catch (Exception error) {
    toolSpan.fail(Map.of(
            "errorType", error.getClass().getSimpleName()
    ));
    throw error;
}

不要把完整工具参数和结果无条件写入观测平台,尤其是包含密码、Token、个人信息和内部策略时。

7. 记录用户反馈

java 复制代码
observability.score(
        trace,
        "user-feedback",
        feedback == Feedback.POSITIVE ? 1.0 : 0.0
);

还可以记录:

  • 是否点击引用;
  • 是否重新提问;
  • 是否人工转接;
  • 是否采纳 Agent 建议;
  • 工单是否最终关闭。

8. Prompt 版本关联

java 复制代码
public record PromptRef(
        String key,
        String version,
        String label) {
}

每次 Generation 记录 Prompt Key 和版本,质量下降时才能判断是模型、检索还是 Prompt 变化导致。

9. 流式调用观测

流式请求建议:

text 复制代码
Generation start
    ↓
记录首 Token 时间
    ↓
记录片段数量或总字符数
    ↓
记录最终 usage
    ↓
Generation end

不要为每个 Token 创建一个独立 Trace 或 Span。可以记录首 Token 延迟、总延迟和片段统计。

10. 创建评估数据集

json 复制代码
{
  "name": "customer-service-rag-v1",
  "items": [
    {
      "input": "差旅报销多久提交",
      "expectedSources": ["travel-policy-v3"],
      "referenceAnswer": "出差结束后十个工作日内提交"
    }
  ]
}

评估结果可以包含:

text 复制代码
context_recall
answer_relevance
faithfulness
citation_accuracy
tool_success_rate

五、常见问题与实践建议

1. 为什么 Trace 太多

常见原因:

  • 每个 Token 都创建事件;
  • 健康检查也被完整追踪;
  • 重试没有关联同一个 Trace;
  • 前端重复提交;
  • 轮询接口没有采样。

设置采样和环境级别:

text 复制代码
开发环境:完整 Trace
测试环境:完整 Trace + 脱敏
生产环境:按比例采样,错误请求全量

2. 是否应该保存完整 Prompt

默认不建议。可以保存:

  • Prompt Hash;
  • Prompt Key 和版本;
  • 长度和 Token;
  • 脱敏摘要;
  • 受控调试样本。

如果合规要求必须保存完整内容,应加密、控制访问并设置保留期限。

3. 多租户怎么隔离

Trace Metadata 中保存 tenantId 只能帮助筛选,不等于权限隔离。观测平台仍需:

  • 团队或项目分区;
  • 用户访问控制;
  • API Key 隔离;
  • 数据保留策略;
  • 管理员审计。

4. 成本为什么和供应商账单不一致

可能是价格配置、Token 统计、缓存、重试和 Fallback 口径不同。将 Langfuse 作为运行成本估算和异常监控,财务结算以供应商账单为准。

5. 观测平台故障是否应该阻塞业务

通常不应该。业务请求不能因为追踪写入失败而整体失败:

java 复制代码
observability.tryRecord(
        () -> trace.end(answer)
);

追踪上报可以异步、批量和降级,但错误请求和安全事件应有单独的可靠日志。

6. Prompt、Trace 和用户隐私

处理原则:

  • 最小化采集;
  • 字段脱敏;
  • 访问分级;
  • 设置删除接口;
  • 限制跨区域传输;
  • 不将生产数据复制到公共评估集。

六、进阶思考

1. Langfuse 与普通 APM 的关系

普通 APM 关注 HTTP、数据库、线程和基础设施;LLM Observability 还关注:

  • Prompt;
  • 模型;
  • Token;
  • 评估;
  • 生成质量;
  • 工具和检索;
  • 用户反馈。

两者应该关联,而不是互相替代。

2. 质量指标和业务指标结合

技术指标:

  • 延迟;
  • 错误率;
  • Token;
  • 成本;
  • 重试率。

业务指标:

  • 工单解决率;
  • 人工转接率;
  • 用户满意度;
  • 引用点击率;
  • 任务完成率。

只优化模型延迟,不一定提升业务效果。

3. 评估集驱动 Prompt 和模型升级

升级流程:

text 复制代码
固定 Dataset
    ↓
运行旧 Prompt / 旧模型
    ↓
保存基线
    ↓
运行新 Prompt / 新模型
    ↓
比较准确率、成本和延迟
    ↓
人工抽查差异
    ↓
灰度发布

4. 线上反馈回流

用户反馈可以回流到 Dataset:

text 复制代码
线上低分 Trace
    ↓
人工标注
    ↓
加入评估集
    ↓
修正切片、Prompt 或模型
    ↓
回归测试

5. 观测平台的数据生命周期

设计:

  • Trace 保留多久;
  • Prompt 是否单独加密;
  • 失败样本是否长期保留;
  • 用户删除如何传播;
  • Dataset 是否包含真实用户数据;
  • 导出和备份如何控制。

观测数据也属于业务数据,不能无限保留。

结论

Langfuse 的价值在于把大模型应用从"能调用"推进到"能解释、能评估、能优化"。接入时应围绕一次完整请求建立 Trace,再把检索、模型、工具和用户反馈作为可关联的步骤记录。

核心实践包括:

  • 为每次对话或 Agent Run 创建 Trace;
  • 用 Span 记录检索和工具,用 Generation 记录模型调用;
  • 记录 Prompt 版本、Token、延迟、成本和错误;
  • 用 Score 和 Dataset 建立质量评估闭环;
  • 对完整 Prompt、工具结果和用户数据做脱敏;
  • 观测失败不应阻塞业务请求;
  • 将 Langfuse 与普通 APM、日志和业务指标关联;
  • 用线上失败样本持续完善评估集。

第一次实践可以先在测试环境部署 Langfuse,接入一个 RAG 请求,完整观察"问题---召回---模型---引用---反馈"的链路,再逐步扩展到 Agent、成本和自动评估。

参考资料

相关推荐
倔强的石头10644 分钟前
LLaMA系列架构详解_Meta开源大模型的技术演进
开源·大模型·llama
miofly1 小时前
macOS 本地 AI 搜索工具 SCM 发布 0.2.4 版本,支持多模型照片视频检索
开源·github
java1234_小锋1 小时前
shadcn/ui 开源项目,专业打造专业UI
ui·开源
microrain1 小时前
权限改了,接口立刻生效,菜单要等重新登录:SagooIoT 权限体系的四道闸门
物联网·golang·开源·sagooiot
文慧的科技江湖2 小时前
2026年10月4日充电桩行业晚报:当“只充80%“成为通行规则,行业开始管单车占桩时长 | 慧知开源充电桩平台
开源·apache·新能源·虚拟电厂·充电桩·ocpp·v2g
零基础1232 小时前
VoiceStudio 开源项目深度解析:特性、对比与实战测试
人工智能·经验分享·python·开源
miofly4 小时前
GitHub 日榜趋势速报 | 2026-10-05
开源·github
m4Rk_4 小时前
【论文阅读】Agent 记忆机制(90):HyperMem——用超图建模长期记忆中的高阶关联
论文阅读·人工智能·学习·开源·github
miofly12 小时前
Aleph Alpha 开源 78B 参数 MoE 模型 Kolibri
开源·github