实战 SOP
实战 SOP

AI Agent 可观测性与线上评测 SOP:链路追踪、成本与告警

生产级 AI Agent 可观测性与线上评测完整 SOP:六步走从量化基线(延迟/token 成本/工具成功率/错误率)、链路追踪(Langfuse @observe 装饰器 + Phoenix register + OpenTelemetry span)、token 与成本追踪、工具调用 artifact 日志、线上评测(LLM-as-judge 自动打分 + 用户 thumbs 反馈 create_score)、到告警与迭代(阈值规则 + 仪表盘)。每步附可复制 Python 代码,6 条踩坑记录,FAQ 5 条。开源工具为主,LangSmith 作为 SaaS 选项提及。

发布于 2026年8月4日8 分钟阅读
<!-- agent-observability-sop | sop | AI Agent 可观测性与线上评测 SOP:链路追踪、成本与告警 -->

Agent 上线后最怕的不是 prompt 不好,是你根本不知道它在干什么。线上跑了一周,用户投诉回答质量下降,你打开日志一看--全是 print("done")。哪一步慢了?哪次工具调用失败了?哪个用户的回答花了 $0.3?一概不知。没有可观测性的 Agent 就是黑盒里的黑盒:LLM 本身是黑盒,Agent 的多步工具调用是黑盒上叠黑盒,出问题时你只能猜。

可观测性不是"加日志"这么简单,它是一套系统工程:先定好要观测哪些指标(延迟、token 成本、工具成功率、错误率),再用链路追踪把每一步串起来,然后做线上评测(LLM-as-judge + 用户反馈),最后设告警自动发现问题。这篇 SOP 走一遍完整流程,每步附可复制的 Python 代码。工具选型以开源为主:Langfuse(开源 LLM 可观测性平台)、Arize Phoenix(开源 tracing + 评测)、OpenTelemetry(通用可观测性标准),LangSmith 作为 LangChain 生态的 SaaS 选项一并提及。和本站《LangGraph 生产级 Agent 搭建 SOP》(langgraph-production-agent-sop) 配套使用--那篇讲怎么搭 Agent,这篇讲怎么监控它。


一、量化基线:要观测什么

写任何 tracing 代码之前,先定义清楚要观测什么。Agent 可观测性的四个核心指标:

  1. 延迟(latency):端到端响应时间,按 p50/p95/p99 分位数统计。平均值会掩盖尾部延迟--p99 高意味着部分用户等很久。
  2. token 成本(cost):每次调用的 input/output token 数和对应费用。Agent 多步调用容易成本失控。
  3. 工具调用成功率(tool-call success rate):每次工具调用的成功/失败比例。工具失败是 Agent 翻车的高频原因。
  4. 错误率(error rate):整个 Agent run 失败的比例。区分可重试错误(API 5xx)和不可重试错误(代码 bug)。

这四个指标构成了一个完整的"健康度仪表盘":延迟反映用户体验,成本反映可持续性,工具成功率反映外部依赖稳定性,错误率反映系统可靠性。少任何一个都有盲区--只看延迟不看错误率,可能速度快是因为失败请求直接返回了;只看成本不看工具成功率,可能省了 token 但工具一直失败在空转。生产环境必须四个一起看,交叉对比才能发现真问题。

把这个四指标体系用代码定义出来:

python
from dataclasses import dataclass, field

