使用 OpenTelemetry 实现 Open WebUI 的可观测性与监控
通过 OpenTelemetry 对自托管的 Open WebUI 进行监控,可以实时掌握部署运行状况。Open WebUI 后端内置 OpenTelemetry,会自动埋点 FastAPI、SQLAlchemy 及其 HTTP 客户端,无需改动任何代码,就能针对 API 请求、数据库查询和对外调用输出 traces、metrics 和 logs。如果你还想获取每次 LLM 调用的 GenAI 遥测数据(模型、token 和成本),可以通过 Open WebUI Pipelines 可选地接入 OpenLIT。
在 SigNoz 中获得完整的 Open WebUI 可观测性后,你可以端到端追踪 API 请求、监控数据库和接口延迟、跟踪各模型的 LLM token 用量与成本、针对错误和延迟设置告警,从而保障部署的稳定性。
前置条件
- 拥有有效 ingestion key 的 SigNoz Cloud 账号,或 自托管的 SigNoz 实例
- 系统上已安装并运行 Docker 和 Docker Compose
- 一个正在运行的 Open WebUI 部署(需为支持 OpenTelemetry 的较新版本)。如果还没有,请参考 Open WebUI 官方文档
- 仅在配置可选的 LLM 遥测插件时需要:OpenAI API key(或其他 OpenAI 兼容的服务商)
用 OpenTelemetry 监控 Open WebUI
Open WebUI 的 OpenTelemetry 组件已打包在后端中,只需通过环境变量开启,无需额外安装埋点包。由于 Open WebUI 的 exporter 不会附加自定义请求头,所以它将 OTLP 数据发送到一个轻量级 OpenTelemetry Collector,由后者附上你的 SigNoz ingestion key 并转发数据。下面三个步骤会用 Docker Compose 把两者串联起来,并将数据接入 SigNoz。搞定之后,你还可以选择用 OpenLIT 添加 LLM 遥测,获取每次调用的模型、token 和成本数据。
步骤 1:配置 OpenTelemetry Collector
创建 otel-collector-config.yaml。该 Collector 接收来自 Open WebUI 和 OpenLIT 的 OTLP 数据,并使用你的 ingestion key 导出到 SigNoz。
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
timeout: 5s
exporters:
otlp/signoz:
endpoint: https://ingest.<region>.signoz.cloud:443
tls:
insecure: false
headers:
signoz-ingestion-key: <your-ingestion-key>
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp/signoz]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [otlp/signoz]
logs:
receivers: [otlp]
processors: [batch]
exporters: [otlp/signoz]
请确认以下值:
<region>:您的 SigNoz Cloud 区域。<your-ingestion-key>:您的 SigNoz 摄取密钥(ingestion key)。
SigNoz Cloud 通过 signoz-ingestion-key 头部进行摄取身份验证。Open WebUI 初始化其 OTLP 导出器时不包含自定义头部,因此无法自行附加该密钥。Collector 代表 Open WebUI 添加了这一信息。如果您使用的是自托管 SigNoz,则可以将 Open WebUI 的导出器直接指向您的 SigNoz OTLP 端点,从而跳过此步骤。
第 2 步:使用 Docker Compose 启动服务栈
创建 docker-compose.yaml。它将在同一网络中运行 Open WebUI 和 Collector,Open WebUI 会将其原生 OTLP 数据导出到 Collector。
services:
otel-collector:
image: otel/opentelemetry-collector-contrib:latest
command: ["--config=/etc/otel-collector-config.yaml"]
volumes:
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml:ro
ports:
- "4317:4317"
- "4318:4318"
open-webui:
image: ghcr.io/open-webui/open-webui:main
depends_on: [otel-collector]
environment:
ENABLE_OTEL: "true"
ENABLE_OTEL_TRACES: "true"
ENABLE_OTEL_METRICS: "true"
ENABLE_OTEL_LOGS: "true"
OTEL_SERVICE_NAME: "open-webui"
OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-collector:4318"
OTEL_OTLP_SPAN_EXPORTER: "http"
OTEL_EXPORTER_OTLP_INSECURE: "true"
ports:
- "3000:8080"
volumes:
- open-webui-data:/app/backend/data
volumes:
open-webui-data:
启动所有服务:
Copydocker compose up -d
上文中的 Open WebUI 环境变量用于控制原生导出:
| 变量 | 必填 | 值 | 作用 |
|---|---|---|---|
ENABLE_OTEL | 是 | true | 开启 Open WebUI 的 OpenTelemetry 功能。 |
ENABLE_OTEL_TRACES / ENABLE_OTEL_METRICS / ENABLE_OTEL_LOGS | 否 | true(默认 false) | 分别启用各类遥测信号。 |
OTEL_SERVICE_NAME | 否 | open-webui | Open WebUI 上报的 service.name。 |
OTEL_EXPORTER_OTLP_ENDPOINT | 是 | http://otel-collector:4318 | Collector 的 OTLP HTTP 端点。 |
OTEL_OTLP_SPAN_EXPORTER | 否 | http(默认 grpc) | 为 traces 选择 OTLP/HTTP 导出器。 |
OTEL_EXPORTER_OTLP_INSECURE | 是 | true | 在本地网络中以明文 OTLP 连接 Collector。 |
大多数步骤完全相同。只需按照 Cloud → Self-Hosted 文档,修改 Collector 的导出端点并移除数据接入密钥请求头即可。
第 3 步:生成遥测数据
- 在
http://localhost:3000打开 Open WebUI,创建第一个(管理员)账号。 - 浏览应用并发起一次对话,触发 API 调用。
应用活动会产生 FastAPI、数据库和 HTTP 相关的 span。空闲实例几乎不产生数据,所以在查看 SigNoz 之前请先使用一下应用,并留出几秒钟的导出时间。至此,Open WebUI 的遥测数据已经进入 SigNoz。
使用 OpenLIT 添加 LLM 遥测(可选)
Open WebUI 的原生埋点可以捕获 API、数据库和 HTTP 的 span,但无法记录 token 用量、成本以及每次调用使用的模型。要捕获这些信息,需要运行一个 Open WebUI Pipelines 服务,并在其中使用经过 OpenLIT 埋点的 OpenAI 客户端。这会额外增加一个容器和一些手动配置,建议在前面的步骤正常上报数据之后再进行设置。
为何选择 OpenLIT,以及为什么采用 pipe 管道?Open WebUI 的 Pipelines 框架支持两种插件类型:pipe(本身可作为可选择的模型)和 filter(包裹现有模型的入口/出口钩子,内置的 Langfuse 和 DataDog 集成即采用这种形式)。我们选用 pipe,因为 OpenLIT 能对其托管的 OpenAI 客户端进行自动化插桩,使每次调用都能输出完整的 gen_ai.* 遥测数据(包括模型、tokens、成本、提示与响应内容、首字延迟等),无需针对单个请求编写额外代码。OpenLIT 也原生支持 OpenTelemetry:它通过 OTLP 协议导出符合 gen_ai.* 语义约定标准的 span,可直接流经同一个 Collector 到达 SigNoz。相比之下,Langfuse 和 DataDog 的 filter 则将数据发送到各自的独立后端,而非通过 OTLP 流向 SigNoz。
创建 pipeline
新建文件 pipelines/openai_openlit_pipeline.py:
"""
title: OpenAI GenAI (OpenLIT)
requirements: openlit, openai
"""
import os
from typing import Generator, List, Union
from pydantic import BaseModel
class Pipeline:
class Valves(BaseModel):
OPENAI_API_KEY: str = ""
OPENAI_MODEL: str = "gpt-4o-mini"
OTLP_ENDPOINT: str = "http://otel-collector:4318"
def __init__(self):
self.id = "openai-genai"
self.name = "OpenAI GenAI (OpenLIT)"
self.valves = self.Valves(
OPENAI_API_KEY=os.getenv("OPENAI_API_KEY", ""),
OTLP_ENDPOINT=os.getenv("OTLP_ENDPOINT", "http://otel-collector:4318"),
)
self.client = None
async def on_startup(self):
import openlit
from openai import OpenAI
# 对 OpenAI 客户端进行插桩,并将 gen_ai.* span 导出至 Collector。
openlit.init(otlp_endpoint=self.valves.OTLP_ENDPOINT, application_name="open-webui-llm")
self.client = OpenAI(api_key=self.valves.OPENAI_API_KEY)
def pipe(self, user_message: str, model_id: str, messages: List[dict], body: dict) -> Union[str, Generator]:
resp = self.client.chat.completions.create(
model=self.valves.OPENAI_MODEL,
messages=messages,
stream=True,
stream_options={"include_usage": True},
)
for chunk in resp:
if chunk.choices and chunk.choices[0].delta.content:
yield chunk.choices[0].delta.content添加 Pipelines 服务
把这个服务添加到第 2 步的 docker-compose.yaml 中,它会把 GenAI 遥测数据发送到同一个 Collector:
pipelines:
image: ghcr.io/open-webui/pipelines:main
depends_on: [otel-collector]
environment:
OPENAI_API_KEY: ${OPENAI_API_KEY}
OTLP_ENDPOINT: "http://otel-collector:4318"
volumes:
- ./pipelines:/app/pipelines
ports:
- "9099:9099"然后在 open-webui 服务的 depends_on 里加上 pipelines,确保它在 Pipelines 服务启动之后再启动:
depends_on: [otel-collector, pipelines]配置 OpenAI API key在重启整套服务之前,先配置 OPENAI_API_KEY 环境变量,这样 pipeline 才能调用 OpenAI。在 docker-compose.yaml 同级目录下创建一个 .env 文件(例如 OPENAI_API_KEY=<your-openai-api-key>)。Docker Compose 会自动读取该文件来填充 ${OPENAI_API_KEY},这样真实的密钥就不会出现在提交到代码库的 compose 文件里。
重启服务:
Copydocker compose up -d连接 pipeline
- 在 Open WebUI 中,进入 Admin Panel → Settings → Connections,添加一个 OpenAI 兼容连接,URL 填
http://pipelines:9099,API key 填0p3n-w3bu!。 - 用 OpenAI GenAI (OpenLIT) 模型发起一个对话。
现在每次对话都会产生携带 gen_ai.* 属性(模型、token 用量、成本)的 GenAI span,归属于服务 open-webui-llm。
Open WebUI 原生的 HTTP 请求和数据库操作 span 不携带 GenAI 属性,因此不会出现在 AI Observability 中。本指南中的 OpenLIT pipeline 会添加能出现在 AI Observability 里的 LLM span。
在 SigNoz 中查看 Open WebUI 的 Traces
配置完成后,Open WebUI 会在服务 open-webui 下发出应用请求的 traces;如果你添加了 OpenLIT 步骤,还会在 open-webui-llm 下发出 LLM 调用的 traces。Traces 可以在 SigNoz 的 Traces 标签页中查看:
