Agent 可观测性与评测:从追踪到打分

Agent 可观测性与评测:从追踪到打分

一、为什么日志不够:Agent 的失败藏在链路里

传统服务的可观测性回答的是"这个请求成功了吗、慢在哪"。Agent 不一样,它至少有三类失败,而只有一类能从最终输出里看出来:

  • 结果错。答非所问——这类最容易发现。
  • 路径错。答案对了,但中间调用了不该调的工具、读到了不该读的数据、或者绕了 20 步才拿到一个本该 2 步得到的结果。最终输出看不出任何异常。
  • 中间步骤不安全。比如在第 7 步执行了一条有副作用的写操作。结果正确,但代价不可逆。

所以 Agent 的可观测性和评测必须回答三个不同的问题:做了什么(轨迹)、怎么做的(每一步)、结果对不对(最终输出)。三者的检查手段完全不同,这也是本文分成追踪、工具、评测三块来讲的原因。

二、追踪:一次 run 就是一条 trace

Agent 追踪的数据模型基本已经收敛成一个共识:一次完整的 Agent 运行 = 一条 trace,里面的每次 LLM 调用、每次工具调用、每次交接、每次护栏检查 = 一个 span。span 之间用父子关系表达"谁触发了谁",于是最终能还原出一棵可以逐层下钻的调用树。

OpenAI Agents SDK 的追踪就是这个模型:它内置记录 LLM 生成、工具调用、handoff、guardrail,以及你自定义的事件。要接入自己的后端,实现一个 TracingProcessor 注册进去即可。它还有一个明显为生产环境准备的开关——trace_include_sensitive_data,默认会带上敏感内容,上生产前应当评估是否需要关掉。

from agents import add_trace_processor, TracingProcessor

class MyExporter(TracingProcessor):
    def on_trace_start(self, trace): ...
    def on_trace_end(self, trace): ...
    def on_span_start(self, span): ...
    def on_span_end(self, span): ...

add_trace_processor(MyExporter())

2.1 用 OpenTelemetry 做统一口径

如果你不想被某一家 SDK 绑死,标准答案是 OpenTelemetry。这方面有一个关键状态必须说清楚:GenAI 语义约定目前整体处于 Development(开发中)状态,还没有稳定。也就是说,gen_ai.* 这些属性名在语义约定仓库里随时可能调整,不适合直接拿来做长期的存储表结构和告警规则。

另一个容易踩坑的点是:GenAI 语义约定的文档已经从这个仓库迁移出去了,现在维护在独立的 open-telemetry/semantic-conventions-genai 仓库里。老链接(包括 OpenTelemetry 官网上的 /docs/specs/semconv/gen-ai/gen-ai-spans)现在只会显示一个"已迁移"的提示页。做集成时记得看新仓库。

已经定义出来的 span 类型覆盖度其实相当不错,值得对照一下自己的系统缺了哪一类:

Span 类型覆盖什么
create agent spanAgent 的创建/实例化
invoke agent client span调用远端 Agent 服务
invoke agent internal span进程内的一次 Agent 运行
invoke workflow span编排多个 Agent 的工作流(图、编排器)
plan span规划步骤
execute tool span工具执行

关键属性包括 gen_ai.agent.namegen_ai.operation.namegen_ai.provider.namegen_ai.request.modelgen_ai.operation.name 的取值里已经有 invoke_agent(调用 Agent)和 generate_content(多模态内容生成)等。

还有一个细节对多轮会话很关键:gen_ai.conversation.id。规范里明确要求——只有在库本身已有会话标识、或应用通过 OpenTelemetry 上下文提供了的时候才填;如果拿不到,就不要填,尤其不要用新生成的 UUID、trace id 或请求内容的哈希去凑。原因很实际:这些"凑出来的" id 每次都不一样,按它聚合会话会得到一堆只有一条 span 的假会话,比不填还糟。文档里把这条单独写成了注脚,说明踩的人不少。

