文章笔记:Evaluating Deep Agents — Our Learnings
| 字段 | 内容 |
|---|---|
| 作者/整理 | 基于 LangChain 官方博客整理 |
| 来源 | LangChain |
| 日期 | 2025 |
引言:为什么 Deep Agent 的评测如此困难?
随着 LLM Agent 从简单的“问答式”应用演变为能够长时间自主运行、维护复杂状态的“Deep Agent”,评测方法也必须相应升级。LangChain 团队在过去一个月内发布了四个基于 Deep Agent harness 构建的应用:
- DeepAgents CLI:编程 Agent
- LangSmith Assist:LangSmith 平台内的辅助 Agent
- Personal Email Assistant:能从交互中学习用户偏好的邮件助手
- Agent Builder:由 meta deep agent 驱动的无代码 Agent 构建平台
在为这些应用编写评测用例的过程中,LangChain 团队总结出五大核心模式,涵盖了从单步验证到多轮对话模拟、从轨迹检查到环境隔离的完整评测体系。
Deep Agent 与传统 LLM 应用的根本区别
传统 LLM 评测假设每个测试用例可以用相同的评测器打分;而 Deep Agent 由于具备状态管理、工具调用、多步推理等能力,每个测试用例可能需要完全不同的断言逻辑(assertion logic)。这是本文所有讨论的出发点。
术语定义
在进入具体评测模式之前,需要先统一本文使用的关键术语。LangChain 团队从两个维度对评测进行分类:Agent 的运行方式和可测试的对象。
| 运行方式 | 说明 |
|---|---|
| Single Step(单步) | 限制 Agent 核心循环只执行一步,确定下一个要执行的动作 |
| Full Turn(完整轮次) | 让 Agent 在单个输入上完整运行,可能包含多次工具调用迭代 |
| Multiple Turns(多轮) | 让 Agent 多次完整运行,模拟用户与 Agent 之间的多轮对话 |
| 测试对象 | 说明 |
|---|---|
| Trajectory(轨迹) | Agent 调用的工具序列及其参数 |
| Final Response(最终响应) | Agent 返回给用户的最终回复 |
| Other State(其他状态) | Agent 运行过程中产生的文件、artifacts 等副产物 |
为什么需要区分运行方式和测试对象?
这两个维度是正交的。同一个测试用例可能在 Full Turn 模式下运行,但只检查 Trajectory;也可能在 Single Step 模式下运行,同时检查 Final Response 和 Other State。理解这种正交关系有助于设计出更精准的测试矩阵。
本章小结
Deep Agent 评测的核心挑战在于状态性(statefulness)和长程性(long-horizon)。传统的 input-output 评测范式无法覆盖 Agent 的工具调用轨迹、中间状态和副产物。LangChain 提出的五大模式从不同粒度和视角切入,构成了一套相对完整的评测框架。
模式一:定制化测试逻辑
传统评测的局限性
传统 LLM 评测遵循一个简洁的三步流程:
- 构建测试数据集
- 编写评测器(evaluator)
- 将应用在数据集上运行,用评测器对输出打分
在这个范式下,所有数据点被“一视同仁”——通过相同的应用逻辑处理,由相同的评测器打分。这对于分类、摘要、翻译等任务是足够的,但对 Deep Agent 来说远远不够。
为什么 Deep Agent 需要定制化?
Deep Agent 的“成功标准”因任务而异,而且往往涉及对 Agent 轨迹和状态的具体断言。文章给出了一个生动的例子:
假设有一个日历调度 Deep Agent,用户说“记住永远不要在早上 9 点之前安排会议”。我们需要验证的不仅仅是 Agent 的回复,还有:
- Agent 是否调用了
edit_file工具修改了memories.md文件?- Agent 是否在最终回复中确认了偏好已记录?
memories.md文件中是否确实包含了关于“不安排 9 点前会议”的信息?
常见误区:只检查最终回复
很多开发者在评测 Agent 时只关注最终输出的文本质量,忽略了 Agent 是否真正完成了任务。一个 Agent 可能回复“好的,已经帮你记住了”但实际上并没有调用任何工具来更新记忆文件。对 Deep Agent 而言,回复内容和实际行为必须同时验证。
Pytest/Vitest 集成实践
LangSmith 提供了 Pytest 和 Vitest 集成,允许开发者为每个测试用例编写不同的断言逻辑。下面是文章给出的核心代码示例:
@pytest.mark.langsmith
def test_remember_no_early_meetings() -> None:
user_input = "I don't want any meetings scheduled before 9 AM ET"
t.log_inputs({"question": user_input})
response = run_agent(user_input)
t.log_outputs({"outputs": response})
agent_tool_calls = get_agent_tool_calls(response)
# 验证 Agent 调用了 edit_file 工具更新 memories.md
assert any(
[tc["name"] == "edit_file"
and tc["args"]["path"] == "memories.md"
for tc in agent_tool_calls]
)
# LLM-as-judge 验证最终回复是否确认了偏好记录
communicated_to_user = llm_as_judge_A(response)
t.log_feedback(key="communicated_to_user",
score=communicated_to_user)
# LLM-as-judge 验证记忆文件是否包含正确信息
memory_updated = llm_as_judge_B(response)
t.log_feedback(key="memory_updated",
score=memory_updated)
代码中有几个关键设计值得注意:
t.log_inputs / t.log_outputs:将输入输出记录到 LangSmith,便于后续调试和追踪get_agent_tool_calls:提取 Agent 的工具调用轨迹,用于轨迹断言llm_as_judge:对于难以用规则匹配的检查项(如“回复是否确认了偏好”),使用 LLM 作为裁判来打分t.log_feedback:将评分结果记录为结构化反馈,而非简单的 pass/fail
定制化测试的三层验证模型
对 Deep Agent 的每个测试用例,建议从三层进行验证:
- 行为层:Agent 是否调用了正确的工具、传入了正确的参数?(轨迹断言)
- 沟通层:Agent 是否在回复中准确传达了执行结果?(LLM-as-judge)
- 效果层:Agent 的操作是否真正产生了预期的副作用?(状态检查)
本章小结
定制化测试逻辑是 Deep Agent 评测的基石。传统的“统一评测器”模式无法覆盖 Agent 的多维度行为。通过 Pytest/Vitest 集成,开发者可以为每个测试用例编写独立的断言逻辑,结合轨迹检查、LLM-as-judge 和状态验证,实现全面的质量保障。
模式二:单步评测 — 高效的“单元测试”
单步评测的核心思想
LangChain 团队报告,在他们的 Deep Agent 评测用例中,约一半采用单步评测模式。单步评测的核心问题是:
给定特定的输入消息序列,LLM 做出的下一步决策是否正确?
这类似于软件工程中的单元测试——不关心整个系统的端到端行为,只验证单个决策点的正确性。
适用场景
单步评测特别适合验证以下类型的决策:
- Agent 是否选择了正确的工具来搜索会议时间?
- Agent 是否检查了正确的目录内容?
- Agent 是否更新了其记忆?
- Agent 是否正确地拒绝了不合理的请求?
为什么回归问题多发生在单个决策点?
LangChain 团队的经验表明,Agent 的回归(regression)更多发生在单个决策点而非完整执行序列上。这与软件工程中 bug 倾向于出现在“接口边界”的规律一致。当 prompt 或模型版本更新时,Agent 在特定场景下的工具选择和参数生成最容易出现偏差。
LangGraph 中断机制
如果使用 LangGraph 框架,可以利用其 streaming 能力在 Agent 执行第一个工具调用后立即中断,从而高效地实现单步评测:
@pytest.mark.langsmith
def test_single_step() -> None:
state_before_tool_execution = await agent.ainvoke(
inputs,
# interrupt_before: 指定在哪些节点前中断
# 在 tools 节点前中断可以检查工具调用参数
interrupt_before=["tools"]
)
# 获取 Agent 的消息历史,包括最新的工具调用
print(state_before_tool_execution["messages"])
单步评测的效率优势
单步评测不仅执行速度快(通常只需一次 LLM 调用),还能大幅节省 token 消耗。对于需要频繁运行的回归测试套件来说,这意味着显著更低的成本和更快的反馈循环。LangChain 建议将单步评测作为 CI/CD pipeline 中的第一道关卡。
本章小结
单步评测是 Deep Agent 评测中最高效的手段。它聚焦于单个决策点的正确性,类似于单元测试。通过 LangGraph 的 interrupt_before 机制可以优雅地实现。建议将约一半的测试用例设计为单步评测,覆盖 Agent 的关键决策分支。
模式三:完整轮次评测 — 端到端验证
完整轮次的三个检查维度
完整轮次评测让 Agent 从接收输入到返回最终结果完整运行一次。与单步评测的“单元测试”类比不同,完整轮次更像是集成测试,关注 Agent 多步协作后的整体效果。LangChain 总结了三个检查维度:
轨迹检查(Trajectory)
验证 Agent 在整个执行过程中是否调用了必要的工具,但不要求严格的调用顺序。例如日历调度 Agent 可能需要多次工具调用才能找到所有参与者都空闲的时间段——我们只关心它最终是否查询了所有相关日历,而不关心查询的顺序。
最终响应检查(Final Response)
对于编程和研究等开放性任务,Agent 到达目标的路径可能有很多种,此时最终输出的质量比具体路径更重要。这与传统的“标准答案”评测模式有根本区别。
其他状态检查(Other State)
很多 Deep Agent 不仅仅产生文本回复,还会创建 artifacts(文件、代码、配置等)。这些副产物也需要纳入评测范围:
| Agent 类型 | 状态检查方式 |
|---|---|
| 编程 Agent | 读取并测试 Agent 生成的代码文件(运行单元测试、检查语法等) |
| 研究 Agent | 验证 Agent 是否找到了正确的链接或信息来源 |
| 邮件 Agent | 检查 Agent 是否正确更新了用户偏好文件 |
| 调度 Agent | 验证日历中是否实际创建了正确的事件 |
轨迹检查不要过度约束
常见错误是对工具调用的顺序做严格断言。Agent 可能因为模型版本更新、temperature 差异等原因改变工具调用顺序,但只要最终结果正确,这种顺序变化是可以接受的。过度约束会导致脆弱测试(flaky tests),增加维护成本。建议使用 any() 而非 assertEqual(trajectory, expected_trajectory) 来做轨迹断言。
LangSmith Trace 可视化
LangSmith 提供了完整轮次的 trace 可视化能力,可以查看:
- 高层指标:延迟(latency)和 token 消耗
- 细粒度步骤:每次模型调用和工具调用的详细信息
- 失败定位:当测试失败时,trace 视图可以快速定位到具体出错的步骤
这种从宏观到微观的多层级追踪对于调试复杂 Agent 行为至关重要。
本章小结
完整轮次评测提供了 Agent 行为的全景视图。通过轨迹、最终响应和其他状态三个维度的检查,可以全面评估 Agent 的端到端表现。关键原则是:检查结果而非路径,对轨迹做适度宽松的断言以避免脆弱测试。
模式四:多轮对话评测 — 模拟真实交互
多轮评测的核心挑战
真实场景中,用户往往与 Agent 进行多轮交互。例如先问“帮我安排明天的会议”,然后根据 Agent 的回复进一步说“改到下午 3 点”。然而,多轮评测面临一个根本性问题:
硬编码多轮输入的脆弱性
如果天真地将多轮对话的用户输入硬编码为一个固定序列,当 Agent 在第一轮的回复偏离预期时,后续的硬编码输入将与上下文脱节,导致整个测试变得无意义。例如,如果 Agent 没有按预期询问“你想安排什么时间?”,而是直接建议了一个时间,那么硬编码的“下午 3 点”回复就毫无意义了。
条件分支策略
LangChain 团队采用的解决方案是在 Pytest/Vitest 测试中引入条件逻辑:
- 运行第一轮,检查 Agent 输出
- 如果输出符合预期,继续运行下一轮
- 如果输出不符合预期,提前终止测试(early fail)
这种方式的优势在于:
- 不需要穷举 Agent 的所有可能分支
- 每一轮都有独立的检查点(checkpoint)
- 失败时可以精确定位到哪一轮出了问题
隔离测试特定轮次
如果需要单独测试第二轮或第三轮的行为,可以直接用适当的初始状态(initial state)启动测试,跳过前面的轮次。这在 LangGraph 中特别方便,因为 Agent 的状态可以被序列化和恢复。这种技巧让多轮测试的编写和维护成本大幅降低。
多轮评测的设计建议
根据 LangChain 的经验,多轮评测的设计应遵循以下原则:
| 原则 | 说明 |
|---|---|
| 最少轮次 | 每个测试用例只包含验证目标行为所需的最少轮数 |
| 条件推进 | 每一轮结束后验证输出,只在预期路径上推进 |
| 早期失败 | 不符合预期时立即终止,避免浪费资源在无效状态上运行 |
| 状态快照 | 支持从任意中间状态恢复,便于隔离测试特定轮次 |
本章小结
多轮对话评测模拟了真实的用户交互场景,但面临输入与上下文脱节的挑战。通过条件分支策略和状态快照机制,可以在保持测试有效性的同时控制复杂度。关键是不要试图穷举所有对话路径,而是选择最关键的场景进行有针对性的测试。
模式五:环境隔离与可复现性
环境对 Deep Agent 评测的关键影响
Deep Agent 具有状态性,能够读写文件、调用 API、修改系统配置。这意味着如果测试环境没有正确隔离,前一个测试用例的副作用会污染后续测试,导致难以复现的测试失败(flaky tests)。
Deep Agent 评测的黄金法则
每个 eval 运行必须获得一个全新、干净的环境,以确保结果可复现。这是 Deep Agent 评测与传统 LLM 评测最大的基础设施差异。
编程 Agent 的环境隔离策略
文章以编程 Agent 为例介绍了两种隔离策略:
| 特性 | Docker 容器/Sandbox | 临时目录 |
|---|---|---|
| 隔离程度 | 完全隔离(进程、文件系统、网络) | 文件系统级隔离 |
| 启动开销 | 较高(秒级) | 极低(毫秒级) |
| 适用场景 | 需要网络隔离或系统级操作的 Agent | 仅需文件系统操作的 Agent |
| 代表实现 | Harbor / TerminalBench | DeepAgents CLI 临时目录方案 |
Harbor 与 TerminalBench
Harbor 是一个为编程 Agent 评测设计的平台,TerminalBench 是其提供的评测基准之一。它为每个评测任务启动独立的 Docker 容器,确保 Agent 的文件操作、进程管理和网络访问互不干扰。对于生产级 Agent 评测系统,这类重量级隔离方案是推荐做法。
Mock API 请求:更快、更可控
除了文件系统隔离,API 调用也需要考虑。LangSmith Assist 需要连接真实的 LangSmith API,但直接调用生产 API 存在两个问题:
- 速度慢:网络请求增加延迟,拖慢整个评测流程
- 成本高:大量 API 调用可能产生费用
- 不稳定:外部服务的状态变化会影响测试结果的可复现性
解决方案是录制-回放(record-replay)模式:
| 语言 | 工具 | 原理 |
|---|---|---|
| Python | VCR.py | 首次运行录制 HTTP 交互到文件,后续回放 |
| JavaScript | Hono proxy | 通过代理应用拦截并回放 fetch 请求 |
Mock 的隐患:API 变更导致过期
录制-回放模式的一个风险是当上游 API 发生变更时,录制的响应可能已经过时(stale)。建议定期用真实 API 重新录制一次基准数据,并在 CI 中设置周期性的“真实 API”测试作为兜底。
本章小结
环境隔离和可复现性是 Deep Agent 评测的基础设施层保障。文件系统操作需要临时目录或容器隔离,API 调用需要录制-回放机制。两者结合可以显著提高评测的速度、成本效率和结果稳定性。
评测策略综合对比
综合前面五种模式,下表从多个维度进行对比,帮助读者根据具体场景选择合适的评测策略:
| 评测模式 | 执行成本 | 覆盖范围 | 调试难度 | 适用阶段 |
|---|---|---|---|---|
| 定制化测试逻辑 | 中等 | 视具体用例 | 低 | 全流程 |
| 单步评测 | 低 | 单决策点 | 极低 | CI/CD 快速验证 |
| 完整轮次评测 | 高 | 端到端 | 中等 | 发布前回归 |
| 多轮对话评测 | 很高 | 用户交互 | 较高 | 关键场景覆盖 |
| 环境隔离 | 基础设施 | 横切关注点 | — | 全流程基础 |
选择评测模式的决策框架
- 首先确保环境隔离(模式五),这是所有其他模式的前提
- 主力使用单步评测(模式二)覆盖关键决策点,约占用例的 50%
- 补充用完整轮次评测(模式三)做端到端验证
- 精选几个关键场景用多轮评测(模式四)模拟真实交互
- 贯穿使用定制化测试逻辑(模式一)为每个用例编写针对性断言
总结与延伸
核心收获
LangChain 这篇文章的核心论点可以归纳为一句话:Deep Agent 的评测不能套用传统 LLM 评测的范式,需要从根本上重新设计。具体来说:
- 测试粒度:从“一个评测器适用所有”到“每个用例定制断言”
- 运行模式:从“全量运行”到“单步 + 全轮 + 多轮”三级体系
- 检查维度:从“只看输出”到“轨迹 + 响应 + 状态”三维验证
- 基础设施:从“无状态评测”到“环境隔离 + API Mock”
与软件工程测试体系的对应关系
Deep Agent 评测体系与经典的软件工程测试金字塔有着惊人的对应关系:
| 软件测试层级 | Deep Agent 评测模式 | 建议占比 |
|---|---|---|
| 单元测试 | 单步评测(Single Step) | \(≈\)50% |
| 集成测试 | 完整轮次评测(Full Turn) | \(≈\)30% |
| 端到端测试 | 多轮对话评测(Multiple Turns) | \(≈\)20% |
拓展阅读
- LangSmith 官方文档:docs.smith.langchain.com --- 详细的评测集成指南
- LangGraph 文档:langchain-ai.github.io/langgraph --- 了解 Agent 状态管理和中断机制
- Harbor / TerminalBench:编程 Agent 专用评测环境
- VCR.py:vcrpy.readthedocs.io --- Python HTTP 录制回放库
- LangChain 博客原文:Evaluating Deep Agents: Our Learnings