AI AgentTechnical Deep Dive

Agent 测试:先测确定性部件,再测真实轨迹

发布时间2026/02/20
分类AI Agent
预计阅读10 分钟
作者吴长龙
*

Agent 的测试不能只停留在“输出像不像对”。更有效的做法是分层验证:先测确定性逻辑,再测真实集成,最后补轨迹评估和回归门槛。

01.Agent 测试为什么比普通后端更难

普通软件里,我们常常可以直接断言:

  • 输入是什么
  • 输出应该是什么
  • 中间步骤是否满足确定规则

但 Agent 系统往往不这么老实。它的问题在于:

  • 模型输出有非确定性
  • 工具调用会受外部服务影响
  • 一次任务由多个步骤组成
  • 同一个目标可能走出不同路径

这意味着,Agent 测试不能只靠“对最终文本做字符串比对”。更有效的办法,是把系统拆成不同层级,分别验证。

LangChain 当前官方测试文档给出的思路很实用:把测试分成 unit tests、integration tests 和 evals。这个分层基本就是 Agent 场景下最值得采用的默认做法。

02.一条更靠谱的测试主线

我更推荐把 Agent 测试看成三层:

  • 单元测试:验证确定性部件
  • 集成测试:验证真实模型、真实工具和真实网络
  • 轨迹评估:验证整个 agent 执行过程是否符合预期

这三层不是互相替代,而是互相补位。

03.第一层:先把确定性部件测稳

Agent 虽然不确定,但它内部一定仍有很多确定性逻辑:

  • 路由函数
  • 参数校验
  • 状态 reducer
  • 工具封装
  • 安全规则

这些部分最适合做单元测试,因为它们快、便宜,而且失败时定位清楚。

例如,一个简单的路由函数就应该直接测:

python snippetpython
from typing import Literal


def route_by_intent(intent: str) -> Literal["search", "execute", "handoff"]:
    if intent in {"faq", "docs"}:
        return "search"
    if intent in {"run", "apply"}:
        return "execute"
    return "handoff"


def test_route_by_intent():
    assert route_by_intent("faq") == "search"
    assert route_by_intent("run") == "execute"
    assert route_by_intent("unknown") == "handoff"

这种测试看起来不起眼,但它能稳定托住系统最关键的骨架。

工具也值得单独测

很多 Agent 问题不是模型出错,而是工具封装本身不稳。

例如:

  • 参数 schema 不严
  • 错误处理不一致
  • 返回结构不稳定

这类问题完全应该在单元测试里先拦住,而不是等到线上 trace 里再看。

04.第二层:用集成测试验证真实链路

LangChain 官方测试文档强调过一个很重要的现实:Agent 应用往往更依赖 integration tests,因为它们天然要串联多个组件,还要面对 LLM 的非确定性。

这层测试的目标不是做精确字符串断言,而是验证:

  • 模型和工具是否真的能协同工作
  • 真实凭证、schema、网络是否可用
  • 延迟和成本是否还在可接受范围

一个更贴近工程的断言方式通常是:

  • 是否调用了正确工具
  • 参数是否符合预期
  • 最终结果是否满足结构约束
  • 是否在步数上限内完成

而不是要求输出句子逐字完全一致。

05.第三层:Agent 真正要补的是轨迹评估

这是普通软件测试和 Agent 测试差异最大的地方。

Agent 的很多质量问题,不会体现在“最后一句话对不对”,而会体现在轨迹里:

  • 工具选错
  • 参数传错
  • 步数过多
  • 本可直接回答却绕远路
  • 不该调用高风险工具时却调用了

所以 LangChain 官方测试文档把 evals 也放进测试主线里,是很合理的。

对 Agent 来说,真正有价值的评估对象通常包括:

  • 工具选择是否正确
  • 参数格式是否正确
  • 轨迹是否满足约束
  • 最终回答是否可用

06.一个实用的测试组合方式

如果只保留一套最小但够用的组合,我会建议:

1. 单元测试测确定规则

  • 路由
  • 工具封装
  • guardrails
  • 状态合并

2. 集成测试测真实 happy path

  • 一两个最关键任务
  • 真实工具调用
  • 真实模型
  • 真实凭证

3. 评估测代表性轨迹

  • 常见任务
  • 高风险任务
  • 边界任务
  • 回归任务

这个组合通常比“为所有地方都写大而全的 LLM 测试”更稳。

07.LangGraph 场景下,值得测节点和部分执行

如果你的系统已经进入 LangGraph,自定义图结构会越来越多。这时除了测整图,还应该测:

  • 单个节点
  • 条件边
  • 中间状态
  • 部分执行

LangGraph 官方测试文档里就强调了一个很实用的模式:每个测试里重新创建图,并为测试编译新的 checkpointer。这样能减少状态污染,也更容易验证图的不同分支。

一个简化示例如下:

python snippetpython
from langgraph.checkpoint.memory import InMemorySaver


def build_graph():
    ...


def test_graph_happy_path():
    graph = build_graph().compile(checkpointer=InMemorySaver())

    result = graph.invoke(
        {"messages": [{"role": "user", "content": "帮我查北京天气"}]},
        {"configurable": {"thread_id": "test-1"}},
    )

    assert result["messages"]

这个例子看上去简单,但它表达了两个重点:

  • 图测试应该隔离状态
  • 测试不仅关注最终输出,也关注中间 state 是否合理

08.不要把“自动生成测试用例”误当成测试体系

AI 当然可以帮助你生成测试代码,但这和“系统已经可验证”是两回事。

自动生成测试最常见的问题是:

  • 只会补 happy path
  • 断言很弱
  • 不理解真实业务风险
  • 生成很多噪音测试

所以更稳的用法是:

  • 让 AI 辅助你补测试样板
  • 让人定义风险边界和验收规则
  • 把测试门槛放在关键行为上,而不是测试数量上

09.把评估接进回归流程,才算真正形成闭环

LangSmith 的 evaluation concepts 文档很明确地区分了 testing 和 evaluation:

  • testing 更像硬性门槛,不通过就不能发
  • evaluation 更像质量度量,用于比较和持续改进

这两个概念最好配合使用。

例如一个实用的回归门槛可能是:

  • 单元测试必须全绿
  • 核心集成测试必须全绿
  • 关键数据集上的离线评估不能低于当前基线

这比只看“模型回答感觉还行”要稳得多。

10.一套更接近工程落地的测试清单

如果你在做一个真实 Agent 项目,我建议优先保证下面这些测试存在:

  • 工具 schema 和错误处理的单元测试
  • 关键路由和 guardrails 的单元测试
  • 至少 1 到 3 条真实任务集成测试
  • 一组小而精的离线评估数据集
  • 针对历史事故和坏例子的回归集

先把这些建起来,再谈更复杂的自动化生成和大规模评估,会更符合投入产出比。

11.总结

Agent 测试最容易走偏的地方,是一上来就试图“验证整个智能系统”,结果什么都测不稳。更靠谱的顺序是:

  • 先测确定性部件
  • 再测真实集成
  • 再测整条轨迹和回归质量

这样做的好处是,问题一旦出现,你更容易判断到底是规则错了、工具错了,还是模型决策本身退化了。

12.参考资料