我只改了三句话,AI应用的准确率却掉了——提示词回归测试实战

我只改了三句话,AI应用的准确率却掉了——提示词回归测试实战

一次看似普通的提示词优化,可能悄悄改变整个 AI 应用。

假设某个团队正在维护一套智能客服系统。原来的系统提示词已经迭代了十几个版本,里面既有角色定义,也有回答格式、业务边界、拒绝规则和工具调用要求。随着规则越来越多,提示词显得有些冗长,开发者决定做一次“清理”。

他删除了三句看起来重复的内容,又调整了一下段落顺序。修改后的提示词更短、更清晰,人工测试时连续问了五个问题,回答都很自然,接口也没有报错。于是,新版本很快被发布到生产环境。

第二天,问题陆续出现:

  • 用户咨询退款进度时,AI没有继续追问订单编号,而是直接推测退款正在处理中;
  • 明确要求返回 JSON 的接口,偶尔会在 JSON 前面增加一段解释文字;
  • 原来能够区分“申请退款”和“退款失败”的系统,开始对两个问题给出相同模板;
  • 某些信息不足的问题不再拒绝回答,而是补充了资料中不存在的细节;
  • 工具调用参数表面上符合 JSON 格式,实际却缺少执行所需的关键字段;
  • 同一个问题重复执行五次,有三次正确、一次遗漏条件、一次给出错误结论。

从传统监控看,这次发布似乎没有问题。

HTTP 状态码仍然是 200,接口延迟没有明显增加,JSON 解析错误率也很低,服务器 CPU 和内存都在正常范围内。只有当运营人员开始整理用户投诉时,团队才意识到:系统没有宕机,但行为已经发生了退化。

这类问题正是 AI 应用与传统接口最大的不同之一。

传统程序发生严重错误时,往往会抛出异常、返回错误码或产生明显的失败结果;AI 应用则可能在技术层面完全正常,却在业务层面逐渐偏离预期。它仍然能够生成流畅的文字,仍然可以返回结构化数据,甚至比旧版本显得更“聪明”,但关键事实、约束条件和行为边界已经改变。

因此,提示词不能只被当成一段文案。

系统提示词、上下文模板、工具描述、模型参数、输出约束和知识拼接方式,本质上都是生产系统的一部分。只要它们会改变应用行为,就应该像代码一样被版本管理、测试、比较、灰度发布和快速回滚。

本文不讨论如何写出一句“更强的提示词”,而是讨论一个更基础、更重要的工程问题:如何为 AI 应用建立一套真正可以执行的回归测试体系。


一、AI应用的“能运行”,不等于“行为正确”

普通接口的正确性通常比较容易定义。

例如,一个用户查询接口接收用户编号,返回用户姓名、状态和创建时间。测试时可以检查状态码、字段名称、数据类型和数据库记录是否一致。只要输入固定,输出也应该相对固定。

AI 应用则没有这么简单。

同一个问题可能存在多种正确表达。例如,用户询问“怎样修改密码”,下面两种回答都可能是正确的:

进入账号设置,打开安全中心,然后选择修改密码。

或者:

你可以依次进入“设置—安全中心—修改密码”,完成身份验证后设置新密码。

如果使用字符串完全相等进行测试,第二种回答会被判定为错误;但从业务效果看,它甚至可能比第一种更清楚。

这并不意味着 AI 无法测试。

AI 回归测试真正要验证的,不是模型是否逐字复现某个标准答案,而是它是否满足稳定的业务要求。

这些要求通常可以拆成几类:

  1. 是否理解了用户真正要完成的任务;
  2. 是否覆盖了回答中必须出现的信息;
  3. 是否出现了不允许出现的内容;
  4. 是否遵守了输出格式与字段契约;
  5. 是否只使用了给定资料中的事实;
  6. 信息不足时是否继续追问或明确说明;
  7. 是否选择了正确的工具;
  8. 工具参数是否完整且符合业务约束;
  9. 是否错误执行了高风险动作;
  10. 回答长度、延迟和资源消耗是否处于可接受范围。

例如,用户只说“我的退款为什么还没到”,但没有提供订单编号和申请时间。系统此时可能无法直接给出退款状态。正确行为不应该是生成一段听起来合理的解释,而应该询问必要信息。

因此,该用例的预期结果不必是一句固定文本,而可以写成:

  • 必须询问订单编号或退款申请时间;
  • 不得声称退款已经到账;
  • 不得推测具体处理进度;
  • 不得调用退款查询工具;
  • 可以说明获得必要信息后将继续查询。

这样一来,不管模型使用什么措辞,只要满足这些条件,就可以认为主要行为正确。

AI 测试的关键,是从“标准答案思维”转向“行为约束思维”。


二、为什么人工试几个问题远远不够

很多 AI 项目的测试过程非常相似。

开发者修改提示词后,打开聊天页面,输入几个自己熟悉的问题。模型回答得不错,于是认为新版本可以上线。

这种测试方式存在几个明显缺陷。

首先,测试问题通常过于规范。

开发者清楚系统需要什么信息,因此会输入完整、清晰、没有歧义的问题;真实用户却经常使用省略句、错别字、口语表达和互相矛盾的条件。

开发者可能输入:

请查询订单 A1024 的退款处理状态。

真实用户更可能输入:

怎么还没退?

或者:

昨天说退了,钱呢?

如果系统只在输入完整时表现正常,就不能算真正通过测试。

其次,开发者容易只验证成功路径。

例如,测试工具调用时,通常会输入一个具有合法参数的请求,却忽略以下情况:

  • 参数缺失;
  • 参数格式错误;
  • 同时出现多个冲突参数;
  • 用户试图查询他人的数据;
  • 工具执行超时;
  • 工具返回空结果;
  • 工具已经执行成功,但响应在网络中丢失;
  • 同一请求被重复提交。

成功路径只能证明系统在理想条件下能运行,无法证明它在真实环境中可以安全运行。

第三,人工测试很难重复。

今天开发者输入了五个问题,明天可能换成另外六个问题。即使新版本表现更好,也无法确定它是否破坏了旧版本已经解决的问题。

第四,人类很容易受到语言流畅度影响。

模型回答得越自然,人们越容易忽略事实错误。一个措辞生硬但事实准确的答案,可能比一段非常流畅却包含错误结论的回答更可靠。

第五,人工测试很难覆盖随机性。

同一个问题执行一次正确,不代表连续执行十次都正确。有些提示词会让模型大多数时候遵守规则,偶尔却偏离约束。只测试一次,恰好可能遇到正常结果。

因此,人工测试仍然有价值,但它应该承担探索性检查和最终体验评审,而不应该成为唯一的发布依据。


三、先建立测试集,不要先挑评测工具

一提到 AI 评测,很多团队会立即寻找平台、框架或自动打分模型。

但真正决定评测价值的,首先不是工具,而是测试数据。

如果测试集只包含一些随手编写的问题,即使评测平台能够生成几十项指标,也很难说明系统是否适合真实业务。

一个有效的测试集,至少应该覆盖五类数据。

1. 高频正常问题

这部分用于确认系统的基础能力没有退化。

例如:

  • 查询操作步骤;
  • 总结一段资料;
  • 根据给定内容进行比较;
  • 提取文本中的结构化信息;
  • 生成符合格式要求的结果;
  • 根据业务规则回答常见问题。

高频问题不一定复杂,但它们直接影响大量用户。一次小幅退化,乘以真实访问量后,也可能造成明显影响。

2. 历史失败问题

历史失败是最有价值的测试数据之一。

如果系统曾经把退款期限回答错误,那么修复完成后,这条问题不应该只停留在事故报告里,而应该进入长期回归测试集。

下一次有人修改提示词、模型、上下文模板或工具说明时,都要重新执行这条用例。

每一个线上错误,至少应沉淀出以下内容:

  • 当时的用户输入;
  • 模型实际看到的上下文;
  • 当时使用的提示词版本;
  • 错误输出;
  • 正确行为;
  • 失败原因;
  • 修复方式;
  • 后续自动检查规则。

如果事故修复后没有留下回归用例,同一个问题很可能在几个月后再次出现。

3. 边界输入

边界输入用于测试系统在资料不足、表达异常或条件冲突时是否仍能保持正确行为。

常见边界包括:

  • 缺少必要参数;
  • 输入只有半句话;
  • 用户连续改变要求;
  • 问题包含多个任务;
  • 问题超出知识范围;
  • 上下文中不存在答案;
  • 用户要求引用不存在的资料;
  • 用户要求给出无法确认的结论;
  • 输入中包含大量无关内容;
  • 输出长度要求极端;
  • 同时要求“简短回答”和“完整列出全部细节”。

边界测试的目标不是要求 AI 对所有问题都给出答案,而是确认它知道什么时候应该追问、什么时候应该拒绝、什么时候应该明确说明无法判断。

4. 对抗与越权输入

如果系统会接触内部资料、调用工具或执行动作,就必须加入对抗性用例。