规范还给出了主流框架里对应哪个调用的说明,可以直接拿来对齐埋点粒度:CrewAI 是 Crew.kickoff()、LangChain/LangGraph 是 *Graph*.invoke()、Microsoft Agent Framework 是 Workflow*.run()、OpenAI Agents SDK 是带 handoff 或子 Agent 的 Runner.run()

2.2 埋点之后要看的四个指标

  1. 每任务 token 与成本。不是每请求——是每个业务任务的总额。Agent 的成本是几次到几十次 LLM 调用的累加,按请求看会严重低估。
  2. 步数分布。同一个任务类型的步数分布出现长尾,通常意味着工具描述不清或 prompt 里有歧义,Agent 在反复试探。
  3. 工具调用失败率与重试次数。Agent 往往会"优雅地"绕过失败的工具,只看最终成功率会掩盖问题。
  4. 首个失败 span 的位置。把失败按 span 类型归类,能立刻区分"是模型不行"还是"是我们的工具不行"。

三、工具横评:Langfuse、LangSmith、Phoenix

这三个是目前最常被拿来对比的。它们的能力有重叠,但取舍差别很大。

维度LangfuseLangSmithArize Phoenix
许可与形态开源(MIT),自托管是一等公民闭源 SaaS,自托管为企业版附加项开源,面向 Agent 开发与评测
接入方式基于 OpenTelemetry,框架无关SDK 覆盖多语言,LangChain 链路最顺OpenInference 语义约定
存储开源栈上的自有数据模型(ClickHouse)自研专有数据库 SmithDB可本地起,uvx arize-phoenix serve
评测代码评测器 + LLM 评审,可跑在线评测数据集评测 + pytest 集成 + 生产告警确定性评测 + LLM-as-a-judge

几个具体的版本事实,选型时会用到:

  • Langfuse v42026 年 8 月 17 日发布,Cloud 与自托管均已可用。官方给出的数字是:大数据集下的首次表格加载从秒级降到毫秒级,大项目里长跨度仪表盘加载至少快 10 倍。Langfuse Cloud 将在 2026 年 11 月 16 日转为仅支持 v4,之后旧 API 与旧接入方式退役。v4 还加入了 Monitors(按成本/质量/时延阈值告警,可推送到 Slack、webhook、GitHub Actions)和代码评测器。
  • LangSmith 在 2026 年 5 月公布了 SmithDB——用 Rust 基于 Apache DataFusion 和 Vortex 文件格式写的专用 trace 数据库,trace 数据放在对象存储上,摄取与查询服务无状态。LangChain 称它已服务 LangSmith 美国区云端的摄取与查询,核心体验最高快 15 倍。同时要留意:LangSmith 的自托管只在企业版提供,不在 Developer / Plus 计划里。
  • Arize Phoenix 的本地起步门槛最低,一条 uvx arize-phoenix serve 就能起来;评测同时支持确定性代码评测器(精确匹配、正则、自定义启发式)和 LLM-as-a-judge。

选择上的经验法则:全部押在 LangChain / LangGraph 上、想要一个托管平台把可观测性和评测一起管掉,LangSmith 摩擦最小;有数据主权要求、需要真正能自托管、或者技术栈不止 LangChain(比如 Java 服务走 OTel、Python 走 SDK 的混合栈),Langfuse 的框架无关路线更合适;只想本地快速看清一次运行的调用树,先用 Phoenix 试。

四、评测:三个层次,别只测最后一层

Agent 评测和单次 LLM 调用评测最大的区别在于必须评轨迹。一个只测最终答案的评测集,会给"碰巧蒙对"和"用错方法但结果对"的系统打高分。实践中的分层大致是这样:

层次评什么手段
结果层最终答案对不对精确匹配、单元测试、断言
轨迹层调用了哪些工具、顺序是否合理、有没有多余步骤期望工具序列比对、LLM 评审轨迹
单步层每次工具调用的参数是否正确、每次检索是否召回确定性校验为主

Langfuse 的评测指南把这套流程按成熟度分成三个阶段:早期开发阶段手动看 trace 收益最大;然后是把人工反馈和标注沉淀成数据集;最后才是把评测跑进 CI,每次改动都回归。这个顺序值得照抄——直接跳到第三阶段,通常会做出一套没人看的评测。

