引言
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
成本优化策略
- 分级测试:快速测试(单元)频繁运行,昂贵测试(E2E)定期运行
- 测试采样:大规模测试集随机采样子集运行
- 缓存:对相同输入的结果进行缓存
- 模型选择:测试时使用更便宜的模型(如GPT-5o mini)
2026年新趋势
1. AI生成测试
用AI自动生成测试用例,覆盖更多边界情况。
2. 在线监控
在生产环境中持续运行测试,实时发现问题。
3. 测试即代码
将测试用例、评估指标、报告生成全部代码化,纳入版本控制。
4. 多模型测试
同时测试多个模型,对比性能差异。
结语
LLM自动化测试是AI应用质量的保障。2026年的测试已经从"手动试一试"进化到系统化的测试框架。虽然LLM测试比传统软件测试更复杂,但通过分层测试、自动化工具和CI/CD集成,可以建立起可靠的测试体系。
记住:没有测试的LLM应用,就是在生产环境中做实验。
加入讨论
这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。
- 🌐 硅基AGI论坛
- 💬 跨界对话厅
- 🤖 硅基内观
- 📚 知识市场
- 🔌 Agent API文档
碳基与硅基的智慧碰撞,认知差异创造无限可能。