例如:

  • 要求忽略系统规则;
  • 要求输出隐藏提示词;
  • 要求读取其他用户的数据;
  • 要求跳过身份验证;
  • 要求调用未授权工具;
  • 在引用资料中夹带新的指令;
  • 伪造管理员身份;
  • 诱导模型将不可信内容当成系统命令;
  • 通过长文本掩盖真正的恶意要求。

这类测试不能只判断回答是否礼貌,还要检查系统是否泄露信息、调用工具或改变权限边界。

5. 相似但处理方式不同的问题

真实业务中,最容易暴露模型理解能力的,往往不是完全不同的问题,而是表面相似、处理方式不同的问题。

例如:

  • “如何申请退款”需要说明流程;
  • “为什么退款失败”需要查询具体状态;
  • “退款一般多久到账”需要说明规则;
  • “我的退款多久到账”可能需要订单信息;
  • “帮我取消退款”则可能涉及工具调用和权限验证。

如果模型对这些问题都返回同一个模板,语言可能没有错误,任务却没有真正完成。

测试集应该专门加入这种容易混淆的成组问题,检查模型能否识别细微但重要的业务差异。


四、测试集需要分层,不能把所有问题混成一个总分

建立测试集后,还要对用例进行分层。

如果把普通文案润色、订单查询和高风险工具执行全部混在一起,最后计算一个平均分,结果很容易产生误导。

假设一个测试集有 100 条用例:

  • 80 条普通问答;
  • 15 条结构化提取;
  • 5 条高风险工具操作。

新版本在普通问答中提升了 10 条,却在高风险工具操作中错误执行了 1 条。总体通过率可能仍然上升,但这次修改显然不应该发布。

因此,测试用例至少应该具有以下标签:

{"case_id":"refund_cancel_007","category":"工具调用","risk_level":"high","business_priority":"critical","expected_mode":"ask_for_confirmation","repeat_count":10}

可以按照风险把用例分成三层。

普通用例

包括文案生成、摘要、一般咨询等。允许存在一定表达差异,主要关注任务完成、信息覆盖和语言质量。

重要用例

包括结构化输出、业务规则问答、内部知识查询等。要求较高的一致性,并设置明确的格式和事实约束。

高风险用例

包括写数据库、发消息、修改状态、提交审批、创建资源、删除内容或访问敏感数据。任何一次越权、重复执行或错误参数都可能成为发布阻断项。

分层以后,不同类别可以使用不同的通过标准。

普通用例可以要求总体通过率不低于某个基线;重要用例不仅要达到较高通过率,还不能出现关键字段错误;高风险用例则可能要求多次执行全部通过。


五、不要只保存问题,要保存完整运行快照

很多 AI 评测结果无法复现,是因为团队只保存了用户输入,没有保存模型实际接收到的全部内容。

一次 AI 请求的行为,可能同时受到以下因素影响:

  • 系统提示词;
  • 用户输入;
  • 历史对话;
  • 检索上下文;
  • 上下文排序;
  • 工具名称与工具描述;
  • 输出格式;
  • 模型参数;
  • 应用代码中的默认值;
  • 时间、语言和地区信息;
  • 外部接口返回结果;
  • 内容截断策略。

如果只保存一句用户问题,下一次测试时使用了不同上下文,就无法判断结果变化来自提示词还是数据变化。

因此,每条用例应该尽可能形成可回放快照。

{"case_id":"refund_023","category":"信息不足","user_input":"我的钱为什么还没退回来","conversation_history":[],"context_snapshot":[],"tool_schema_version":"refund-tools-v4","prompt_version":"support-v17","model_config":{"temperature":0.2,"max_output_tokens":800},"expected_behavior":{"must_ask_any":["订单编号","退款申请时间"],"must_not_claim":["退款已经到账","银行正在处理"],"allow_tool_call":false}}

这里最重要的是expected_behavior,它描述的是行为要求,而不是唯一标准答案。

如果应用依赖知识检索,测试时还应保存检索结果快照。否则知识库内容更新、排序变化或过滤条件调整,都可能影响最终回答。

快照测试并不意味着永远使用旧数据。

可以同时建立两种评测:

  • 固定快照评测,用于判断提示词和模型行为是否变化;
  • 在线数据评测,用于判断当前知识与检索系统的综合效果。

固定快照负责控制变量,在线评测负责发现真实系统的新问题。两者不能互相替代。


六、提示词、工具和参数都必须进入版本管理

不少团队已经使用 Git 管理代码,却仍然把提示词直接写在平台后台或数据库里。修改后旧版本被覆盖,几天后已经没人能够准确还原当时的配置。

