Vision-Agents 可观测性实战:用 Prometheus + Grafana 采集并可视化语音与视觉 Agent 的实时指标
2026/9/16 10:37:31 网站建设 项目流程

Vision-Agents 可观测性实战:用 Prometheus + Grafana 采集并可视化语音与视觉 Agent 的实时指标

【免费下载链接】Vision-AgentsOpen Vision Agents by Stream. Build voice and vision agents quickly with any model or video provider. Uses Stream's edge network for ultra-low latency.项目地址: https://gitcode.com/GitHub_Trending/vi/Vision-Agents

本篇技术指南以 Vision-Agents 仓库的 06_prometheus_metrics_example 示例为核心,讲解如何通过 OpenTelemetry 将运行中的语音/视觉 Agent(LLM、STT、TTS、语音轮次检测、Realtime LLM 等组件)的指标实时导出到 Prometheus,并在 Grafana 中借助预置仪表盘进行可视化监控。读完本文,你将掌握在 Vision-Agents 上启用指标采集的完整链路:从应用内配置 OpenTelemetry 的 Prometheus 导出器,到编写 Prometheus 抓取配置,再到部署开箱即用的 Grafana 看板,并理解MetricsCollector在源码层的自动挂载与合并原理。

示例概览:一个可观测的实时语音 Agent

该示例构建了一个基于 Gemini LLM + Deepgram STT + ElevenLabs TTS + GetStream Edge 的实时语音 Agent。它除了演示基本的"问天气"对话能力外,核心目的是展示指标采集能力:Agent 内部的 LLM、STT、TTS、Turn Detection 等组件在通话过程中会自动产生结构化指标,并在http://localhost:9464/metrics以 Prometheus 文本格式暴露出来。

示例的三大目标(与 README 声明一致):

  1. 用 OpenTelemetry 的 Prometheus 导出器完成指标出口配置;
  2. 在实时视频/语音通话期间从/metrics端点抓取指标;
  3. 用预置 Grafana 仪表盘可视化指标。

整个示例的关键设计是:指标采集默认开启。正如示例源码注释(prometheus_metrics_example.py)与核心库文档(observability/metrics.py)所述,每个Agent在构造时都会自动创建一个MetricsCollector,因此只要应用配置好 OpenTelemetry 的 MeterProvider,指标就会自动落盘,无需逐组件手动埋点。

快速开始:两种接入方式

方式一:仅暴露指标端点(最快验证)

cd examples/06_prometheus_metrics_example uv sync uv run python prometheus_metrics_example.py run

启动后打开 http://localhost:9464/metrics,即可在与 Agent 对话的同时实时观察原始指标文本。uv sync会根据该目录下的 pyproject.toml 解析依赖,其中vision-agents及其各插件均通过[tool.uv.sources]以可编辑方式(editable)指向仓库本体的agents-coreplugins/目录。

依赖清单中与可观测性直接相关的包:

  • opentelemetry-api/opentelemetry-sdk:OpenTelemetry 指标 API 与 SDK;
  • opentelemetry-exporter-prometheus:将 OTel 指标桥接到 Prometheus 格式的导出器;
  • prometheus-client:提供start_http_server,用于启动/metricsHTTP 服务。

方式二:完整可观测性栈(Prometheus + Grafana)

# 1. 启动 Prometheus + Grafana 容器 cd examples/06_prometheus_metrics_example docker compose up -d # 2. 运行 Agent(另开终端) uv sync uv run python prometheus_metrics_example.py run # 3. 打开 Grafana # http://localhost:3000 (无需登录,已启用匿名访问)

Grafana 预置仪表盘会展示以下指标面板(README 明确列出):

  • LLM 延迟(p50 / p95 / p99)
  • STT 延迟(p50 / p95 / p99)
  • TTS 延迟(p50 / p95 / p99)
  • 轮次时长(Turn duration)
  • 轮次尾部静默时长(Turn trailing silence)
  • 错误率(Error rates)

结束时停止观测栈:

docker compose down

数据流架构

README 给出了简洁的架构图,本文稍作注释保留:

┌─────────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ Stream Agent │────▶│ Prometheus │────▶│ Grafana │ │ (port 9464) │ │ (port 9090) │ │ (port 3000) │ │ │ │ │ │ │ │ Metrics endpoint: │ │ Scrapes every │ │ Pre-built │ │ /metrics │ │ 5 seconds │ │ dashboards │ └─────────────────────┘ └─────────────────┘ └─────────────────┘

Agent 进程内的 Prometheus HTTP Server(9464 端口)是被抓取目标,Prometheus 容器以 5 秒间隔抓取,Grafana 通过预置数据源与仪表盘完成可视化(详见 docker-compose.yml 与 prometheus.yml)。