4.1 一个容易被忽略的指标:pass^k

τ-bench(τ-bench,论文 arXiv:2406.12045,被 ICLR 2025 收录)提出了一个比 pass@k 更适合 Agent 的指标 pass^k:同一任务重复跑 k 次,k 次全部成功才算通过。它衡量的是可靠性,而不是"多试几次能不能蒙对"。

τ-bench 的模拟方式是让语言模型扮演用户,与带领域 API 工具和业务规则的 Agent 进行多轮对话。官方仓库公布的数字很能说明可靠性问题:在 airline 域,采用 tool-calling 策略的 claude-3-5-sonnet-20241022 从 pass^1 的 0.460 掉到 pass^4 的 0.225;retail 域从 0.692 掉到 0.462。也就是说,一个看起来"能过一半"的 Agent,连续四次都做对同一件事的概率只有两三成。这个落差才是生产环境的真实体感。

τ-bench 仓库顶部有两条提示要留意:原始仓库的 airline 和 retail 任务已经不更新了,官方指向 τ²-bench;而 τ²-bench 又已经更新为 τ³-bench,新增了 banking 域和 voice 评测形态,并修复了 airline/retail 的任务。如果要做对比,先确认自己在跑哪一版。

4.2 基准测的是不同能力,不能当难度阶梯读

  • GAIA(arXiv:2311.12983)测的是通用助手式的任务完成,题目对人不难、对 AI 很难。原论文的数字是人类答题者约 92%,带插件的 GPT-4 约 15%。它的题目需要多模态、网页浏览、工具使用串起来才能完成,因此主要衡量链式工具使用
  • τ-bench 系列测的是与用户的动态对话 + 遵守业务规则,即"能不能按政策办事"。
  • SWE-bench 及其衍生版本测的是软件工程产出,判分依据是仓库自己的测试。

这三者不是一条难度曲线上的三个点,而是三个近乎正交的能力维度。一个系统在其中一个上得分高,对另外两个几乎没有预测力。另外要清醒地认识到:榜单分数不等于生产可用性。基准题目的口径固定、失败成本为零,生产环境里工具会 429、用户会改需求、数据格式会变。把基准当"下限筛查"用,别当"上线依据"用。

五、LLM-as-judge 怎么用才不骗自己

开放式任务没有办法写断言,所以一定会走到 LLM 评审这一步。这条路可行,但有一组已知的系统性偏差必须先接受:

  • 位置偏差(position bias)。成对比较时倾向偏爱某个位置的回答,与内容质量无关。有系统研究(arXiv:2406.07791)专门量化了这个问题。
  • 冗长偏差(verbosity bias)。偏爱更长的输出。
  • 自我增强偏差(self-enhancement bias)。偏爱与自己风格相近的输出。

另一条来自综述文章《When AIs Judge AIs: The Rise of Agent-as-a-Judge Evaluation for LLMs》(arXiv:2508.02994)的结论也值得记住:agent-as-a-judge 这类"用 Agent 评 Agent"的做法,能够评估整条轨迹而不只是最终答案,但它的定位是补充而非替代人工监督。文中把偏差、鲁棒性和元评估列为尚未解决的核心挑战。

落到工程上的几条戒律:

  1. 固定评审模型和 prompt 版本。换一次 judge 模型,历史分数就不可比了。版本号要写进评测结果里。
  2. 成对比较时交换顺序各跑一次。两次结论不一致的样本单独统计,这批样本本身就是噪声来源的量化。
  3. 能用代码判的绝不用模型判。工具参数是否正确、是否调用了禁用的工具、输出是否符合 JSON schema——这些都不需要 LLM。
  4. 人工抽检校准。定期从评测集里抽 30-50 条人工打一遍分,算一下 judge 与人类的一致率。一致率掉了,说明评测集已经跑偏。
  5. 同一个输入多跑几次看方差。评审本身也是随机采样,单次评分不具备可复现性。

六、一个可落地的最小闭环