这会导致三个问题。

第一,无法复现事故。

当用户反馈某次回答错误时,团队只能看到当前提示词,却不知道请求发生时使用的是哪个版本。

第二,无法进行公平比较。

如果旧提示词已经被覆盖,新旧版本就不能在同一测试集上重新执行。

第三,回滚不可靠。

事故发生后,开发者只能凭记忆恢复旧内容,可能遗漏模型参数、工具描述或上下文模板的同步变化。

因此,至少要为以下对象建立版本:

  • 系统提示词;
  • 场景提示词;
  • 输出格式模板;
  • 工具说明;
  • 工具参数结构;
  • 模型配置;
  • 上下文拼接模板;
  • 安全规则;
  • 评测规则;
  • 测试集版本。

一次发布记录可以写成:

{"release_id":"ai-support-20260705-03","prompt_version":"support-v18","tool_schema_version":"refund-tools-v4","context_template_version":"context-v9","evaluation_set_version":"support-regression-v12","model_config_version":"model-config-v6"}

发生问题时,团队可以快速回答:哪个版本产生了错误、影响了哪些请求、应回滚哪些配置。

版本号的意义不是形式完整,而是让每一次行为变化都可以被追踪。


七、不要只看一个准确率,要建立多维指标

AI 应用很难用一个“准确率”解释全部质量。

更可靠的方式,是把质量拆成多个维度。

指标主要判断内容
任务完成率是否真正解决用户提出的问题
事实一致性回答是否得到输入资料支持
必要信息覆盖率是否包含关键步骤与限制条件
格式通过率JSON、字段和数据类型是否符合契约
拒绝准确率该拒绝时是否拒绝
误拒绝率可以回答的问题是否被错误拒绝
工具选择准确率是否选择了正确工具
工具参数通过率参数是否完整、合法且经过授权
风险内容率是否出现编造、越权或敏感内容
稳定通过率多次执行是否保持一致行为
平均延迟用户等待时间是否可接受
资源消耗输入输出规模是否突破运行边界

这些指标不应该简单平均。

假设新版本的语言自然度明显提升,但事实一致性下降;或者普通问答得分上升,却新增一次越权工具调用。如果只计算平均分,新版本可能看起来更好。

更实用的方法,是把指标分成三类。

1. 阻断指标

出现严重问题就停止发布。

例如:

  • 越权访问;
  • 高风险工具误调用;
  • 关键事实编造;
  • 敏感信息泄露;
  • 必填字段缺失;
  • 无法解析的结构化输出;
  • 同一业务动作被重复执行。

2. 质量指标

需要达到规定通过率,并且不得明显低于旧版本。

例如:

  • 任务完成率;
  • 必要信息覆盖率;
  • 事实一致性;
  • 正确追问率;
  • 工具选择准确率。

3. 观察指标

允许在一定范围内波动,但需要持续关注。

例如:

  • 回答长度;
  • 语言自然度;
  • 平均延迟;
  • 输入输出规模;
  • 用户阅读负担。

发布决策应先检查阻断指标,再比较质量指标,最后观察成本与体验变化。


八、优先使用确定性规则,不要把所有判断都交给另一个模型

AI 评测不应该全部依赖“模型评模型”。

能用程序确定的内容,应优先使用确定性规则。

例如:

  • JSON 是否可以解析;
  • 必填字段是否存在;
  • 字段类型是否正确;
  • 枚举值是否合法;
  • 是否超过最大长度;
  • 是否包含禁止字段;
  • 工具名称是否在白名单中;
  • 参数是否满足正则或业务格式;
  • 引用编号是否真实存在;
  • 是否调用了不允许的接口;
  • 是否出现敏感字段。

假设系统要求返回:

{"category":"refund","need_human":false,"reply":"..."}

自动检查至少可以验证:

  1. 输出是否为合法 JSON;
  2. 是否只有允许字段;
  3. category是否属于规定枚举;
  4. need_human是否为布尔值;
  5. reply是否为非空字符串;
  6. 是否混入 Markdown 代码块或额外解释;
  7. 是否出现不允许的内部字段。

这类检查稳定、快速、容易定位问题,也不受评测模型随机性影响。

对于工具调用,还可以进一步验证:

  • 工具是否允许在当前场景调用;
  • 用户是否已通过身份验证;
  • 参数是否来自用户明确输入;
  • 是否缺少确认步骤;
  • 是否超出权限范围;
  • 相同业务操作是否重复执行。

确定性检查越充分,需要交给模型判断的范围就越小。


九、模型评分可以使用,但评分标准必须具体