@dataclass
class AgentMetrics:
    latencies: list = field(default_factory=list)
    token_costs: list = field(default_factory=list)
    tool_success: int = 0
    tool_total: int = 0
    errors: int = 0
    total_runs: int = 0

    def record_latency(self, seconds: float) -> None:
        self.latencies.append(seconds)

    def record_cost(self, cost_usd: float) -> None:
        self.token_costs.append(cost_usd)

    def record_tool_call(self, success: bool) -> None:
        self.tool_total += 1
        if success:
            self.tool_success += 1

    def record_run(self, error: bool = False) -> None:
        self.total_runs += 1
        if error:
            self.errors += 1

    @staticmethod
    def percentile(values: list, p: float) -> float:
        if not values:
            return 0.0
        sorted_vals = sorted(values)
        idx = min(int(len(sorted_vals) * p / 100), len(sorted_vals) - 1)
        return sorted_vals[idx]

    def summary(self) -> dict:
        return {
            "latency_p50": self.percentile(self.latencies, 50),
            "latency_p95": self.percentile(self.latencies, 95),
            "latency_p99": self.percentile(self.latencies, 99),
            "cost_avg": sum(self.token_costs) / len(self.token_costs)
                        if self.token_costs else 0,
            "tool_success_rate": self.tool_success / self.tool_total
                                 if self.tool_total else 0,
            "error_rate": self.errors / self.total_runs
                          if self.total_runs else 0,
        }

这个 AgentMetrics 是所有后续步骤的基础--tracing 采集数据,metrics 聚合数据,评测和告警消费数据。


二、链路追踪:OpenTelemetry + Langfuse/Phoenix

指标告诉你"出了什么问题",tracing 告诉你"在哪一步出的"。Agent 一次 run 可能调 3-5 次工具、2-3 次 LLM,没有 trace 你无法定位是哪一步慢了或错了。

Langfuse:@observe 装饰器

Langfuse 的 @observe() 装饰器是最轻量的 tracing 方式--给函数加一行注解,自动捕获输入、输出、耗时和异常:

python
from langfuse import observe

@observe(name="agent_run")
def run_agent(query: str) -> str:
    research = search_tool(query)
    answer = draft_answer(research)
    return answer

@observe(name="search_tool")
def search_tool(query: str) -> str:
    # 替换为你的搜索 API 调用
    return f"搜索结果:{query}"

@observe(name="draft_answer")
def draft_answer(context: str) -> str:
    # 替换为你的 LLM 调用
    return f"基于 {context} 的回答"

外层 run_agent 自动成为一个 trace,内层 search_tooldraft_answer 成为它的子 span。在 Langfuse UI 里能看到完整调用树--每一步的输入输出、耗时、是否出错。

Phoenix:register + OpenTelemetry spans

Phoenix 基于 OpenTelemetry,用 register() 一行初始化 tracer:

python
from phoenix.otel import register
from opentelemetry import trace

# 需先 pip install arize-phoenix-otel
tracer_provider = register(
    project_name="my-agent",
    endpoint="http://localhost:6006/v1/traces",
    auto_instrument=True,
)
tracer = trace.get_tracer("agent")

def run_agent_phoenix(query: str) -> str:
    with tracer.start_as_current_span("agent_run") as span:
        span.set_attribute("input.value", query)
        result = f"回答:{query}"
        span.set_attribute("output.value", result)
        return result

auto_instrument=True 会自动给 OpenAI、LangChain 等常用库加 tracing。手动 span 用 start_as_current_span,通过 set_attribute 记录输入输出。Phoenix 遵循 OpenInference 语义约定(input.valueoutput.value 等属性名),详见 OpenInference 规范

Langfuse 和 Phoenix 的核心区别:Langfuse 更偏"全生命周期管理"--tracing + prompt 管理 + 评测 + 用户反馈一体化,自托管简单(Docker 一键起);Phoenix 更偏"分析和评测"--强在 trace 分析视图、漂移检测和 embedding 可视化,适合需要深度下钻的场景。如果你用 LangChain/LangGraph 生态,LangSmith 是 SaaS 里集成最深的,但数据要出你的网络。三者不互斥:Langfuse 做主 tracing 后端,Phoenix 做评测分析,是常见组合。

@observe 的参数(as_typename)和 register() 的返回值在不同 SDK 版本可能有差异,以官方文档为准


三、token 与成本追踪

Agent 多步调用 LLM,成本很容易失控--一次 run 调 5 次 LLM,每次 2000 token,跑 1000 次就是 1000 万 token。不追踪成本,月底账单会吓你一跳。

