Braintrust · 官方

如何评估有状态 agent

How to eval stateful agents

二〇二六年六月三十日 · 英文原文

有状态 agent 在非结构化环境中跨多步骤积累工作记忆、产生副作用(如创建工单、更新数据库、发送消息)并依赖外部系统,其行为对轨迹敏感且难以通过经典 prompt-响应评估。Braintrust 提出一套评估生命周期:通过追踪记录工具调用与中间状态,将生产失败转化为测试用例,在单步与端到端两个层面评分,并接入 CI 管道防止回归。该方法强调环境需足够真实且可重置,并利用 Topics 聚类自动发现大规模失败模式。

2026年6月26日 Izzy Hurley 15分钟

大多数评估(eval)设置都涉及发送 prompt、获取响应并对其进行评分。这涵盖了许多常见任务,如摘要、分类、提取或单轮问答。但一旦你的 agent 开始在非结构化环境中长时间执行操作,这种模式就会失效。

状态性(Statefulness)使 agent 能够远远超越经典的 prompt-响应模型。凭借保留的记忆,有影响力的行动轨迹可以被编码到 agent 中并对其有所期望。一个有状态的 agent 会创建工单、更新数据库行、发送消息、部署代码、修改配置以及配置资源。它会在多个步骤和长时间内积累上下文。它会做出决策,关闭一些路径并打开其他路径。其行为取决于外部系统的状态,而这些状态在不同运行之间可能会发生变化。

你不能通过重放单个 prompt 来评估一个有状态的 agent。你需要一种不同的方法,来考虑有状态 agent 所带来的不同范式。

图1:比较经典评估(prompt、LLM、评分)与有状态 agent(在多个步骤中构建上下文、在现实世界中采取行动、并依赖外部系统)的示意图

什么使 agent 具有状态性

在实践中,"有状态 agent" 意味着什么?它是一个跨步骤累积工作记忆的 agent。agent 会记住它已经尝试过什么、客户三轮对话前说了什么、以及它得出了哪些中间结论。每一步都建立在上一步的基础上。上下文窗口是一个活跃的工作空间,它塑造着每一个后续决策。

有状态 agent 能做什么

这种工作记忆的积累和使用改变了 agent 能做什么,以及它对你的技术栈可能产生的下游影响。

有状态 agent 会产生副作用。 agent 会改变世界。它创建工单、运行数据库迁移、发送电子邮件。它不仅仅是起草一封邮件,而是会发送它。在无状态系统中,一个糟糕的决策会产生一个糟糕的答案,但在有状态系统中,一个糟糕的决策会产生糟糕的后果。

有状态 agent 依赖外部系统。 agent 与 CRM、代码仓库、数据仓库、SaaS API 和内部工具进行交互。这些系统有自己的状态,并且这些状态会独立变化。同一个 agent 在周一和周四运行相同的任务,可能会因为底层数据发生了变化而得到不同的结果。

有状态 agent 对轨迹敏感。 早期的选择会改变后续的可能性。如果 agent 在第二步选择了工具 A 而不是工具 B,整个下游路径就会发生偏移。对一个 API 调用的一个错误参数可能会级联影响到后续的每一步。操作的顺序会影响最终输出。

一个有效的有状态评估应该能够管理这些条件的某种组合。一个会积累上下文、采取实际行动、依赖实时系统、并且可能基于早期决策走上截然不同路径的 agent,是无法通过静态的 prompt-响应检查来正确评估的。

为什么有状态 agent 不同

当今最有价值的 agent 不像早期模型的聊天机器人。它们是创建和回滚构建、配置资源和管理部署的基础设施 agent;协调 CRM、电子邮件、文档和工单系统的多工具助手;或者遵循程序同时更新三个不同系统中记录的支持 agent。

这些 agent 做的是实际工作。这正是它们有价值的原因,也是它们更难评估的原因。

特别是,状态性引入了几种偏离原始意图的新方式。

错误但一致的叙述。 如果 agent 错误地总结了早期步骤,后续步骤会建立在该总结之上,因此整个轨迹是自洽且错误的,看起来像是"经过深思熟虑"的。

中间上下文遗忘。 在长任务中,早期的重要事实可能会丢失,因此 agent 完成的目标与实际意图略有不同,却没有任何明显的错误信号。

