传统应用的可观测性(Metrics/Logs/Traces)在 LLM 应用面前依然成立,但要新增三个 LLM 特有的观测维度:Token 与成本(每次调用消耗多少、花了多少钱)、模型质量(回答对不对、是否幻觉、是否符合预期)、模型安全(提示注入、有害内容、PII 泄露)。大模型是"黑盒",它的行为是概率性的——同一提示词每次输出都不同,这决定了 GenAI 可观测性不能只看"延迟和错误码",还要看语义层面的质量与安全。本指南系统构建 GenAI 应用可观测体系:LLM 调用追踪、OTel GenAI 语义约定、成本用量监控、质量评估(LLM-as-Judge)、RAG 评估、安全监控、漂移检测与反馈回路,最后给出完整架构。
一、GenAI 应用需要观测什么
1.1 传统维度 + LLM 特有维度
传统(继承自常规应用):
· 延迟:首 Token 延迟(TTFT)、总生成时间
· 错误:超时、限流、模型不可用
· 流量:调用量、QPS、并发
LLM 特有(新增):
· Token:输入/输出 token 数(= 成本)
· 成本:按模型按次核算金额
· 质量:回答正确性、幻觉率、相关性
· 安全:提示注入、有害内容、PII 泄露
· 模型行为:温度、top_p、版本变化
ℹ️ 核心洞察:LLM 应用可观测性 = 传统可靠性监控 + 语义质量监控。前者回答"服务是不是通的",后者回答"回答靠不靠谱"——两者缺一不可。
1.2 三类观测对象
① LLM 调用本身:每次 generate/chat 的输入输出、token、耗时
② 编排链路:Agent 的每一步(工具调用、记忆检索、子任务)
③ 业务效果:用户满意度、转化率、回答采纳率(与业务指标联动)
二、LLM 调用追踪
2.1 Span 设计
一次 LLM 调用的 Span 结构:
Span: llm / openai.chat / anthropic.complete
· attributes: gen_ai.provider, gen_ai.model
· attributes: gen_ai.request.temperature, max_tokens
· events: message(input / output,含 token 计数)
· span metrics: token 数、耗时、成本
RAG 流程的 Span 链:
parent: 用户请求
├─ 检索(embedding 调用)
├─ 知识库查询(DB)
├─ 上下文组装
└─ LLM 生成(llm span)
Agent 流程:
parent: Agent 决策
├─ 记忆检索
├─ 工具调用(tool span)
└─ LLM 再次决策(loop)
2.2 OTel GenAI 语义约定
OTel GenAI 语义约定(genai conventions):
gen_ai.provider # openai / anthropic / ...
gen_ai.model # gpt-4o / claude-3-5-sonnet
gen_ai.request.temperature
gen_ai.request.max_tokens
gen_ai.request.model
gen_ai.response.id
gen_ai.response.finish_reason # stop / length / tool_calls
gen_ai.usage.input_tokens
gen_ai.usage.output_tokens
gen_ai.operation.name # chat / embeddings / complete
Span 事件(记录输入输出内容):
gen_ai.prompt # 输入消息
gen_ai.completion # 输出消息
2.3 手动埋点示例(Python)
# genai_tracing.py — 手动为 LLM 调用打 span
from opentelemetry import trace
from opentelemetry.semconv.ai import GenAIAttributes
tracer = trace.get_tracer("genai.app")
@tracer.start_as_current_span("llm.chat")
def chat_with_model(user_query: str) -> str:
span = trace.get_current_span()
span.set_attribute(GenAIAttributes.PROVIDER, "openai")
span.set_attribute(GenAIAttributes.MODEL, "gpt-4o")
span.set_attribute(GenAIAttributes.OPERATION, "chat")
response = model.chat(user_query)
usage = response.usage # token 统计
span.set_attribute(GenAIAttributes.USAGE_INPUT_TOKENS, usage.prompt_tokens)
span.set_attribute(GenAIAttributes.USAGE_OUTPUT_TOKENS, usage.completion_tokens)
span.add_event("gen_ai.completion", {"text": response.content})
return response.content
2.4 SDK 集成(LangChain / OpenAI)
# OpenAI SDK 自动埋点(借助 OpenAI OTel 集成)
from openai import OpenAI
from openai_opentelemetry import enable_tracing
enable_tracing() # 自动为每个 API 调用创建 span
client = OpenAI()
# LangChain 自动埋点
from langchain_core.callbacks import tracing_v2_enabled
with tracing_v2_enabled("my-app"):
result = chain.invoke({"question": "..."})
三、LLM 指标与告警
3.1 关键指标定义
# LLM 核心指标(通过 span metrics / 埋点上报到 Prometheus)
genai_llm_call_total{provider, model, operation} # 调用量
genai_llm_token_input_total{model} # 输入 token
genai_llm_token_output_total{model} # 输出 token
genai_llm_cost_usd_total{model} # 成本($)
genai_llm_first_token_latency_seconds{model} # TTFT
genai_llm_total_latency_seconds{model} # 总延迟
genai_llm_error_total{provider, code} # 错误
genai_llm_quality_score{model, metric} # 质量分
genai_llm_toxic_total # 有害输出
genai_llm_prompt_injection_total # 注入攻击
3.2 告警规则示例
groups:
- name: genai.rules
rules:
# 错误率
- alert: LLMErrorRateHigh
expr: |
sum(rate(genai_llm_error_total[5m]))
/ sum(rate(genai_llm_call_total[5m])) > 0.05
for: 5m
# 成本突增(预算控制)
- alert: LLMCostSpike
expr: |
sum(rate(genai_llm_cost_usd_total[1h])) > 10
labels:
severity: warning
# TTFT 超阈值
- alert: LLMFirstTokenSlow
expr: |
histogram_quantile(0.95,
rate(genai_llm_first_token_latency_seconds_bucket[5m])
) > 5
for: 3m
四、Token 成本监控
4.1 成本归因
成本可观测维度:
· 按模型(gpt-4o vs claude vs 本地)
· 按服务/场景(客服、写作、推荐)
· 按用户/租户(多租户成本分摊)
· 按时间(日/周趋势)
成本 = Σ(token_in × 输入单价 + token_out × 输出单价)
→ 输出 token 往往更贵(5-10x)
4.2 成本计算埋点
# cost_metrics.py — 按模型单价计算成本
MODEL_PRICES = {
"gpt-4o": {"input": 0.0025, "output": 0.010}, # $/1K tokens
"claude-3-5-sonnet": {"input": 0.003, "output": 0.015},
"llama-3.1-70b": {"input": 0.0002, "output": 0.0003},
}
def report_cost(model, input_tokens, output_tokens):
price = MODEL_PRICES[model]
cost = (input_tokens / 1000) * price["input"] \
+ (output_tokens / 1000) * price["output"]
# 上报到 Prometheus counter
prometheus_counter("genai_llm_cost_usd_total",
value=cost, labels={"model": model})
return cost
4.3 预算治理
成本治理手段:
· 每日预算 + 告警(费用超过当日预算 80% 触发)
· 按租户配额(限额即停)
· 模型路由:低成本任务走便宜模型
· 语义缓存:命中缓存免调用
· 降采样:对评测性调用按比例抽样
五、质量评估(LLM-as-Judge)
5.1 评估维度
LLM 输出质量评估维度:
· 正确性(factual correctness)
· 相关性(relevance to query)
· 忠实度(faithfulness,是否基于给定上下文)
· 连贯性(coherence)
· 安全性(harmfulness)
· 可读性(format)
评估方式:
· LLM-as-Judge:用强模型打弱模型的输出(生产高频)
· 规则/正则:硬性约束(格式、关键词)
· 人工抽样:定期标注校准
5.2 生产在线评估
# judge.py — LLM-as-Judge 在线评估
from openai import OpenAI
judge = OpenAI()
JUDGE_PROMPT = """
你是质量评估员。给定用户问题与 AI 回答,输出 1-5 分:
- 正确性: {1..5}
- 相关性: {1..5}
- 忠实度: {1..5}(是否基于提供的上下文,不臆造)
返回 JSON: {"correctness": x, "relevance": x, "faithfulness": x}
"""
def evaluate_response(query, context, answer):
resp = judge.chat.completions.create(
model="gpt-4o-mini",
response_format={"type": "json_object"},
messages=[
{"role": "system", "content": JUDGE_PROMPT},
{"role": "user", "content":
f"问题: {query}\n上下文: {context}\n回答: {answer}"},
],
)
scores = json.loads(resp.choices[0].message.content)
# 上报质量分指标
for metric, val in scores.items():
prometheus_histogram("genai_llm_quality_score",
value=val, labels={"metric": metric})
return scores
5.3 质量告警
# 平均质量分低于阈值(如 4.0)
avg(genai_llm_quality_score{metric="faithfulness"}[1h]) < 4.0
# 低分率占比
sum(genai_llm_quality_score{metric="correctness"} < 3)
/ count(genai_llm_quality_score{metric="correctness"}) > 0.05
六、RAG 评估
6.1 RAG 特有的观测点
RAG 链路观测:
· 检索命中率:检索出的文档与问题相关度
· 上下文利用率:回答是否真的用了检索内容
· 引用可验证性:回答引用的文档是否存在
· 检索延迟与失败
· 向量库相关指标(embedding 调用、相似度分布)
关键问题:
· "回答对但没引用" → 检查上下文是否真正注入
· "引用了但答错" → 检索相关性差 / 文档冲突
· "无引用乱答" → 上下文丢失 / 组装 bug
6.2 指标与追踪
def rag_pipeline(question):
# 检索 span
with tracer.start_as_current_span("rag.retrieve"):
docs = vector_store.similarity_search(question, k=5)
span.set_attribute("rag.retrieved_docs", len(docs))
span.set_attribute("rag.top1_score", docs[0].score if docs else 0)
# 组装 + 生成
return generate(question, context=docs)
# 指标:
# rag_retrieval_hit_rate # 检索有结果的比例
# rag_context_relevance # 检索相关度(judge 评估)
# rag_citation_accuracy # 引用正确率
6.3 RAG 质量告警
# 检索命中率骤降
sum(rate(rag_retrieval_hit_rate_total[5m])) < 0.8
# 引用准确率下降
avg(rag_citation_accuracy[1h]) < 0.9
七、安全监控
7.1 LLM 安全观测维度
安全观测四类:
① 提示注入攻击:输入含注入指令(间接/直接)
② 有害内容:输出涉黄暴恐/歧视/仇恨
③ PII 泄露:输入或输出含敏感个人信息
④ 数据外泄:训练数据在输出中被复现(越狱)
检测手段:
· 输入/输出过滤(关键词、分类器)
· LLM-as-Judge 安全评估(违规检测)
· 模型安全套件(Guardrails)
7.2 注入检测埋点
def detect_injection(user_input: str) -> bool:
# 规则 + 模型双重检测
rule_hit = any(kw in user_input.lower()
for kw in ["ignore previous", "you are now",
"system prompt", "jailbreak"])
model_verdict = guardrail.check(user_input)
if rule_hit or model_verdict.is_violation:
prometheus_counter("genai_prompt_injection_total",
labels={"source": "user_input"})
return True
return False
7.3 安全告警与响应
# 注入攻击率
sum(rate(genai_prompt_injection_total[5m])) > 0.01
# PII 泄露
sum(rate(genai_pii_exposure_total[5m])) > 0
响应动作:
· 拦截输入(不调用模型)
· 过滤输出(替换/截断)
· 记录攻击样本(安全分析)
· 限流封禁(高频来源 IP/用户)
八、漂移检测与反馈回路
8.1 模型漂移观测
漂移检测:
· 输出分布漂移(回答风格/长度变化)
· 输入分布漂移(用户问题类型变化)
· 质量分趋势下滑(长期)
· 模型版本变更对比(升级前后 A/B)
方法:
· 质量分滑窗均值 + 趋势
· 输出长度/置信度分布
· 用户行为反馈(点赞/点踩率)
8.2 反馈回路
# 用户反馈采集 → 修正评估集 → 回归测试
def collect_feedback(response_id, rating, comment=""):
# 存反馈样本库(eval set)
store_feedback(response_id, rating, comment)
# 低分样本定期加入评测集
if rating <= 2:
eval_set.add(response_id)
# 触发告警:低分率上升
track_low_rating_ratio()
8.3 离线评估与发布门禁
GenAI 发布门禁(类似测试门禁):
1. 黄金评测集(golden set)跑分
2. 质量分达标(正确性/相关性 ≥ 阈值)
3. 安全测试通过(注入/有害样本 0 泄露)
4. 成本增量可接受
5. 线上灰度 A/B,观测质量分与用户反馈
→ 把"观测数据"变成"上线决策依据"
九、完整 GenAI 可观测性架构
9.1 架构蓝图
应用(SDK/Agent) ──► OTel Collector ──► 后端
│ 埋点: │
│ · LLM 调用 span ├─► Tempo(追踪)
│ · token/成本 metric ├─► Prometheus(指标)
│ · 访问日志 ├─► Loki(日志)
│ · 质量/安全评估 └─► 评估平台(judge 结果)
▼
评估服务(LLM-as-Judge / Guardrails)
└─► 质量分 / 安全分 上报
可视化:Grafana(指标/成本/质量面板)+ Tempo(链路)
告警:错误率、成本、TTFT、质量分、安全事件
反馈回路:线上评分 → 评测集 → 回归门禁
9.2 面板设计
GenAI 观测面板(Grafana):
· 总览:调用量、QPS、总成本、平均质量分
· 模型对比:各模型延迟/成本/错误
· Token 趋势:输入/输出/按服务拆分
· 质量:正确性/相关性/忠实度时间序列
· 安全:注入/有害/PII 事件
· 链路:Top 慢调用、失败 Trace
9.3 落地清单
□ LLM 调用统一埋点(SDK 自动 + 手动补业务语义)
□ Token/成本指标上报(按模型/服务/租户)
□ 质量评估(LLM-as-Judge + 规则 + 人工抽样)
□ 安全检测(注入/有害/PII/外泄)
□ RAG 指标(检索命中、引用准确)
□ 漂移检测 + 用户反馈回路
□ 发布门禁(golden set + 安全 + 成本)
□ 告警(错误/成本/TTFT/质量/安全)
总结:GenAI 可观测性决策表
| 维度 | 观测对象 | 手段 |
|---|---|---|
| 可靠性 | 调用量、延迟、错误 | OTel span + Prometheus |
| 成本 | Token 用量、费用 | 埋点 + 单价表 |
| 质量 | 正确性/相关性/忠实度 | LLM-as-Judge |
| 安全 | 注入/有害/PII | Guardrails + 检测 |
| RAG | 检索命中/引用准确 | 链路埋点 |
| 演进 | 漂移、反馈 | 评测集 + 门禁 |
GenAI 可观测性把传统"三支柱"延伸到了语义世界——你不但要知道服务是通是堵,还要知道模型答得对不对、贵不贵、有没有泄露风险。这套体系让 LLM 应用从"黑盒冒险"变成"可验证的工程":每次上线前用评测集把关,上线后用指标/质量/安全实时观测,再把线上反馈回流到评测集形成闭环。落地时抓住五件事:埋点(LLM 调用 span)、记价(Token 成本)、打分(LLM-as-Judge)、护线(安全 Guardrails)、闭环(反馈→门禁)。做完这五步,你的 LLM 应用就有了与传统应用同等的可靠性与治理能力。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。