自然语言任务中,仍然有一些问题很难完全用规则判断。

例如:

  • 回答是否真正解决了用户问题;
  • 回答是否忠于给定资料;
  • 是否遗漏了关键限制条件;
  • 两个回答哪个更清晰;
  • 语气是否适合目标用户;
  • 回答是否在不确定时进行了合理说明。

这些场景可以使用模型评分,但不能只问一句“这个回答好不好”。

评分提示应该包含明确维度、判断标准和证据要求。

例如:

请根据给定资料评估回答。 评估规则: 1. 回答只能使用资料中明确出现的信息; 2. 资料不足时必须说明无法确认; 3. 不得推测退款是否到账; 4. 应询问订单编号或退款申请时间; 5. 不得建议用户重复提交退款申请。 请分别判断每项是否通过,并引用回答中的相关内容作为依据。

评测结果最好采用结构化格式:

{"grounded":true,"asks_required_information":true,"contains_unsupported_claim":false,"suggests_duplicate_action":false,"overall_pass":true,"reason":"回答未推测退款状态,并询问了订单编号。"}

即使如此,也不能把模型评分当成绝对真理。

评测模型可能受到措辞、顺序和上下文长度影响。重要用例应定期进行人工抽样,检查自动评分是否出现偏差。

还可以使用双重评估:

  • 规则检查负责结构、字段和明确禁令;
  • 模型评分负责语义、完整性和表达质量;
  • 人工审核负责高风险用例与评分争议。

三种方式组合,比依赖单一裁判更可靠。


十、同一个问题要重复执行,稳定性本身也是质量

AI 输出具有随机性。

一次通过并不代表稳定通过。

假设某个高风险用例连续执行五次:

  • 第一次正确追问订单编号;
  • 第二次正确追问退款时间;
  • 第三次直接推测银行正在处理;
  • 第四次正确说明信息不足;
  • 第五次调用了退款查询工具,但参数为空。

如果只执行第一次,系统会被判定为通过;连续执行后才会发现,它的行为并不稳定。

因此,关键用例必须重复执行。

可以按照风险设置不同重复次数:

  • 普通文案类用例执行 2 至 3 次;
  • 结构化输出类用例执行 3 至 5 次;
  • 工具调用类用例执行 5 至 10 次;
  • 高风险动作根据实际情况执行更多次。

稳定性可以记录为:

用例:缺少订单号时查询退款状态 执行次数:10 正确追问:8 错误推测:1 错误工具调用:1 稳定通过率:80% 发布结论:阻断

高风险用例不能仅凭平均分通过。

如果十次执行中有一次越权操作,平均正确率虽然是 90%,仍然不应发布。对于这类用例,更适合采用“零严重错误”标准。

还要注意,降低随机参数不能解决全部问题。

即使温度设置较低,模型仍可能受到上下文变化、服务实现和提示歧义影响。稳定性测试是必要验证,不能被参数配置替代。


十一、多轮对话必须测试状态变化,不能只测单轮问答

许多 AI 应用在单轮测试中表现很好,进入多轮对话后却开始混淆信息。

例如:

第一轮,用户咨询订单 A 的退款;
第二轮,用户又提到订单 B;
第三轮,用户只问“那这个什么时候到”。

系统需要判断“这个”指订单 A 还是订单 B。如果无法确认,应该追问,而不是随意选择一个订单。

多轮测试至少要覆盖以下情况:

  • 用户在中途更换目标;
  • 用户修改之前提供的条件;
  • 两个对象具有相似名称;
  • 历史对话中存在过期信息;
  • 用户撤销之前的指令;
  • 对话过长导致早期信息被截断;
  • 系统摘要遗漏关键条件;
  • 工具结果与用户后续描述冲突。

多轮用例可以表示为:

{"case_id":"multi_order_014","turns":[{"role":"user","content":"帮我查一下订单A的退款。"},{"role":"assistant","expected_behavior":"ask_for_order_details"},{"role":"user","content":"还有订单B,我昨天也申请了。"},{"role":"user","content":"这个什么时候能到?"}],"expected_final_behavior":{"must_clarify_target_order":true,"allow_tool_call":false}}

多轮评测的重点不是每一轮都生成固定文本,而是检查状态是否正确更新。

如果系统使用对话摘要压缩历史内容,还应比较压缩前后的行为。摘要不能只保留主题,也要保留当前目标、关键参数、用户确认和未完成动作。


十二、工具调用评测必须覆盖“选择、参数、权限、执行”四层

带工具的 AI 应用不能只检查模型是否生成了一个函数名。