过时的假设。 agent 记住了早期的环境或策略,并在其失效后继续遵守它,因此其行为与当前世界不一致,尽管它们与存储在状态数据中的历史记录一致。

状态损坏。 并发任务、有缺陷的更新或糟糕的工具可能会悄然损坏记忆,导致矛盾或约束违反,而这些只有在许多步骤之后才会显现。

这些失败模式与你从无状态系统中看到的不同。一个给出糟糕答案的无状态 agent 很烦人。一个给出糟糕答案的有状态 agent 可能已经基于那个糟糕答案执行了不可逆的操作。

还有一些失败模式只在多个步骤后才会出现。一个孤立看起来没问题的代码更改,可能在五步之后导致某些东西崩溃。一个基于第二步信息看似合理的决策,可能与 agent 在第六步学到的内容相矛盾。这些回归不会在单步评估中显现,因为它们需要轨迹才能浮现。

基于 LLM 的系统的非确定性对有状态 agent 产生了独特的影响。在相同任务上运行同一个 agent 两次,可能会产生不同的工具调用序列、不同的中间状态或不同的结果,因为它所依赖的外部系统返回了略有不同的数据。一个不是为这种差异而构建的评估,根本就不是为有状态 agent 构建的。

挑战在于状态,而非评分

当团队在有状态评估中挣扎时,本能反应是寻找更好的指标或更花哨的评分系统。这通常是错误的诊断。困难的部分在于正确处理状态。

你需要 agent 与足够真实的环境进行交互,以便有意义地捕获评估中的状态。一个应该查找订单并发放退款的客户支持 agent,需要一个实际的订单数据库来查询,以及一个实际的退款系统来执行退款。一个部署 agent 需要部署的目标。一个基础设施 agent 需要基础设施。

但"足够真实以有意义"和"完全逼真的生产环境"是非常不同的,在这两者之间找到正确的平衡可能会让团队既费时又费钱。

为评估目的构建生产环境的完美副本,设置成本高昂且难以维护。每次真实环境发生变化,你的评估环境也需要随之改变。尝试这种方法的团队,往往花在维护评估基础设施上的时间比实际改进 agent 的时间还要多。

实用的方法是审慎地决定哪些需要真实,哪些可以模拟。

使状态显式化。 在构建任何东西之前,写下 agent 实际与环境中的哪些部分交互,以及这些交互中哪些需要足够真实才能使评估有意义。

使环境可重置。 当你确实需要真实状态时,确保你可以在运行之间重置它。如果每次评估运行都会留下影响下一次运行的工件,你的结果很快就会变得不可靠。

不要追求完美的重放。 轨迹差异会随着工具深度的增加而增加。一个进行两次工具调用的 agent,其可能的路径数量是可管理的,但一个进行十五次工具调用的 agent,其路径数量会呈组合爆炸式增长。专注于结果和关键决策点,而不是试图重现精确的序列。

有状态评估生命周期:观察、捕获、测试、迭代

对于有状态评估,最高效的模式是从生产环境开始,从真实失败中构建测试用例,对 agent 的路径和结果进行评分,然后在未来的 CI/CD 工作流中以编程方式实施评估。一旦你经历了这个过程,并将评估确立为团队开发生命周期的一部分,你将能够更快、更有效地迭代。

步骤 1:观察真实运行中发生的情况

记录追踪(trace)、工具调用、输入、输出、元数据和中间状态。当 agent 创建工单时,记录它创建了什么。当它进行 API 调用时,记录参数和响应。当它更新记录时,记录更新前后的状态。

Braintrust 可以轻松地检测你的 agent。SDK 包装了常见的 provider,因此每次 LLM 调用、工具调用和应用层交互都会被捕获为结构化的 span。@traced 装饰器(Python)或 wrapTraced()(TypeScript)处理嵌套,因此多步骤的 agent 运行会产生一个显示完整执行路径的追踪树。每个 span 会自动记录 token 计数、延迟、首个 token 时间以及预估成本。

Braintrust UI 中的追踪视图允许你浏览完整的执行图。你可以在树状视图(查看 span 层级)、时间线视图(发现延迟瓶颈)和线程视图(将对话作为连续交流阅读)之间切换。对于有状态 agent,树状视图通常最有用,因为它显示的是决策结构,而不仅仅是对话。