可用指标全景:五类核心指标 + 两类进阶指标

LLM 指标

指标名(Prometheus 导出后)类型含义
llm_latency_ms_millisecondshistogramLLM 完整响应延迟
llm_time_to_first_token_ms_millisecondshistogram流式响应首 Token 时间
llm_tokens_input_totalcounter输入/提示词 Token 消耗
llm_tokens_output_totalcounter输出/补全 Token 生成
llm_errors_totalcounterLLM 错误次数
llm_tool_calls_totalcounter工具/函数调用次数
llm_tool_latency_ms_millisecondshistogram工具执行延迟

STT 指标

指标名类型含义
stt_latency_ms_millisecondshistogramSTT 处理延迟
stt_audio_duration_ms_millisecondshistogram被处理音频的时长
stt_errors_totalcounterSTT 错误次数

TTS 指标

指标名类型含义
tts_latency_ms_millisecondshistogramTTS 合成延迟
tts_audio_duration_ms_millisecondshistogram合成音频时长
tts_characters_totalcounter合成字符数
tts_errors_totalcounterTTS 错误次数

轮次检测指标(Turn Detection)

指标名类型含义
turn_duration_ms_millisecondshistogram检测到的轮次时长
turn_trailing_silence_ms_millisecondshistogram轮次结束前的尾部静默时长

Realtime LLM 指标

指标名类型含义
realtime_sessions_totalcounter启动的 Realtime 会话数
realtime_session_duration_ms_millisecondshistogram会话时长
realtime_audio_input_bytes_bytescounter发送的音频字节数
realtime_audio_output_bytes_bytescounter接收的音频字节数
realtime_responses_totalcounter收到的响应数
realtime_errors_totalcounterRealtime 错误数

VLM 与视频处理指标(README 之外,源码已内置)

从源码看,指标定义并不止于 README 所列。核心库的 observability/metrics.py 还定义了 VLM(视觉语言模型)与视频处理器指标:

  • vlm_inference_latency_ms_milliseconds(histogram,VLM 推理延迟)、vlm_inferences_total(counter,推理请求数);
  • vlm_tokens_input_total/vlm_tokens_output_total(counter,VLM 输入输出 Token);
  • vlm_errors_total(counter);
  • video_frames_processed_total(counter,处理的视频帧数)、video_processing_latency_ms_milliseconds(histogram,视频帧处理延迟)、video_detections_total(counter,视频中检测到的目标数)。

如果你的 Agent 接了 VLM 或视频处理器(如 05_security_camera_example 之类),这些指标同样会自动出现在/metrics中。

指标命名:从 OTel 名到 Prometheus 名的转换

metrics.py中的 OTel 指标采用点分命名、并声明单位,例如meter.create_histogram("stt.latency.ms", unit="ms")meter.create_counter("realtime.audio.input.bytes", unit="By")。经PrometheusMetricReader导出后,名称按 Prometheus 约定转换:点号转为下划线,单位追加为后缀——于是stt.latency.ms变成stt_latency_ms_millisecondsmsmilliseconds),realtime.audio.input.bytes变成realtime_audio_input_bytes_bytesBybytes)。这是观察/metrics输出与 README 指标名时值得留意的对应关系。

源码级原理:指标为何"零埋点"即可采集

Agent 自动创建并合并 MetricsCollector

在 agents/agents.py 中,Agent.__init__内部会自动完成:

self._collector = MetricsCollector() # Merge plugin metric collectors so plugin on_*() calls forward to the agent root for plugin in [stt, tts, turn_detection, llm, avatar, *self.processors]: if plugin is not None: self._collector.merge(plugin.metrics)

即:每个 Agent 都有一个根MetricsCollector,所有组件(STT/TTS/TurnDetection/LLM/Avatar/Processors)各自持有的 collector 通过merge()挂到根上,构成一棵收集器树。这正是 README 所说"每个 Agent 自动创建 MetricsCollector、指标采集默认开启"的代码依据。

双通道写入:本地聚合 + OTel 输出

MetricsCollector(observability/collector.py)的设计要点:

  • 每次事件(如on_llm_responseon_stt_transcripton_tts_synthesison_turn_ended等)都会先更新本地AgentMetrics聚合数据(对应 observability/agent.py 中的Counter/Average结构,可用于单次调用级别的agent.metrics访问),再向父 collector 转发;
  • 只有根 collector(parent is None)才真正写入 OpenTelemetry meter,从而保证无论合并深度如何,每次事件对 OTel 只写一次("OTel is emitted exactly once per call regardless of merge depth");
  • 指标记录时附带丰富属性(attribute),例如 LLM 指标携带provider/model,工具指标携带tool_name/success,错误指标携带error_type/error_code——这些属性会成为 Prometheus 的 label 维度,便于按模型、按工具、按错误类型聚合。

