手把手教你为 AI 应用接入专有的可观测平台,追踪每一次模型调用、Token 消耗与成本。
写在前面
在前文中,我们分别介绍了 ARMS (阿里云商业方案,需挂载 Java Agent)和 Zipkin(开源通用链路追踪,基于 Micrometer + Brave)。这两个方案都能帮我们"看到" AI 应用内部发生了什么,但它们并不是为 AI 场景量身定做的------比如,你无法直接看到某次对话消耗了多少 Token、花了多少钱。
本篇文章的主角 LangFuse,正是为解决 AI 应用观测痛点而生的开源平台。我们将通过一个完整的 Spring AI Alibaba 示例项目,带你理解它背后的原理,并亲手将它跑起来。
🔖 本文适合:正在使用 Spring AI Alibaba 开发 LLM 应用的开发者,希望获得比普通链路追踪更深入的 AI 调用分析。
一、 AI 专用可观测性
在传统微服务中,我们关心的是:
- 请求耗时
- 错误率
- 调用链关系
在 AI 应用中,还需要关注:
- 每次对话的 Token 输入/输出数量
- 不同模型(如 qwen-max、gpt-4)的 单次与累计成本
- Prompt 和 Completion 的 真实内容(用于调试和审计)
- 工具调用(Tool Calling)的 参数与结果
通用链路追踪系统(如 Zipkin、Jaeger)并不解析 LLM 请求体,自然无法提供上述信息。而 LangFuse 在 OpenTelemetry 标准之上,额外解析了 AI 调用的语义字段,从而生成 Token 统计、成本分析等报表。
二、LangFuse 整体架构(含 Mermaid 图)
下图展示了用户请求进入 Spring Boot 应用,经过 OpenTelemetry 埋点,最终上报到 LangFuse 的完整数据流:
Spring Boot 应用
方法调用被拦截
创建/结束 Span
每隔几秒导出
OTLP/HTTP + Protobuf
解析 AI 语义
展示
HTTP 请求
用户 / 客户端
AI Controller
Chat / Image / Embedding
Spring AI Bean
如 ChatClient, ImageModel
OpenTelemetry Instrumentation
自动拦截 AI 调用
OpenTelemetry SDK
生成 Span + Metrics
OtlpHttpExporter
批量上报
LangFuse OTLP Collector
https://cloud.langfuse.com/api/public/otel
LangFuse 存储
LangFuse 控制台
Traces / Analytics / Prompts
开发者 / 运维
原理说明:
- Spring AI 内部已集成 Micrometer Observation API。当调用
ChatClient、ImageModel等方法时,会自动生成一个Observation(观测上下文)。 - 项目中加入
opentelemetry-spring-boot-starter后,Micrometer 的Observation会被桥接到 OpenTelemetry 的Span。 - OpenTelemetry SDK 负责采样、合并 Span,并通过
OtlpHttpExporter定期将数据以 Protobuf 格式发送到配置好的 OTLP Endpoint。 - LangFuse 的 OTLP 接收器不仅存储通用 Span,还会识别
gen_ai.开头的属性(如gen_ai.request.model、gen_ai.usage.input_tokens),从而生成 AI 专用的可视化面板。
三、十分钟快速体验:从零到看见 Trace
3.1 准备环境
确保你的电脑上有:
- JDK 17+(推荐 Eclipse Temurin 或 Oracle OpenJDK)
- Maven 3.8+
- Git
bash
java -version
mvn -version
git --version
3.2 注册 LangFuse 云端账号(免费)
LangFuse 提供免费云端版,非常适合测试------不需要自己维护数据库。
- 访问 https://cloud.langfuse.com,点击 Sign up(可用 GitHub 登录)。
- 验证邮箱后登录,点击 + New Project ,取名
spring-ai-demo,环境选Development。 - 进入左下角 Settings → API Keys ,点击 Create API Key 。你会得到:
Public Key(形如pk-lf-xxxxxxxx)Secret Key(形如sk-lf-xxxxxxxx)
⚠️ 密钥只显示一次,请妥善保存。
3.3 生成 Base64 认证头
LangFuse 的 OTLP 端点使用 HTTP Basic Auth ,用户名 = Public Key,密码 = Secret Key。我们需要将它们 base64 编码后放在 Authorization: Basic 头中。
在终端执行(替换成你真实的 Key):
bash
echo -n "pk-lf-xxxxxx:sk-lf-xxxxxx" | base64
# 输出类似:cGstbGYtbnVsbDpzay1sZi1udWxs
记下这个 Base64 字符串,稍后要用。
3.4 获取通义千问 API Key
访问 阿里云百炼平台控制台,创建 API Key(形如 sk-xxxx)。
3.5 下载并配置示例项目
bash
git clone https://github.com/alibaba/spring-ai-alibaba.git
cd spring-ai-alibaba/spring-ai-alibaba-observability-example/observability-langfuse-example
编辑 src/main/resources/application.yml,或通过环境变量配置。推荐使用环境变量(避免硬编码密钥):
bash
export AI_DASHSCOPE_API_KEY="sk-你的通义千问Key"
export LANGFUSE_BASE64_AUTH="你的Base64字符串"
如果希望直接修改 application.yml,找到下面片段并替换:
yaml
exporter:
otlp:
endpoint: "https://cloud.langfuse.com/api/public/otel"
headers:
Authorization: "Basic ${LANGFUSE_BASE64_AUTH}" # 注意这里会读取环境变量
3.6 启动应用
bash
mvn clean spring-boot:run
看见 Tomcat started on port 8080 即成功。
3.7 发起测试请求并查看观测数据
打开另一个终端,执行:
bash
# 1. 普通对话
curl "http://localhost:8080/observability/chat?prompt=你好,请介绍自己"
# 2. 向量化(embedding)
curl "http://localhost:8080/observability/embedding"
# 3. 生成图片(会下载png)
curl "http://localhost:8080/observability/image/generate" -o test.png
# 4. 工具调用(天气)
curl "http://localhost:8080/observability/tools?prompt=杭州天气如何"
然后登录 LangFuse 控制台,点击 Traces,你会看到每条请求对应一条 Trace,点进去可以查看:
- 模型名称(qwen-max)
- 输入 Prompt 内容
- 输出 Completion 内容
- Token 用量(输入/输出)
- 耗时与 Metadata
切换到 Analytics 页面,还能看到 Token 趋势图和成本估算。
四、核心依赖与原理详解
很多开发者困惑:为什么只加了几行依赖,AI 调用就能自动上报?下面我们来剖析 pom.xml 中关键的几个模块。
xml
<!-- Spring AI 观测自动配置(关键!) -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-autoconfigure-model-chat-observation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-autoconfigure-model-embedding-observation</artifactId>
</dependency>
<!-- 图片、向量存储等类似,不一一列举 -->
<!-- OpenTelemetry Spring Boot Starter -->
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-spring-boot-starter</artifactId>
<version>2.9.0</version>
</dependency>
<!-- Micrometer 到 OpenTelemetry 的桥接 -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
<!-- OTLP 导出器 -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
原理详解:
| 组件 | 职责 |
|---|---|
spring-ai-autoconfigure-*-observation |
为每个 AI 模型(Chat、Embedding、Image)定义 Observation 约定:何时开始、结束、记录哪些字段(prompt、completion、token 用量等)。 |
opentelemetry-spring-boot-starter |
自动配置 OpenTelemetry SDK,并开启对常见框架(WebClient、RestTemplate、数据源)的埋点。它会读取 otel.* 配置。 |
micrometer-tracing-bridge-otel |
关键桥接层:使 Micrometer 的 Observation 与 OpenTelemetry 的 Span 互通。Spring AI 发出 Observation 事件 → 桥接器自动创建/结束 OpenTelemetry Span。 |
opentelemetry-exporter-otlp |
将 OpenTelemetry Span 和 Metrics 通过 OTLP 协议(HTTP/gRPC)发送到远端 Collector。LangFuse 正是扮演了 OTLP Collector 的角色。 |
💡 通俗比喻:Observation 是"事件日记本",桥接器是"翻译官",OTLP 导出器是"快递员",LangFuse 是"AI 专项仓库"。
五、配置的常见困惑与最佳实践
原示例中存在两处 observations 配置,容易混淆。我们梳理出清晰、推荐的配置结构:
yaml
spring:
application:
name: observability-langfuse-demo
ai:
dashscope:
api-key: ${AI_DASHSCOPE_API_KEY}
# 统一的 AI 观测开关
observations:
log-prompt: true # 在日志中打印 prompt
log-completion: true # 在日志中打印 completion
include-error-logging: true
# OpenTelemetry 相关配置
otel:
service:
name: ${spring.application.name}
traces:
sampler:
always_on # 100% 采样(生产环境可改为概率采样)
exporter:
otlp:
endpoint: "https://cloud.langfuse.com/api/public/otel"
headers:
Authorization: "Basic ${LANGFUSE_BASE64_AUTH}"
logs:
exporter: none # LangFuse 暂时不支持日志导出,避免报错
注意:
spring.ai.observations.*控制 Spring AI 内部的观测行为(是否记录详细内容)。otel.*控制 OpenTelemetry SDK 的导出行为。- 原文档中有
chat.client.observations和顶层observations,它们是不同作用的配置(一个针对 ChatClient 的特定配置,另一个被误用),建议统一使用spring.ai.observations。
六、代码走读:四个 Controller 分别展示了什么?
项目中有四个控制器,对应 AI 能力的观测演示。
6.1 ChatModelController -- 对话流式输出
java
@GetMapping
public Flux<String> chat(@RequestParam(defaultValue = "hello!") String prompt) {
return chatClient.prompt(prompt).stream().content();
}
当执行这个请求时,Spring AI 的 ChatClient 内部会触发 chat.observation,OpenTelemetry 会记录:
gen_ai.request.model(从配置自动获取)gen_ai.request.prompt(如果开启 log-prompt)gen_ai.response.completiongen_ai.usage.input_tokens/output_tokens
6.2 ImageModelController -- 图片生成并直接返回
java
ImageResponse imageResponse = imageModel.call(new ImagePrompt(DEFAULT_PROMPT));
String imageUrl = imageResponse.getResult().getOutput().getUrl();
// ... 代理输出图片流
图片生成也会产生一个独立的 Observation,记录生成参数(如尺寸、质量)和结果 URL。
6.3 EmbeddingModelController -- 文本向量化
嵌入模型调用一般用于 RAG 检索,LangFuse 会记录向量维度(1536 等)和耗时。
6.4 ToolCallingController -- 工具调用(天气查询)
Spring AI 的工具调用会被拆分为多个 Span:一个主 Chat Span + 每个 tool call 的子 Span。LangFuse 能清晰展示模型先决定调用工具,工具返回结果后模型再最终回答的过程。
七、生产环境部署与调优
7.1 打包与运行
bash
mvn clean package -DskipTests
java -jar target/observability-langfuse-example-1.0.0-SNAPSHOT.jar
7.2 Docker 化
创建 Dockerfile:
dockerfile
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY target/*.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
构建并运行:
bash
docker build -t spring-ai-langfuse .
docker run -p 8080:8080 -e AI_DASHSCOPE_API_KEY="xxx" -e LANGFUSE_BASE64_AUTH="xxx" spring-ai-langfuse
7.3 成本控制与采样
生产环境若流量很大,建议降低采样率,同时保留错误请求的 100% 采样。
yaml
otel:
traces:
sampler:
type: traceidratio
ratio: 0.05 # 5% 采样
更高级的方案:使用 parentbased_traceidratio 保证已采样链路的完整性。
7.4 自建 LangFuse(数据不出网)
当你对数据隐私有要求时,可通过 Docker 自建:
bash
git clone https://github.com/langfuse/langfuse.git
cd langfuse/infrastructure/docker
docker-compose up -d
然后修改 application.yml 中的 OTLP endpoint 为 http://your-server:3000/api/public/otel。
八、常见问题解决(真·有效)
8.1 认证失败:401 Unauthorized
原因 :Base64 凭证错误,或未正确设置 Authorization 头。
解决方法:
bash
# 重新生成 base64(注意 -n 参数防止换行)
echo -n "你的公钥:你的私钥" | base64
# 复制输出的字符串,确保没有多余空格
8.2 控制台看不到任何 Trace
排查步骤:
-
检查采样率:确认
otel.traces.sampler.always_on生效。 -
开启 OpenTelemetry 调试日志:
yamllogging.level.io.opentelemetry: DEBUG重启后若看到
Exporting 1 spans...说明数据已发送。 -
确认网络:
curl https://cloud.langfuse.com/api/public/otel能通。 -
等待 10~30 秒:LangFuse 控制台有缓存延迟。
8.3 编译报错 "Name for argument not present"
原因 :Maven 缺少 -parameters 编译参数,导致一些 Spring 参数名反射失败。
解决 :在 pom.xml 的 maven-compiler-plugin 中加入:
xml
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
九、LangFuse vs Zipkin vs ARMS 最终选型建议
| 维度 | Zipkin | LangFuse | ARMS |
|---|---|---|---|
| Token/成本分析 | ❌ | ✅ 专精 | ✅ 需购买 |
| 自建难度 | 低(单一 jar) | 中(需 Postgres+ClickHouse) | 不可自建 |
| 免费额度 | 无限制 | 每月 10k 事件免费 | 有限免费额度 |
| LLM 调试体验 | 一般 | 极好(展示完整对话) | 好(阿里云控制台) |
| 推荐场景 | 简单链路 + 不想付费 | AI 应用首选 | 企业级全栈 + 已有阿里云 |
一句话总结:
- 如果你是个人开发者或创业团队,做 AI 应用 → LangFuse 免费版性价比最高。
- 如果你公司已有阿里云全套服务,且需要基础设施统一监控 → ARMS。
- 如果你只关心调用链是否存在断点,不关心 Token → Zipkin。
十、总结与扩展
通过本文,你已经学会:
- 为什么 AI 应用需要 LangFuse 这类专用观测平台。
- OpenTelemetry 与 Spring AI 观测如何协作。
- 完整搭建一个从配置到运行再到分析的示例项目。
- 解决接入过程中 90% 的常见问题。
下一步可以做的:
- 给应用增加 RAG 链路(如向量数据库检索),LangFuse 会自动记录检索耗时和返回文档数。
- 利用 LangFuse 的 Prompt Management 功能,将 prompt 版本与调用 trace 关联。
- 设置 评分与反馈(用户点赞点踩),LangFuse 支持关联到具体 trace,用于评估模型表现。
如果你在实操中遇到任何问题,欢迎在评论区留言。🚀