通过 OpenTelemetry 实现 LLM 可观测性
OpenTelemetry 是 CNCF 项目,提供一套规范、API 和库,定义了从应用收集分布式 trace 和指标的标准方式。
Litefuse 可以作为 OpenTelemetry Backend 工作,在 /api/public/otel(OTLP)端点接收 trace。除了 Langfuse SDK 和 原生集成 之外,这个 OpenTelemetry 端点旨在提升与 SDK 与原生集成之外的框架、库和语言的兼容性。常用的 OpenTelemetry 库包括 OpenLLMetry 和 OpenLIT,它们将 Litefuse tracing 的语言支持扩展到 Java 与 Go,并覆盖 AutoGen、Semantic Kernel 等框架。
由于 GenAI trace 属性的 Semantic Conventions 仍在演进中,Litefuse 会将收到的 OTel trace 映射到 Litefuse 数据模型,并支持 OTel GenAI 生态中常见的额外属性(属性映射)。如果某个集成未按预期工作或没有解析到正确的属性,请 提交 issue。
同时使用其他基于 OTEL 的工具? 如果你将 Litefuse 与其他基于 OpenTelemetry 的工具一起使用,可能会出现冲突。配置指引见 将 Litefuse 与已有的 OpenTelemetry 设置一起使用。
接入选项
OpenTelemetry 原生 Langfuse SDK v3
最快开始使用 Litefuse 进行 tracing 的方式是新的 OTEL 原生 Langfuse SDK v3。该 SDK 是官方 OpenTelemetry 客户端之上的薄层,会自动将发出的 span 转换为丰富的 Litefuse observation(spans、generations、events 以及 其他 observation 类型),并为 token 用量、成本追踪、prompt 关联和打分等 LLM 专属能力提供一等公民式的辅助函数。
由于它运行在共享的 OpenTelemetry 上下文中,其他被 OTEL 插桩的库产生的 span 也可以被导出到 Litefuse。默认情况下,Litefuse 会聚焦于与 LLM 相关的 span(Langfuse SDK 的 span、带 gen_ai.* 属性的 span,以及已知的 LLM instrumentor)。如需导出全部内容,可以按 SDK 进阶文档 中的说明使用宽松的自定义过滤器。
可以从这里的 Python 实现专属指南开始:/docs/observability/sdk/overview。
OpenTelemetry 端点
Litefuse 可以在 /api/public/otel(OTLP)端点接收 trace。
如果你使用的是基于 OpenTelemetry SDK 导出 trace 的 Collector,可以使用以下配置:
OTEL_EXPORTER_OTLP_ENDPOINT="https://litefuse.cloud/api/public/otel"
# OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:3000/api/public/otel" # 🏠 Local deployment (>= v3.22.0)
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic ${AUTH_STRING}"Litefuse 使用 Basic Auth 来鉴权请求。
可以使用以下命令获取 base64 编码后的 API Key(即 AUTH_STRING):echo -n "pk-lf-1234567890:sk-lf-1234567890" | base64。
对于较长的 API Key,在 GNU 系统上你可能需要在末尾加上 -w 0,因为 base64 默认会自动按列换行。
如果你的 collector 需要按信号类型设置环境变量,trace 端点是 /api/public/otel/v1/traces。
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://litefuse.cloud/api/public/otel/v1/traces"请注意,Litefuse 目前支持基于 HTTP 的 OTLP,包括 HTTP/JSON 和 HTTP/protobuf。gRPC 暂不支持。
通过 OpenTelemetry SDK 自定义
你可以使用 OpenTelemetry SDK,按上述配置直接将 trace 导出到 Litefuse。这样 Litefuse 的语言支持就被扩展到 Langfuse SDK(Python 与 JS/TS)之外的语言。
使用 OpenTelemetry GenAI 插桩库
任何兼容 OpenTelemetry 的插桩都可以用来将 trace 导出到 Litefuse。可以参考下面这些常用插桩 SDK 的端到端示例来快速开始:
库
OpenTelemetry 插桩库对比
| 类别 | 项目 | OpenLLMetry | openlit | Arize |
|---|---|---|---|---|
| LLMs | AI21 | ✅ | ||
| Aleph Alpha | ✅ | |||
| Amazon Bedrock | ✅ | ✅ | ✅ | |
| Anthropic | ✅ | ✅ | ✅ | |
| Assembly AI | ✅ | |||
| Azure AI Inference | ✅ | |||
| Azure OpenAI | ✅ | ✅ | ||
| Cohere | ✅ | ✅ | ||
| DeepSeek | ✅ | |||
| ElevenLabs | ✅ | |||
| GitHub Models | ✅ | |||
| Google AI Studio | ✅ | |||
| Google Generative AI (Gemini) | ✅ | |||
| Groq | ✅ | ✅ | ✅ | |
| HuggingFace | ✅ | ✅ | ✅ | |
| IBM Watsonx AI | ✅ | |||
| Mistral AI | ✅ | ✅ | ✅ | |
| NVIDIA NIM | ✅ | |||
| Ollama | ✅ | ✅ | ||
| OpenAI | ✅ | ✅ | ✅ | |
| OLA Krutrim | ✅ | |||
| Prem AI | ✅ | |||
| Replicate | ✅ | |||
| SageMaker (AWS) | ✅ | |||
| Titan ML | ✅ | |||
| Together AI | ✅ | ✅ | ||
| vLLM | ✅ | |||
| Vertex AI | ✅ | ✅ | ✅ | |
| xAI | ✅ | |||
| Vector DBs | AstraDB | ✅ | ||
| Chroma | ✅ | |||
| ChromaDB | ✅ | |||
| LanceDB | ✅ | |||
| Marqo | ✅ | |||
| Milvus | ✅ | ✅ | ||
| Pinecone | ✅ | ✅ | ||
| Qdrant | ✅ | ✅ | ||
| Weaviate | ✅ | |||
| Frameworks | AutoGen / AG2 | ✅ | ✅ | |
| ControlFlow | ✅ | |||
| CrewAI | ✅ | ✅ | ✅ | |
| Crawl4AI | ✅ | |||
| Dynamiq | ✅ | |||
| EmbedChain | ✅ | |||
| FireCrawl | ✅ | |||
| Guardrails AI | ✅ | ✅ | ||
| Haystack | ✅ | ✅ | ✅ | |
| Julep AI | ✅ | |||
| LangChain | ✅ | ✅ | ✅ | |
| LlamaIndex | ✅ | ✅ | ✅ | |
| Letta | ✅ | |||
| LiteLLM | ✅ | ✅ | ✅ | |
| mem0 | ✅ | |||
| MultiOn | ✅ | |||
| Phidata | ✅ | |||
| SwarmZero | ✅ | |||
| LlamaIndex Workflows | ✅ | |||
| LangGraph | ✅ | |||
| DSPy | ✅ | |||
| Prompt flow | ✅ | |||
| Instructor | ✅ | |||
| GPUs | AMD Radeon | ✅ | ||
| NVIDIA | ✅ | |||
| JavaScript | OpenAI Node SDK | ✅ | ||
| LangChain.js | ✅ | |||
| Vercel AI SDK | ✅ |
基于 OpenTelemetry 的框架集成
- Hugging Face smolagents
- CrewAI
- AutoGen
- Semantic Kernel
- Pydantic AI
- Spring AI
- LlamaIndex
- LlamaIndex Workflows
从 OpenTelemetry Collector 导出
如果你运行了 OpenTelemetry Collector,可以使用以下配置将 trace 导出到 Litefuse:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
memory_limiter:
# 80% of maximum memory up to 2G
limit_mib: 1500
# 25% of limit up to 2G
spike_limit_mib: 512
check_interval: 5s
exporters:
otlphttp/litefuse:
endpoint: "https://litefuse.cloud/api/public/otel"
headers:
Authorization: "Basic ${AUTH_STRING}" # Previously encoded API keys
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlphttp/litefuse]过滤发送到 Litefuse 的 span
如果你希望有选择地将 OTel span 发送给 Litefuse,可以使用 OTel Collector 的 filterprocessor。 它允许你基于属性、span 名称等条件来过滤 span。 由于过滤是在 span 级别生效的,你可能会得到不完整的 trace,所以在使用复杂过滤规则时要谨慎。 Litefuse 还要求 root span 必须发送到我们的后端,以便正确创建 trace。
下面的配置只会转发 gen_ai.system 属性等于 openai 的 span:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
filter/openaisystem:
error_mode: ignore
traces:
span:
- 'attributes["gen_ai.system"] != "openai"'
exporters:
otlphttp/litefuse:
endpoint: "https://litefuse.cloud/api/public/otel"
headers:
Authorization: "Basic ${AUTH_STRING}" # Previously encoded API keys
service:
pipelines:
traces:
receivers: [otlp]
processors: [filter/openaisystem]
exporters: [otlphttp/litefuse]属性映射
Litefuse 致力于兼容 OpenTelemetry GenAI 语义约定 并支持主流的 LLM 插桩框架。
此外,Litefuse 在 langfuse.* 命名空间下使用一些属性,把 OpenTelemetry span 属性直接映射到 Litefuse 数据模型。这些专属属性始终优先于通用的 OpenTelemetry 约定,推荐所有手动插桩应用的用户使用。
如果某个映射或集成未按预期工作或没有解析到正确的属性,请 在 GitHub 上提 issue。
Litefuse 区分 trace 级别属性和 observation 级别属性。
- Trace 级别属性 表示整次交互的共享上下文。如果 Litefuse 在某个 span 上检测到这些属性,会把它们当作整个 trace 的属性。
- Observation 级别属性 描述 trace 内的单个步骤。Litefuse 会将它们保留在 observation 级别。
元数据映射的工作方式
OpenTelemetry span 可以携带任意属性。Litefuse 会根据它们的命名方式以不同方式处理这些属性:
| 属性类型 | 在 Litefuse 中的位置 | 示例 |
|---|---|---|
| 显式元数据映射 | metadata 中的一级 key(可过滤) | langfuse.trace.metadata.customer_tier → metadata.customer_tier |
| 未映射的 OTel 属性 | 嵌套在 metadata.attributes 下(兜底) | http.method → metadata.attributes.http.method |
| 资源属性 | 嵌套在 metadata.resourceAttributes 下 | service.name → metadata.resourceAttributes.service.name |
Langfuse SDK 与标准 OpenTelemetry SDK
- Langfuse SDK 提供了一些工具函数(比如带
metadata参数的update()),它们会自动设置带langfuse.*.metadata.*前缀的属性。这意味着自定义元数据会出现在一级 key 中并可被过滤。 - 标准 OpenTelemetry SDK 会直接把属性设置在 span 上。除非你显式使用
langfuse.trace.metadata.*或langfuse.observation.metadata.*前缀,否则这些属性会落入metadata.attributes兜底区域,无法在 Litefuse 中直接被过滤。
将 trace 属性传播到所有 span
当你使用 OpenTelemetry 插桩将 trace 发送到 Litefuse 时,某些 trace 级别的属性应该被传播到 trace 内的 所有 span,以便在 Litefuse 中进行准确的聚合与过滤。这些属性包括:
userId(通过langfuse.user.id或user.id)sessionId(通过langfuse.session.id或session.id)metadata(通过langfuse.trace.metadata.*设置顶级 metadata key)version(通过langfuse.version)release(通过langfuse.release)tags(通过langfuse.trace.tags)
在未来某个版本中,Litefuse 的聚合查询和过滤将作用于单个 observation(span),而不仅是 trace 级别。这意味着如果你想按这些属性进行过滤或聚合,它们必须出现在 trace 中的每一个 span 上。我们强烈建议现在就实现这种传播,以便兼容未来版本的 Litefuse。
使用 OpenTelemetry Baggage 进行传播
推荐的做法是使用 OpenTelemetry Baggage 配合 BaggageSpanProcessor 把这些属性传播到所有 span。Baggage 是 OpenTelemetry 内置的上下文传播机制,可以自动把指定的键值对复制到 trace 上下文中的所有 span。
要实现这个模式:
- 在 trace 起始处把目标属性设置为 baggage 条目
- 在当前激活的 span 上设置这些属性
- 在你的 OpenTelemetry 设置中配置
BaggageSpanProcessor,自动把 baggage 条目复制到 span 属性上 - 处理器会确保 trace 上下文中所有下游 span 都收到这些属性
实现细节和代码示例可以参考 Python 与 JavaScript 的 OpenTelemetry 文档。
安全注意事项:OpenTelemetry baggage 会跨服务边界传播,并被传到第三方 API。使用此方式时 不要包含敏感信息(密码、API Key、个人数据等),因为它会被传输到所有下游服务。
备选:使用 Langfuse SDK
如果你使用 Langfuse SDK 配合 OpenTelemetry 集成,可以使用便捷方法 propagate_attributes()(Python)或 propagateAttributes()(TypeScript),它们会自动处理属性传播。这些方法提供了更简洁的接口,是使用 Langfuse SDK 时的推荐做法。
Trace 级别属性
这些属性会被应用到 Litefuse 中的 trace 记录上。它们可以设置在 trace 中的任意 span 上。
| Litefuse 字段 | 描述 | 映射自的 OTel 属性 |
|---|---|---|
name | trace 的名称。 | • langfuse.trace.name:string• root span 的 span 名称 |
userId | 终端用户的唯一标识。 | • langfuse.user.id:string• user.id:string |
sessionId | 用户会话的唯一标识。 | • langfuse.session.id:string• session.id:string |
release | 应用的发布版本。 | • langfuse.release:string |
public | 布尔标志,用于将 trace 标记为公开,从而可以通过 URL 分享。 | • langfuse.trace.public:boolean |
tags | 用于给 trace 分类或打标签的字符串数组。 | • langfuse.trace.tags:string[] |
metadata | 一个灵活对象,用于在 trace 上存放任意附加的非结构化数据。见下方说明。 | • langfuse.trace.metadata.*:string• root span 的 observation metadata |
input | 整个 trace 的初始输入。 | • langfuse.trace.input:string• root span 的 observation input |
output | 整个 trace 的最终输出。 | • langfuse.trace.output:string• root span 的 observation output |
version | trace 的 版本,用于跟踪应用逻辑的变更。 | • root span 的属性映射到 version |
environment | trace 产生时所在的部署 环境。 | • root span 的属性映射到 environment |
在 Litefuse 中按 metadata key 过滤
Litefuse 只支持按事件 metadata 中的顶层 key 进行过滤。
默认情况下,所有 OpenTelemetry 属性和资源属性会被映射到 metadata 中的 attributes 和 resourceAttributes key 下,因此无法直接查询。
如果你想按特定属性查询,可以使用 langfuse.trace.metadata 前缀,把它们映射到 trace 的顶层 metadata 对象。
下面的代码片段会在 trace 的 metadata 对象中产生一个可过滤的 user_name 属性:
with tracer.start_as_current_span("Langfuse Attributes") as span:
span.set_attribute("langfuse.trace.metadata.user_name", "user-123")Observation 级别属性
这些属性会应用到 trace 中的单个 observation(span)上(数据模型)。
| Litefuse 字段 | 描述 | 映射自的 OTel 属性 |
|---|---|---|
type | observation 类型。任何带有 model 属性的 span 都会被记为 generation。 | • langfuse.observation.type:"span" | "generation" | "event",默认 "span" |
level | observation 的 严重级别。 | • langfuse.observation.level:"DEBUG" | "DEFAULT" | "WARNING" | "ERROR",默认 "DEFAULT"• 由 span.status.code 推断 |
statusMessage | 描述 observation 状态的消息,常用于错误。 | • langfuse.observation.status_message:string• 由 span.status.message 推断 |
metadata | 用于存放附加非结构化数据的灵活对象。见下方说明。 | • langfuse.observation.metadata.*:string |
input | 该 observation 的输入数据。 | • langfuse.observation.input:(JSON) string• gen_ai.prompt• input.value(OpenInference)• mlflow.spanInputs(MLFlow) |
output | 该 observation 的输出数据。 | • langfuse.observation.output:(JSON) string• gen_ai.completion• output.value(OpenInference)• mlflow.spanOutputs(MLFlow) |
model | 所使用的生成式模型名称。仅 generation 适用。 | • langfuse.observation.model.name• gen_ai.request.model• gen_ai.response.model• llm.model_name• model |
modelParameters | 模型调用设置的键值对。仅 generation 适用。 | • langfuse.observation.model.parameters:JSON string• gen_ai.request.*• llm.invocation_parameters.* |
usage | 此次 generation 的 token 计数。仅 generation 适用。 | • langfuse.observation.usage_details:JSON string• gen_ai.usage.*• llm.token_count.* |
cost | 计算得到的费用(USD)。仅 generation 适用。 | • langfuse.observation.cost_details:JSON string• gen_ai.usage.cost(设为 total key) |
prompt | 在 Litefuse 中管理的版本化 prompt 名称。仅 generation 适用。 | • langfuse.observation.prompt.name:string• langfuse.observation.prompt.version:integer |
completionStartTime | 模型开始生成时的时间戳。仅 generation 适用。 | • langfuse.observation.completion_start_time:ISO 8601 date string |
version | observation 的 版本。 | • langfuse.version:string |
environment | observation 产生时所在的部署 环境。 | • langfuse.environment• deployment.environment• deployment.environment.name |
在 Litefuse 中按 metadata key 过滤
Litefuse 只支持按事件 metadata 中的顶层 key 进行过滤。
默认情况下,所有 OpenTelemetry 属性和资源属性会被映射到 metadata 中的 attributes 和 resourceAttributes key 下,因此无法直接查询。
如果你想按特定属性查询,可以使用 langfuse.observation.metadata 前缀,把它们映射到 observation 的顶层 metadata 对象。
下面的代码片段会在 metadata 对象中产生一个可过滤的 user_name 属性:
with tracer.start_as_current_span("Langfuse Attributes") as span:
span.set_attribute("langfuse.observation.metadata.user_name", "user-123")故障排查
- 如果在自托管 Litefuse 时遇到
4xx错误,请将部署升级到最新版本。OpenTelemetry 端点最早在 Litefuse v3.22.0 引入,之后又有显著改进。 - Litefuse 支持基于 HTTP 的 OTLP,包括
HTTP/JSON和HTTP/protobuf。gRPC暂不支持。