尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

LLM可见性实战:从Langfuse可观测性到RAG内容溯源

LLM可见性实战:从Langfuse可观测性到RAG内容溯源 当你在 GitHub Discussion 或 Reddit 里看到有人抛出那句经典的提问——“Has anyone tried this tool to improve LLM visibility?”时提问者往往没有展开细节但做过 LLM 应用的人立刻能理解他想要什么。他想要的是在模型返回一段结果后能清楚地看到这次调用内部到底发生了什么。Prompt 最终是什么样子、RAG 检索到了哪些片段、模型消耗了多少 token、为什么最终给了这个回答这一连串问题如果在生产环境里都答不上来LLM 应用和“黑盒”就没有区别。LLM visibility 不是一个可选项而是 LLM 应用从 Demo 走向工程化的分水岭。个人在 Notebook 里跑通一个聊天机器人确实不需要关注这些可一旦进入测试联调、灰度发布、成本核算、用户反馈排查没有 visibility 的 LLM 应用会让人寸步难行。这篇文章不押注某一个具体工具而是把 LLM visibility 拆成两层运行态可观测性Observability和内容层可见性Content/Source Visibility。我会先讲清楚概念差异再给出一套可以直接跑通的 Langfuse 自建接入实践最后补充知识库类场景AnythingLLM、Dify、LLM wiki的可见性方案。读完你可以立刻判断自己的 LLM 项目该选哪个方向补 visibility以及怎么落地。1. LLM visibility 到底是什么先分清两层含义很多开发者第一次接触 visibility 这个词是从 LLM 可观测性工具的宣传语里看到的。但严格来说visibility 在 LLM 应用里至少有两层含义把它们混为一谈会导致选型错误。第一层是运行态可观测性。它关心的是 LLM 应用作为一个软件系统调用链是否可见包括每次请求的 Prompt 和原始响应输入输出 token 数量模型名称、温度等参数调用耗时和失败原因多步链路中每个节点的输入输出尤其典型的是 RAG 和 Agent 场景成本分摊和用量统计。这一层对应的技术栈和传统后端项目的 APMApplication Performance Monitoring应用性能监控有些相似但对象从 HTTP 接口扩展到了模型调用和 AI Agent 的推理链。代表性工具是 Langfuse、LangSmith、Arize Phoenix、Helicone。第二层是内容层可见性。它关心的是模型回答是不是“有据可查”。比如一个 RAG 聊天机器人回答了“报销流程是什么”用户想知道这个回答来自哪一篇文档而不是模型凭空编造。知识库产品里的“引用来源”“文档命中列表”“相似度分数”都属于内容层可见性。如果你在用 AnythingLLM 或 Dify 搭建知识库对这种体验应该不陌生。在这两层之外还有一种更偏开发者个人实践的 visibility把 LLM 相关的模型配置、Prompt 模板、排错记录沉淀成一个可检索的 Markdown 知识库。社区里常说的LLM wiki以及用 Obsidian 管理 LLM 笔记本质上是让“认知过程”可见方便自己在项目里快速复用和迭代。层面关注对象典型工具/方法核心价值运行态可观测性调用链、Token、耗时、成本Langfuse、LangSmith、Helicone、Phoenix定位问题、优化 Prompt、成本归因内容层可见性引用来源、命中片段、相似度AnythingLLM 引用、Dify 日志防止幻觉、增强可信度认知层可见性个人知识沉淀Obsidian、LLM wiki减少重复试错沉淀经验明白了这层区分之后再看“提升 LLM visibility 的工具”就清晰很多不同工具解决的是不同层面的可见性问题。2. 为什么 LLM 应用跑起来容易“不可见”三大黑盒要理解这些工具的价值得先知道 LLM 应用为什么比传统应用更难观测。我总结为三个黑盒。2.1 模型推理黑盒传统 API 返回一个 JSON字段是确定的报错信息是明确的。LLM 返回的是自然语言而且同样的 Prompt 每次都可能给出不同回答。模型内部为什么生成这些 token从技术上是很难完全解释的。你能做的是把输入和输出都记录下来然后通过对比多次调用来判断是 Prompt 的问题、模型的问题还是上下文的问题。没有 trace 数据你连对比的依据都没有。2.2 上下文工程黑盒RAG 应用看起来是“问一个问题得到一个答案”但中间实际上经历了问题改写、向量检索、重排序、Prompt 拼接、模型生成五个阶段。任何一个阶段出问题最终答案都会偏。比如检索到的 Top 3 文档其实和问题无关但模型依然会强行基于它们作答。这种问题从表面回答里很难定位必须看到中间每一跳的输入输出。RAG 增强 LLM 的调试本质上就是在排查上下文工程黑盒。2.3 成本与质量黑盒传统后端接口的瓶颈往往是 CPU、内存、数据库连接指标非常明确。LLM 应用的成本单位和质量单位都是 token输入 token 多少、输出 token 多少、缓存命中多少、哪个用户消耗最多。没有 usage 统计你无法回答“这个功能每个月要烧多少钱”这种最基础的经营问题。更麻烦的是如果接入了多个模型供应商模型之间的成本对比也无法做。所以很多团队先用网关层记录 token再逐步上可观测平台这是完全合理的演进路径。这三个黑盒叠加起来就形成了 LLM 应用特有的“可见性缺口”。补上这个缺口正是后面要介绍的工具要解决的问题。3. 提升 LLM visibility 的 5 类代表性工具与选型逻辑目前市面上能提升 LLM visibility 的工具很多但类型完全不同。我按实现方式和适用场景把它们分成 5 类。3.1 工具全景类型代表工具开源/商业特点LLM 可观测追踪平台Langfuse、LangSmith、Arize Phoenix、WB Weave、MLflow混合提供 Trace、Span、Token、评估、Prompt 管理LLM API 网关/代理Helicone、Portkey混合通过代理层统一记录日志、成本、限流OpenTelemetry 扩展Traceloop OpenLLMetry开源把 LLM 调用转成标准 OTel Span对接现有链路框架内置可观测能力LangGraph Studio、Dify 运行日志、AnythingLLM 引用混合不用额外接入框架自带部分可见性知识管理与认知可见性Obsidian LLM wiki、AnythingLLM 知识库开源/免费沉淀知识、展示引用来源3.2 选型逻辑选型不需要追求功能最多的工具而是看你的场景在哪一层。如果团队已经使用 LangChain、LangGraph 深度开发你的项目又接受 SaaSLangSmith 的集成成本最低基本是配置环境变量就能看到完整链路。如果项目是微服务架构希望把 LLM 追踪纳入统一的 OpenTelemetry 基础设施Traceloop OpenLLMetry 这种扩展更合适。如果需要数据不出公司或者只想做一个内部低成本的可观测平台Langfuse 自托管是非常典型的选择。如果只是用到 Dify 或 AnythingLLM 这一类低代码/开箱即用产品不需要额外接可观测平台先吃透产品自带的日志和引用能力更实际。真正需要警惕的是“先选工具再想问题”。visibility 的起点是明确你缺哪一层数据是缺调用链还是缺来源引用还是缺成本统计。数据需求定了工具自然有答案。4. 实战一用 Langfuse 自建 LLM 可观测平台Langfuse 是目前 LLM 可观测性领域最常被提到的开源方案之一项目开源、可自托管支持 OpenAI SDK、LangChain、LlamaIndex 等主流生态的自动埋点并且能展示 Token 用量、延迟、成本和完整的 Trace 树。下面演示如何在本地把它跑起来并接入一个 Python 调用。4.1 环境准备推荐环境Linux 或 macOSWindows 可通过 WSL2 运行 DockerDocker Engine 和 Docker ComposePython 3.9版本请以 Langfuse 官方要求为准本文演示通用思路一个可用的 OpenAI 兼容 API Key用于测试真实调用。docker compose命令需要能正常访问 Docker Hub 拉取镜像。如果你在中国大陆的网络环境无法直接拉取 Docker 官方镜像请先为 Docker 配置可用的镜像源再继续操作。4.2 部署 LangfuseLangfuse 官方仓库提供了完整的 Docker Compose 编排文件。推荐做法是拉取官方仓库进入docker目录启动git clone https://github.com/langfuse/langfuse.git cd langfuse/docker cp .env.example .env docker compose up -d如果你不想 clone 整个仓库也可以直接获取官方docker-compose.yml和.env.example放到独立目录中然后执行docker compose up -d。这个流程会启动 Web 应用、PostgreSQL 数据库、Redis 等基础组件。启动完成后浏览器访问http://localhost:3000注册管理员账号并登录。首次启动的默认端口和基础配置都在.env中如果你改了端口后面 SDK 的LANGFUSE_HOST也要对应修改。4.3 创建项目并获取密钥登录 Langfuse Web 界面后在项目设置中创建一个新项目然后在项目 API Keys 区域创建一对密钥Public Key类似pk-lf-...Secret Key类似sk-lf-...。后面 Python SDK 通过这两个 Key 完成鉴权LANGFUSE_HOST指定自建实例地址。4.4 接入 OpenAI SDK先安装依赖pip install langfuse openaiLangfuse 提供了langfuse.openai的自动集成模块。你只需要在原来的 OpenAI 调用代码上加上observe()装饰器Langfuse 就会自动记录该函数的输入输出、Token 用量和耗时。创建一个 Python 文件llm_visibility_demo.py# 文件路径llm_visibility_demo.py import os import time from langfuse.decorators import observe from langfuse.openai import openai # 从环境变量读取 Langfuse 配置 os.environ.setdefault(LANGFUSE_PUBLIC_KEY, pk-lf-你的公钥) os.environ.setdefault(LANGFUSE_SECRET_KEY, sk-lf-你的私钥) os.environ.setdefault(LANGFUSE_HOST, http://localhost:3000) # 设置模型供应商的 API Key openai.api_key os.environ.get(OPENAI_API_KEY) observe() def ask_llm(question: str) - str: 一行装饰器让整个函数变成可观测的 trace。 resp openai.chat.completions.create( modelgpt-4o-mini, messages[ {role: system, content: 你是一个严谨的技术助手回答尽量简洁。}, {role: user, content: question}, ], ) return resp.choices[0].message.content if __name__ __main__: answer ask_llm(什么是 LLM visibility) print(answer) print(等待 2 秒让异步上报完成...) time.sleep(2)这段代码的关键点有两个一是observe()装饰器。它会把ask_llm函数包裹成一个 Trace函数内的 LLM 调用自然成为 Trace 下的 Span。二是from langfuse.openai import openai。这一步非常关键如果你从openai原始模块导入Langfuse 就无法自动捕获 Token 用量和模型调用耗时必须使用它包装后的 openai 模块。运行方式export OPENAI_API_KEY你的 OpenAI API Key python llm_visibility_demo.py运行成功后程序会正常打印模型返回内容。此时打开http://localhost:3000在 Traces 页面应该能看到一条新的 trace 记录。4.5 接入 LangChain如果你的项目用 LangChain 组装链路Langfuse 也提供了 Callback Handler。示例代码如下# 文件路径langchain_langfuse_demo.py import os from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage from langfuse.callback import CallbackHandler os.environ.setdefault(LANGFUSE_PUBLIC_KEY, pk-lf-你的公钥) os.environ.setdefault(LANGFUSE_SECRET_KEY, sk-lf-你的私钥) os.environ.setdefault(LANGFUSE_HOST, http://localhost:3000) langfuse_handler CallbackHandler() llm ChatOpenAI(modelgpt-4o-mini) response llm.invoke( [HumanMessage(content介绍一下 RAG 检索增强生成)], config{callbacks: [langfuse_handler]}, ) print(response.content)这种方式适合已经用 LangChain 写了链路的团队基本上是在原来的invoke配置里加一个callbacks参数即可侵入性非常小。4.6 手动创建 Trace 与 Span自动埋点适合标准调用场景。但对于自定义业务逻辑比如“先查数据库再调模型最后做后处理”这类链路手动创建 Trace 和 Span 更灵活。下面是手动上报的示例# 文件路径manual_trace_demo.py import os import time from langfuse import Langfuse os.environ.setdefault(LANGFUSE_PUBLIC_KEY, pk-lf-你的公钥) os.environ.setdefault(LANGFUSE_SECRET_KEY, sk-lf-你的私钥) os.environ.setdefault(LANGFUSE_HOST, http://localhost:3000) langfuse Langfuse() def handle_question(question: str): # 创建整个业务请求的 trace trace langfuse.trace( namerag-query, input{question: question}, metadata{source: demo, user_id: user_demo_001}, ) # 模拟检索阶段 retrieval_span trace.span(namevector-search, input{query: question}) time.sleep(0.3) retrieval_span.end(output{chunks: [doc_1, doc_2], top_score: 0.87}) # 记录一次模型生成 generation trace.generation( namechat-completion, modelgpt-4o-mini, model_parameters{temperature: 0.2}, input{messages: [{role: user, content: question}]}, output{message: 这是根据检索结果生成的回答。}, usage{input: 45, output: 120, total: 165}, ) generation.end() trace.update(output{answer: 这是根据检索结果生成的回答。}) handle_question(报销流程是什么) print(手动 trace 已上报等待异步刷新...) time.sleep(3)运行之后在 Langfuse 的 Traces 页面里你会看到rag-query这个 Trace 下面挂着一个vector-searchSpan 和一个chat-completionGeneration。这种手动埋点的好处是可以把业务语义和模型调用统一建模适合在复杂业务链路中快速定位瓶颈。5. 实战二用 LangSmith 和 OpenTelemetry 打通已有链路Langfuse 是自托管路线的一个代表。如果你的团队用了 LangChain 但不想自建平台希望在模型提供商后台直接查看完整链路LangSmith 是另一个选择。LangSmith 是 LangChain 生态的商业产品接入方式非常轻量。你只需要设置几个环境变量# 文件路径langsmith_env_demo.py import os # 开启 LangChain Tracing os.environ[LANGCHAIN_TRACING_V2] true os.environ[LANGCHAIN_API_KEY] lsv2-你的密钥 os.environ[LANGCHAIN_PROJECT] my-llm-project from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage llm ChatOpenAI(modelgpt-4o-mini) response llm.invoke([HumanMessage(content你好)]) print(response.content)设置完成后LangChain 的每次调用会自动上报到 LangSmith 后台包括 Prompt、响应、Token 用量、延迟、模型调用链。对于已经深度绑定 LangChain 生态的团队这个接入成本是所有方案里最低的。如果你的团队已经有一套 OpenTelemetry 基础设施比如用 Jaeger、Grafana Tempo 或自建 Collector那么更推荐的路线是 Traceloop OpenLLMetry。它的核心思路是把 OpenAI 调用、LangChain 调用、向量数据库调用统一转成标准的 OpenTelemetry Span这样 LLM 调用就能和普通后端服务共享同一套链路追踪体系不需要额外维护一个独立的可观测平台。这种方式适合微服务数量多、已经有统一可观测基建的中大型团队。它带来的问题是你需要在基础设施里配置 OTLP Exporter 才能看到数据部署成本比 Langfuse 自托管略高但长期看可以和现有监控体系融为一体。6. 内容层可见性AnythingLLM、Dify 与 LLM wiki前面几节讲的是运行态可观测性下面回到内容层可见性。这个方向常常被开发者忽视但在实际业务中它和用户体感直接相关。6.1 AnythingLLM 的引用可见性如果你用 AnythingLLM 搭建知识库问答机器人它天然会展示“引用来源”。用户提问后回答区域会展示命中的文档片段和相关度这就是内容层可见性的体现。它解决的核心问题是模型回答是否可信用户能不能自己去核对原文。在 RAG 增强 LLM 的场景里引用来源的 visibility 意义重大。它可以显著降低幻觉带来的信任问题模型如果回答错误用户可以通过来源文档快速发现运维人员也可以根据引用命中的文档反推向量检索效果。6.2 Dify 的运行日志与工作流可见性Dify 这类 LLM 应用开发平台内置了工作流运行日志。你可以在日志中看到每个知识库检索节点的输入输出、命中文档和相似度分数。对于不是以代码为核心的项目这种产品内置的 visibility 已经足够日常调试不需要额外接入 Langfuse。不过要提醒一点内置日志通常只保留在平台内部不适合做长期成本归因和跨项目对比。如果公司同时运行多个 Dify 应用还是建议把日志导出到统一的存储或可观测平台。6.3 LLM wiki用 Markdown 沉淀认知可见性社区里提到的 LLM wiki 并不是一个固定工具而是一种实践维护一份自己的、可持续更新的 LLM 知识库。你可以用 Obsidian 或任意 Markdown 编辑器来建重点是把散落在聊天记录、博客、官方文档里的信息片段整理成结构化知识。一个推荐的目录结构如下llm-wiki/ ├── 01-基础概念/ │ ├── token.md │ ├── 上下文窗口.md │ └── temperature.md ├── 02-模型与供应商/ │ ├── 模型对比.md │ └── API-Key管理.md ├── 03-Prompt-Templates/ │ ├── 系统提示词模板.md │ └── RAG-Prompt模板.md ├── 04-实战案例/ │ ├── RAG调试记录.md │ └── Agent工具调用问题.md └── 05-排错记录/ ├── 常见报错汇总.md └── Token超限处理.md这套方法和运行态可观测性的关系在于可观测平台解决“当前系统在跑什么”的问题LLM wiki 解决“过去踩过什么坑、为什么这么配置”的问题。两者结合团队的知识才不会只停留在个人脑子里。7. 运行结果与效果验证Langfuse 接入后怎么判断系统真的在正常工作不一定非得等到出问题再排查可以先做一个最小验证。启动 Langfuse 后用账号登录进入 Traces 页面。然后运行一次 4.4 节中的 Python 文件。如果集成成功你会在 Traces 列表中看到一条新的 trace时间戳是刚才请求的时间。点击这条 trace左侧是完整的调用树右侧是详细信息。你应该能看到函数名ask_llm输入问题和模型返回的完整回答模型名称、Token 用量请求耗时和延迟。如果 Trace 列表为空先回到代码检查LANGFUSE_HOST是否正确指向http://localhost:3000再检查LANGFUSE_PUBLIC_KEY和LANGFUSE_SECRET_KEY是否复制完整。还有一个容易被忽略的点Langfuse 的上报是异步的运行完脚本后稍微等 1 到 3 秒再刷新页面。验证通过后我建议把验证脚本保留下来作为接入新项目的冒烟测试用例。每次接入新的模型或修改 Prompt 时跑一遍这个脚本通过 Trace 页面确认数据能够正常上报再进入功能开发。8. 常见问题与排查思路以下是我认为最值得先收藏的排查清单都是实际项目中容易踩的坑。问题现象可能原因排查方式解决方案Langfuse 页面一直没有新 Trace环境变量未生效、公钥/私钥不匹配、上报是异步的检查 Linux 环境变量是否真的注入等待 2~3 秒刷新页面重启 Python 进程确认LANGFUSE_HOST可访问Trace 里 Token 用量显示为 0用了原始 OpenAI SDK 而不是langfuse.openai或模型供应商未返回 usage在代码中打印resp.usage确认是否为空改用 Langfuse 包装模块手动填充 usage 字段报错provider rejected the request schema or tool payloadTool calling 参数结构与该模型不兼容打印实际请求 payload重点看tools参数格式调整 Tool Schema或暂时关闭工具调用测试定位报错llm request timed out模型推理时间过长、供应商响应慢、客户端超时设置过短查看供应商后台和可观测平台中的耗时数据增加超时时间开启流式输出必要时切换更低延迟模型只看到单个 Span没有完整调用链业务代码没有把多个操作挂到同一个 Trace检查是否使用了trace.span()或装饰器嵌套用observe()或手动创建 Trace 并关联 spanDocker 容器启动后反复重启镜像使用latest导致组件版本不兼容或.env配置错误docker compose logs查看容器日志固定镜像 Tag按环境变量模板检查配置Trace 数据包含用户敏感内容没有做数据脱敏直接上报查看 Trace 中的输入输出内容接入时过滤手机号、身份证、Token 等敏感信息9. 最佳实践让 LLM visibility 真正落地工具接入只是开始真正让 LLM visibility 发挥作用的是工程规范。这里分享几条值得长期坚持的建议。第一尽早接入不要等到线上出问题再补。LLM 应用的问题很多时候是“没有对比就没有结论”。你需要在版本迭代之前就有链路数据才能通过 diff 定位是哪次改动导致回答质量下降。Debug 的黄金法则是先有观测后有判断。第二统一 Trace 命名和元数据。在 Langfuse 或 LangSmith 里建议统一 trace 的 name 和 metadata 结构。比如trace.span(namevector-search)固定叫vector-search不要在不同代码路径里叫search和retrieve混着来。metadata 里统一放入user_id、project_id、model_name等字段后续做成本归因时才能按维度聚合。第三生产环境默认脱敏。LLM 应用的输入输出往往包含用户问题、内部文档、业务数据。如果使用 SaaS 可观测平台必须先做敏感信息过滤。自托管 Langfuse 时同样要在入口层过滤身份证号、手机号等个人信息。这里真正容易踩坑的是开发环境上传了真实数据然后导出的数据又被用于其他分析。第四固定版本避免 latest。自托管 Langfuse 或任何 Docker 服务生产环境都要固定镜像 Tag不要使用latest。否则一次docker compose pull就可能带来破坏性变更。每次升级前先备份 PostgreSQL 数据并先在预发环境验证。第五让 Trace 和业务指标打通。visibility 的最终目标不是“能看图”而是“能回答问题”。建议把 Token 消耗、成功率、平均延迟同步到告警系统。当某个应用 Token 成本异常上涨时第一件事不是大事渲染而是到 trace 列表里按项目、用户、模型维度筛选找出到底是哪个环节在烧钱。第六最小权限原则。公司内部使用可观测平台时不要所有人都能看所有项目的 Trace。管理员、开发、运维的权限要区分开。模型调用密钥和可观测平台密钥都应该放到配置中心或密钥管理服务里而不是写死在代码仓库。10. 最后不要忘了最基础的可见性回看开头那个问题Has anyone tried this tool to improve LLM visibility? 无论你最终选 Langfuse、LangSmith 还是 Dify 自带日志有一个习惯比工具更重要所有 LLM 调用都要先打印原始 Prompt 和原始响应再做结构化 Trace。这句建议听起来简单但大量线上问题靠的就是这两行原始日志定位出来的。你不需要等一个完美平台从今天起在自己的 LLM 项目里加上最基础的输入输出日志然后再逐步接入 Trace、Token 统计和成本归因。visibility 不是一步到位的它是一次次“多记一条信息、多留一条后路”的结果。先让数据可见再谈优化。
返回列表