前面已经做了很多底层工作:
- 对每次模型调用打了
LLMCallLog,记录耗时、token、错误类型等; - 给多智能体/工作流每个节点打了 Trace,能看到「一次请求走过哪些节点」;
- 还有异常检测、自愈、A/B 实验等机制。
但如果这些信息只躺在日志或数据库里,不做一个「一眼就能看懂」的看板,日常用起来还是很痛苦:
- 想看最近是不是变慢了,要到处 grep 日志;
- 想知道哪条工作流最费钱,要自己写脚本算;
- 想查某次异常请求的执行路径,更是翻半天。
这篇就从工程角度讲清楚一件事:
如何基于前面已经埋好的日志和指标,
搭一张大模型应用可观测看板 ,
让你能在浏览器里实时看到:调用量、错误率、延迟、token、成本、节点耗时等。
我用的是「通用思路 + 偏伪代码」的方式来讲,你可以用任意监控栈(Prometheus/Grafana、ClickHouse+Superset、自写管理页)去实现。
一、先想清楚:看板上要"看什么"?
不要一上来就堆一堆图表,先列需求。
对一个大模型应用来说,最有用的几类视图通常是:
-
全局概览
- 总调用量(按分钟/小时)
- 成功率 / 错误率趋势
- 平均延迟 / P95 延迟
- 平均 token 数
- 预估总费用
-
按场景拆分(scene 维度)
- 问答(qa)、总结(summary)、翻译(translate)等;
- 每个场景的调用量、成功率、延迟、成本。
-
按 Agent / 工作流节点拆分
- 哪个 Agent 被调用最多;
- 哪个节点最慢 / 错误最多;
- 某个复杂工作流中,各节点耗时占比。
-
质量相关
- 低质量回答占比(基于前面简单规则或用户反馈);
- RAG 命中率、检索条数分布等。
-
异常 & 自愈
- 最近触发了哪些熔断 / 降级;
- 哪些资源(模型、向量库、外部 API)出问题最频繁。
搞清这 5 类,剩下就是「怎么把它们做成图表」的问题。
二、数据打平:把日志变成"可查询事件表"
无论你是写入文件、数据库,还是时序数据库,最终都可以抽象成一张「事件表」:
llm_calls
---------
- timestamp
- trace_id
- model
- scene
- agent
- success (bool)
- error_type (string)
- latency_ms (float)
- prompt_tokens (int)
- completion_tokens (int)
- total_tokens (int)
- estimated_cost (float)
还有一张「工作流节点 Trace 表」:
workflow_traces
---------------
- timestamp
- trace_id
- workflow_name
- node_name
- status (success/error_xxx)
- duration_ms (float)
只要有这两张表,你要的各种图基本都能算出来。
如果你现在是把 LLMCallLog 打到日志文件里,可以写个小采集脚本(示意伪代码):
python
import json
import sqlite3
from datetime import datetime
def ingest_logs_to_db(log_file: str, db_path: str):
conn = sqlite3.connect(db_path)
cur = conn.cursor()
cur.execute("""
CREATE TABLE IF NOT EXISTS llm_calls (
ts TEXT,
trace_id TEXT,
model TEXT,
scene TEXT,
agent TEXT,
success INTEGER,
error_type TEXT,
latency_ms REAL,
prompt_tokens INTEGER,
completion_tokens INTEGER,
total_tokens INTEGER,
estimated_cost REAL
)
""")
with open(log_file, encoding="utf-8") as f:
for line in f:
if "[LLM_CALL]" not in line:
continue
data = json.loads(line.split("[LLM_CALL]", 1)[1].strip())
cur.execute("""
INSERT INTO llm_calls VALUES (?,?,?,?,?,?,?,?,?,?,?,?)
""", (
data.get("ts") or datetime.utcnow().isoformat(),
data.get("trace_id", ""),
data["model"],
data["scene"],
data["agent"],
1 if data["success"] else 0,
data.get("error_type", ""),
data["latency_ms"],
data["prompt_tokens"],
data["completion_tokens"],
data["total_tokens"],
data.get("estimated_cost", 0.0),
))
conn.commit()
conn.close()
后面你可以把 SQLite 换成 MySQL / ClickHouse / 时序库都行,思路完全一样。
三、几个关键指标的 SQL 计算示例
假设我们用的是一个支持 SQL 的存储(比如 ClickHouse 或 SQLite),下面给几个典型查询示范,你可以直接拿去做图表的数据源。
3.1 全局概览:最近 24 小时调用趋势
按 5 分钟聚合一次:
python
SELECT
strftime('%Y-%m-%d %H:%M:00', ts) AS bucket,
COUNT(*) AS calls,
SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) * 1.0 / COUNT(*) AS success_rate,
AVG(latency_ms) AS avg_latency_ms,
AVG(total_tokens) AS avg_tokens,
SUM(estimated_cost) AS total_cost
FROM llm_calls
WHERE ts >= datetime('now', '-1 day')
GROUP BY bucket
ORDER BY bucket;
你可以据此画出:
- 请求数折线;
- 成功率折线;
- 平均延迟折线;
- 费用面积图。
3.2 按场景(scene)拆分表现
python
SELECT
scene,
COUNT(*) AS calls,
SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) * 1.0 / COUNT(*) AS success_rate,
AVG(latency_ms) AS avg_latency_ms,
AVG(total_tokens) AS avg_tokens,
SUM(estimated_cost) AS total_cost
FROM llm_calls
WHERE ts >= datetime('now', '-1 day')
GROUP BY scene
ORDER BY calls DESC;
在看板上,你可以做一个「场景排行榜」:
- 调用最多的前 N 个场景;
- 哪个场景延迟异常高;
- 哪个场景最烧钱。
3.3 按 Agent 拆分
python
SELECT
agent,
COUNT(*) AS calls,
AVG(latency_ms) AS avg_latency_ms,
SUM(estimated_cost) AS total_cost
FROM llm_calls
WHERE ts >= datetime('now', '-1 day')
GROUP BY agent
ORDER BY calls DESC;
用这个可以诊断:
- 哪个 Agent 是"热点";
- 哪个 Agent 总是最慢或最贵。
3.4 工作流节点耗时分布
python
SELECT
workflow_name,
node_name,
COUNT(*) AS calls,
AVG(duration_ms) AS avg_ms,
percentile_95(duration_ms) AS p95_ms
FROM workflow_traces
WHERE ts >= datetime('now', '-1 day')
GROUP BY workflow_name, node_name
ORDER BY workflow_name, avg_ms DESC;
这张表特别适合做「瀑布图」或「条形图」,用来识别:
- 某个工作流中,究竟是哪几个节点拖慢了整体。
四、在前端做一张"技术同事看了就想用"的看板
你可以用任何前端技术栈,这里给的是信息布局思路,而不是框架代码。
4.1 页面分区布局建议
可以做成四大块:
-
顶部:全局 KPI 概览
- 今日调用量 / 成功率 / 平均延迟 / 预估总费用;
- 昨日同比环比的小箭头。
-
左侧:时间趋势区
- 调用量 + 成功率双轴图;
- 延迟 P95 / 平均延迟随时间变化;
- Token 和成本趋势。
-
右侧:场景 & Agent 榜单
- 表格或条形图:
- Top N 场景:调用量、成功率、延迟、成本;
- Top N Agent:调用量、平均延迟、节点错误率。
- 表格或条形图:
-
底部:工作流详情 + Trace 追踪
- 下拉选择一个工作流名;
- 显示:
- 各节点平均耗时、P95;
- 最近几次异常请求的 Trace(按时间线展示)。
4.2 Trace 时间线展示的核心数据结构
后端可以给前端返回这样的结构:
python
{
"trace_id": "abc-123",
"workflow": "qa_pipeline",
"start_ts": "2026-02-07T10:00:00Z",
"end_ts": "2026-02-07T10:00:02Z",
"nodes": [
{
"name": "router",
"start_offset_ms": 0,
"duration_ms": 10,
"status": "success"
},
{
"name": "retrieve",
"start_offset_ms": 10,
"duration_ms": 100,
"status": "success"
},
{
"name": "answer",
"start_offset_ms": 110,
"duration_ms": 1800,
"status": "success"
}
]
}
前端只要按 start_offset_ms + duration_ms 做一个水平条形时间线,就能直观看到:
- 整个调用花了 1.9s;
- 其中绝大部分时间耗在
answer节点。
五、把"异常检测 / 自愈"也挂到看板上
前一篇我们加了异常检测和自愈机制,现在可以在看板上做一块「异常面板」:
5.1 异常事件表结构
可以存一张 anomalies 表:
python
anomalies
---------
- ts
- type # latency / error / quality / token_burst / rag_degrade 等
- severity # info / warning / critical
- workflow
- node
- trace_id
- message
- auto_healed # 是否已被自愈逻辑处理
5.2 异常看板内容
- 最近 1 小时 / 24 小时异常数量趋势;
- 按类型的堆叠柱状图(延迟异常、错误、质量下降等);
- 最近 N 条严重异常列表(可点进去看 Trace);
- 自愈效果统计:
- 多少异常被自动处理;
- 自动处理后的平均耗时变化。
六、成本维度:用已有 token 数据做一个"成本雷达"
你前面已经在 LLMCallLog 里算了 estimated_cost,现在可以从看板上做一块「成本分析」:
6.1 按模型拆分成本
python
SELECT
model,
SUM(estimated_cost) AS total_cost,
COUNT(*) AS calls,
SUM(estimated_cost) / COUNT(*) AS avg_cost_per_call
FROM llm_calls
WHERE ts >= datetime('now', '-7 day')
GROUP BY model
ORDER BY total_cost DESC;
适合画成:
- 模型成本占比饼图;
- 每次调用平均花费柱状图。
6.2 按场景拆分成本
再配合场景,就能知道:
- 哪个场景最烧钱;
- 哪个场景单位成本最高(每次调用花多少钱)。
这对后面做「路由策略」「模型分层」非常有参考价值。
七、落地路线:用最少工作量让看板先跑起来
推荐一个「最小可行方案」路径:
-
先把 LLM 调用日志 + 工作流 Trace 写进一个能跑 SQL 的存储
- 小项目可以用 SQLite/PostgreSQL;
- 大一点可以上 ClickHouse / TimescaleDB;
- 如果已有监控栈(Prometheus),LLM 指标也可以直接写成时序指标。
-
写几个最关键的查询
- 全局概览;
- 按场景/Agent 拆分;
- 节点耗时统计;
- 异常事件列表。
-
用一个可视化工具快速搭一版
- Superset / Metabase / Grafana 都可以;
- 先不追求 UI 完美,只要团队能看到数据就行。
-
等大家开始用看板后,再逐步优化
- 把最常用的视图放到首页;
- 加筛选维度(按时间、按场景、按模型);
- 把异常 & 自愈信息挂上去。
做到这里,你就从:
「知道有日志有指标,但用起来很费劲」
升级成:
「打开一个地址,就能看到今天大模型系统跑得怎么样,
哪个场景出问题了,哪个 Agent 该优化,
甚至知道大概花了多少钱。」