Blade Agent 长期在线监控建议

本报告总结关于 Jaeger、长期监控、细粒度性能定位的讨论,目标是帮助团队建立能长期运行、能告警、也能定位慢请求根因的可观测性体系。

主结论

长期在线监控不应以 Jaeger 为核心。主干应是 Prometheus/Grafana,Trace 和 Profiler 作为定位工具。

关键修正

Jaeger 能看一次慢请求的阶段耗时,但不能替代 continuous profiling 来定位具体慢函数。

推荐组合

Prometheus + Grafana + OpenTelemetry + Tempo/Jaeger + Pyroscope/Parca + Loki。

1. 问题定义

需要监控的不是一次性排障,而是长期在线运行中的性能状态,重点包括:

长期监控要同时回答三个问题:是否慢了、慢在哪个阶段、阶段内部是哪段代码慢。

2. Jaeger 的定位

Jaeger 是 trace viewer,适合查看一次请求经过哪些 span、每个阶段花了多久。它适合做慢请求链路分析,但不适合作为长期在线监控的主系统。

能力 Jaeger 是否适合 说明
查看单次慢请求链路 适合 能展示 chat、LLM、tool、projection、socket 等 span 的耗时关系。
长期趋势和告警 不适合作为主系统 p95、p99、错误率、吞吐、并发、token/s 这类指标更适合 Prometheus/Grafana。
定位具体慢函数 不充分 Trace 只能说明某个 span 慢,不能自然回答 span 内部哪条函数调用栈最耗时。
全量 token 流细粒度记录 不建议 对每个 token 或每个 delta 建 span 会产生极高数据量和噪声。

3. 推荐架构

建议采用分层可观测性架构,每一层负责不同问题。

层级 推荐工具 回答的问题
长期指标 Prometheus + Grafana 系统是否变慢,吞吐是否下降,错误率是否升高,是否需要告警。
请求链路 OpenTelemetry + Tempo 或 Jaeger 一次慢请求慢在哪个架构阶段。
函数级定位 Pyroscope 或 Parca 慢 span 内部具体是哪段 Python/Go/前端函数或调用栈在耗时。
日志上下文 Loki 或结构化日志系统 错误、异常、请求上下文、session_id、chat_run_id 的补充证据。
LLM 语义层 Langfuse / Helicone prompt、completion、model、usage、tool call、agent loop 的 LLM 特有分析。
如果团队已经偏 Grafana 生态,优先组合是 Prometheus + Grafana + Tempo + Pyroscope + Loki;Jaeger 可以作为 Tempo 的替代 trace UI,但不是 profiler 的替代品。

4. 为什么不能给每个函数都打 span

“细到代码函数”这个目标是正确的,但实现方式不应该是给每个函数手写 span。

更合理的做法是:对架构边界打 span,对少数高风险热路径打手工 span,再用 continuous profiler 自动采样函数调用栈。

5. 建议的 Trace 边界

Trace 应该表达一次 chat 请求的主要阶段,而不是表达每个内部函数。

chat.run
  session.load_context
  prompt.build
  llm.stream
    llm.first_token
    llm.delta_batch
  projection.apply_event
  projection.serialize_patch
  socket.emit_patch
  history.append
  tool.run

这些 span 能先回答慢在哪个阶段。例如:

6. Stream Telemetry 设计

对于“模型 100 token/s,用户可见 50 token/s”的问题,需要专门记录流式链路指标。

LLM Provider上游 delta 到达
Backend LLM Clienton_delta 调用
Projection Builderpatch 构建与序列化
Socket.IOemit 到浏览器
Frontendreceive、store apply、render

建议长期记录的指标

upstream_ttft_ms
upstream_tokens_per_sec
backend_first_patch_ms
backend_patch_count
backend_patch_chars_per_sec
socket_emit_lag_ms
frontend_receive_lag_ms
frontend_apply_lag_ms
frontend_visible_tokens_per_sec
stream_slowdown_ratio = upstream_tokens_per_sec / frontend_visible_tokens_per_sec

这些指标进入 Prometheus/Grafana 后,可以长期观察趋势并做告警;当指标异常时,再通过 trace 和 profiler 下钻到具体请求与具体函数。

7. Profiler 的必要性

Trace 能告诉你 projection.serialize_patch 慢,但 profiler 才能告诉你它为什么慢。

慢阶段 Profiler 要回答的问题
projection.serialize_patch 是否卡在 Pydantic model_dump、JSON 序列化、深层结构复制。
prompt.build 是否卡在 tokenizer、模板渲染、历史裁剪、文件读取。
history.append 是否卡在同步磁盘 IO、flush、锁等待。
socket.emit_patch 是否 event loop 被阻塞、payload 太大、发送队列积压。
前端可见速度慢 是否 store update、diff、markdown 渲染或 React render 成本过高。

8. 落地顺序

  1. 先建立 Prometheus metrics endpoint 和 Grafana dashboard,覆盖 chat 延迟、错误率、并发、LLM token/s、stream slowdown ratio。
  2. 基于 OpenTelemetry 增加架构边界 span,导出到 Tempo 或 Jaeger。
  3. 接入 Pyroscope 或 Parca,启用 Python 后端的 continuous profiling。
  4. 前端增加 performance mark,记录 socket receive、store apply、render visible 的时间差。
  5. 将 trace_id、session_id、chat_run_id 写入结构化日志,方便从 dashboard 跳转到 trace、profile 和日志。
  6. 对慢请求和错误请求提高 trace 采样率;普通请求低采样,避免长期存储爆量。

9. 最终建议

长期在线监控应以指标为主,以 trace 和 profiler 为下钻工具:

Prometheus/Grafana  -> 发现趋势、告警、容量问题
OpenTelemetry Trace -> 定位一次慢请求慢在哪个阶段
Pyroscope/Parca     -> 定位慢阶段里具体哪个函数或调用栈耗时
Loki/结构化日志      -> 补充错误和上下文
Langfuse/Helicone   -> 保留 LLM 语义层分析
简短结论:Jaeger 可以接,但不应作为主监控。真正能长期解决性能问题的是“指标 + trace + continuous profiler”的组合。