未配置 Provider 时优雅降级

metrics.py的模块注释明确指出:metrics.get_meter("vision_agents.core")会使用应用配置的 provider,若应用未配置任何 provider,则所有指标操作都是 no-op。换言之,可观测性是完全可选(opt-in)的能力,不配置 OpenTelemetry 不会对 Agent 造成额外开销。这与示例"先配置 Provider,再创建 Agent"的顺序要求一致。

示例代码逐段解析

配置 OpenTelemetry → Prometheus

prometheus_metrics_example.py 中,导入各组件之前就完成了三件事:

PROMETHEUS_PORT = 9464 reader = PrometheusMetricReader() provider = MeterProvider(metric_readers=[reader]) metrics.set_meter_provider(provider)

随后在if __name__ == "__main__":中调用start_http_server(PROMETHEUS_PORT)启动 9464 端口的 HTTP 服务,并最终通过Runner(AgentLauncher(create_agent=create_agent, join_call=join_call)).cli()拉起 Agent 的 CLI 入口(支持run --call-type default --call-id test-metrics之类的参数)。

README 中的核心模式节选(与原文档一致,可作为自己项目的最小模板):

from opentelemetry import metrics from opentelemetry.exporter.prometheus import PrometheusMetricReader from opentelemetry.sdk.metrics import MeterProvider from prometheus_client import start_http_server from vision_agents.core import Agent # Start Prometheus exporter on localhost:9464 start_http_server(9464) # Configure OpenTelemetry to use Prometheus reader = PrometheusMetricReader() provider = MeterProvider(metric_readers=[reader]) metrics.set_meter_provider(provider) # Setup and run the agent agent = Agent(...)

构建 Agent 与注册工具

create_agent(prometheus_metrics_example.py)组装了 Gemini 的gemini-flash-lite-latest模型、ElevenLabs TTS、启用eager_turn_detection的 Deepgram STT,以及 GetStream 边缘网络连接;并通过llm.register_function注册get_weather工具——该工具调用会触发on_tool_call,进而产生llm_tool_calls_totalllm_tool_latency_ms_milliseconds指标,方便在 Grafana 上观察函数调用的频率与耗时。

加入通话并产生流量

join_call(prometheus_metrics_example.py)打印出将要采集的指标清单到 stderr,随后agent.create_callagent.join(call)agent.simple_response(...)建立会话并主动发起一轮问候,之后与 Agent 对话即可持续产生指标流量。

Prometheus 抓取配置详解

README 给出最小抓取配置(加入你自己的prometheus.yml):

scrape_configs: - job_name: 'stream-agents' static_configs: - targets: [ 'localhost:9464' ] scrape_interval: 15s

示例仓库自带的完整配置(observability/prometheus/prometheus.yml)则做了两处关键增强:

  1. 全局配置scrape_interval: 15sevaluation_interval: 15s,并打上外部标签monitor: 'stream-agents-monitor'
  2. stream-agents 抓取任务:目标为host.docker.internal:9464(而非localhost),抓取间隔缩短到 5 秒、超时 5 秒,并为每个样本附加service: 'stream-agents'environment: 'development'标签,便于多环境、多服务聚合;另有一个prometheusjob 抓取 Prometheus 自身指标用于自监控。

注意:README 的快速配置与仓库内配置的目标地址不同(localhost:9464vshost.docker.internal:9464),差异源于运行方式——Agent 跑在宿主机、Prometheus 跑在容器内时,容器内无法通过localhost访问宿主进程,必须使用host.docker.internal;若两者都在宿主机上运行,则用localhost即可。

Grafana 可视化:预置仪表盘与 PromQL 查询

开箱即用的容器编排

docker-compose.yml 定义了三个服务:

  • prometheus(9090 端口):挂载prometheus.yml,启用--web.enable-lifecycle以支持热重载;
  • grafana(3000 端口):以环境变量开启匿名访问(GF_AUTH_ANONYMOUS_ENABLED=trueGF_AUTH_ANONYMOUS_ORG_ROLE=Admin),禁用登录表单,并将provisioning目录与dashboards目录分别挂载到容器内;
  • grafana-init:基于curlimages/curl的初始化容器,执行 init-home-dashboard.sh,等待 Grafana 健康检查通过后,通过 REST API 将组织与 admin 用户的默认首页设置为stream-agents-metrics这个仪表盘。

数据源与仪表盘自动供给

