猪头少年 - 云南AI专家 - 云南独立开发者

Engineering note

测试 Agent,而不是只测试方法

这是「Agent 工程实战」的第 15 篇。专题从一个能聊天、能调工具的 .NET Agent 出发,逐步补齐可靠性、安全、测试与发布能力。

本篇要解决的问题: 用可重复任务、假模型和工具轨迹来验证 Agent 行为,而非只看最终回答。

返回专题路线


本章定位:本章讨论如何测试具有不确定性和外部依赖的 Agent。你会用 fake model、fake tool 和本地 SSE 服务测试行为轨迹,而不是只看最终文本。

建议阅读方式:先通读原理,再对照当前项目源码,最后完成本章实践。测试的目标是保护 Agent 的决策边界,让你敢于更换模型、提示词和工具实现。

本章导读

本章讨论如何测试具有不确定性和外部依赖的 Agent。你会用 fake model、fake tool 和本地 SSE 服务测试行为轨迹,而不是只看最终文本。

本章采用“源码观察 → 概念拆解 → 工程改造 → 实践验证”的顺序。示例中的接口和代码骨架用于说明设计方向,真正提交代码时应结合项目当前状态逐步落地。

15.1 为什么 Agent 测试更难

模型输出具有不确定性,直接调用真实 API 会带来成本、速度和稳定性问题。因此要把模型客户端抽象出来,用 fake response 驱动 Agent Loop。

15.2 最小 fake model

public sealed class FakeModelClient : IModelClient
{
    public Queue<ModelEvent> Events { get; } = new();

    public async IAsyncEnumerable<ModelEvent> StreamAsync(
        ModelRequest request,
        [System.Runtime.CompilerServices.EnumeratorCancellation]
        CancellationToken cancellationToken = default)
    {
        while (Events.TryDequeue(out var item))
        {
            cancellationToken.ThrowIfCancellationRequested();
            yield return item;
            await Task.Yield();
        }
    }
}

15.3 必须覆盖的场景

  • 纯文本回答;
  • 一次工具调用后回答;
  • 多次工具调用;
  • 无效 JSON 参数;
  • 缺少参数;
  • 工具抛异常;
  • 模型连续调用工具;
  • HTTP 429 和 5xx;
  • 用户取消;
  • 工具超时;
  • 输出包含敏感数据时的脱敏。

15.4 端到端测试

端到端测试可以用本地 fake HTTP server 验证 SSE 解析。真实模型评测则放到单独的评测集,不要让每次普通单元测试都访问线上模型。

15.5 本章交付物

  • Agent.Tests 测试项目;
  • 工具单元测试;
  • SSE 解析测试;
  • Agent Loop 集成测试;
  • 一组固定的回归用例。

15.6 测试金字塔

测试可以分三层:

  1. 纯单元测试:路径解析、参数转换、SSE 解析、工具策略;
  2. 组件测试:Agent Loop + fake model + fake tools;
  3. 端到端测试:本地 HTTP server 或少量真实模型任务。

越靠近真实服务,成本和不稳定性越高,因此数量应越少。不要用一组昂贵的真实模型测试去替代几十个确定性的单元测试。

15.7 测试工具调用轨迹

最终文本不是唯一断言。更重要的是轨迹:

Assert.Collection(executor.Calls,
    call => Assert.Equal("filesystem.read_file", call.Name),
    call => Assert.Equal("knowledge.search", call.Name));

还应断言禁止调用的工具没有被调用,参数被正确校验,工具失败后是否按策略重试。

15.8 记录回归样例

每次发现 bug,都把用户输入、fake model 响应和预期轨迹保存成回归用例。不要只修代码不留样例,否则下一次重构很可能重新引入同一问题。

样例中不要包含真实密钥、私人文件和不可公开的业务数据。可以把敏感内容替换成结构相同的假数据。

15.9 属性测试与模糊测试

解析器和路径解析器很适合做边界测试。例如生成随机的 SSE 空行、截断 JSON 和特殊路径,验证程序不会崩溃、不会访问 workspace 外资源。

在引入模糊测试前,先定义不变量:非法路径永远不能解析成功,解析器永远不能把任意文本当成成功工具调用。

15.10 练习:先写测试再修循环

先写一个失败测试:fake model 第一次返回最终文本,期望模型客户端只被调用一次;再写一个工具调用测试,期望第二次请求携带 tool message。最后才修改 Agent Loop。这个过程能让测试成为设计工具,而不只是验收工具。

15.11 本章产出

测试的最终目标不是追求覆盖率数字,而是让你敢于替换模型客户端、注册中心和工具执行器,同时知道 Agent 的行为没有悄悄改变。


下一阶段:让 Agent 进入真实工作流。 后续文章处理检索、计划、服务化、审批与发布。

单篇实战作业

实践:先写一个断言工具调用轨迹的失败测试,再修改 Agent Loop,体会测试如何反向塑造接口。

建议把作业拆成一个独立提交,并在提交说明中写清楚:改动前的行为、改动后的行为、验证命令、尚未解决的风险。测试的目标是保护 Agent 的决策边界,让你敢于更换模型、提示词和工具实现。

章节复盘

复盘问题:测试失败时,失败的是模型随机性还是系统契约?把随机部分替换为可重复的 fake。

本章的完成标准不是把所有设计一次性做完,而是能把它变成项目中的一个明确边界,并为下一章留下可验证的接口。


下一篇:第 16 篇《知识库与检索增强:先让答案可追溯》

如果你正在把 Agent 放进真实工作流,建议完成本篇的实战作业后再继续:每一步都应留下可验证的代码、测试或运行记录。

Next step

不要停在单篇文章。

沿主专题继续阅读,查看同一问题从概念到实战的完整路径。

返回「Agent 工程实战」路线