当我最初开始学习关于对话式 AI 测试时,有一个问题一直困扰着我:预期结果在哪里?
来自传统软件测试,我习惯于一种熟悉的模式。
需求告诉我们系统应该做什么。我们创建一个测试用例,提供输入,定义预期结果,执行测试,并将实际结果与我们的预期进行比较。
例如:
| 测试 | 输入 | 预期结果 |
|---|---|---|
| 有效登录 | 正确的用户名和密码 | 用户登录 |
| 无效登录 | 密码错误 | 显示错误消息 |
| API 请求 | 有效的请求载荷 | HTTP 200 并返回预期响应 |
然后我开始学习对话式 AI。突然,同样的方法并不那么完美契合。
如果我问 AI 代理 “我如何重置密码?”,它可能会回答:“您可以使用登录页面上的‘忘记密码’选项重置密码。”
再次提出同样的问题,它可能会说:“从登录屏幕选择‘忘记密码’,并按照发送到您注册邮箱的说明进行操作。”
措辞不同,但两种回答都可能完全可以接受。那么当确切的响应可能会变化时,我们该如何测试呢?
这个问题改变了我进行对话式 AI 测试的方式。
在本文中,我将介绍我在学习对话式系统行为时认为最重要的几个测试领域,并展示传统 QA 技术如何适应于 AI 代理。
考虑以下三条消息:
"我该如何重置密码?"
"我无法访问我的账户。"
"忘记密码。"
它们看起来不同。但根据应用的不同,它们可能都代表同一个底层用户目标:
PASSWORD_RESET
在对话式 AI 中,用户输入的句子通常被称为 utterance,而该背后的目标可以用 intent 表示。
这提出了一个重要的测试问题:当用户以不同方式表达时,系统能否理解相同的意图?
一个简单的测试集可能如下所示:
| 话语 | 预期意图 |
|---|---|
| 我忘记密码了 | PASSWORD_RESET |
| 我该如何修改密码? | PASSWORD_RESET |
| 我登录不了账户 | PASSWORD_RESET |
| 帮我恢复登录 | PASSWORD_RESET |
| 密码无法使用 | PASSWORD_RESET |
让我们看一个小例子:
test_cases = [
{ "message": "I forgot my password",
"expected_intent": "PASSWORD_RESET",
},
{ "message": "How do I change my password?",
"expected_intent": "PASSWORD_RESET",
},
{ "message": "Can't get into my account",
"expected_intent": "PASSWORD_RESET",
},
]
for test in test_cases:
response = ai_agent.send(test["message"])
assert response.intent == test["expected_intent"]
在运行此测试前,你需要先知道预期的意图。它通常来自应用已批准的意图定义或经过审查的测试数据集。自动化并不会决定正确的意图是什么,而是检查 AI 代理是否按照团队已经定义的行为对用户消息进行了分类:
Input: "Can't get into my account"
Expected intent: PASSWORD_RESET Actual intent: PASSWORD_RESET
PASS
不要仅仅因为句子表达清晰就停止。
真实用户常会拼写错误、使用缩写、提供不完整的信息,有时只输入几个字。
因此我也会测试:
"忘记密码"
"无法登录"
"密码帮助"
"被锁定"
这就是对话式 AI 测试开始变得有趣的地方。我们不是在测试系统是否能识别一个预定义的句子,而是在测试它是否能理解用户目标的各种变体。
我最初需要重新考虑的习惯之一是逐字比较实际响应和预期响应。
假设预期的回答是:\"您可以通过使用忘记密码链接来重置密码。\"
但 AI 的回答是:\"在登录屏幕上选择忘记密码以开始重置密码。\"
精确的字符串比较会失败。但从用户的角度来看,该回答可能完全正确。
与其将预期结果定义为一句话,不如定义一个好的响应必须具备的属性。
例如,响应应该:
解释如何启动密码重置流程
提供可操作的下一步
不要要求用户透露密码
避免编造账户信息
保持与密码恢复相关
现在,多个响应可以在不完全相同的情况下都通过测试。这对我来说是最大的改变之一。
对于确定性应用,预期输出通常是一个值。对于对话式 AI,预期结果可能需要是一组评估标准。
正确性很重要,但它不应该是你评估的唯一方面。我发现将响应质量分解为几个维度很有帮助。
准确性:信息是否正确?如果 AI 声称客户可以通过电子邮件重置密码,而实际流程需要联系支持,那么即使听起来很有说服力,该响应也会失败。
相关性:AI 是否回答了用户实际提出的问题?一个响应可能包含准确的信息,但仍然与问题无关。
完整性:回复是否包含用户继续前进所需信息?
清晰度:用户能否轻松理解答案?
有用性:回复是否真的帮助用户实现目标?
一个简单的评分标准可能如下所示:
| 标准 | 得分 |
|---|---|
| 准确性 | 0–2 |
| 相关性 | 0–2 |
| 完整性 | 0–2 |
| 清晰度 | 0–2 |
| 有用性 | 0–2 |
| 总分 | 0–10 |
然后您可以根据自己的应用定义合适的阈值。
确切的评分系统并不是重点。重要的是让评估标准明确起来,而不是凭感觉说“这个答案看起来不错”。
单轮测试很有用,但用户很少会用完全孤立的问题与 AI 代理互动。
考虑以下对话:
用户: 我需要更新我的地址。
AI 解释了该流程。
然后:
用户: 我可以在线完成吗?
什么是"那个"?第二条消息完全取决于第一条。
现在设想:
用户: 我需要更新我的地址。
AI: 当然。我可以帮忙。
用户: 实际上,在那之前,您能告诉我我的下一笔付款什么时候到期吗?
AI: 您的下一笔付款到期时间是 9 月 15 日。
用户: 谢谢。现在回到地址话题。
系统能否回到原始话题?
这是另一种类型的测试。
您的多轮测试套件应包括以下情景:
后续问题
对早期消息的引用
话题切换
返回之前的话题
用户更正
信息不完整
含糊的问题
重复的问题
这改变了我对测试单位的看法。有时您在测试响应,有时您在测试整个对话。
以下是一个示例:
ai_agent.send("My order number is A10245")
response = ai_agent.send("When will it arrive?")
assert response.order_id == "A10245"
第二条消息不包含订单号。此检查用于验证 AI 代理是否保留了之前轮次的信息,而不是将“何时会到达?”视为无关的问题。
人们会改变主意并犯错。
例如:
用户:我的账号以 4567 结尾。
然后:
用户:抱歉,我意思是 4576。
接下来会发生什么?
理想情况下,系统应使用更正后的信息,而不是继续使用原始值。
同样的原则也适用于其他对话细节。
“我要去波士顿。”
接着:
“实际上,改为芝加哥。”
或者:
“我需要六月的报告。”
接着:
“抱歉,七月。”
这些测试很有用,因为它们能揭示代理是否真正在维持对话上下文,还是仅仅在积累信息而不了解哪些信息是当前的。
用户并不总是提供足够的信息。
想象有人输入:'我想要更改它。'
要更改什么?他们的地址?密码?支付方式?通知偏好?
一个糟糕的对话系统可能会猜测。一个更好的系统可能会问:'您想更改什么?'
这为我们提供了另一个重要的测试类别:澄清行为。
创建故意模糊的表达,例如:
"我该如何更新它?"
"它不起作用。"
"你能改变那个吗?"
"我需要帮助处理我的账户。"
然后评估 AI 是否能识别信息缺失,避免做出无根据的假设,并提出适当的澄清问题。
有时,最好的 AI 回复不是答案,而是另一个问题。
起初,我几乎完全关注 AI 说了什么。随后我意识到,一个糟糕的答案并不必然意味着语言模型本身有问题。
该系统可能使用知识库、检索系统、文档、API 或其他企业数据源。
如果这些信息错误、不完整、相互冲突或过时,即使模型按设计运行,AI 也可能产生糟糕的回应。
假设官方政策规定:客户有 30 天退货期。但一篇过时的知识文章称客户有 60 天。
如果 AI 检索到了那篇过时文章并自信地回答“60 天”,那么回答就是错误的。
但调查不应止步于:“AI 产生了幻觉。” 测试者需要确定错误信息的来源。
我会调查的问题包括:
响应使用了哪些来源?
来源是否已获批准?
信息是否最新?
多个来源是否存在矛盾?
检索是否返回了正确的文档?
最终响应是否准确反映了检索到的信息?
在使用检索增强生成(RAG)的系统中,这一点尤为重要。
最重要的对话式 AI 测试之一其实很简单:询问系统不知道的事情。
假设一个内部支持助手包含产品 A、B 和 C 的文档。请问:'产品 Z 的取消政策是什么?'
产品 Z 不存在。
那么应该怎样?最坏的结果是系统自信地编造一个取消政策。
根据应用场景,更好的表现可能是:
"我没有关于产品 Z 的信息。"
或者:
"我找不到该信息。您需要我把您转接给支持人员吗?"
一个有用的幻觉测试套件应包括:
不存在的产品
虚假的政策名称
不支持的功能
故意的错误假设
超出知识领域的问题
系统无法提供的信息请求
您在测试 AI 是否知道何时 不 应该回答。
每个对话系统最终都会收到它无法理解的内容。但这并不一定是失败。
重要的问题是接下来会发生什么?
想象一下这样的场景:
用户:我需要帮助调整我的 ZXP。
系统不识别 'ZXP'。
较差的回退可能会反复说:'抱歉,我不明白。' 更好的回退可能会问:'您能多告诉我一些关于您所说的 ZXP 调整的细节吗?'
如果系统仍然无法理解请求,它可能需要提供另一种途径。
回退测试应覆盖:
未知意图
拼写错误
不完整的请求
不支持的主题
冲突的请求
重复的误解
还应测试多次失败后会发生什么。AI 代理不应让用户陷入无尽循环:'抱歉,我不明白。'
有时 AI 代理需要意识到它已无法可靠地处理对话。这可能发生在用户明确要求人工介入、请求超出代理能力范围,或情境需要人类判断时。此时继续生成答案,不如把对话交给人工。
考虑以下情况:
反复误解
不受支持的账户问题
用户请求人工介入
敏感工作流
自动化流程无法处理的例外情况
如果升级是产品设计的一部分,应测试整个转移过程。
例如:
用户: 我想和人工客服交谈。
AI 能否识别该请求?它是否能正确转移对话?人工客服是否能收到相关的对话历史?用户是否需要重复说明一切?在本应进行升级的时候,AI 是否仍在尝试回答?
即使技术上转移成功,如果所有上下文都丢失,仍可能导致体验不佳。
对话式界面可以让复杂的系统看起来简单。
用户看到:
"我的订单状态是什么?"
但在这句话背后,代理可能会:
识别用户意图
验证客户身份
调用订单 API
检索订单
解释响应
生成自然语言回答
传统的测试技能在这里变得极其宝贵。
如果 API 返回:
{
"order_id": "A10245",
"status": "SHIPPED"
}
AI 不应告诉用户:“您的订单仍在处理中。”
要检查这些集成,请确保您进行以下测试:
正确的 API 映射
身份验证失败
超时
空响应
格式错误的响应
不可用的服务
错误的状态码
部分数据
AI 不会取消传统的集成测试,而是在此基础上增加了一层。
手动探索性测试在您了解 AI 行为时很有用,但最终您需要可重复性。这时,黄金数据集 就显得尤为重要。
黄金数据集是一份经过精心挑选的、代表性的测试输入及其预期行为的集合,可在系统变更时重新运行。
例如:
| ID | 用户输入 | 预期行为 |
|---|---|---|
| INT-001 | 忘记密码 | 识别密码重置意图 |
| INT-002 | 无法访问账户 | 引导至账户访问流程 |
| CTX-001 | 我能在线上完成吗? | 解决之前的对话上下文 |
| AMB-001 | 我想修改它 | 请求澄清 |
| HAL-001 | 不存在的产品 Z 的政策 | 不要编造政策 |
| ESC-001 | 让我与人工客服交谈 | 启动升级 |
| KB-001 | 退货期是多久? | 根据批准的知识回答 |
然后,为每个重要意图添加改写、边缘情况、负面情况以及多轮对话场景。
每当提示、知识、模型、集成或对话逻辑变更时,重新运行数据集。
现在,您拥有的东西与传统回归测试更为接近。
假设您执行了 1,000 次对话测试,其中 950 次通过。95% 的通过率听起来不错。
但到底是什么失败了?是五百个无害的常见问题?还是五个关键的账户安全场景?
仅凭总体通过率无法讲完整个故事。根据应用场景,有用的指标可能包括:
意图识别准确率:用户的目标被正确理解的频率是多少?
回退率:系统未能理解用户的频率是多少?
任务完成率:用户成功完成预期任务的频率是多少?
升级成功率:当需要人工帮助时,转移是否成功?
基础错误: 响应与批准的知识冲突的频率是多少?
上下文错误: 在多轮对话中,系统丢失重要信息的频率是多少?
严重幻觉: 系统自信地提供未经证实信息的频率是多少?
合适的指标取决于产品及其风险。客服FAQ机器人和支持金融决策的AI系统不一定需要相同的质量阈值。
这是另一个在对话系统中也非常适用的传统QA原则。
并非所有AI故障的影响都相同。如果AI对“您的营业时间是什么?”这样的问题回答得生硬,那只是不便。
如果它在支付、账户安全、医疗指导或金融政策方面提供错误信息,影响可能会大得多。
因此,按风险对场景进行分类。
例如:
| 风险 | 示例 | 测试优先级 |
|---|---|---|
| 低 | 常见FAQ | 普通 |
| 中等 | 账户导航 | 高 |
| 高 | 金融/账户操作 | 极高 |
| 关键 | 安全/隐私行为 | 强制回归 |
然后将回归测试的重点放在那些错误的AI行为可能造成最大危害的场景上。
如果我今天要启动一个对话AI的QA工作,我会将其组织为以下几层:
系统能否在语言表达多样的情况下理解用户的需求?
响应是否准确、相关、完整、清晰且有用?
系统能否在多轮对话中保持上下文?
答案是否得到批准且最新信息的支持?
当信息不足时,系统是否会避免自信地回答?
当系统不理解时,它能否恢复,并在必要时将问题转交给人工?
APIs、身份验证、数据库和下游系统是否正常运行?
在模型、提示、知识或应用变更后,重要行为能否重新执行?
这为 QA 团队提供了比仅仅打开聊天机器人并随机提问更具结构化的起点。
当我最初开始学习对话式 AI 时,我认为我需要忘记我所知道的所有传统测试知识。但我不再这么认为了。
我们已有的许多技能可以极好地迁移。我们已经知道如何:
质疑假设
探索边界情况
设计负面测试
在多个系统中追踪故障
验证集成
按风险优先级排序
构建回归测试套件
调查意外行为
变化的是对预期结果的定义。
对于某些 AI 场景,预期结果并不是:
响应 = X
它更接近:
响应必须满足 X、Y 和 Z,同时避免 A 和 B。
一次我理解了这一区别,对话式 AI 测试对我的意义就变得更加清晰。
我最初学习对话式 AI 时的直觉是去寻找测试用例。
现在我认为这是错误的起点。应该从用户出发。
他们试图完成什么?
他们可能有哪些不同的提问方式?
AI 需要哪些信息?
有用的答案应包含什么?
系统永不应该说什么?
如果 AI 不知道会怎样?
当对话方向改变时会发生什么?
哪些证据能让你有足够信心将该体验发布给真实用户?
这些问题最终会成为你的测试用例。
对话式 AI 可能比许多 QA 工程师习惯测试的应用程序的确定性要低。但这并不意味着它不可测试。这仅仅意味着我们需要超越以下问题的提问:
"我是否得到了我所期望的确切输出?"
而开始提出:
"系统在真实用户可能的各种交互方式下,是否表现得正确、安全且有用?"
对我而言,这是最大的转变。工具在变化,界面也在变化。即使预期结果的定义也在变化。但质量工程的基本责任几乎没有改变:在用户自己发现之前,了解系统可能出现的故障方式。
——
一个热爱技术的程序员,喜欢分享前沿AI知识和开发经验。