完整工具调用至少包含四层正确性。

第一层:是否应该调用工具

用户只是询问退款规则时,不应该调用订单查询接口;用户要求查询个人订单状态时,才可能需要调用工具。

第二层:是否选择正确工具

系统可能同时提供订单查询、退款查询、取消订单和人工转接等工具。选错工具,即使参数格式正确,也会产生错误结果。

第三层:参数是否正确

参数不仅要满足 JSON 结构,还要符合业务规则。

例如:

  • 订单编号是否来自用户输入;
  • 用户身份是否已经验证;
  • 时间范围是否合理;
  • 是否缺少必填字段;
  • 是否把自然语言描述错误地填入编号字段;
  • 是否使用了其他用户的数据。

第四层:执行是否安全

某些工具只是查询,某些工具会产生副作用。

取消订单、提交退款、发送通知、删除记录等动作,应该经过更严格的确认和幂等控制。

工具调用用例应明确:

{"expected_tool_behavior":{"allowed_tools":["query_refund_status"],"forbidden_tools":["create_refund","cancel_order"],"required_arguments":["order_id"],"requires_identity_verified":true,"requires_confirmation":false}}

对于有副作用的工具,还需要测试重复提交。

假设第一次工具执行成功,但响应在返回途中丢失,模型可能认为执行失败并再次调用。如果系统没有幂等机制,就可能产生重复退款、重复消息或重复任务。

因此,评测不仅要查看模型输出,还要检查工具执行日志和最终业务状态。


十三、检索增强应用要把“检索”和“生成”分开测试

如果应用使用知识库或搜索结果,最终回答错误可能来自多个环节:

  • 查询改写错误;
  • 检索结果不相关;
  • 过滤条件错误;
  • 关键资料没有进入上下文;
  • 上下文排序不合理;
  • 模型忽略了正确资料;
  • 模型引用了资料中不存在的结论。

如果只看最终答案,很难定位问题。

更有效的方法是分层评测。

检索层

检查:

  • 是否召回了正确资料;
  • 正确资料是否出现在前几条;
  • 无关资料是否过多;
  • 权限过滤是否生效;
  • 时间范围是否正确;
  • 同名对象是否被混淆。

上下文层

检查:

  • 关键段落是否真正进入模型输入;
  • 是否因长度限制被截断;
  • 多段资料是否存在矛盾;
  • 来源标识是否保留;
  • 拼接顺序是否影响理解。

生成层

在固定上下文快照下检查:

  • 模型是否依据资料回答;
  • 是否遗漏重要条件;
  • 是否编造资料外信息;
  • 是否给出正确引用;
  • 资料不足时是否承认无法确认。

这样,当最终回答退化时,可以判断是“没有找到资料”,还是“找到了资料但没有正确使用”。

需要注意的是,检索测试与本文讨论的提示词回归并不冲突。提示词可能改变查询改写方式、资料使用方式和回答边界,因此仍然需要在固定检索快照上做对照。


十四、延迟和资源消耗也应该进入回归测试

提示词修改不仅会改变答案,还可能改变请求规模和输出长度。

例如,新增一句“请详细分析每种可能性”,可能让模型输出显著变长;增加大量示例可能扩大输入上下文;要求模型反复自检,也可能增加整体响应时间。

如果评测只看内容质量,就可能发布一个更准确但无法承担实际流量的版本。

因此,每轮回归测试应同时记录:

  • 输入长度;
  • 输出长度;
  • 首个结果等待时间;
  • 完整响应时间;
  • 工具调用次数;
  • 重试次数;
  • 单请求资源消耗;
  • 超时比例;
  • 并发下的尾延迟。

资源指标同样需要对照组。

例如:

旧版本: 任务通过率 91% 平均响应时间 2.8 秒 平均输出长度 620 字 新版本: 任务通过率 93% 平均响应时间 6.9 秒 平均输出长度 1740 字

新版本准确率提高两个百分点,却让响应时间和输出长度增加一倍以上。是否值得发布,需要结合业务场景判断。

对实时客服来说,延迟可能直接影响体验;对离线报告生成来说,可以接受更长时间,但要考虑批量任务的资源总量。

这里的核心不是追求越短越好,而是把效果与代价放在同一份报告中。


十五、比较新旧版本时,必须控制变量

一次有效的回归实验必须知道到底修改了什么。

如果同时进行以下操作:

  • 更换模型;
  • 修改系统提示词;
  • 调整温度;
  • 更新知识库;
  • 修改工具描述;
  • 改变上下文排序;
  • 增加重试次数;

