智能Agent测试全流程解析:从单元测试到端到端验证

1次阅读
没有评论

共计 2486 个字符,预计需要花费 7 分钟才能阅读完成。

image.webp

为什么智能 Agent 测试更困难?

最近在团队里折腾 AI Agent 的测试方案,发现和传统软件测试相比有三个头疼问题:

智能 Agent 测试全流程解析:从单元测试到端到端验证

  1. 非确定性输出:同样的输入可能得到不同回复(比如带随机性的 LLM)
  2. 复杂状态管理:Agent 内部状态机可能随对话变化
  3. 外部依赖黑洞:API 调用、数据库访问、第三方服务像定时炸弹

分层测试策略

我们的解决方案是分层拆解,就像吃蛋糕要一层层来:

graph TD
    A[单元测试] -->| 验证决策逻辑 | B(组件测试)
    B -->| 验证服务集成 | C[端到端测试]
    C -->| 监控生产环境 | D[Canary 发布]

第一层:单元测试(核心逻辑)

用这个测试基类搞定大部分场景:

from typing import Any, Dict
import pytest

class AgentTestBase:
    """所有测试类的父类,包含通用工具方法"""

    @staticmethod
    def assert_response_contains(
        response: str, 
        keywords: list[str],
        threshold: int = 1
    ) -> None:
        """检查响应是否包含至少 threshold 个关键词"""
        count = sum(1 for kw in keywords if kw in response)
        assert count >= threshold, f"预期包含 {threshold} 个关键词,实际匹配 {count} 个"

    @pytest.fixture
    def mock_openai(self, mocker):
        """自动 mock OpenAI API 调用"""
        return mocker.patch('openai.ChatCompletion.create')

第二层:集成测试(服务协作)

重点处理外部依赖,推荐两种模式:

  1. Mock 模式:快速但可能失真
  2. Recording 模式:录制真实响应后回放
import json
from pathlib import Path

class WeatherAgentTest(AgentTestBase):
    """测试天气查询 Agent 的集成场景"""

    @pytest.mark.asyncio
    async def test_weather_query(self, tmp_path: Path):
        # 使用 Recording 模式
        recording_file = tmp_path / "weather_api.json"

        if recording_file.exists():
            # 回放模式
            with open(recording_file) as f:
                mock_data = json.load(f)
            self.mock_weather_api.return_value = mock_data
        else:
            # 录制模式
            real_data = await real_api_call()
            with open(recording_file, 'w') as f:
                json.dump(real_data, f)

        agent = WeatherAgent()
        response = await agent.query("北京天气")
        self.assert_response_contains(response, ["气温", "摄氏度"])

第三层:端到端测试(用户视角)

用这个模板测试完整链路:

@pytest.mark.e2e
class ShoppingAgentE2ETest:

    @pytest.mark.timeout(30)  # 设置超时防止死循环
    async def test_complete_order_flow(self):
        """模拟从商品咨询到下单的全流程"""
        agent = ShoppingAgent()

        # 第一轮:商品咨询
        resp1 = await agent.chat("想买无线耳机")
        assert "推荐" in resp1

        # 第二轮:加入购物车
        resp2 = await agent.chat("把 AirPods Pro 加入购物车")
        assert "已添加" in resp2

        # 第三轮:支付验证
        resp3 = await agent.chat("用支付宝支付")
        assert "订单号" in resp3

生产环境实战技巧

测试数据管理

建议目录结构:

tests/
├── unit/
├── integration/
│   ├── __recordings__/  # 存放录制的 API 响应
│   └── test_weather.py
└── e2e/
    └── fixtures/  # 端到端测试的初始数据

CI/CD 流水线配置

GitLab CI 示例片段:

stages:
  - test

agent_tests:
  stage: test
  image: python:3.10
  script:
    - pip install -r requirements-test.txt
    - pytest tests/unit/ --cov=src  # 单元测试要求 100% 覆盖
    - pytest tests/integration/ --record-mode=none  # 禁止录制模式
    - pytest tests/e2e/ -m "not slow"  # 跳过标记为 slow 的测试

踩坑经验分享

  1. 时间敏感测试:遇到检查「今天天气」这类用例,可以用 freezegun 固定时间:

    from freezegun import freeze_time
    
    @freeze_time("2023-08-01")
    def test_date_sensitive():
        assert agent.get_date() == "2023 年 8 月 1 日"

  2. 并行化陷阱:使用 pytest-xdist 并行运行时要小心共享状态,建议:

  3. 每个测试创建独立 Agent 实例
  4. 用 tmp_path 处理文件操作

扩展思考

试着为你的 Agent 设计测试矩阵,考虑这些维度:

  1. 输入覆盖:边界值(空输入、超长文本)、异常字符
  2. 状态路径:测试状态机所有可能转移
  3. 失败模式:故意断开 API 连接、返回错误响应
  4. 性能基线:记录关键操作的耗时区间

可以先用这个表格规划:

测试类型 验证目标 工具链 执行频率
单元测试 决策逻辑正确性 pytest+mock 每次提交
集成测试 服务交互可靠性 pytest-vcr 每日
端到端测试 用户体验完整性 playwright 发布前
压力测试 高并发稳定性 locust 月度
正文完
 0
评论(没有评论)