Blade Agent 可观测性建议 v2

在 v1(指标为主干、trace 与 profiler 做下钻)的基础上,按两类真实部署环境分档给出组件清单与落地顺序: 盒子环境(DGX Spark 128G,需本机部署大模型,剩余资源紧张)与 服务器环境(典型 8c 32G,模型走外部 API,资源相对宽裕)。

主结论不变

长期监控以 Prometheus 指标为主干;trace 定位阶段、profiler 定位函数。Jaeger/Tempo 只是下钻工具。

v2 核心变化

组件清单按环境分档:盒子环境只保留零常驻依赖的埋点与日志;服务器环境部署完整分析栈。

埋点只写一套

用 OpenTelemetry 统一埋点,metrics 与 trace 同源导出。环境差异只体现在「后端收集器部署与否」,不体现在业务代码里。

1. 两类环境的约束差异

维度 盒子环境 服务器环境
硬件 DGX Spark,128G 统一内存,但需本机部署大模型(推理引擎 + 权重常驻),留给业务与监控的内存、磁盘都很紧张 典型 8c 32G,模型走外部 API(LLM 网关),资源主要留给业务本身
网络 离线断网交付,不能依赖任何外部服务 内网或受控外网,可访问内部监控服务
运维 无人值守,出问题靠事后导出数据分析 团队可登录、可实时看 dashboard
监控目标 留证据:出问题后能拿到足够数据定位 看趋势 + 告警 + 主动下钻
盒子环境的关键约束不是 CPU 而是内存和磁盘:模型权重与推理引擎已占大头,任何常驻监控组件(Grafana、Tempo、Pyroscope、Loki 都是常驻进程 + 本地存储)都在挤占推理可用资源。因此盒子上的原则是:只埋点、只落盘轻量数据,不部署分析栈

2. 分档组件清单

盒子环境(随产品出厂,零常驻分析组件)

组件 说明
/metrics endpoint FastAPI 进程内暴露 Prometheus 格式指标,开销可忽略。不部署 Prometheus server,指标由巡检脚本定期抓取快照落盘(如每分钟一次 curl 追加到滚动文件)
结构化日志(JSON lines) 每条日志带 trace_id / session_id / chat_run_id,本地滚动保留(如 7 天),不部署 Loki
诊断 span 文件(默认低采样) span 埋点始终存在;盒子环境不依赖常驻 OTel Collector/Tempo,而是写入本地滚动 diagnostic JSONL span 文件。慢请求(超阈值)和报错请求强制采样,正常请求 1%~5%
诊断包导出命令 一条命令打包最近 N 天的指标快照 + 日志 + diagnostic JSONL span 文件,拷回内部环境后导入 Tempo/Grafana 离线分析
py-spy(按需) 镜像里预装二进制但不常驻。现场出现慢时手动 py-spy dump / record 采样,替代常驻 profiler

服务器环境(8c 32G,部署完整分析栈)

组件 预估常驻内存 说明
Prometheus + Grafana ~1–2G 主监控:chat p95/p99、错误率、并发、token/s、stream slowdown ratio,配告警规则
Tempo(或 Jaeger) ~0.5–1G 接收 OTel trace,Grafana 内直接从指标面板跳转 trace
Loki ~0.5–1G 收结构化日志,靠 trace_id 与 trace 互跳
Pyroscope(第二阶段默认部署) ~0.5G 用于长期 continuous profiling,回答「慢 span 内部具体哪个函数/调用栈耗时」。第一批先完成指标与 trace,第二阶段默认接入;py-spy 仅作为现场临时抓样工具
Langfuse(已有) 已部署 LLM 语义层(prompt / completion / usage / agent loop)。与 OTel 通过 trace_id 打通,语义内容只在 Langfuse 存一份,避免与 Tempo 重复存储

合计常驻约 3–5G 内存,在 32G 机器上可控;全部走 docker compose 一键部署,与业务容器同机或独立监控机均可。

3. 埋点只写一套:OTel 同源导出

当前 feat/distributed-tracing 分支已在做 OTel span 埋点。建议在此基础上:

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

4. Stream Telemetry:两个环境都要,且优先落地

「模型 100 token/s、用户可见 50 token/s」这类问题在盒子上尤其重要——本机推理引擎与业务进程抢资源,流式变慢的概率更高。这组指标属于轻量 counter/histogram,盒子上开销可忽略,两档环境都默认开启

