引言

LLM应用的测试与传统软件测试截然不同:输入空间无限大、输出不确定、质量主观。2026年,LLM自动化测试已经形成了一套完整的方法论和工具链。本文将系统介绍如何构建LLM自动化测试体系。

LLM测试的挑战

挑战一:输入空间无限

传统软件的输入是结构化的(如表单字段),而LLM的输入是自由文本,可能的组合无限多。

挑战二:输出不确定

同一个输入,LLM可能给出不同的输出(即使temperature=0,不同版本也可能不同)。

挑战三:质量主观

“好的回答"的定义因任务、用户、上下文而异。

挑战四:成本高

每次测试都需要调用LLM API,大规模测试成本可观。

测试分层架构

┌─────────────────────────────────┐
│         端到端测试 (E2E)         │  ← 模拟真实用户场景
├─────────────────────────────────┤
│         集成测试                 │  ← 测试模块间协作
├─────────────────────────────────┤
│         提示测试                 │  ← 测试提示效果
├─────────────────────────────────┤
│         单元测试                 │  ← 测试单个功能
└─────────────────────────────────┘

第一层:单元测试

测试LLM的基本功能:

class TestLLMUnit:
    def test_json_output(self):
        """测试JSON输出格式"""
        response = llm.generate("输出JSON格式:{\"name\": \"test\"}")
        assert is_valid_json(response)
    
    def test_language_detection(self):
        """测试语言识别"""
        response = llm.generate("用中文回复:Hello")
        assert is_chinese(response)
    
    def test_length_constraint(self):
        """测试长度约束"""
        response = llm.generate("用50字以内回答:什么是AI?")
        assert len(response) <= 100  # 中文字符数

第二层:提示测试

测试提示在不同输入上的表现:

class TestPrompt:
    def test_sentiment_analysis(self):
        """测试情感分析提示"""
        test_cases = [
            {"input": "太棒了!", "expected": "positive"},
            {"input": "太差了!", "expected": "negative"},
            {"input": "还行吧。", "expected": "neutral"},
        ]
        
        for case in test_cases:
            response = llm.generate(prompt.format(input=case["input"]))
            assert case["expected"] in response.lower()
    
    def test_robustness(self):
        """测试提示鲁棒性"""
        # 测试不同表述方式
        inputs = [
            "这部电影怎么样?",
            "你觉得这部电影如何?",
            "评价一下这部电影",
        ]
        
        responses = [llm.generate(prompt.format(input=i)) for i in inputs]
        # 检查输出是否一致(语义相似度)
        for i in range(len(responses)-1):
            similarity = compute_similarity(responses[i], responses[i+1])
            assert similarity > 0.7

第三层:集成测试

测试多个模块协作:

class TestIntegration:
    def test_rag_pipeline(self):
        """测试RAG流水线"""
        # 测试 检索 → 生成 完整流程
        query = "什么是大语言模型?"
        
        # 步骤1:检索
        retrieved_docs = retriever.search(query)
        assert len(retrieved_docs) > 0
        
        # 步骤2:生成
        context = format_docs(retrieved_docs)
        response = llm.generate(f"基于以下信息回答:\n{context}\n问题:{query}")
        
        # 验证
        assert "大语言模型" in response or "LLM" in response
        assert len(response) > 50

第四层:端到端测试

模拟真实用户场景:

class TestE2E:
    def test_user_conversation_flow(self):
        """测试用户对话流程"""
        # 模拟用户多轮对话
        messages = [
            "你好,我想了解Python",
            "它有哪些优点?",  # 指代Python
            "给我一个简单的例子",
        ]
        
        conversation = []
        for msg in messages:
            conversation.append({"role": "user", "content": msg})
            response = llm.chat(conversation)
            conversation.append({"role": "assistant", "content": response})
        
        # 验证最终回复
        final_response = conversation[-1]["content"]
        assert "python" in final_response.lower() or "def " in final_response

测试数据管理

测试集构建

class TestDataset:
    def __init__(self):
        self.cases = {
            "standard": [...],    # 标准测试用例
            "edge": [...],        # 边界测试用例
            "adversarial": [...], # 对抗性测试用例
            "regression": [...],  # 回归测试用例
        }
    
    def sample(self, category, n=10):
        """随机采样测试用例"""
        return random.sample(self.cases[category], min(n, len(self.cases[category])))

自动生成测试用例

用LLM生成测试用例:

def generate_test_cases(task_description, n=50):
    """
    用LLM自动生成测试用例
    """
    prompt = f"""
    请为以下任务生成{n}个测试用例:
    
    任务:{task_description}
    
    每个测试用例包含:
    - input: 输入文本
    - expected: 期望输出类型/内容
    - difficulty: easy/medium/hard
    - category: standard/edge/adversarial
    
    以JSON数组格式输出。
    """
    
    response = call_llm(prompt)
    return parse_json(response)

CI/CD集成

GitHub Actions示例

# .github/workflows/llm-test.yml
name: LLM Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'
      
      - name: Install dependencies
        run: pip install -r requirements.txt
      
      - name: Run unit tests
        run: pytest tests/unit/ -v
      
      - name: Run prompt tests
        run: pytest tests/prompts/ -v
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
      
      - name: Run regression tests
        if: github.event_name == 'pull_request'
        run: pytest tests/regression/ -v
      
      - name: Generate test report
        run: python scripts/generate_report.py
      
      - name: Upload report
        uses: actions/upload-artifact@v4
        with:
          name: test-report
          path: reports/

测试工具

PromptFoo

# promptfooconfig.yaml
description: "情感分析提示测试"

prompts:
  - file://prompts/v1.txt
  - file://prompts/v2.txt

providers:
  - openai:gpt-5
  - anthropic:claude-4-sonnet

tests:
  - vars:
      input: "这部电影太棒了!"
    assert:
      - type: contains
        value: "positive"
  - vars:
      input: "服务很差"
    assert:
      - type: contains
        value: "negative"

DeepEval

from deepeval import evaluate
from deepeval.metrics import HallucinationMetric, AnswerRelevanceMetric
from deepeval.test_case import LLMTestCase

# 定义测试用例
test_case = LLMTestCase(
    input="什么是Python?",
    actual_output=llm_response,
    expected_output="Python是一种编程语言..."
)

# 定义评估指标
metrics = [
    AnswerRelevanceMetric(threshold=0.7),
    HallucinationMetric(threshold=0.8),
]

# 执行测试
evaluate([test_case], metrics)

性能测试

延迟测试

def test_latency():
    """测试响应延迟"""
    latencies = []
    
    for _ in range(100):
        start = time.time()
        response = llm.generate("Hello")
        latency = time.time() - start
        latencies.append(latency)
    
    p50 = percentile(latencies, 50)
    p95 = percentile(latencies, 95)
    p99 = percentile(latencies, 99)
    
    assert p50 < 1.0   # P50 < 1秒
    assert p95 < 3.0   # P95 < 3秒
    assert p99 < 5.0   # P99 < 5秒

负载测试

async def test_concurrent_load():
    """测试并发负载"""
    concurrent_requests = 50
    
    async def make_request():
        return await llm.async_generate("Hello")
    
    tasks = [make_request() for _ in range(concurrent_requests)]
    results = await asyncio.gather(*tasks, return_exceptions=True)
    
    success_rate = sum(1 for r in results if not isinstance(r, Exception)) / len(results)
    assert success_rate > 0.95  # 成功率 > 95%

成本控制

测试成本估算

def estimate_test_cost(test_suite):
    total_tokens = 0
    for test in test_suite:
        # 输入token
        total_tokens += count_tokens(test["input"])
        # 预期输出token
        total_tokens += count_tokens(test["expected_output"])
    
    cost_per_token = 0.00001  # $0.01/1K tokens
    return total_tokens * cost_per_token

成本优化策略

  1. 分级测试:快速测试(单元)频繁运行,昂贵测试(E2E)定期运行
  2. 测试采样:大规模测试集随机采样子集运行
  3. 缓存:对相同输入的结果进行缓存
  4. 模型选择:测试时使用更便宜的模型(如GPT-5o mini)

2026年新趋势

1. AI生成测试

用AI自动生成测试用例,覆盖更多边界情况。

2. 在线监控

在生产环境中持续运行测试,实时发现问题。

3. 测试即代码

将测试用例、评估指标、报告生成全部代码化,纳入版本控制。

4. 多模型测试

同时测试多个模型,对比性能差异。

结语

LLM自动化测试是AI应用质量的保障。2026年的测试已经从"手动试一试"进化到系统化的测试框架。虽然LLM测试比传统软件测试更复杂,但通过分层测试、自动化工具和CI/CD集成,可以建立起可靠的测试体系。

记住:没有测试的LLM应用,就是在生产环境中做实验。

加入讨论

这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。

碳基与硅基的智慧碰撞,认知差异创造无限可能。