本章导读

        如果你带着传统测试的思维去做大模型测试,一定会碰得头破血流。  

        本章会深入剖析传统测试的底层逻辑与大模型的核心差异,并帮你建立“评估能力边界”的新思维。

读完本章,你将理解:

  • 为什么等价类、边界值、断言在 LLM 测试中大面积失效

  • 大模型测试的本质是什么

  • 如何从“验证正确性”转向“评估能力边界”

1.1 传统软件测试的底层逻辑

在讨论差异之前,我们先回顾传统软件测试的基石——确定性系统

1.1.1 确定性系统的定义

传统软件(Web 应用、移动 App、后端服务、嵌入式系统等)本质上是确定性系统:给定相同的输入,系统总是输出相同的结果。

【图1-1:确定性系统示意图】

基于这个确定性,我们发展出了一整套成熟的测试方法论:

方法 核心思想 示例
等价类划分 将输入域划分为若干等价类,每个类取一个代表值 年龄输入框:有效类 1-100,无效类 <1,无效类 >100
边界值分析 重点关注等价类边界的值 边界值:0、1、100、101
判定表 描述输入条件组合与输出结果的关系 会员等级 + 消费金额 → 折扣率
状态转换 测试系统在不同状态间的迁移 订单状态:待支付 → 已支付 → 已发货 → 已完成

这些方法的共同特点是:我们可以穷举或近似穷举输入空间,并明确知道每个输入对应的预期输出。

1.1.2 传统测试的核心假设

传统测试建立在三个核心假设之上:

  1. 可预测性:给定输入,输出是确定的

  2. 可复现性:缺陷可以在相同条件下复现

  3. 可判定性:存在明确的“正确/错误”判定标准

经验提示
这三个假设在大模型测试中全部被打破。如果你在转行时仍然固守这些假设,你会发现自己寸步难行

1.2 大模型:非确定性系统

1.2.1 什么是非确定性

大语言模型是一个概率生成模型。它的每一次输出,都是从概率分布中采样的结果。

【代码1-1:大模型的非确定性】

import openai
from openai import OpenAI

# 初始化客户端
client = OpenAI(api_key="your-api-key-here")

def test_non_deterministic(prompt: str, n_calls: int = 3, temperature: float = 0.7):

    print(f"{'='*50}")
    print(f"Prompt: {prompt}")
    print(f"Temperature: {temperature}")
    print(f"{'='*50}\n")
    
    responses = []
    
    for i in range(n_calls):
        response = client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[{"role": "user", "content": prompt}],
            temperature=temperature
        )
        
        answer = response.choices[0].message.content
        responses.append(answer)
        
        print(f"【第 {i+1} 次调用】")
        print(f"{answer}\n")
        print("-" * 50)
    
    return responses

# 测试示例
if __name__ == "__main__":
    prompt = "用一句话解释什么是人工智能"
    test_non_deterministic(prompt, n_calls=3, temperature=0.7)

即使将 temperature 设为 0,由于浮点数精度、并行计算、GPU 内核的不确定性,结果仍然可能产生微小波动。对于生成任务,这种波动可能导致完全不同的输出。

1.2.2 非确定性带来的根本挑战

挑战1:没有“标准答案”

传统测试中,我们可以写出这样的断言:

assert calculator.add(1, 1) == 2

但在大模型测试中,你问“什么是人工智能”,模型可能给出以下任意一种回答:

  • “人工智能是让机器模拟人类智能的技术”

  • “AI is the simulation of human intelligence in machines”(中文提问下模型有时会输出英文)

  • 一段 500 字的详细解释

  • 一个反问:“你指的是强人工智能还是弱人工智能?”

这些回答可能都是合理的,也可能部分合理。你无法用简单的等值判断。

挑战2:测试用例无法“固化”

传统测试中,一个测试用例是一个固定的 (输入, 预期输出) 对。
在大模型测试中,同样的输入对应无限种合理输出。你无法穷举“预期输出”,只能通过评测标准动态判断。

挑战3:缺陷难以复现(幽灵 Bug)

作者在使用目前市面上的一些大模型产品时发现,这种情况并不少见,大模型“一本正经”的在输出结果,但是这些结果乍一看没有问题,但是实际采纳就会发现存在BUG。

例如:在配置spring项目多数据源时,有别于经常使用的MySQL数据库,笔者使用postgresql数据库时,基于mybatis-plus,大模型在yml文件中推荐的写法中,url参数输出结果为“jdbcurl”,导致mapper相关错误。排查代码逻辑很容易忽略配置相关信息。

1.3 传统测试方法为何失效——具体分析

本节用具体例子说明,为什么等价类、边界值、断言等方法无法直接应用于大模型测试。

1.3.1 等价类划分的失效

场景:测试一个电商客服大模型,用户问题按业务类型分为“退款”“物流”“产品咨询”“投诉”四类。