Grafana 的 provisioning(免手工配置)由两处文件驱动:

  • provisioning/datasources/prometheus.yml:注册名为Prometheus的数据源,url: http://prometheus:9090(走 Docker 内部网络),uid: prometheus,设为默认数据源,并声明timeInterval: 5s与抓取节奏对齐;
  • provisioning/dashboards/default.yml:以文件 provider 方式加载/var/lib/grafana/dashboards目录下的仪表盘(即挂载进去的 stream-agents.json),每 10 秒检测一次更新。

常用 PromQL 查询

README 给出了四组可直接上手的 PromQL,覆盖延迟均值、Token 速率、错误率与分位延迟:

# 平均 LLM 延迟随时间变化 rate(llm_latency_ms_milliseconds_sum[5m]) / rate(llm_latency_ms_milliseconds_count[5m]) # Token 使用速率 rate(llm_tokens_input_total[5m]) + rate(llm_tokens_output_total[5m]) # 错误率 rate(llm_errors_total[5m]) # 95 分位延迟 histogram_quantile(0.95, sum(rate(llm_latency_ms_milliseconds_bucket[5m])) by (le))

前两条利用了 histogram 的_sum/_count伴生序列与 counter 的速率语义;分位查询则借助histogram_quantile_bucket序列求 p95。将llm_latency_ms_milliseconds替换为stt_tts_turn_duration_turn_trailing_silence_前缀,即可获得 README 仪表盘中列出的其他面板(p50/p95/p99)所对应的查询。

环境变量配置

示例通过load_dotenv()加载项目根目录下的.env,需要以下密钥(README 原文列出):

GOOGLE_API_KEY=your_key DEEPGRAM_API_KEY=your_key ELEVENLABS_API_KEY=your_key STREAM_API_KEY=your_key STREAM_API_SECRET=your_secret

分别对应 Gemini LLM、Deepgram STT、ElevenLabs TTS 与 GetStream 边缘网络的鉴权信息。

故障排查

Prometheus 无法抓取指标

  • 确保Agent 先于 Prometheus 启动,或在 Agent 启动后重启 Prometheus 容器;
  • macOS 下host.docker.internal通常开箱即用;Linux 下可能需改用--network="host"或调整目标地址(对应仓库配置中的host.docker.internal:9464说明)。

Grafana 无数据

  • 等待数秒让指标完成首轮抓取;
  • 到 Prometheus 的 Targets 页面(http://localhost:9090/targets)确认stream-agentsjob 处于 UP 状态;
  • 确认 Agent 正在处理通话流量——指标只有在真实通话(create_call + join)期间才会产生,空跑进程不会出现 STT/TTS/LLM 序列。

文件结构索引

examples/06_prometheus_metrics_example/ ├── prometheus_metrics_example.py # 主示例代码 ├── docker-compose.yml # Prometheus + Grafana 编排 ├── observability/ │ ├── prometheus/ │ │ └── prometheus.yml # Prometheus 抓取配置 │ └── grafana/ │ ├── dashboards/ │ │ └── stream-agents.json # 预置仪表盘 │ ├── provisioning/ │ │ ├── dashboards/ │ │ │ └── default.yml # 仪表盘供给配置 │ │ └── datasources/ │ │ └── prometheus.yml # 数据源配置 │ └── init-home-dashboard.sh # 设置默认首页仪表盘 └── README.md

与本文对应的核心库源码与测试位置:

  • 指标定义: agents-core/vision_agents/core/observability/metrics.py
  • 采集器实现: agents-core/vision_agents/core/observability/collector.py
  • 本地聚合结构: agents-core/vision_agents/core/observability/agent.py
  • 自动挂载逻辑: agents-core/vision_agents/core/agents/agents.py
  • 相关测试: tests/test_observability.py

小结

通过 06_prometheus_metrics_example,Vision-Agents 展示了"配置即观测"的理念:应用只需在启动前配置 OpenTelemetry 的 Prometheus 导出器并启动/metricsHTTP 服务,Agent 内部自动创建的MetricsCollector就会把 LLM、STT、TTS、轮次检测、Realtime LLM(乃至 VLM 与视频处理)的延迟、Token、错误与工具调用指标持续输出;配合仓库自带的 Prometheus 抓取配置与 Grafana 供给文件,即可在几分钟内获得带 p50/p95/p99 延迟面板与错误率监控的完整可观测性栈。这套模式同样适用于把指标接入云端 Prometheus、VictoriaMetrics 等兼容后端的生产场景——只需替换导出器与抓取目标,核心 Agent 代码无需任何改动。

【免费下载链接】Vision-AgentsOpen Vision Agents by Stream. Build voice and vision agents quickly with any model or video provider. Uses Stream's edge network for ultra-low latency.项目地址: https://gitcode.com/GitHub_Trending/vi/Vision-Agents

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询