AI 生成界面的隐藏状态审查:测试演示里永远看不到的部分
一套面向创始人的隐藏状态审查方法,用于在 AI 构建应用上线前检查加载、空数据、错误、权限、重复操作与恢复行为。
AI 应用构建器可以在一个下午里生成一套看起来相当完整的仪表盘。演示账号里有数据,网络很快,账号拥有最高权限,而创始人也清楚每一个按钮该怎么点。于是,整个产品看上去已经做完了。
但真正的用户可能第一次进入时什么数据都没有;第一次点击 创建 后没看到反馈,于是又点了一次;AI 任务运行到一半时登录状态过期;他从另一个工作区打开了一条旧链接;模型虽然返回了格式正确的结果,却漏掉一个业务必填字段。到了这些时刻,界面仍然必须说真话。
许多 AI 生成产品正是在这里停止“像一个产品”。正常状态的截图已经存在,但从“操作前”到“成功”之间的那些状态,从来没有被当作产品承诺的一部分认真设计。
本文提供一套可在 75 分钟内执行的界面状态审查方法,适合创始人和小团队使用。它不能替代无障碍认证、安全审计或可靠性验证;它的目标是找出用户能直接感受到的矛盾:界面什么都不说、说错了、展示了用户不能安全执行的操作,或者让用户失去回到有效工作的路径。
你可以把它作为 Y Build AI 应用上线质量审查中的界面层检查。如果问题来自模型或工具依赖,可以继续阅读英文版的 AI 应用降级演练;如果某项操作能够发送消息、花钱、公开发布、删除数据或修改权限,则应先定义人工审批闸门,再去打磨页面细节。
一个页面不只有一种状态
以“生成客户报告”页面为例。设计稿可能只展示一个文本框、一个生成按钮,以及一份完成后的报告。真正运行的产品还需要处理更多状态:
- 新账号第一次进入,还没有任何报告。
- 已经有报告,但当前没有选中任何一份。
- 输入缺失、过长、不受支持,或引用的资源已经不存在。
- 请求已经被接受,但结果尚未返回。
- 任务耗时较长,用户离开页面后仍在继续。
- 模型返回了部分结果,但尚未通过业务校验。
- 操作失败,但原始输入还可以恢复。
- 页面已经超时,却无法确定服务端是否实际完成了操作。
- 用户可以查看报告,却不能重新生成、分享或删除。
- 报告已经在另一个标签页里被删除、归档或修改。
- 结果已经成功,但键盘用户或屏幕阅读器用户没有收到任何通知。
因此,审查对象不应该是一张静态截图,而应该是一整段状态转换:
起始状态 → 用户操作 → 等待状态 → 实际结果 → 安全的下一步
如果团队无法为重要流程说清这五个环节,界面很可能依赖了用户并不知道的内部假设。
测试前先建立状态矩阵
先选择一条真正产生价值的用户旅程,例如创建提案、邀请成员、生成分析、上传文档或修改订阅。第一次审查不要试图盘点整个应用。
为这条旅程建立一张表,每一种有实际意义的状态占一行:
| 状态 | 触发条件 | 用户看到什么 | 允许的操作 | 必须保留的数据 | 完成证据 |
|---|---|---|---|---|---|
| 空数据 | 新账号没有报告 | 解释这里为什么为空,并给出一个主要下一步 | 创建第一份报告 | 无 | 创建后真实报告出现 |
| 输入无效 | 缺少必要来源 | 指向具体字段的错误与修正方法 | 修改后重新提交 | 所有合法字段 | 服务端没有创建任务 |
| 正在提交 | 用户点击生成 | 立即确认已收到操作;重复点击不产生新请求 | 仅在确实支持时允许取消 | 草稿与逻辑请求 ID | 服务端确认只接受了一次请求 |
| 正在处理 | 工作超过即时响应时间 | 可持久保存的任务状态和返回入口 | 按真实能力允许离开、刷新或取消 | 草稿和任务状态 | 通过校验的结果进入终态 |
| 权限不足 | 只读用户尝试编辑 | 清楚说明边界,同时不泄露私有信息 | 请求权限或返回 | 已获授权的只读内容 | 没有发生写入 |
| 失败 | 依赖或校验失败 | 哪些已保存、哪些没有发生,以及下一步 | 安全时允许重试或修改 | 原始输入 | 失败被记录,不能标记为完成 |
| 完成 | 通过校验的结果已保存 | 确认信息和真实产物 | 检查、编辑或分享 | 结果以及产品所需的来源记录 | 稳定记录或外部系统 ID 存在 |
写完这张表,你往往会发现缺失的并不是一句文案,而是一项后端能力。例如,页面想写“你可以放心关闭窗口”,但任务实际上只存在浏览器内存里,那么这句话就是假的。又例如,错误提示承诺“没有发送任何内容”,但系统根本不知道外部服务是否已经执行完成,那么需要补的是结果对账,而不是把提示写得更温柔。
六道隐藏状态闸门
1. 空状态要教会用户下一步,而不是假装已经成功
一张只有表头的空表,只能证明组件成功渲染。好的空状态应该解释为什么这里没有内容、添加内容后能得到什么,以及最小的有效操作是什么。
至少要区分三种“空”:
- 新账号为空: 用户从未创建过任何内容。
- 筛选后为空: 内容真实存在,只是被当前搜索或筛选条件隐藏。
- 异常为空: 原本应该有内容,但因为权限、删除或加载失败而没有显示。
测试时还应移除演示数据。AI 生成的仪表盘有时会用虚构图表和示例记录填满首屏,让页面显得完整。示例数据要么明确标注,要么不要进入真实工作区。创始人必须能分辨哪些数值来自产品、哪些来自用户、哪些只是占位内容。
2. 等待状态必须确认已收到操作,并说明由谁继续负责
点击后如果没有快速的视觉反馈,用户很自然会再点一次。Chrome 团队关于 Interaction to Next Paint(INP)的说明强调了即时反馈的重要性:即使后台已经开始工作,缓慢的界面响应仍会让用户觉得页面失灵。
等待状态至少要回答:
- 系统收到这次操作了吗?
- 用户可以安全地再点一次吗?
- 现在可以离开页面吗?
- 工作是在浏览器里进行,还是已经交给服务端?
- 稍后到哪里找结果?
- “取消”是真的停止工作,还是只让页面不再等待?
也不要本能地禁用整个页面。HTML 的 disabled 属性会让控件失去焦点,并且不随表单提交;使用不当会导致字段值被遗漏,或者让键盘用户失去上下文。只禁用确实不能重复执行的操作,保持状态信息可访问,同时让服务端也真正执行防重复规则。
3. 输入错误必须具体,并且不能浪费用户已经完成的工作
W3C 的 WCAG 指南要求:当系统自动检测到输入错误时,应指出具体项目,并用文字描述错误。GOV.UK 设计系统进一步给出了一条实用的文案原则:说明发生了什么、如何修复,不要只写“发生错误”。
对选中的用户旅程,至少测试以下情况:
- 每个必填字段分别留空。
- 所有必填字段同时留空。
- 格式错误、长度超限、不支持的文件以及已过期资源。
- 通过浏览器校验、却违反业务规则的值。
- 前端先接受输入,服务端随后拒绝的情况。
还要注意,fetch() 在服务端返回 HTTP 错误状态时仍可能正常解析为一个响应对象,前端必须主动检查状态码。如果代码把所有成功返回的 Promise 都当作业务成功,页面甚至可能在 403、422 或 500 后显示绿色确认提示。
4. 权限必须同时匹配操作者、资源和工作区
隐藏一个“编辑”按钮并不等于完成授权控制,服务端仍必须拒绝未经授权的写入。但如果界面持续展示用户无法使用或不应使用的操作,也会制造错误预期,并掩盖权限测试缺口。
可以为关键流程建立一张小型授权矩阵:
| 操作者 | 自己的资源 | 同工作区资源 | 其他工作区资源 | 敏感操作 |
|---|---|---|---|---|
| 未登录用户 | 拒绝 | 拒绝 | 拒绝 | 拒绝 |
| 普通成员 | 按产品规则 | 按产品规则 | 拒绝 | 通常拒绝 |
| 管理员 | 按产品规则 | 按规则允许 | 拒绝 | 再次确认或加强认证 |
OWASP 建议用“操作者—资源—操作”来表达授权规则,并在产品变化时持续做回归测试。测试不能只看按钮是否隐藏,还要检查真实请求:更换对象 ID、打开复制来的深层链接、在另一个标签页切换工作区、撤销角色后重新执行操作。拒绝页面要给出足够的恢复信息,但不能反过来确认一条私有资源是否存在。
也不要把所有拒绝都包装成“升级套餐”。有些确实是套餐限制,但也可能来自所有权、角色、租户隔离、内部政策或登录过期。下一步必须和真正的拒绝原因一致。
5. 重复操作不能造成重复后果
要主动测试双击、着急时反复点击、提交中刷新、浏览器返回后再次提交、两个标签页同时操作,以及页面超时后服务端响应才到达的情况。
把按钮改成“处理中”能减少误点,却不能保证后端只产生一次结果。对于创建或更新类的重要操作,应使用稳定的幂等键或逻辑操作 ID。Stripe 的 API 文档展示了这种契约的核心:使用相同幂等键重试时,系统返回第一次操作的结果,而不是再创建一个对象。
下列操作尤其需要产品自己的幂等规则:
- 创建付费订单。
- 发送邀请或营销活动。
- 公开发布文档。
- 启动成本较高的生成任务。
- 应用 AI 建议的真实改动。
AbortController 可以终止浏览器侧的请求,但它无法证明服务端或下游工具已经撤销接受的工作。界面文案必须忠于系统的实际边界。
6. 完成状态必须可证明,也必须能恢复
一个两秒后消失的提示框,并不是很强的完成证据。最终状态应该对应一个持久结果:已保存记录、通过校验的产物、收据、版本号,或外部系统返回的稳定标识。
W3C 的状态消息标准要求,重要的动态消息应能被程序识别,从而让辅助技术在不移动焦点的情况下通知用户。成功、进度和错误状态都应该用键盘操作和至少一种屏幕阅读器测试,不能因为肉眼看见了文字就推断无障碍体验已经通过。
接着测试恢复路径:
- 成功后刷新页面。
- 从稳定 URL 重新打开结果。
- 退出账号后再次登录。
- 从失败状态重试。
- 在另一个标签页修改底层资源。
- 任务进行中登录过期,之后重新打开应用。
一次 75 分钟的创始人审查
第 0–10 分钟:定义产品承诺
补完这句话:“这条流程成功后,用户得到 ______,我们通过 ______ 证明它已经完成。”证明必须是持久结果,而不能只是“页面出现了成功提示”。
同时写下这条流程中后果最严重的操作,以及失败后必须保留的数据。
第 10–25 分钟:完成状态矩阵
加入空数据、输入无效、等待、权限拒绝、重复操作、失败和完成状态。对每一行分别写清:界面可以声称什么,服务端必须证明什么。任何当前架构无法支持的承诺都要明确标记。
第 25–50 分钟:主动制造这些状态
只使用测试账号和合成数据。降低网络速度、阻断一个 API 请求、返回有代表性的 4xx 和 5xx、移除角色、切换工作区、连续提交两次、刷新页面,并让登录状态过期。不要在客户数据或生产数据上进行破坏性测试。
每一道失败闸门都要保存截图或短视频,并记录观察到的请求和最终结果。只有截图,无法证明系统没有发生重复写入。
第 50–65 分钟:测试可访问性与恢复
仅使用键盘完成整条流程。检查焦点是否容易理解、错误是否与输入关联、状态变化是否被通知,以及禁用控件是否造成操作陷阱。刷新每一个终态,确认页面仍然如实反映结果。
第 65–75 分钟:设定发布闸门
将发现分为三类:
- 阻断上线: 数据丢失、跨工作区访问、虚假成功、重复产生重要后果、不可逆操作没有复核,或完全没有安全恢复路径。
- 公开推广前修复: 通用错误、含糊的等待状态、失效的空状态路径、缺少状态通知,以及移动端或键盘操作阻断。
- 指定负责人后进入待办: 不改变含义、不妨碍完成任务的纯视觉不一致。
把人工观察变成稳定检查
最不能回归的状态转换应该自动化。Playwright 的 web-first assertions 会等待异步条件达到预期状态,比点击后立刻读取页面更符合真实 Web 应用的行为。断言应检查产品含义,而不是脆弱的实现细节:
- 提交后出现明确状态。
- 主要操作不会产生第二个逻辑请求。
- 服务端拒绝后,合法输入仍然保留。
- 另一个工作区的成员看不到受保护数据。
- 完成结果在刷新后仍然存在。
- 键盘焦点按设计到达错误汇总或相关字段。
先为每一种“阻断上线”的风险建立一个自动化检查。产品状态模型还在变化时,不要为了追求覆盖率数字而写大量容易失效的 UI 测试。
常见失败模式
文案承诺了系统并不具备的能力。 “我们会通知你”需要持久任务和通知链路;“没有发送任何内容”需要系统真正知道外部结果。 把客户端状态当作系统事实。 禁用按钮、本地转圈或取消浏览器请求,都不能证明服务端阻止了、完成了或撤销了操作。 所有错误共用同一种提示。 输入无效、登录过期、权限拒绝、供应商故障和结果未知,需要完全不同的下一步。 只使用管理员账号测试。 过于宽松的权限会掩盖角色和工作区隔离问题。 把截图当成完整测试策略。 视觉一致不能证明业务规则、无障碍、持久化或没有重复副作用。 把每个边缘情况都升级成上线阻断。 优先级应同时考虑后果和频率。罕见的间距问题,与重复扣款或泄露其他工作区数据不是同一个等级。这套审查的边界
这套方法适用于普通 Web 产品和早期 AI 应用,但不能替代正式的 WCAG 一致性审查、渗透测试、威胁建模、压力测试、隐私审查或监管验证。医疗、金融、法律、安全关键或就业决策等高风险系统,需要合格专业人员和更严格的控制。
这次审查也只能证明你主动制造过的状态。它无法说明所有网络时序、浏览器、辅助技术、竞态条件和外部依赖都安全。当角色、计费、状态存储、任务执行、模型供应商或重要操作发生变化时,应重新执行审查。
最重要的转变很简单:不要再只问“AI 生成的页面看起来做完了吗”,而要问“当用户是第一次使用、输入错误、网络缓慢、权限不足、反复点击、连接中断或稍后返回时,每一次重要状态转换是否仍然诚实”。一个 AI 演示正是在这些地方,开始变成真正可靠的产品。
参考资料
- W3C Web Accessibility Initiative,Web Content Accessibility Guidelines (WCAG) 2.2,重点包括错误预防、组件状态与可被程序识别的状态消息。
- W3C Web Accessibility Initiative,Understanding Error Identification,关于如何标记输入项目并以文字描述检测到的错误。
- GOV.UK Design System,Error Message,关于具体、一致且可执行的错误提示文案。
- Playwright,Best Practices 与 Visual Comparisons,关于 web-first assertions 以及截图基准的限制。
- Chrome 团队,Interaction to Next Paint,关于交互响应和用户操作后的可见反馈。
- OWASP Cheat Sheet Series,Authorization Regression Testing,关于“操作者—资源—操作”矩阵与持续授权测试。
- Stripe API Reference,Idempotent Requests,一个利用幂等请求避免安全重试产生重复结果的实现范例。
- MDN Web Docs,Using the Fetch API 与 AbortController,关于 HTTP 响应处理与浏览器侧请求取消边界。