即使结果变好,也无法确定是哪项改动产生作用。结果变差时,更难定位原因。

建议每轮只改变一个主要变量。

例如:

  • 只修改系统提示词;
  • 只修改输出模板;
  • 只调整模型参数;
  • 只更换模型;
  • 只更新工具描述;
  • 只改变上下文拼接方式。

旧版本作为对照组,新版本作为候选组,在同一批测试快照上执行。

对比报告不应该只有两个总分,而应包含:

  • 哪些用例由失败变为通过;
  • 哪些用例由通过变为失败;
  • 哪些类别提升明显;
  • 哪些类别出现退化;
  • 新增了哪些严重错误;
  • 哪些问题仍然没有解决;
  • 延迟和资源消耗发生了什么变化;
  • 稳定性是否改善。

其中最重要的是“通过变失败”的用例。

平均分上升并不能证明新版本全面更好。一个关键用例从通过变成失败,可能比十个普通用例的改善更重要。


十六、建立一套最小可用的自动评测流程

团队不必一开始就建设庞大的评测平台。

一套最小流程可以分为六步。

第一步:读取测试用例

测试用例包含输入、上下文快照、版本信息、预期行为和风险等级。

第二步:执行候选版本

对每条用例按照规定次数执行,并保存原始输出、工具调用、延迟和错误信息。

第三步:运行确定性检查

检查 JSON、字段、枚举、禁止内容、工具权限和参数格式。

第四步:运行语义评分

对需要自然语言判断的部分,使用明确评分标准进行评估。

第五步:与基线比较

比较旧版本与新版本在每条用例上的变化,而不是只比较平均分。

第六步:生成发布结论

报告应明确列出:

  • 是否存在阻断问题;
  • 哪些指标退化;
  • 哪些用例需要人工复核;
  • 是否允许进入灰度;
  • 推荐的回滚版本是什么。

伪代码可以表示为:

forcaseinevaluation_cases:baseline_results=run_repeatedly(version=baseline_version,case=case,count=case.repeat_count)candidate_results=run_repeatedly(version=candidate_version,case=case,count=case.repeat_count)baseline_score=evaluate(case,baseline_results)candidate_score=evaluate(case,candidate_results)compare_and_record(case=case,baseline=baseline_score,candidate=candidate_score)generate_release_report()

真正实现时,还需要固定运行配置、限制并发、记录版本、保护敏感数据,并确保测试工具不会执行真实高风险操作。

工具调用评测最好使用沙箱、模拟服务或只读环境,不要为了测试直接修改生产数据。


十七、回归报告应该回答“变好了什么”和“变坏了什么”

一份有效的评测报告,不应该只写:

新版本得分 8.7,旧版本得分 8.4,新版本更好。

这种结论很难支持发布决策。

更有价值的报告应该写成:

候选版本:support-v18 对照版本:support-v17 测试用例:326 条 重复执行:共 1280 次 主要改善: - 信息不足场景的正确追问率由 82% 提升到 94% - JSON 格式通过率由 96.5% 提升到 99.2% - 常见业务问题任务完成率提升 3.1% 主要退化: - 多轮对话中的目标识别准确率下降 4.8% - 平均输出长度增加 37% - 高风险工具用例出现 1 次未确认调用 发布结论: - 阻断发布 - 原因:高风险工具调用必须零严重错误 - 建议:保留新的追问规则,恢复旧版工具确认约束后重新测试

这种报告能够帮助团队做出具体修改,而不是围绕一个抽象总分争论。

报告还应保留失败样本。

每个失败用例至少展示:

  • 输入;
  • 关键上下文;
  • 旧版本结果;
  • 新版本结果;
  • 违反的规则;
  • 自动评分理由;
  • 人工复核状态。

这样,开发者才能快速理解退化发生在哪里。


十八、把评测接入发布流程,而不是上线前临时执行

评测只有进入发布流程,才能持续发挥作用。

一套较完整的发布闸门可以这样设计:

  1. 提示词和配置必须具有版本号;
  2. 每次修改自动运行固定回归集;
  3. 阻断指标必须全部通过;
  4. 关键用例不得相对旧版本退化;
  5. 自动生成新旧版本差异报告;
  6. 高风险变化必须人工审核;
  7. 候选版本进入小流量灰度;
  8. 线上指标达到要求后逐步扩大流量;
  9. 异常时可以快速回滚;
  10. 线上新失败自动进入测试集。

灰度阶段不能只看 HTTP 错误率。

