你的 AI Agent 为什么总是"抽风"?这篇深度解析让你豁然开朗
你有没有遇到过这样的场景?
你辛辛苦苦开发了一个 AI Agent,本地测试时表现完美——它能理解用户的复杂指令,调用正确的工具,给出准确的回答。你信心满满地把它部署到生产环境,结果第二天就收到用户反馈:"你们的机器人怎么胡言乱语?"
你急忙去查日志,却傻眼了——根本没有错误日志。没有堆栈跟踪,没有报错信息。你的 Agent 跑了 200 步,花了两分钟,然后给出了一个完全错误的答案。问题出在哪?
这就是 AI Agent 时代的核心挑战:我们正在从"调试代码"转向"调试推理"。
一、传统软件 vs LLM 应用 vs Agent:不确定性逐级递增
传统软件 vs LLM apps vs Agents
传统软件是确定性的——给定相同的输入,永远得到相同的输出。你可以阅读代码,准确预知系统的行为。出问题的时候,日志会指向具体的服务或函数,你回到代码就能理解并修复。
LLM 应用引入了不确定性——单次调用 LLM,自然语言的"模糊性"开始显现。但仍然局限在一次调用内,相对可控。
Agent 则完全打破了确定性假设——它在循环中反复调用 LLM 和工具,可能持续数十甚至数百步,维护状态,根据上下文调整行为。你写的代码和提示词只是"建议",Agent 真正会做什么,只有运行了才知道。
二、Agent 可观测性的三大核心原语
要理解和调试 Agent,我们需要全新的观测工具。LangChain 提出了三个核心概念:
1. Run(单次执行):捕捉 LLM 的一步决策
Agent Run 示例
Run 记录单次 LLM 调用的完整信息:提示词、可用工具、上下文、模型的输出。
它有两个核心用途:
- • 调试:精确查看 Agent 在某一步"思考"了什么——提示词里有什么?有哪些工具可用?为什么选择这个行动?
- • 评估:对这一步进行断言——Agent 调用了正确的工具吗?参数是否正确?
举个例子:你开发了一个日程管理 Agent,想验证它在安排会议前会先检查可用时间,而不是直接创建会议。Run 级别的评估让你精确测试这一步决策。
2. Trace(完整轨迹):记录端到端执行
Trace 示例
Trace 将一次完整的 Agent 执行中所有的 Run 串联起来,形成一个完整的推理轨迹。它包含:
- • 每一步输入模型的完整信息(作为 Runs 被捕获)
- • 所有工具调用及其参数和结果
- • 嵌套结构,展示步骤之间的关系
Agent Trace 的规模是传统分布式 Trace 的数百倍甚至数千倍。 一个典型的微服务 Trace 可能只有几百字节,而复杂的 Agent Trace 可能达到数百 MB。但正是这种海量上下文,才让我们能够调试和评估 Agent 的推理过程。
3. Thread(会话线程):跨轮次维护上下文
Thread 示例
Thread 将多次 Agent 执行(Traces)组合成一个完整的会话,保留:
- • 多轮上下文:用户与 Agent 按时间顺序的所有交互
- • 状态演化:Agent 的记忆、文件或其他工件在轮次间的变化
- • 时间跨度:会话可能持续几分钟、几小时甚至几天
Thread 对于理解 Agent 行为的时序演化至关重要。
举个例子:一个编程 Agent 在前 10 轮表现正常,第 11 轮突然出错。只看第 11 轮的 Trace,你可能发现 Agent 调用的工具似乎合理。但查看完整 Thread 后,你发现第 6 轮时 Agent 用一个错误的假设更新了记忆——到了第 11 轮,这个错误上下文已经累积成了严重的 Bug。
三、三个层次的 Agent 评估
理解了 Run、Trace、Thread 这三个原语,我们就可以在不同粒度上评估 Agent:
单步 vs 完整回合 vs 多回合评估
1. 单步评估(Run 级别):决策的单元测试
单步评估示例
单步评估验证单个 Run——Agent 在这一步做出了正确的决策吗?
这就像是 Agent 推理的"单元测试":设置特定的状态(对话历史、可用工具、当前任务),让 Agent 运行一步,然后断言它做出了正确的决策。
为什么需要 Run 级别的详细捕获? 单步测试通常来自生产环境中出错的实际案例。要重现这些问题,你需要 Agent 在这一步之前的精确状态。详细的 Run 捕获是获取这些信息的唯一方式。
在实践中,大约一半的 Agent 测试套件使用单步测试,在不需要完整 Agent 执行开销的情况下,隔离和验证特定的推理行为。
2. 完整回合评估(Trace 级别):端到端轨迹验证
完整回合评估
完整回合评估验证完整的 Trace——Agent 正确执行了整个任务吗?
这让你能够从多个维度进行测试:
轨迹(Trajectory) :Agent 调用了必要的工具吗?对于一个修复 Bug 的编程 Agent,你可以断言:"Agent 应该先后调用 read_file、edit_file、run_tests。" 确切的顺序可能有所不同,但某些工具必须被调用。
最终响应(Final Response) :输出正确且有用吗?对于研究或编程等开放式任务,最终答案的质量往往比具体路径更重要。
状态变更(State Changes) :Agent 创建了正确的工件吗?对于编程 Agent,你会检查它写入的文件,验证其中包含正确的代码。对于有记忆的 Agent,你会检查它是否存储了正确的信息。
测试 Agent 是否记住用户偏好,需要验证三个要素:
-
- 轨迹:Agent 是否调用了
edit_file来更新记忆文件?
- 轨迹:Agent 是否调用了
-
- 最终响应:Agent 是否向用户确认了更新?
-
- 状态:记忆文件是否真的包含了该偏好?
每个断言都需要 Trace 的不同部分。如果不捕获完整的轨迹和状态变更,你就无法评估这些维度。
3. 多回合评估(Thread 级别):真实对话流程
多回合评估
某些 Agent 行为只在多轮交互后才显现。Agent 可能在前 5 轮正确维护上下文,第 6 轮却失败;或者单独处理每个请求没问题,但当请求相互依赖时却出错。
多回合评估验证 Thread——包含多次 Agent 执行的会话。你测试 Agent 是否正确累积上下文、在轮次间维护状态、处理基于先前交换构建的对话流程。
例如,测试上下文持久性:
- • 第 1 轮:用户分享偏好("我喜欢 Python 胜过 JavaScript")
- • 第 2 轮:用户基于该偏好提问("给我展示一个例子")
- • 第 3 轮:测试偏好是否持续("为此写个脚本")
Agent 应该在第 2 和第 3 轮提供 Python 示例,而非 JavaScript。这需要在轮次间维护上下文。
多回合测试的挑战在于保持测试"在轨道上"。如果 Agent 在第 1 轮偏离预期路径,你预设的第 2 轮输入可能就不再合理。使用条件逻辑检查每轮后 Agent 的输出,如果偏离轨道就尽早失败。
多回合评估需要 Thread 来将多次 Agent 执行(Traces)组合成一个对话。当多回合测试失败时,你需要显示所有轮次的 Thread 来理解哪里出了问题。
四、选择合适的评估粒度
评估粒度选择
选择哪种粒度评估 Agent 没有唯一的正确答案。以下是一些实用经验:
Trace 级别评估(完整回合)通常最容易设计输入
这些是你的 Agent 的输入,所以设计起来相对容易(也是必要的)。但设计预期输出和/或程序化验证方法可能更难。这意味着你可能会有段时间只自动化运行 Agent 处理这些数据点,但不做评分。
Run 级别评估(单步)最容易完全自动化评分
这只是单次模型调用,通常可以通过检查调用了哪些工具来评估。但要注意:如果你频繁更改 Agent 的内部逻辑(哪些工具可用、调用工具的正确顺序),这些评估可能很快过时并需要更新。因此,我们通常看到团队只在 Agent 整体架构相对稳定后才构建这些评估。
Thread 级别评估(多回合)最难有效实现
它们需要设计一系列输入,但这系列输入通常只有在 Agent 在输入间表现出特定行为时才合理。它们也很难自动评估。这是我们见过的最不常见的评估类型。
大多数生产 Agent 使用组合策略:完整回合测试用于核心工作流,单步测试用于生产中发现的已知失败模式,多回合测试用于有状态交互。
五、何时评估 Agent
离线 vs 在线评估
Agent 行为只有在运行时才完全显现,这意味着何时评估 Agent 也与传统软件不同。
离线评估(Offline Evaluation)
这相当于发布前运行单元测试。要运行这些测试,你需要收集输入数据集,以及可选的用于比较的基准输出。根据在这些数据上运行和评估 Agent 的成本,你可以在每次提交时运行这些评估,或只在推送到生产环境前运行。如果频繁运行离线评估,你会希望设置某种缓存,避免不必要地调用模型。
注意:当大多数人谈论"评估"时,离线评估是他们最可能指的主要类型。
在线评估(Online Evaluation)
既然直到运行 Agent 才知道它的表现,你可能希望在 Agent 运行在生产数据上时"在线"运行评估。这样做时,这些评估器本质上需要是"无参考的"。在线评估器通常在摄入生产数据时运行。
临时评估(Ad-hoc Evaluation)
Agent 的输入和行为非常开放,所以你并不总是提前知道要测试什么。如果你在生产环境中有大量 Trace,你可能想在它们被摄入之后测试它们。这种探索性数据分析对于理解你的 Agent 至关重要。LangSmith 中的 Insights Agent 等系统可以帮助你完成这项工作。
六、可观测性如何为评估提供动力
Traces 到评估的数据流向
你为可观测性生成的 Trace,正是驱动评估的同一批 Trace,它们形成了一个统一的基础。
Traces → 人工调试
当你在本地运行 Agent 处理临时查询并手动检查结果时——这仍然是一种(手动的)评估形式!Trace 为这种工作流提供动力,让你能深入过程的每一步,精确找出哪里出了问题。
Traces → 离线评估数据集
生产环境的 Trace 自动成为你的评估数据集。例如,当用户报告 Bug 时,你可以在 Trace 中看到:确切的对话历史和上下文、Agent 每一步的决定、以及具体哪里出了问题。
典型工作流:
-
- 用户报告异常行为
-
- 找到生产环境的 Trace
-
- 提取失败点的状态
-
- 从这个确切状态创建测试用例
-
- 修复并验证
这样,你的离线评估测试套件可以从真实数据点构建。
Traces → 在线评估
为调试生成的同一批 Trace,也为持续的生产验证提供动力。在线评估在你已经捕获的 Trace 上运行。你可以对每条 Trace 运行检查,或策略性地采样:
- • 轨迹检查:标记异常的工具调用模式
- • 效率监控:检测性能退化趋势
- • 质量评分:在生产输出上运行 LLM-as-judge
- • 失败告警:在用户报告前暴露错误
这实时暴露问题,验证开发行为在生产环境依然成立。
当 Trace 包含 10 万+ 行数据,或 Thread 跨越数十轮时,人工检查变得不可能。这时 AI 辅助分析帮助你查询 Trace 和 Thread:
- • 在众多 Agent 执行中呈现使用模式
- • 识别常见失败模式和效率问题
- • 解释具体决策:"Agent 为什么在这步调用这个工具?"
- • 对比成功与失败的执行以发现模式
举个例子:最近我们在调查为什么一个 Agent 采取了低效路径。我们没有手动阅读 150 步的 Trace,而是使用 AI 助手识别出 Agent 对同一文件多次调用 read_file,而不是将内容存储在上下文中。修复只是一个简单的提示词调整(而手动发现这个模式可能需要数小时)。
七、对 Agent 开发团队的启示
能交付可靠 Agent 的团队,已经接受了从调试代码到调试推理的转变。传统软件将 Tracing(用于调试)和 Testing(用于验证)分开。现在我们调试跨越长时间运行、有状态过程的非确定性推理,这两种实践开始融合。你需要推理 Trace 来评估 Agent 行为,也需要系统化的评估来理解 Trace。
从一开始就同时采用这两种实践的团队,才能交付真正可用的 Agent。
写在最后
Agent 时代正在重塑我们构建和调试软件的方式。这不是简单的技术升级,而是思维范式的根本转变——从追求确定性到拥抱不确定性,从调试代码到调试推理,从静态测试到动态评估。
可观测性不再是"可选项",而是 Agent 开发的"基础设施"。 没有 Trace,你就无法知道 Agent 在做什么;没有评估,你就无法知道它做得对不对。这两者缺一不可。
如果你正在构建 Agent,现在就开始思考:你的可观测性策略是什么?你的评估体系如何设计?生产环境的 Trace 如何回流到开发流程中?
Agent 的未来,属于那些既会构建,也会观察,更会评估的工程师。
参考资料:
- • 原文:Agent Observability Powers Agent Evaluation
- • 工具:LangSmith - 用于 Agent 可观测性和评估的平台
关注我们
欢迎关注 【维度坍缩】 ,获取更多 AI 技术前沿内容!
公众号二维码