传统思路:每类取 3-5 个典型问题,构成测试集。

问题所在

  • 同一个业务类内部,问题的语义差异远大于传统等价类的差异。“退款需要多久”和“退款被拒绝了怎么办”虽然都属于“退款”类,但模型处理逻辑完全不同。

  • 模型的表现不仅取决于问题类别,还取决于措辞、语气、上下文长度、对话历史等变量。等价类划分无法覆盖这些维度。

1.3.2 边界值分析的失效

场景:测试模型对输入长度的处理。模型的上下文窗口为 4096 个 token。

传统思路:测试长度为 4095、4096、4097 token 的输入。

问题所在

  • 长度边界确实需要测试,但大模型真正的“边界”往往是语义边界。例如:

    • 当输入接近上下文窗口上限时,模型是否会遗忘开头的内容?

    • 在长文本中插入关键信息,模型能否正确提取?

    • 跨越多个段落的指代消解是否仍然准确?

  • 这些语义边界无法用简单的数值边界覆盖。

1.3.3 自动化断言的失效

场景:自动化测试中,需要判断模型回答是否包含正确答案。

传统写法:

assert "北京" in model_response  # 判断回答中是否包含“北京”

问题

  • 模型可能回答“中国的首都是 Beijing”,你的断言会失败(大小写/中英文)

  • 模型可能回答“北京,也就是北平”,断言通过但语义不完整

  • 模型可能回答“上海”,断言失败,但“上海”本身也是一个合理的城市名

更严重的问题:你无法为每个测试用例手写复杂的语义匹配规则。业界实践是用模型评估模型——但这引入了新的不确定性(评估模型本身也会犯错)。

【表1-1:传统断言 vs LLM评测方法对比】

维度 传统断言 LLM 评测方法
判定依据 字符串/数值精确匹配 语义相似度、LLM-as-Judge
预期输出 固定值 可接受范围/参考集
通过标准 100% 精确 统计阈值(如相似度 > 0.8)
可维护性 低(随业务变化频繁修改) 中(需要持续校准评估器)

1.4 大模型测试的新范式

1.4.1 核心转变:从“验证正确性”到“评估能力边界”

基于上述分析,我提出大模型测试的新定义:

大模型测试的本质,不是验证模型在某个输入下是否输出正确答案,而是系统性地评估模型的能力边界——它擅长什么、不擅长什么、在什么条件下会失败、安全底线在哪里。

这个定义带来了三个核心转变:

转变一:从“断言”到“评测体系”

我们不再写死预期,而是建立多维度的量化指标。常见的评测维度包括:

维度 定义 量化方式示例
准确性 事实性错误的比例 人工标注错误率 / 事实一致性得分
完整性 回答是否覆盖用户问题的所有要点 要点覆盖率(0-100%)
有用性 回答是否解决用户实际需求 人工评分(1-5分)/ 点赞率
安全性 是否输出有害内容 违规率 / 红线用例通过率
流畅性 语言是否通顺自然 困惑度(PPL)/ 人工评分

风格一致性

是否符合预设的语气和风格 风格分类器得分
结果满意程度 对于测试结果符合预期的程度 语义、结果的匹配程度

转变二:从“单点测试”到“统计测试”

由于大模型的非确定性,单次测试结果没有意义。你必须在统计层面评估模型表现。

操作示例:评估模型在某个 Prompt 上的稳定性

#发出问题的
user_argent = ConversableAgent(
    name="数据分析师",
    llm_config=llm_config,
    system_message="""你是数据分析专家。根据用户要求,必须使用工具来解决问题。
    工具如下:
    - get_weather(city): 查询城市天气
    - calculate(expression):计算数学表达式
    根据用户的问题,正确选择工具。
    """,
    function_map={
        "get_weather": get_weather,
        "calculate": calculate,
    }
)

工具调用成功率>95%,返回结果正确性符合预期,响应时间<300ms。

转变三:从“功能验证”到“持续监控”

传统测试通常在上线前完成。但大模型是动态演化的:

  • 外部 API 会悄悄升级(OpenAI、Claude 等)

  • Prompt 会被频繁修改

  • 用户的使用模式会变化

  • 模型的输出分布可能发生漂移

因此,测试必须左移(在开发/微调阶段介入)且右移(持续线上监控)。

1.5 结尾总结

  • 传统软件测试基于确定性系统,依赖可预测性、可复现性、可判定性三大假设。

  • 大模型是非确定性概率生成模型,打破了上述所有假设。

  • 传统方法(等价类、边界值、断言)在大模型测试中大面积失效,原因是无法处理语义多样性、统计波动和评估主观性。

  • 大模型测试的新范式是:从验证正确性转向评估能力边界,具体包含三个转变:

    • 从“断言”到“评测体系”

    • 从“单点测试”到“统计测试”

    • 从“功能验证”到“持续监控”

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