K5.3.4 Task 5.3

"不存在同行评审研究"——实际上,停机结束后找到了 47 篇论文

一个研究系统报告”不存在关于海上风电补贴的同行评审研究。“在同一数据库手动搜索找到了 47 篇匹配论文。学术数据库在查询期间有部分中断。子代理返回了 {results: [], isError: false}——把一次访问失败转换成了一个错误的事实声明。

这是静默吞没最危险的形式:不只是隐藏错误,而是从一次系统故障生成了一个肯定断言(“数据不存在”)。

核心区分

结果含义isError操作
访问失败(超时、认证、服务宕机)数据可能存在,我们查不了true重试、切换来源、报告缺口
有效的空结果(查询成功,零匹配)数据确实不存在(已确认)false接受为确定性答案

当两者返回同样的空结果时,编排器分不清。它把”查不了”当成了”查了,确认是空的”。

数据:85% 的”没有数据”实际是查询失败

一个 15% 的子代理响应为空的系统:

实际原因百分比需要的处理
服务超时60%重试
认证失败25%刷新凭证
真正无匹配15%接受为答案

85% 的”未找到数据”结论是需要恢复的访问失败。只有 15% 是正确答案。包含这些空响应的报告有 40% 的用户投诉率,而数据完整的报告只有 5%。

一次浪费了 3 个月的误诊

一个支持系统报告 8% 的案例以”无法找到客户信息”结束。团队假设是数据质量问题,改进了数据录入界面。3 个月后:8% → 7.2%。改善微乎其微。

调查发现:45% 真正无匹配(拼写错误),35% 数据库超时,20% 权限错误。数据录入修复帮到了 45% 但对 55% 的系统故障毫无作用。真正的修复:区分访问失败和有效的空结果,让各自得到合适的处理。

安全关键:访问失败时闭合

一个 CI 流水线在允许合并前检查 3 个漏洞数据库。如果数据库不可达,选择是:

  • 开放式失败(错误): 把不可达当作”未发现漏洞” → 有潜在漏洞的代码合并到生产
  • 闭合式失败(正确): 访问失败时阻止合并,因为”查不了” ≠ “查了没发现”

在安全上下文中,访问失败和有效空结果之间的区分不只是质量问题——是安全边界。开放式失败把系统故障转换成了虚假的安全通行证。

修复:isError 区分

// 访问失败
{"results": [], "isError": true, "failure_type": "timeout", "retry_recommended": true}

// 有效的空结果
{"results": [], "isError": false}

编排器不同路由:

  • isError: true → 重试、切换来源、报告缺口
  • isError: false → 接受为确定性结果,据此行动

客服应用

每天 200 次空订单查询:140 次真正的无效订单(70%),60 次数据库中断(30%)。目前全部收到”请验证您的订单号。”

有了 isError 区分:重试 60 次中断案例(大部分成功),只对 140 次真正的空结果提示验证。有有效订单的客户不再被告知他们的订单不存在。

不要通过统一错误路径来简化

有人提议把所有空/错误响应都当作”没有数据”,代码复杂度从 15 条错误路径降到 1 条。但它对每一次访问失败都产出静默的错误结果。结构化错误处理的维护成本远低于因混淆两种结果而产生的虚假声明、沮丧用户和安全漏洞的成本。


一句话总结: 用 isError 区分”无法访问数据”和”数据确实不存在”——85% 的空响应是被误分类为有效空结果的访问失败,在安全上下文中这个区分是开放式失败 vs 闭合式失败的安全边界。