图2:Braintrust 中的 Agent States 视图,显示 Claude Opus agent 运行的 span 时间线,包括轮次、思考、评分、函数和工具调用

你可以使用类似 SQL 的表达式,根据输入、输出、元数据、评分或你记录的任何字段,在日志中进行过滤和搜索。通过 Topics,Braintrust 会自动呈现最可能相关的 agent 行为模式。对于高流量的 agent,这通常是找到 agent 失败的具体追踪集的最佳方式。例如,你可以过滤查看所有元数据标签指示信息已在先前步骤从 CRM 中拉取的 span,并将其与未拉取的 span 进行比较,从而揭示冗余的 CRM 调用是否引入了延迟、降低了下游输出质量,或者管道是否简单地忽略了它已有的状态。

步骤 2:将失败转化为测试用例

当生产环境中出现问题时,检测能力使你能够捕获该特定场景。利用这些信息,将其转化为回归测试。这比合成测试用例更有价值,因为它代表了真实客户遇到的失败模式。

Braintrust 有几种方法可以做到这一点。最简单的方法是浏览你的日志,找到一个糟糕的追踪,然后直接将其提升到数据集中。选择该追踪或其中的特定 span,选择 Add to dataset,它就会成为版本化数据集中的一行,你可以在未来的评估运行中使用它。你可以从 UI 或 bt CLI 执行此操作。

对于批量操作,数据集管道(dataset pipelines)可以自动化此过程。你在代码中定义一个管道,包含源、转换函数和目标数据集。使用 bt datasets pipeline run 运行它,它会拉取匹配的追踪,将其转换为数据集行,并写入你的目标数据集。你可以按元数据标志、评分阈值、错误状态或任何其他字段进行过滤。例如,在处理 IT 访问申请时,你可以构建一个管道,自动拉取每个品牌一致性评分低于 50% 的追踪,并将其转化为测试用例:

typescript

DatasetPipeline({ source: { projectName: "IT Access Agent", filter: "scores.brand_alignment < 0.5", scope: "trace", }, transform: ({ trace }) => ({ input: trace.input, expected: trace.metadata?.expected_outcome, metadata: { original_score: trace.scores?.brand_alignment }, }), target: { projectName: "IT Access Agent", datasetName: "Low-quality cases", },});

分阶段的工作流(pulltransformpush)允许你在提交之前检查和编辑转换后的行,这在需要人工审查某个追踪是否真的是值得编码的失败时非常有用。

随着时间的推移,你的数据集会从生产数据中增长,反映出你的特定 agent 在特定环境中的实际失败模式。

步骤 3:对步骤和结果进行评分

有状态 agent 需要在两个层面进行评分。单步评分检查单个决策是否正确,而端到端评分检查整体任务是否成功。

Braintrust 支持两者。对于单步评分,你可以在 span 级别附加评分器。一个 LLM-as-a-judge 评分器可以评估每个工具调用在给定上下文中是否合适。一个基于代码的评分器可以检查结构化输出,例如 SQL 查询是否匹配预期的 schema、API 调用是否使用了正确的端点、或者响应是否解析正确。

对于端到端评分,追踪范围的评分器评估完整执行过程。一个追踪级别的评分器可以通过 trace.getThread() 访问整个对话线程,并通过 trace.getSpans() 访问所有 span。它可以检查 agent 的任务是否完成、是否采取了合理的路径到达那里、以及是否将环境留在了正确的状态。

你可以使用 eval 任务函数中的 hooks 参数将中间结果挂钩到你的评分器中。如果 agent 进行了工具调用,将它们附加到元数据中,这样你的评分器就可以评估所选的具体工具和传递的参数。这就是你如何捕获 agent 通过错误路径得出正确答案的情况,对于具有潜在副作用的有状态 agent 来说,这本身和答案一样重要。

两个层面的评分都在在线模式下工作。在 Braintrust UI 的 Automations 下配置在线评分规则,根据你的流量设置采样率,评分就会出现在你的日志中,附加到相关的 span 或追踪上,如果你使用 LLM-as-a-judge,还会附带判断者的推理过程。

步骤 4:在发布前运行评估