先定义定价表和成本计算函数:

python
# 定价表(USD per 1K tokens),按你的模型更新
PRICING = {
    "gpt-4o": {"input": 0.0025, "output": 0.01},
    "gpt-4o-mini": {"input": 0.00015, "output": 0.0006},
}

def compute_cost(model: str, input_tokens: int, output_tokens: int) -> float:
    rates = PRICING.get(model)
    if rates is None:
        return 0.0
    return (input_tokens * rates["input"]
            + output_tokens * rates["output"]) / 1000

然后给 LLM 调用加 tracing,记录 token 用量。Langfuse 在 as_type="generation" 时会解析 usage 字段:

python
from langfuse import observe

@observe(name="llm_call", as_type="generation")
def call_llm(model: str, messages: list) -> dict:
    # 替换为你的 LLM SDK 调用(如 openai.chat.completions.create)
    response = {
        "content": "模型回复",
        "usage": {"prompt_tokens": 500, "completion_tokens": 200},
    }
    usage = response["usage"]
    cost = compute_cost(model, usage["prompt_tokens"],
                        usage["completion_tokens"])
    return {
        "content": response["content"],
        "cost_usd": cost,
        "input_tokens": usage["prompt_tokens"],
        "output_tokens": usage["completion_tokens"],
    }

更深入的成本优化策略(前缀缓存、模型路由、batch API)见本站《大模型 API 成本优化 SOP》(llm-api-cost-optimization-sop)。这里补充一个生产实践:成本追踪要按"每次 Agent run"聚合,而不是只看单次 LLM 调用。一次 run 可能调 5 次 LLM,单次每次都便宜,但加起来可能 $0.15--跑 10000 次就是 $1500。在 trace 里记录 cost_usd 字段后,在 Langfuse dashboard 按 trace 聚合,看 p50/p95 的单次 run 成本,这才是用户视角的真实成本。


四、工具调用与 artifact 日志

Agent 的工具调用是出问题的高发区--搜索 API 返回空、代码执行报错、数据库查询超时。每个工具调用的输入输出都应该作为 artifact 记录下来,方便事后排查。

python
import json
from langfuse import observe

@observe(name="web_search_tool")
def web_search(query: str) -> dict:
    # 替换为实际搜索 API 调用
    raw_result = {
        "title": "示例结果",
        "snippet": "相关内容摘要",
        "url": "https://example.com",
    }
    return {
        "result": raw_result["snippet"],
        # artifact 存原始返回,方便排查
        "artifact": json.dumps(raw_result, ensure_ascii=False),
    }

@observe(name="code_executor_tool")
def execute_code(code: str) -> dict:
    # 替换为沙箱化代码执行
    return {
        "stdout": "执行输出",
        "exit_code": 0,
        "artifact": code,  # 存执行的代码
    }

@observe 自动把函数返回值记录到 trace 里。如果返回值包含 artifact 字段,在 Langfuse UI 里能看到完整的工具原始输出。排查"为什么这次搜索没找到结果"时,直接看 artifact 就行。


五、线上评测:LLM-as-judge + 用户反馈

离线评测在上线前跑固定测试集(见本站《AI agent 评测与基准测试 SOP》(ai-agent-evaluation-sop)),线上评测在真实流量上持续跑。两种方式互补:离线评测挡回归,线上评测发现真实世界的漂移和边缘 case。线上评测的关键设计是采样策略--不是每条 trace 都跑 judge(成本太高),而是按规则采样:100% 采错误 trace(必看),10% 采正常 trace(随机抽样),100% 采用户点踩的 trace(最真实的负反馈信号)。这样既控制了 judge 成本,又覆盖了最需要关注的 case。

LLM-as-judge:自动打分

用一个 LLM 给另一个 LLM 的输出打分,覆盖线上 trace 的一个采样(如 10%):

python
from langfuse import observe