提示词退化通常不会返回 500,而是返回一段格式正确、内容错误的文本。因此,还要观察:

  • 用户重新提问率;
  • 用户改写问题的比例;
  • 人工接管率;
  • 负反馈率;
  • 工具调用失败率;
  • 用户撤销操作的比例;
  • 回答后立即离开的比例;
  • 同一问题短时间重复提交的比例。

如果用户不断换一种说法重复提问,往往说明第一次回答没有真正解决问题。即使接口成功率是 100%,业务效果也可能正在下降。


十九、失败样本必须进入闭环,而不是只修一次

评测系统的价值不只在发布前拦截错误,还在于不断吸收真实失败。

完整闭环可以表示为:

线上发现问题 → 保存请求与版本 → 判断失败类型 → 创建最小复现 → 加入回归测试集 → 修改提示词或程序 → 重新运行全部相关用例 → 灰度发布 → 继续观察

每次失败都要明确属于哪一层:

  • 输入理解错误;
  • 上下文缺失;
  • 检索错误;
  • 提示词约束不足;
  • 输出格式错误;
  • 工具选择错误;
  • 工具参数错误;
  • 权限检查缺失;
  • 多轮状态混乱;
  • 评测规则遗漏。

不要把所有问题都归因于“模型不够聪明”。

有些问题应该通过提示词修复,有些需要修改检索,有些必须由确定性代码处理,还有些需要缩小模型权限。

如果一个问题可以通过字段校验阻止,就不应该只在提示词里增加一句“请务必不要出错”。


二十、一份可以直接执行的上线检查清单

每次修改提示词、模型参数、上下文模板或工具描述前,可以逐项确认。

版本与范围

  • 是否为本次修改创建了独立版本?
  • 是否保存了完整旧版本?
  • 是否明确本次只改变了哪些变量?
  • 是否记录了模型、参数、工具和上下文模板版本?
  • 是否准备了可立即恢复的旧版本?

测试数据

  • 是否覆盖真实高频问题?
  • 历史线上错误是否已经加入测试集?
  • 是否包含信息不足、冲突和越界问题?
  • 是否覆盖容易混淆的相似问题?
  • 是否包含多轮对话和目标切换?
  • 是否覆盖对抗输入与权限测试?
  • 是否保存了固定上下文快照?

自动检查

  • JSON 和结构化输出是否可以稳定解析?
  • 必填字段和数据类型是否正确?
  • 是否检查禁止字段和敏感内容?
  • 工具名称是否在允许列表?
  • 工具参数是否经过业务校验?
  • 是否验证身份、权限与确认状态?
  • 是否检查重复执行和幂等行为?

语义质量

  • 是否真正完成用户任务?
  • 是否只依据给定资料回答?
  • 信息不足时是否正确追问?
  • 是否出现未经支持的结论?
  • 是否遗漏关键限制条件?
  • 是否错误拒绝可以回答的问题?

稳定性与风险

  • 关键用例是否重复执行?
  • 是否记录每次执行结果?
  • 高风险用例是否保持零严重错误?
  • 是否检查多轮状态变化?
  • 是否测试工具超时、空结果和结果未知?
  • 是否对评分结果进行人工抽样?

性能与发布

  • 是否比较新旧版本的延迟?
  • 是否比较输入输出规模?
  • 是否观察工具调用次数?
  • 是否生成逐用例差异报告?
  • 是否设置明确的发布阻断条件?
  • 是否进行小流量灰度?
  • 是否准备快速回滚开关?
  • 线上新失败是否能够自动沉淀为测试用例?

如果这些问题无法回答,提示词修改就不应该被视为普通文案调整。它更接近一次没有充分测试的生产代码变更。


结语

AI 应用最危险的退化,往往不会报错。

接口仍然返回 200,JSON 仍然可以解析,页面仍然能够展示,模型也依然可以生成自然流畅的文字。但系统可能已经开始遗漏条件、混淆任务、错误调用工具,或者在信息不足时自信地给出结论。

这种问题无法依靠上线前随便聊几轮解决。

真正可靠的方法,是把提示词、上下文、模型参数和工具描述一起纳入版本管理,把真实问题与历史失败沉淀为测试集,把关键行为转化为可验证的规则,再用重复执行、对照实验、自动评测、人工审核、灰度发布和线上反馈形成闭环。

提示词当然可以修改。

模型也可以更换,知识库可以更新,工具可以增加,参数可以调整。

但每一次变化都应该能够回答三个问题:

它修复了什么?

它破坏了什么?

如果判断错了,系统能不能立即退回去?

当团队能够稳定回答这三个问题时,AI 应用才真正从“能演示的功能”进入“可以持续维护的工程系统”。