upstream_ttft_ms                  # 上游首 token 延迟
upstream_tokens_per_sec           # 模型侧输出速度
backend_first_patch_ms            # 后端首个 patch 发出时间
socket_emit_lag_ms                # emit 排队延迟
frontend_visible_tokens_per_sec   # 用户实际可见速度
stream_slowdown_ratio = upstream_tokens_per_sec / frontend_visible_tokens_per_sec

前端指标(receive / apply / render 时间差)通过现有 Socket.IO 或 REST 回传到后端汇总,不引入任何外部 RUM 服务(离线约束)。

5. 落地顺序

  1. 完成 OTel 架构边界 span(当前分支工作),并从 span 同源导出阶段耗时指标;运行态和流式吞吐用 OTel metrics 显式记录;exporter 按环境切换(diagnostic JSONL span 文件 / Tempo+Prometheus)
  2. Stream Telemetry 指标:后端各阶段计数 + 前端回传,两档环境默认开启
  3. 服务器环境部署分析栈:Prometheus + Grafana + Tempo + Loki,一套 compose;dashboard 覆盖 chat 延迟、错误率、token/s、slowdown ratio,配告警
  4. 盒子环境补齐留证能力:指标快照落盘、diagnostic JSONL span 文件导出、诊断包一键打包命令、py-spy 预装
  5. Langfuse 与 trace_id 打通,语义数据单份存储;慢请求 / 错误请求强制采样,正常请求低采样
  6. Pyroscope 第二阶段默认接入:服务器环境完成基础 dashboard 和 trace 后,引入 continuous profiling,补齐函数级长期定位能力

6. 最终监控结果会是什么样子

落地后不是只得到一堆原始 trace,而是形成「长期面板 → 告警 → 慢请求下钻 → 函数级定位 → 诊断包导出」的闭环。

服务器环境:Grafana 首页

面板 能看到什么 用于判断什么
系统健康总览 在线 session 数、running chat 数、错误率、chat p50/p95/p99、CPU/内存、事件循环阻塞时间 系统是否健康,是否有整体卡顿或资源压力
LLM 与流式体验 TTFT、上游 token/s、用户可见 token/s、stream slowdown ratio、首个 patch 延迟、socket emit 延迟 模型慢、后端慢、socket 慢、前端渲染慢分别在哪里发生
Agent 阶段耗时 context build、prompt build、llm.stream、tool.run、projection.serialize、history.append 的耗时分布 慢请求主要集中在哪个架构阶段
工具与沙盒 各工具调用次数、失败率、p95 耗时、sandbox command 耗时、文件读写耗时 是否是工具、沙盒、文件系统拖慢了 agent
容量与趋势 近 1h/24h/7d 的请求量、慢请求比例、token 吞吐、错误率、资源曲线 是否需要扩容、限流、优化热点路径或调整模型配置

一次慢请求的下钻路径

Grafana 告警 / 慢请求列表
  → 点击 trace_id 打开 Tempo/Jaeger
  → 看到 chat.run 下各阶段 span 耗时
  → 定位到 projection.serialize_patch 或 socket.emit_patch 慢
  → 跳到 Pyroscope 查看同一时间窗口的 CPU/Wall time flamegraph
  → 确认具体函数:例如 model_dump、json.dumps、markdown render、history flush
  → 回到 Loki 用 trace_id 查看对应错误/上下文日志

典型告警

盒子环境:现场能导出什么

盒子环境没有常驻分析栈,最终形态是一个诊断包。现场或客户复现问题后,执行一条命令导出最近 N 天数据,带回内部服务器离线分析。

blade-agent-diagnostics-2026-07-09.tar.gz
  metrics/
    metrics-2026-07-09.prom
  traces/
    spans-2026-07-09.jsonl
  logs/
    server.jsonl
    agent.jsonl
  profiles/
    py-spy-2026-07-09.svg        # 只有按需采样时存在
  manifest.json                  # 机器信息、版本、时间范围、采样率、脱敏状态
最终使用体验应该是:平时看 Grafana 判断趋势;收到告警后点进 trace;trace 定位慢阶段;Pyroscope 定位函数;日志补上下文;盒子环境则通过诊断包把同样证据带回内部分析。

7. 最终结论

埋点层(两档相同):OTel span + 同源指标 + Stream Telemetry + 结构化日志
盒子环境:只落盘留证(指标快照 / diagnostic JSONL spans / 日志),py-spy 按需,一键导出诊断包
服务器环境:Prometheus/Grafana 主监控 + Tempo 下钻 + Loki 日志 + Pyroscope 持续 profiling + Langfuse 语义层
一句话:埋点统一、部署分档。盒子环境把资源留给模型,只保证「事后能查」;服务器环境部署完整分析栈,保证「实时能看、能告警、能下钻」。