@observe(name="llm_judge")
def evaluate_answer(query: str, answer: str) -> float:
    judge_prompt = (
        "请给以下回答打分(1-5 分),评估准确性和有用性。\n"
        f"问题:{query}\n"
        f"回答:{answer}\n"
        "只回复一个 1-5 的数字。"
    )
    # 替换为你的 judge LLM 调用
    # 建议 judge 用比生产更强的模型,避免自我偏好偏差
    score_text = "4"  # judge_response 解析后
    return float(score_text)

用户反馈:thumbs up/down

显式用户反馈是最真实的质量信号。用 Langfuse 的 create_score API 把反馈关联到 trace:

python
from langfuse import get_client

def submit_user_feedback(trace_id: str, thumbs_up: bool) -> None:
    langfuse = get_client()
    langfuse.create_score(
        trace_id=trace_id,
        name="user_feedback",
        value=1 if thumbs_up else 0,
        data_type="NUMERIC",
        comment="用户点赞/点踩",
    )

前端收集到 thumbs up/down 后调这个函数,把分数写回 Langfuse。在 dashboard 里按 user_feedback 分数筛选 trace,对比"被踩的"和"被赞的"回答特征差异,定位质量瓶颈。

create_score 的参数签名在不同 SDK 版本可能有差异,以官方文档为准


六、告警与迭代:阈值与仪表盘

有了数据还要能自动发现问题。定义告警规则,当指标越过阈值时触发通知:

python
from dataclasses import dataclass

@dataclass
class AlertRule:
    metric: str
    threshold: float
    comparator: str  # "gt"(大于触发)或 "lt"(小于触发)

    def check(self, value: float) -> bool:
        if self.comparator == "gt":
            return value > self.threshold
        return value < self.threshold

RULES = [
    AlertRule("latency_p95", 10.0, "gt"),        # p95 延迟 > 10s
    AlertRule("error_rate", 0.05, "gt"),          # 错误率 > 5%
    AlertRule("tool_success_rate", 0.90, "lt"),   # 工具成功率 < 90%
    AlertRule("cost_avg", 0.50, "gt"),            # 平均成本 > $0.50/run
]

def check_alerts(snapshot: dict) -> list:
    """检查指标快照,返回触发的告警列表。"""
    triggered = []
    for rule in RULES:
        value = snapshot.get(rule.metric, 0.0)
        if rule.check(value):
            triggered.append(
                f"ALERT: {rule.metric}={value:.4f} "
                f"({rule.comparator} {rule.threshold})"
            )
    return triggered

snapshot 就是前面 AgentMetrics.summary() 的返回值。生产环境把这个检查放到定时任务里(每 5 分钟跑一次),触发告警后发 Slack/钉钉/邮件。Langfuse 和 Phoenix 都内置了 dashboard,可以直接在 UI 里看 p95 延迟、错误率、成本趋势等图表,不用自己搭 Grafana。告警迭代的核心循环是:设阈值 -> 触发告警 -> 人肉排查 -> 根因修复 -> 调整阈值。前两周阈值会频繁调整,趋于稳定后改为月度 review 一次。


七、踩坑记录

坑一:只看平均值不看分位数。 平均延迟 2 秒看起来没问题,但 p99 可能是 30 秒--每 100 个用户就有 1 个等半分钟。平均值会被大量快请求拉低,掩盖尾部问题。生产环境必须看 p95 和 p99。

坑二:tracing 开了但没传 usage。 Langfuse/Phoenix 的自动捕获依赖 SDK 集成。如果你直接用 requests.post 调 LLM API 而不是用官方 SDK,token 用量不会被自动记录。要么换用 instrumented 的 SDK,要么手动在 trace 里设置 token 属性。