一旦你有了真实失败案例的数据集和一组评分器,就将它们接入你的 CI 管道。Braintrust 有一个 GitHub Action,可以在每个 pull request 上运行你的评估套件,并直接将结果发布在 PR 中。它会将评分与你的生产基线进行比较,并显示差异,例如哪些测试用例改进了、哪些退步了、以及退步了多少。如果未达到质量阈值,合并将被阻止。

这就是如何将一个生产失败转化为一个测试用例,该测试用例会在每次代码更改时自动评分。如果有人引入了一个会导致之前捕获的失败再次出现的回归,CI 会在它发布之前捕获它。例如,以增加冗长的方式更改来自 agent 状态记忆存储的通信,可能会悄无声息地将模型推过其上下文窗口、降低指令遵循能力、或者导致下游 span 误读它们期望以更紧凑格式呈现的结构化数据。

步骤 5:迭代

修复问题,重新运行测试用例,验证其通过,并检查没有其他东西被破坏。将该测试用例添加到你的永久套件中。

这个过程,一旦以编程方式实现,会随着时间的推移而复合。每个周期都会使你的评估套件更具代表性,你的 agent 更健壮。

这在实践中是什么样子

考虑一个处理内部 IT 请求的示例 agent。一名员工向 agent 提交"我需要访问分析仪表板",agent 应该检查请求者是谁、验证他们是否被授权、在身份提供者中创建访问授权、并向请求者确认完成。

一个无状态评估会测试 agent 是否对该请求生成了一个听起来合理的响应。一个有状态评估会验证 agent 行为的完整链条:它是否查找了正确的人、是否检查了正确的授权策略、是否使用正确的权限创建了访问授权、是否在正确的系统中创建了它、以及是否准确地进行了确认?整体轨迹是否合理、没有过度重复、并且在走向正确行动的过程中没有采取有害行动?

这些步骤中的每一步都依赖于状态。查找依赖于身份提供者的数据。授权检查依赖于策略引擎的当前规则。访问授权依赖于身份提供者接受写入。如果这些系统中的任何一个行为与预期不同,agent 可能会以静态评估永远无法捕获的方式失败。

在 Braintrust 中,你会检测 agent,使每一步都作为追踪中的一个独立 span 进行记录。span 范围的在线评分会单独检查每一步,而追踪范围的评分器会评估结果。

当 agent 失败时,你在日志中找到该追踪,按错误模式过滤,并将其提升到数据集中。你的转换函数会捕获请求者、当时的策略状态和 API 响应。你修复解析逻辑,运行你的评估套件,验证测试用例通过,并且 GitHub Action 会阻止任何未来会重新引入该 bug 的更改。

大规模发现模式

单个追踪审查对于调试特定失败很有用,但它们无法扩展。如果你的 agent 每天处理数千个请求,你需要聚合模式。

Braintrust 的 Topics 功能会为每个追踪生成自然语言摘要,然后根据 agent 行为中出现的关键模式将这些摘要聚类到不同的桶中。

每个追踪都会被标记上其所属的聚类。你可以查看分布、深入分析最紧迫的聚类、检查评分,并识别出值得调查的特定失败类别。它将一堵追踪日志墙转化为一个按频率和严重性排序的优先问题列表。在处理有状态 agent 时,像这样的自动化可以使整个评估过程随着复杂性的增长而更易于管理。

最重要的 agent 做重要的工作

有状态 agent 评估从根本上说是一种不同类别的 AI 基础设施。状态管理增加了新的复杂性,例如设置足够真实以有用、足够可重置以可靠、并且足够便宜以维护的环境。

从可观测性开始。检测你的 agent,使每一步都记录为结构化的 span。当出现问题时,找到这些追踪,将它们提升到数据集中,并构建检查单个步骤和整体结果的评分器。将整个流程接入 CI,以便在回归发布之前捕获它们。使用在线评分和聚类来监控生产环境,并在新的失败模式出现时将其呈现出来。

做实际工作的有状态 agent 值得投资,而且它们也更难评估。这两个事实之间的差距,正是你的评估基础设施需要成长和改变的地方。开始使用 Braintrust 为重要的 agent 构建评估。

译自 Braintrust · 官方 · 录于 二〇二六年六月三十日