把上面几块串起来,一个务实的起步方案是:用 OpenTelemetry 语义约定做埋点(接受它还在 Development 状态),写到一个支持自托管的观测后端,再把关键用例固化成 3-5 个代码评测器 + 1 个 LLM 评审,最后挂进 CI。

# 伪代码:CI 里的 Agent 回归评测
def evaluate_agent(cases, agent, code_checks, llm_judge):
    report = []
    for case in cases:
        trace = agent.run(case.input)          # 完整轨迹,含每次工具调用

        item = {"case_id": case.id, "final_ok": case.expected == trace.output}

        # 结果层:确定性校验
        item["checks"] = {name: fn(trace) for name, fn in code_checks.items()}

        # 轨迹层:工具序列是否符合预期
        used = [s.tool_name for s in trace.spans if s.kind == "tool"]
        item["tool_sequence_ok"] = used == case.expected_tools

        # 单步层:有没有调用被禁用的工具
        item["no_forbidden_tool"] = not (set(used) & FORBIDDEN_TOOLS)

        # 开放部分:LLM 评审,记录 judge 版本以便跨版本不可比时能识别
        item["judge"] = {
            "model": JUDGE_MODEL, "prompt_version": JUDGE_PROMPT_V,
            "score": llm_judge(trace, rubric=case.rubric),
        }
        item["tokens"] = trace.total_tokens          # 成本要跟着指标一起看
        report.append(item)
    return report

这个骨架有个刻意的设计:成本指标和精度指标放在同一条记录里。Agent 评测里最没有意义的数字是"准确率提高了 5%",如果没同时看到"token 涨了 3 倍"。两者必须一起看。

七、小结

Agent 可观测性和评测的核心,是把"这个 Agent 好不好"拆成可以分别测量的三件事:轨迹(做了什么)、单步(怎么做的)、结果(对不对)。追踪侧尽量贴近 OpenTelemetry 语义约定,但要清醒地知道它目前仍是 Development 状态,别把存储 schema 钉死在上面;工具选择上,自托管诉求强选 Langfuse,全栈 LangChain 选 LangSmith,本地快查选 Phoenix。评测侧,先手动看 trace,再固化数据集,最后才进 CI,并且一定要引入 pass^k 这类衡量可靠性的指标——pass^1 的分数会系统性地高估生产表现。

最后一条务实的提醒:这套设施本身也是有成本的。如果 Agent 一天只跑几十次、错了人肉看一眼就能定位,先别上平台;等 trace 长到肉眼读不完、或者改了 prompt 不知道有没有变好时再投入,投入产出比才成立。

参考来源

  • OpenTelemetry GenAI 语义约定仓库:open-telemetry/semantic-conventions-genaidocs/gen-ai/gen-ai-agent-spans.mdgen-ai-spans.md(状态:Development)
  • OpenTelemetry 规范站点关于 GenAI 语义约定迁移的提示页
  • OpenAI Agents SDK 官方文档(追踪模块、TracingProcessortrace_include_sensitive_data)与 GitHub Releases v0.22.0(2026-08-19)
  • Langfuse,《Langfuse v4 is live》(2026-08-17)与《Agent Evaluation: How to Evaluate LLM Agents》指南
  • Langfuse,《Langfuse vs. LangSmith》对比文档(2026 年 7 月更新版)
  • LangChain / LangSmith 官方资源:《What is LangSmith?》、pytest 评测集成、SmithDB(2026 年 5 月公布)
  • Arize Phoenix 官方文档与评测快速入门
  • Yao 等,τ-bench: A Benchmark for Tool-Agent-User Interaction in Real-World Domains,arXiv:2406.12045(ICLR 2025)与 sierra-research/tau-bench 官方榜单
  • Mialon 等,GAIA: a benchmark for General AI Assistants,arXiv:2311.12983
  • 《Judging the Judges: A Systematic Study of Position Bias in LLM-as-a-Judge》,arXiv:2406.07791
  • Yu,《When AIs Judge AIs: The Rise of Agent-as-a-Judge Evaluation for LLMs》,arXiv:2508.02994