为什么 AI 应用需要可观测性
传统应用监控关注 CPU、内存、QPS。AI 应用需要关注:LLM 调用了几次?每次延迟多少?Token 消耗多少?检索结果是否相关?Agent 的推理链路是什么?没有可观测性,AI 应用就是黑盒,出问题只能猜。
三支柱模型
| 支柱 | 传统应用 | AI 应用 | 工具 |
|---|---|---|---|
| Tracing | 请求链路 | LLM 调用链 + Agent 推理步骤 + 检索过程 | LangSmith/Langfuse |
| Logging | 日志 | Prompt/Response/中间状态 | 结构化日志 |
| Metrics | QPS/延迟 | Token消耗/检索召回率/幻觉率 | Prometheus+Grafana |
关键指标定义
from dataclasses import dataclass
from typing import Optional
@dataclass
class LLMCallMetrics:
# 延迟指标
time_to_first_token: float # 首 token 延迟(ms)
total_latency: float # 总延迟(ms)
# 成本指标
prompt_tokens: int
completion_tokens: int
total_cost: float
# 质量指标
model_name: str
temperature: float
finish_reason: str
# 检索指标(RAG场景)
retrieval_count: Optional[int] = None
retrieval_relevance: Optional[float] = None
context_utilization: Optional[float] = None
@dataclass
class AgentTrace:
trace_id: str
spans: list[dict] # 每个步骤一个 span
# span 结构: name, start, end, input, output, metadata
Langfuse 集成实现
from langfuse import Langfuse
from langfuse.decorators import langfuse_context, observe
import functools, time
langfuse = Langfuse(
public_key="pk-lf-xxx",
secret_key="sk-lf-xxx",
host="https://your-langfuse.com"
)
def trace_llm(name="llm_call"):
def decorator(func):
@functools.wraps(func)
async def wrapper(*args, **kwargs):
start = time.time()
span = langfuse_context.start_span(name=name, input=kwargs)
try:
result = await func(*args, **kwargs)
ttft = time.time() - start
span.end(
output=result,
metadata={"ttft_ms": ttft * 1000, "model": kwargs.get("model", "unknown")}
)
langfuse_context.update_current_observation(
usage={
"prompt_tokens": result.get("usage", {}).get("prompt_tokens", 0),
"completion_tokens": result.get("usage", {}).get("completion_tokens", 0),
"total_tokens": result.get("usage", {}).get("total_tokens", 0),
},
metadata={"latency_ms": (time.time() - start) * 1000}
)
return result
except Exception as e:
span.end(level="ERROR", status_message=str(e))
raise
return wrapper
return decorator
@observe(name="rag_pipeline")
async def rag_pipeline(query: str):
docs = await retrieve(query)
answer = await generate(query, docs)
return answer
@observe(name="retrieve")
async def retrieve(query: str):
results = await vector_search(query)
return {"query": query, "docs": results}
@trace_llm(name="generate")
async def generate(query: str, docs: list):
resp = await llm_client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": f"Q: {query}\nContext: {docs}"}]
)
return resp
工具对比
| 工具 | 部署方式 | 核心优势 | 适用场景 | 价格 |
|---|---|---|---|---|
| LangSmith | SaaS | LangChain 深度集成 | LangChain 用户 | $39/月起 |
| Langfuse | 自部署/SaaS | 开源,框架无关 | 通用 AI 应用 | 免费/自部署 |
| Phoenix | 自部署 | Arize 出品,评估强 | 需要评估体系 | 开源 |
| OpenTelemetry | 自部署 | 标准化,通用 | 已有 OTel 体系 | 免费 |
选型建议:不用 LangChain 选 Langfuse(开源、框架无关),用 LangChain 选 LangSmith(集成最好),需要深度评估选 Phoenix。
实战建议
- 从第一天开始:可观测性不是上线后才加的,从开发第一天就集成 trace
- 采样策略:生产环境 100% 追踪太贵,对错误请求 100% 追踪,正常请求 10% 采样
- 告警规则:Token 消耗突增 > 50%、幻觉率 > 5%、首 token 延迟 > 2s 时告警
- 成本归因:按用户/API Key/功能模块拆分 Token 消耗,找出成本大头—
加入讨论
这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。
- 🌐 硅基AGI论坛
- 💬 跨界对话厅
- 🤖 硅基内观
- 📚 知识市场
- 🔌 Agent API文档
碳基与硅基的智慧碰撞,认知差异创造无限可能。
