
先给结论Langfuse 是目前做智能体评估和大模型应用观测绕不开的一个开源平台。它解决的问题很明确大模型调用链路太长、中间步骤不可见、Prompt 一改就不知道效果是变好还是变坏、Agent 多步推理出错了只能靠猜。如果你正在做智能体、RAG、自动化脚本或者基于 LangChain / OpenAI SDK 的 LLM 应用Langfuse 能帮你把“黑盒调用”变成一条一条可回放、可评分、可对比的链路记录。这篇文章适合两类人。一类是刚把大模型 API 跑通正在发愁怎么调试 Agent 中间结果的人另一类是已经接了日志系统但发现传统日志很难还原“模型输入、上下文、工具调用、评分结果”这类结构化信息的人。Langfuse 更像是给大模型应用准备的“监控台 调试器 评测记录表”它不替代你的代码逻辑而是把每次调用的前因后果都留下来。下面按我实际搭建和使用的顺序拆一遍。先讲它为什么值得用再讲部署、接入、评估、性能分析和排错。整篇文章没有涉及特别复杂的商业功能全部基于开源版本和常见 Python 项目流程你可以照着在自己的项目里复现。1. 为什么大模型应用比传统应用更需要可观测性1.1 传统日志框架在 LLM 链路里不够用传统后端项目打日志一般就是记录“某个接口收到了什么参数、返回了什么结果、耗时多少、有没有报错”。这套方式放到大模型应用里会变得很难用原因是大模型应用一次用户请求往往不是单纯的 HTTP 请求而是多轮调用用户输入先被送到 Prompt 模板里加上历史对话、知识库检索结果再送给大模型生成第一轮内容大模型可能还会触发工具调用工具返回结果后再送回去生成最终答案。整个过程涉及多次 token 计费、多次网络请求、多段上下文拼装。如果只打一行普通日志根本看不出是哪一步导致回答变差。Langfuse 的核心思路是把整条链路当成一次 trace 来记录。trace 里有多个 spanspan 可以表示一次模型调用、一个工具执行、一段检索过程或者一个代码函数。每个 span 都带输入、输出、耗时、Token 用量、模型名称、Prompt 版本等字段。这样排查问题时就变成了观看回放而不是去翻一堆无结构文本。1.2 Langfuse 在智能体评估里扮演的角色智能体评估比单次模型调用更麻烦。你不仅关心“模型最终答了什么”还关心“Agent 有没有正确选择工具”“中间检索到的内容是不是对的”“哪一步消耗的 token 最多”“为什么同样的输入两次结果完全不一样”。Langfuse 在这里能承担三件事追踪把 Agent 每一步的决策、工具结果、上下文变化完整记录下来。评测人工或自动给某次运行打分数、写标注形成评估数据集。对比跑多个 Prompt 版本、多个模型参数组合用同一组测试用例做对比。也就是说它既是观测工具也是评估结果沉淀的地方。把 Langfuse 接到智能体项目里不是在代码外面套一层监控而是让每次运行的“思维链快照”可保存、可回放、可量化。2. 先把 Langfuse 跑起来本地部署与最小配置2.1 准备环境Langfuse 官方提供云服务、Docker 自托管和本地开发模式。不打算折腾服务器的话本地开发模式最快需要多人协作或长期保留生产环境数据建议直接用 Docker 部署。本地开发模式要求很低电脑能跑 Python 就行。官方常见做法是用 Node.js 和 Docker 来运行完整服务但如果只是想快速看界面也可以用 Langfuse 的托管环境或直接拉取 Docker Compose 配置。我的建议是第一次尝试不要引入太多外部依赖先保证服务能启动、SDK 能上报数据。比较省事的启动流程是git clone https://github.com/langfuse/langfuse.git cd langfuse docker compose up -d等容器启动后浏览器打开http://localhost:3000注册一个本地账号创建组织并进入项目。这里会生成两个关键值公钥、私钥。公钥也就是LANGFUSE_PUBLIC_KEY私钥对应LANGFUSE_SECRET_KEY。项目里还会有一个区域地址比如自托管时是http://localhost:3000。这三个配置后面都需要写进环境变量。注意自托管版本功能更新很快2.x 版本和早期 1.x 的部署方式有差异。建议以当前仓库里的docker-compose.yml为准不要拿网上很老的文章命令直接跑。2.2 创建项目并获得密钥Langfuse 里的层级关系是组织 - 项目 - trace。一个项目可以对应一个应用、一个 Agent 服务或者一次评估实验。同一个组织下可以建多个项目方便区分开发环境和生产环境。进入项目设置后你会看到“API Keys”页面。新建一个 Key把SECRET_KEY和PUBLIC_KEY一次性保存好因为平台之后不会完整展示私钥。这里很多人第一次会踩坑以为后续还能再看结果只能重新创建。2.3 初始化 Python SDKPython 项目常用langfusePython SDK。安装很简单pip install langfuse推荐把配置放在环境变量里不要硬编码到代码中export LANGFUSE_PUBLIC_KEY你的公钥 export LANGFUSE_SECRET_KEY你的私钥 export LANGFUSE_HOSThttp://localhost:3000在代码里初始化from langfuse import Langfuse langfuse Langfuse()如果你使用 LangChainSDK 还会提供对应的 handler。后面接入时会自动捕获调用信息不需要手动把每个模型的输入输出复制出来。3. 从单次调用到链路追踪接入大模型调用3.1 OpenAI 普通调用如何打点最基础的方式是手动创建 span显式记录模型调用的输入和输出。假设你有一段调用 OpenAI 的代码from openai import OpenAI from langfuse.decorators import observe, langfuse_context client OpenAI() observe() def ask_gpt(question: str): response client.chat.completions.create( modelgpt-4o-mini, messages[ {role: system, content: 你是一个项目助理。}, {role: user, content: question} ] ) return response.choices[0].message.content加上observe()装饰器后这个函数的调用就会自动记录到 Langfuse。装饰器能捕获函数名、入参、返回值和执行时间。你打开 Langfuse 界面刷新一次记录就能看到一条 trace里面有这次调用的完整输入输出。这样做的好处是完全不动原有业务逻辑。协程函数用observe()也能工作SDK 内部会处理异步上下文。3.2 LangChain 调用如何自动捕获如果项目基于 LangChainLangfuse 提供了回调处理器。在创建链或者调用链时加上它整个链的调用流程都会自动拆分from langfuse.callback import CallbackHandler langfuse_handler CallbackHandler() chain.invoke({question: 北京适合三天旅行去哪里}, config{callbacks: [langfuse_handler]})LangChain 内部的 Prompt 拼接、模型调用、解析器执行会被记录成多个 span。排查 Agent 时你可以从界面上展开完整的 trace看到每步走了哪个工具、传了什么参数、模型有没有重复调用同一个函数。如果项目不是 LangChain而是自研 Agent 框架也不用担心。利用observe()装饰器标记关键步骤函数即可observe() def call_retriever(question: str): # 检索逻辑 return chunks observe() def call_llm_with_context(question: str, chunks: list): # 拼接 Prompt 后调用大模型 return answer这样即使没有 LangChain每一条检索和生成路径也能完整拆开。4. 智能体评估的核心Span、Event 与 Score4.1 用 Trace 还原 Agent 每一步决策Langfuse 的数据模型可以这样理解Trace一次完整请求例如用户从提问到收到最终回答。Span一次可追踪的操作阶段例如调用工具、调用模型、读取文件。Event某个时间点发生的独立事件例如检索命中、错误抛出。Generation专门用于模型调用的一种 span会额外记录模型名、token 消耗、参数配置。智能体排查时我最常看的是 Span 之间的嵌套关系。比如 Agent 第一步生成的意图应该决定是否调用搜索工具如果搜索结果为空Span 里能看出来检索耗时、检索命中的片段数和模型下一步的输入。如果没有 trace你只能靠事后打日志猜测而且日志很难把“这个上下文是检索来源拼进去的”这类关系保留下来。拿到 trace 后Langfuse 界面提供类似链路图和时间轴的视图。某个环节比较慢点击对应 span 就能看到完整输入输出。调试 Prompt 时可以直接把这条 trace 里的实际输入复制出来到模型对话里试改复盘效率会高很多。4.2 把大模型输出打上质量分Langfuse 不只是记录链路还提供 Score 机制。你可以给某次 trace 打分分数来源可以是人工标注也可以是代码自动计算。常用打分方式有这么几类人工评分在界面里打开一条 trace选择“评测”打 1 到 5 分并写备注。代码自动评分把判断结果写成函数再用 Langfuse SDK 上报。模型评分用另一个大模型对输出内容按维度打分例如是否忠实于检索内容、是否有代码格式错误。以自动评分为例可以在拿到最终回答后执行评分函数from langfuse import Langfuse langfuse Langfuse() def evaluate_answer(trace_id, answer: str): score 4 if len(answer) 20: score 1 langfuse.score( trace_idtrace_id, nameanswer_quality, valuescore, comment答案太短可能没有完整回答, )关键点在于评分要跟着 trace_id 走而不是单独存到另一个数据库。否则你之后想分析“低分样本有什么共性”时还要自己做 join非常麻烦。如果你跑了一组评估实验想对比两个 Prompt 哪个更好可以把实验分到不同的 Session 或者给 trace 打上相同标签之后在 Langfuse 的“数据集”页面统一看结果。更完整的做法是使用 Langfuse 的Prompt Management和 Dataset每次运行使用测试集并把模型输出和分数自动汇总。提示不是所有效果问题都能靠自动分数解决比如“语气是否自然”这类主观项建议保留少量人工抽检。自动评分适合判断格式、关键词、长度、相似度、代码正确性等客观项。5. 性能优化从日志里找到瓶颈5.1 先看耗时分布再调参数做性能优化时首要任务不是凭感觉调大并发或者更换模型而是先看 trace 各阶段耗时比例。一次 Agent 交互可能被拆成下面几个阶段阶段可能出现的耗时点优化方式输入解析意图分类 Prompt 过长精简 Prompt不做无用分类知识检索向量数据库查询、重排序加缓存、限制候选数量、优化索引上下文拼装历史消息、检索结果全部塞入做滑窗截断、只保留相关片段模型生成输出长度过大、推理模型思考过长限制 max_tokens、换低延迟模型工具调用Agent 连续多次错误调用工具增加工具描述准确度添加最大调用次数在 Langfuse 里打开一条慢 trace先看哪一个 span 耗时最长。如果模型生成占了 80% 以上后面优化重点就是输出长度和模型参数如果检索阶段耗时高那就该去看向量库索引而不是继续压 GPU 或调 Prompt。优化完再次运行同一条用例Langfuse 会自动保存新的 trace。你可以在界面上对比新旧 trace 的耗时不需要自己另建统计表。不过要注意大模型输出有随机性两次运行即使配置完全相同耗时也可能差很多。做对比时最好用同一组测试用例各跑多轮别拿单次结果下结论。5.2 Prompt 调试与回归对比Langfuse 的另一个实用功能是 Prompt 管理。你可以在平台里维护多个 Prompt 版本调用时使用版本号获取 Prompt 模板而不是把字符串硬编码在代码里。这样做的好处是每次 Prompt 改动都会有版本记录。上线后如果发现效果变差可以直接回滚到上一个可用版本不用去 Git 历史里翻代码文件。有一个常见误区是改 Prompt 后只看一两个测试用例觉得“变好了”就急着更新线上版本。正确做法是准备 10 到 20 条有代表性的用例使用旧版本和新版本各跑一遍再在 Langfuse 里对比结果。你甚至可以给两个版本跑出来的 trace 都打上分数用平均值判断哪个更稳定。5.3 成本与 Token 消耗跟踪Langfuse 会自动统计模型调用的 Token 数。在 trace 详情里能看到每个 Generation 的 input tokens、output tokens以及对应的模型名和价格配置。如果你使用了多模型组合例如先用小模型做意图识别再用大模型生成正式回答页面上的 token 统计能直观显示哪部分成本最高。成本优化经常和性能优化是矛盾的。降低答案长度会减少 token 消耗但可能牺牲回答完整性。这里不推荐直接压 max_tokens 到很小值。更稳妥的方法是先分析请求日志找出哪些调用没必要使用高规格模型只把关键生成步骤切换到强模型把分类、关键词提取等任务留在小模型上。Langfuse 的 token 统计只是参考不同厂商和不同计费方式需要自行配置价格。如果你没有配置价格表页面只会显示 token 数不会自动换算出金额。不要因为界面没显示钱数就误以为不计费。6. 批次任务与团队协作6.1 批量实验怎么组织在评估智能体效果时很多人会一次性把几十条测试用例放到循环里跑然后去 Langfuse 看结果。刚开始不建议这么干。最合理的路径是先拿 1 条用例写完接入和打标代码确认 trace 能正常生成、score 能正常写入再跑 3 到 5 条做稳定性验证最后再扩展到完整测试集。批量跑的时候有几件事要提前设计每条 trace 如何命名可以用用例 ID 模型版本 时间方便搜索。错误如何上报某条用例异常时不能只不输出结果要把错误信息记录到 trace 的 output 中。评分是否有重试判断模型评分服务偶发超时要设置重试而不是让它直接丢失评分。并发多大如果直接开 100 个并发网络和服务端都会受到影响需要根据模型 API 的速率限制来调节。Langfuse 支持多进程写入官方 SDK 的接口线程安全。但如果你在独立进程任务里上报需要保证进程结束时能正常 flush否则可能出现 trace 部分丢失的情况。批量任务脚本最后可以调用langfuse.flush()确保日志缓冲全部落盘。6.2 多人团队共享观察数据Langfuse 自托管版支持多账号和项目管理团队内成员可以通过同一个 Web 界面查看 trace。这里的好处是产品和算法可以一起看同一批评估结果而不是靠测试同学截图再发到群里。我比较推荐的协作方式是这样的开发负责接入 SDK把主要 Agent 步骤拆成 span。测试或产品维护一组标准测试问题和预期结果。算法同学修改 Prompt 后在 Langfuse 中运行回归测试。每周或者每次发布前把关键用例的评分平均值记录下来做趋势对比。如果团队已经有 Gitee、GitLab 这类代码仓库Langfuse 的配置信息和测试脚本最好也纳入版本管理。至少要让项目里的LANGFUSE_HOST、LANGFUSE_PUBLIC_KEY这类变量能随环境切换避免有人用测试环境 Key 把生产数据写进开发项目里。7. 排查问题顺序与常见坑点7.1 如果 trace 没出现先按这个顺序查很多人接入 Langfuse 后第一反应是“代码没写对”于是反复改装饰器。但实际大概率是配置问题。我自己常用的排查顺序是先确认服务本身能访问浏览器打开 Langfuse 地址能打开说明 Web 服务正常。再确认 Key 是否正确公钥和私钥别填反。LANGFUSE_PUBLIC_KEY对应公钥LANGFUSE_SECRET_KEY对应私钥。检查 host 是否写对本地自托管时是http://localhost:3000注意不要漏掉端口。看后端日志SDK 一般会打印网络错误或 401、403 状态码直接看控制台输出比猜准。检查函数是否真的执行如果异步任务没有 await可能在进程退出前还没发出去。确认 flush在脚本末尾调用langfuse.flush()防止缓冲数据丢失。如果只有部分 trace 缺失优先看是不是有异常导致函数提前返回或者并发执行时使用了同一个 trace 上下文。7.2 几个容易踩的坑第一个坑把observe()加在类方法里但方法里又创建了新的子线程。Langfuse 的 trace 上下文通常跟随异步上下文或当前执行线程直接新开线程会丢失父级关系。处理方式是手动传入 trace_id或者在子线程中重放上下文。第二个坑用 LangChain 时同时挂了 Langfuse handler 和别的 handler顺序可能导致某些事件覆盖。建议每次构建 chain 时显式传入一个 handler 实例不要依赖全局配置。第三个坑评分时不知道 trace_id 从哪里拿。observe()装饰器可以在函数内部使用langfuse_context.get_current_trace_id()获取当前 trace id。from langfuse.decorators import observe, langfuse_context observe() def main(): trace_id langfuse_context.get_current_trace_id() print(trace_id)第四个坑认为 Langfuse 能捕获所有大模型调用。实际上只有通过 SDK 接入的部分才会被记录。如果你的代码在另一个子进程里调用模型或者通过调 HTTP 服务间接访问模型Langfuse 看不到内部 prompt 和响应只能记录到外部服务名这类信息。第五个坑数据量涨起来后页面查询会明显变慢。Langfuse 官方默认配置在小规模项目里没问题但如果每天几十万条 trace建议提前考虑数据库存储分表策略或者使用官方部署推荐的高配置。别等到日志库已经几十 GB 再来处理。8. 真正的落地顺序和边界如果你准备在现有智能体项目里接入 Langfuse我的建议是先不要追求把所有功能都吃透。按这个顺序推进先接基础 trace让输入输出、耗时和 token 能在界面看到再给关键环节拆 span比如检索、工具调用、意图分类然后定义两三个最关心的评分项最后再考虑 Prompt 管理、数据集和批量回归。这个顺序前两步解决的是“能不能看清”后两步解决的是“能不能比较”。如果一开始就把时间花在搭建复杂的自动评分体系上反而容易因为 trace 链路不完整导致评分没有意义。Langfuse 不是一个“装上就自动优化性能”的工具。它真正改变的是你排查和评估问题的方式。过去面对 Agent 回答错误你可能要做大量假设现在你能看到链路全貌把问题限定到某个 span。性能优化也不再只是看慢函数日志而是能看到一次请求里模型调用、工具调用和上下文拼接的耗时结构从而找到更值得花力气的地方。同时它也解决了一个团队协作问题Prompt 修改和模型调用评估可以沉淀成结构化数据而不是散落在聊天记录和手工记录表里。每次改进都有 trace、分数和时间线项目的演化过程也会更透明。最后留一个我自己判断 Langfuse 使用成熟度的参考不是看接了多少个装饰器也不是看 API 调用量而是当别人问你“上周改的 Prompt 到底有没有用”时你能不能直接打开一个对比页面让结果自己说话。能做到这一点这套观测评估体系才算真正落地。