坑三:LLM-as-judge 不校准就上线。 Judge 模型有自己的偏好--可能偏向长回答、偏向某种格式。不拿人工标注的样本校准,你可能在优化"judge 喜欢"而不是"用户喜欢"。先跑 50-100 条人工标注,算 judge 和人工的一致率(如 Cohen's kappa),低于 0.6 不能上线。

坑四:artifact 日志太大撑爆存储。 搜索结果、网页 HTML、API 返回的 JSON 可能几十 KB 甚至几 MB。全量记录 artifact 会让 trace 存储成本飙升。对超过 4KB 的 artifact 截断,只保留前 2000 字符加省略号。

坑五:告警阈值拍脑袋设。 没有基线数据就设阈值,要么告警风暴(阈值太低)要么漏报(阈值太高)。先跑 1-2 周收集数据,看指标的 p95 在哪,然后设在 p95 的 1.5-2 倍处。

坑六:Langfuse 和 Phoenix 同时开互相干扰。 两者都基于 OpenTelemetry,如果同时注册 tracer provider 且不隔离,span 可能被重复导出或路由到错误后端。选一个作为主 tracing 后端,另一个用单独的 OTEL_EXPORTER_OTLP_ENDPOINT 配置,或通过 resource attribute 区分。


FAQ

Q1:Langfuse、Phoenix、LangSmith 怎么选? A:Langfuse 是开源 LLM 可观测性平台,可自托管,适合要求数据内网的团队。Phoenix(Arize)也是开源的,强项在评测和漂移检测,适合评测密集型场景。LangSmith 是 LangChain 的 SaaS,与 LangChain/LangGraph 集成最深但有厂商锁定。自托管加框架无关选 Langfuse;评测为主选 Phoenix;纯 LangChain 生态选 LangSmith。配合本站《LangGraph 生产级 Agent 搭建 SOP》(langgraph-production-agent-sop) 使用效果最佳。

Q2:@observe 装饰器影响性能吗? A:开销很小--每个 span 几毫秒的序列化和异步批量上传。Langfuse v4 用异步 batch 上传,trace 不阻塞主循环。但高吞吐场景(1000+ calls/sec)需调 batch 参数(flush_atflush_interval),否则内存堆积。

Q3:LLM-as-judge 用哪个模型? A:建议 judge 用比生产模型更强的模型(如生产用 GPT-4o-mini,judge 用 GPT-4o),避免自我偏好偏差。成本敏感时对线上 trace 采样 10% 跑 judge,而不是全量。更多评测方法见本站《AI agent 评测与基准测试 SOP》(ai-agent-evaluation-sop)。

Q4:用户反馈(thumbs)数据量太少怎么办? A:显式反馈天然稀疏--大多数用户不会点赞或点踩。补充隐式信号:回答被复制(满意)、用户重新问同一问题(不满意)、会话长度突变。隐式信号权重低于显式反馈,但能覆盖更多 case。

Q5:线上评测和离线评测什么关系? A:离线评测在部署前跑固定测试集,是上线门禁(挡回归)。线上评测在真实流量上持续跑,是运行时监控(发现漂移和边缘 case)。两者互补:离线测的是"已知场景",线上测的是"真实世界"。缺了离线评测回归没人挡,缺了线上评测真实问题没人发现。成本优化的预算分配见本站《大模型 API 成本优化 SOP》(llm-api-cost-optimization-sop)。


看法

可观测性的核心矛盾是:你恨不得记录一切,但记录一切的成本(存储、性能、噪音)会拖垮系统。好的可观测性不是"全量记录",而是"分层记录"--trace 记全链路但采样 10%,metrics 记聚合值但全量,artifact 记摘要但不存原始大对象。Langfuse 和 Phoenix 的价值不只是工具本身,而是它们定义了一套 LLM 可观测性的语义约定(什么该记、怎么记、记到什么粒度),让你不用从零设计 schema。最后一句:可观测性是 Agent 能上生产的必要条件,不是可选功能。一个你看不见的系统,你不敢让它自动决策。


参考来源

本文由 AI 辅助生成,经人工审核编辑。最后更新:2026-08-04

常见问题

Langfuse、Phoenix、LangSmith 怎么选?
Langfuse 是开源 LLM 可观测性平台,可自托管,适合要求数据内网的团队。Phoenix(Arize)也是开源的,强项在评测和漂移检测,适合评测密集型场景。LangSmith 是 LangChain 的 SaaS,与 LangChain/LangGraph 集成最深但有厂商锁定。自托管加框架无关选 Langfuse;评测为主选 Phoenix;纯 LangChain 生态选 LangSmith。配合本站《LangGraph 生产级 Agent 搭建 SOP》(langgraph-production-agent-sop) 使用效果最佳。
`@observe` 装饰器影响性能吗?
开销很小--每个 span 几毫秒的序列化和异步批量上传。Langfuse v4 用异步 batch 上传,trace 不阻塞主循环。但高吞吐场景(1000+ calls/sec)需调 batch 参数(`flush_at`、`flush_interval`),否则内存堆积。
LLM-as-judge 用哪个模型?
建议 judge 用比生产模型更强的模型(如生产用 GPT-4o-mini,judge 用 GPT-4o),避免自我偏好偏差。成本敏感时对线上 trace 采样 10% 跑 judge,而不是全量。更多评测方法见本站《AI agent 评测与基准测试 SOP》(ai-agent-evaluation-sop)。
用户反馈(thumbs)数据量太少怎么办?
显式反馈天然稀疏--大多数用户不会点赞或点踩。补充隐式信号:回答被复制(满意)、用户重新问同一问题(不满意)、会话长度突变。隐式信号权重低于显式反馈,但能覆盖更多 case。
线上评测和离线评测什么关系?
离线评测在部署前跑固定测试集,是上线门禁(挡回归)。线上评测在真实流量上持续跑,是运行时监控(发现漂移和边缘 case)。两者互补:离线测的是"已知场景",线上测的是"真实世界"。缺了离线评测回归没人挡,缺了线上评测真实问题没人发现。成本优化的预算分配见本站《大模型 API 成本优化 SOP》(llm-api-cost-optimization-sop)。

相关文章

实战 SOP

AI 数字人制作实战 SOP:从脚本到成品的可复制流程

把 AI 数字人制作拆成六步可复制流程:明确用途选工具(HeyGen/D-ID/Synthesia/Colossyan/DeepBrain 及国内腾讯智影/硅基智能)、写口播脚本(附 prompt 模板)、选或定制形象、先定音色再生成口型、字幕剪辑与合规后处理、平台适配发布。附 5 个避坑(形象授权/口型对不齐/多语言音色/长视频成本/合规标识)和 5 条 FAQ。代表性流程,非单一工具实测,功能以官网为准。

2026年8月7日8 分钟阅读
实战 SOP

block/buzz 自托管部署 SOP:从 Docker 到 agent 入组

block/buzz 自托管部署完整 SOP(与 buzz-hive-mind 热点文成对):本地开发栈(just setup/build/dev)+ 生产单节点(deploy/compose Docker,Postgres/Redis/MinIO)+ 配置(.env:RELAY_URL/BUZZ_RELAY_PRIVATE_KEY/RELAY_OWNER_PUBKEY)+ agent 入组(Nostr keypair NIP-98 签名,buzz-admin 管成员)+ 闭门 relay + 5 FAQ。部署命令全据 README/compose/.env/CLI/ARCHITECTURE,未编造。

2026年8月6日9 分钟阅读
实战 SOP

n8n 搭建 AI agent 工作流实战 SOP:部署与避坑

在 n8n 画布里搭一个能自主调用工具的 AI agent 工作流的完整 SOP:Docker 自托管一条命令部署、AI Agent 节点四件套解剖(Language Model+Memory+Tools+System Prompt)、分步搭建(选触发器->配节点->加工具->输出->测试发布)、五个避坑(Memory 失忆/API Key 硬编码/过度设计/上下文漂移/数据格式不匹配)+5 FAQ。节点参数以 n8n 官方文档为准,给配置逻辑不伪造完整 JSON。

2026年8月6日9 分钟阅读