一句话定位:本文是《空圈容错视角 — HarmonyOS 7 架构体检》 (母篇最新 V3.7,原基准 V3.4)的下钻篇。母篇看的是「整机架构真稳还是假兜底」, 本篇只钻一处——一条跨越多个 Skill 的 Agent 长任务链,断在半路时,系统到底有没有真冗余。

  • 作者:空圈容错理论(Liaiyang66 + AI 协作)
  • 版本:V2.0(终审定稿 · 全量吸收外部审稿两轮共六刀;V2.0 为校订版:编号自洽、§ 引用校正、代码围栏复位、特殊字符清理、内部计数校平,不改判据与结论)
  • 理论框架:空圈 · 容错整合理论

(空圈五公理 / C·M·P 三层拓扑 / R1–R9 检测框架 / ∅_safe 安全空集 / 元公式 / 砍三刀)


📌 框架口径与跨篇映射说明

项本篇口径
R 编号沿用母篇 V3.7 领域版:R1 前置缺失 / R4 范式绑架 / R6 假兜底 / R7 无异构通道 / R8 自指闭锁 / R9 跨层完美同一(本体论死锁)。本次列示 R4 / R8 / R6 / R7 / R9;R2 由 §3.2 的 R8 统一承载(并刀判据见 §3.2);R1 / R3 / R5 不在本次扫描列示
CMP 三层(操作级重定义)C = 主干底座(Agent 框架 + 分布式底座);M = 收容机制(小艺规划与调度);P = 冗余通道(熔断 / 重试 / 降级 / 端侧兜底)
标记体系R 扫描用「强命中 / 半命中 / 弱命中 / 未命中」;CMP 操作级仅用「稳 / 漂移 / 弱」。§3.7 对照表「母篇(整机)」一列按母篇原档位「极稳 / 半稳(漂移)/ 弱」标注,仅作跨维对照,不参与本篇判定
颗粒度对齐与系列《数据管道脚本实战》《轴承磨削工序实战》同档——对象都是「单次作业级的闭环」。母篇给管理层看,本篇给一线开发者看
口径迁移提示CMP 定义会随分析维度变化。跨系列阅读、或单独转发本篇时,请留意开篇这段口径说明

⚠️ 本篇的 CMP 是「单次作业 · 操作级」重定义,与母篇「整机维度」的档位名称相同、含义不同。 混用是本次扫描里最容易被误读的一处,请先记住这一句。


声明(边界)

本报告不提供代码级漏洞挖掘,不评价产品的商业成败,不代表华为官方结论。 文中的工程量级、阈值、参数均为方向级建议值,不是官方 SLA、也不是标准值,请按自己项目的实测分布调整。

本文讨论的是「应用侧如何在鸿蒙 Agent 框架之上自建一层兜底」: 不改动系统框架,也不假设系统框架已经提供这些能力。(这一条,请和 §2.2.1 的「能力落点矩阵」连起来读——五动作里,只有一部分是应用侧今晚就能自己上的。)


〇 定位:为什么只钻「长任务链」这一处

母篇对 R4(端云协同范式绑架)判了强命中,判词是: 「整个系统的智能表现,被端侧感知 + 云侧推理这条范式焊死。」

这句话在整机架构图上是一句判词;落到具体场景里,它有一个 最直接、最可验证、也最容易出真金白银损失的暴露面—— 一条跨越多个 Skill 的 Agent 长任务链。

理由有三:

  1. 它是端云绑架的放大器:短任务(问一句天气)云侧抖一下,用户重问一遍就行; 长任务(订票 + 订房 + 约车)链上有 N 个写操作,云侧抖一下, 代价可能是真金白银的重复扣款。
  2. 它是系统侧补不了的那一角:母篇给开发者的五条目标中, 「熔断与降级」排在第一位(针对 R4)——因为系统侧补的是进程级崩溃, 业务级半完成,只能应用侧自己兜。
  3. 它是可交付性最强的一处:一条链的容错机制,能被完整地写成 「裸奔版 vs 加固版」两段代码、一张成本账、一份六问清单——今晚就能拿自己的链试一遍。

所以本篇只做一件事: 把「这条链的容错」从一句架构判词,做成一份能落地的工程动作。


一、共同体验的那个瞬间:进度条 70%,还是绿的

这个剧本,是加固版上线之前会发生的事。下文每一刀,都是为了让它不再发生。

下午两点四十,你对着手机说: 「下周三我要去上海开会,帮我订一张上午到虹桥的机票,订一间会场附近的酒店,再约一辆接机车。」

小艺把这件事拆成了五步 —— 查航班 → 订票 → 查酒店 → 订房 → 约车。前三步跑得很顺,机票已经出票,酒店锁定。

第五步,你的手机从写字楼 Wi-Fi 走进了地下车库,切进弱网。 于是你看到:任务卡片停在「正在为您预约接机……」,进度条 70%,转圈,不动了。

你等了一分钟,不耐烦,点了重试。 晚上落地上海,你打开订单:

  • 机票——两张;
  • 酒店——两间;
  • 接机车——一辆(这个倒是对了)。

这不是段子,这是「无幂等 + 无超时上限」在任何 Agent 系统上的必然结果。 母篇讲的「端云协同焊死」,在用户侧就长这样。

还有一种更隐蔽、也更坏的形态: 链其实在第四步就静默断了(云侧限流,子 Agent 返回了空结果但没报错), 可是界面最后弹了一个「任务已完成」。 因为你到机场排队办登机时才被告知——没有这张票。

「进度条全绿、任务显示完成、用户实际什么都没办成」——这就是本篇要拆的那一盏绿灯。

和《数据管道脚本实战》里的「跑批全绿、老板拿不到对的数据」、 和《轴承磨削工序实战》里的「套圈全绿、装机三个月却剥落」,是同一盏灯。


二、两条链摆一起:裸奔版 vs 加固版

2.1 裸奔版:线性直连链

```typescript
// ❌ 裸奔版:无锚
// TripIntent / Task / Step 为本篇业务伪类型,业务项目需自行补全类型定义
async function bookTrip(intent: TripIntent) {
  const plan = await xiaoyi.plan(intent); // 云侧规划
  
  for (const step of plan.steps) {
    const res = await Agent.startAgent({ // 无显式超时上限
      agentName: step.skill,
      intent: step.args,
    });
    
    if (res.code !== 0) { // 只看返回码
      toast('任务失败,请重试'); // 一把梭兜底
      return; // 前 N 步副作用已经发生
    }
  }
  
  toast('任务已完成'); // ← 绿灯幻觉的产地

这段代码里有五处空圈,全都不显眼:

位置空圈后果
startAgent 无超时云侧限流时一直挂起用户以为卡死,手动重试
无幂等键重试即重发重复下单、重复扣款
无检查点断了就断在原地只能从头再来,重复烧 token、重复扣款
循环走完就报「完成」「200 / 没抛异常」就算成功报「完成」,实际业务没成
资金 / 授权无硬闸门模型判断即放行触发即灾难级(R9)

2.2 加固版:三道锚(V1.9 · 检查点为唯一事实源)

第一段:主循环代码

// ✅ 加固版:三道锚 + 检查点驱动状态机
// TripIntent / Task / Step / Checkpoint 均为本篇业务伪类型,需自行补全定义
const TIMEOUT_MS = 8000;
const BREAKER = new SlidingWindowBreaker({ window: 20, errorRate: 0.3 });

async function bookTripHardened(task: Task) {
  // ★ 契约:链恢复时以检查点为唯一事实源,task 只是它的投影(见 §2.2.5 resume)
  const restored = resume(task);
  if (restored.stop) return restored.value;
  task = restored.task;

  for (const step of task.pending) { // ← 每轮都读「当前」task.pending
    
    // ── 锚一:资金 / 授权硬闸门(只拦「未确认」,不拿版本号误杀)
    assertPrecondition(step);

    // ── 锚三:熔断(闭闸期零网络,半开探测才是真请求,见 §四)
    if (BREAKER.isOpen(step.skill)) {
      return degrade(task, step, '该能力当前不可用,已为您保留已完成部分');
    }

    // ── 锚二:本轮意图版本「有 intent 就复用,没有才生新」
    //      key 点:超时重试全程用同一把 idemKey,服务端去重才兜得住 ×2
    const intentCp = checkpoint.latestIntent(task.id, step.id);
    const thisVer  = intentCp?.idemKey ?? bumpVersion(task.confirmVersion);
    
    if (!step.confirmed) throw new ConfirmationRequired(step.id);
    const idemKey = hash(task.id, step.id, thisVer);

    let res;
    try {
      res = await withTimeout(
        Agent.startAgent({
          agentName: step.skill,
          intent: { ...step.args, idemKey },
        }),
        TIMEOUT_MS
      );
    } catch (e) {
      if (isTimeoutError(e)) {
        BREAKER.record(step.skill, false);             // 超时也是失败样本,喂给熔断
        await checkpoint.save(makeIntentCp(task, step, thisVer)); // 先固化意图版本
        return degrade(task, step, '云侧超时,操作可能已发出,请先确认');
        //          ↑ 绝不能说「已失败 / 已回滚」:远端可能票已出
      }
      throw e;                                          // 非超时异常,上抛
    }

    // ── 锚一:调用后校验业务事实,而不是看返回码
    const fact = await verifyFact(step, idemKey);
    if (!fact.ok) {
      BREAKER.record(step.skill, false);
      await checkpoint.save(makeIntentCp(task, step, thisVer));
      return degrade(task, step, '操作结果未确认,请先核对订单');
    }
    BREAKER.record(step.skill, true);

    // ── 锚二 + 两阶段检查点:先落「意向态」→ 回读命中才升「已确认态」
    //      ★ 派生快照,立刻回写到 task,下一轮拿到的就是最新值(§2.2.5)
    const done    = [...task.done, step.id];
    const pending = task.pending.slice(1);

    await checkpoint.save({
      taskId: task.id,
      stepId: step.id,
      state:  'confirmed',        // 回读命中 → 才可续跑
      done, pending,
      idemKey: thisVer,           // 把本轮键落盘,重试 / 续跑都读它
      lastObs: fact.summary,
      retry: 0,
      confirmVersion: thisVer,
    });

    task.done    = done;          // ← V1.9 关键:推进投影
    task.pending = pending;       // ← 否则下一轮的 done/pending 用的是 stale 解构值
    task.confirmVersion = thisVer;
  }

  await reconcile(task); // 独立对账,不靠自己汇报
  toast('任务已完成');
}

// ──────────────────────────────────────────────
// 辅助:意图态检查点(不可续跑,只用于防重 + 待确认)
function makeIntentCp(task: Task, step: Step, thisVer: string): Checkpoint {
  return {
    taskId: task.id,
    stepId: step.id,
    state: 'intent', // 意向态:明确不可续跑
    done: task.done,
    pending: task.pending,
    idemKey: thisVer,
    lastObs: null,
    retry: (task.retry ?? 0) + 1,
    confirmVersion: thisVer,
  };
}

第二段:闸门校验代码(放在 §2.2.1 里)

// ── 锚一:资金 / 授权硬闸门
function assertPrecondition(step: Step) {
  if (step.sideEffect !== 'money' && step.sideEffect !== 'auth') return;
  
  // 唯一硬拦:用户没确认
  if (!step.confirmed) throw new ConfirmationRequired(step.id);
  
  // 续跑一致性:检查点有上轮记录时,才要求「确认版本 === 上轮版本」
  const last = checkpoint.lastConfirmed?.(step.id) ?? null;
  if (last !== null && step.confirmVersion !== last) {
    throw new ConfirmationRequired(step.id);
  }
  
  // ★ 注意:不在这里写 step.confirmVersion = thisVer
  // 用户「确认版本」与本轮「意图版本」是两个东西,压平会吞掉确认语义(见 §2.2.1)
}

双轨表

版本谁生成谁消费推进时机一句话
用户确认版本 step.confirmVersion用户点确认时绑定闸门(续跑一致性校验)用户重新确认时才换管「这一刀敢不敢放」
本轮意图版本 thisVerbumpVersion(首跑)/从 intent 检查点读回(重试)幂等键、检查点落盘、对账回读命中后才写进 task.confirmVersion管「这把键落在哪、重试还认不认」

三条铁律

  1. 闸门只看「有没有确认 + 上轮对不对」,绝不因为版本号对不上就误杀首次发写。
  2. idemKey = hash(taskId, stepId, thisVer) 全程恒定:首跑生一次,超时重试从 intent 检查点读回同一个,不许 retry 一次 bump 一次——否则键漂移,服务端去重失效,照样 ×2。
  3. thisVer 只在回读命中后才推进成 task.confirmVersion;推进前它就是「待确认态的键」。

反例(不要这么做):

const thisVer = bumpVersion(task.confirmVersion);
step.confirmVersion = thisVer; // ❌ 把用户确认版悄悄换成系统刚生的号

后果:断点续跑时 lastConfirmed 是旧号、比对必炸,闸门误杀;幂等键与服务端订单的确认语义拧开,×2 更难查。

2.2.2 两阶段检查点:为什么「先落盘,再发写」在资金这一步要打折(V1.9 新增)

补一句边界,免得「先落检查点,再发起写操作」被照字面误用。

对可逆 / 可本地化的副作用,检查点可以「先落已确认态、再发写」,断点续跑直接跳过已做步骤。

但资金 / 授权是不可逆写操作,物理上做不到「先落一个已确认的检查点、再出票」—— 票还没出、座位还没锁,那个「已确认」是假的,断网重启后会误以为票已出、再发一次,正好造 ×2。

所以资金这一步的检查点必须是两阶段:

意向态 intent ──发写──▶ 回读命中 ──▶ 已确认态 confirmed(可续跑,推进 thisVer)
↑ 只防重放 / 存键 ↑ 此刻才知道「到底成没成」
不可续跑 下一轮才敢跳过这步

  • 能「先落」的只有意向态:状态=准备中,明确不可续跑,只用来固化 idemKey、挡重复提交;
  • 可续跑的已确认态:必须等 verifyFact 命中后才落;
  • 把两阶段混成一个 save,要么续跑造 ×2,要么不敢续——这是 R8 最阴的接缝,别省那一行状态。

2.2.3 为什么「超时不能报失败」:超时 ≠ 远端没执行

withTimeout 只代表调用方放弃等待,不代表云侧把操作撤销了。 网络断在「已发出、回包丢了」那一瞬,票可能早就出了。

所以超时只有一个合法终点:degrade 的待确认态。

// ✅ 合法文案
degrade(task, step, '云侧超时,操作可能已发出,请先确认订单');
// ❌ 绝对不能写
degrade(task, step, '操作失败,已为您回滚'); // 你在撒谎,且会造 R9

// confirmWhat 让降档可解释到「确认什么」这一层(不是一句黑话):
function degrade(task: Task, step: Step, reason: string) {
  const local = runLocalFallback(step); // 无副作用的端侧兜底:缓存查询 / 本地比价 / 待办草稿
  
  return notifyUser({
    status: 'DEGRADED',
    done: task.done, // 哪些成了
    blocked: step.id, // 卡在哪
    reason, // 为什么
    // ★ 降档可解释的最低标准:不是「需要你确认」,而是「确认什么」
    confirmWhat: step.sideEffect === 'money' || step.sideEffect === 'auth'
      ? `请确认是否${step.label}` // 例:请确认是否出票·上海→虹桥 08:15
      : undefined, // 非敏感降档不必弹确认
    local, // 端侧能先给你的
    needConfirm: step.sideEffect === 'money' || step.sideEffect === 'auth',
  });
}

2.2.4 能力落点矩阵(★今晚能不能「上手」,看这张表)

声明里说过「不假设框架已经提供这些能力」。 那 reconcile、checkpoint、idemKey 到底谁给?这是全稿最容易被拆的一问,摊开回答。

加固能力应用侧自己能上的必须靠框架 / 合作方给的口拿不到时的退路
幂等去重客户端生成 idemKey + 本地去重表 + 键恒定(§2.2.1)服务端须认这个键并做唯一约束出账前回读订单唯一性,命中重复即拒绝
检查点本地 KV / Preferences 落盘(两阶段,§2.2.2)跨端续传要云同步意向态只防重、不续跑;丢一步标『待确认』,不报完成
熔断进程内滑动窗口计数,闭闸期零网络、零依赖 ✅—五动作里闭闸期零依赖的两把之一;半开探测仍是真请求
调用后回读端侧发起只读查询要有可读的服务端查询口查不到 → 走降级,不当成成功
独立对账 reconcile换一条路径 / 换一套凭据再问一次需另一个只读视图或审计账没有第二双眼睛 → 最多给『已提交,待确认』,永远别说『已完成』
端侧降档端侧本地算:缓存查询、本地比价 ✅(无副作用)不扣钱、不发写、不产生副作用断网也能把「我替你记着」交出去
硬闸门端侧 UI 确认组件,零依赖 ✅确认事件须进检查点没确认 → 连发写都不许进

结论(咬死): 严格零依赖(连网络都不要)的有两把——熔断、硬闸门;断网仍可交付的还有一类——端侧降档(缓存查询、本地比价、待办草稿,不花钱、不发写)。 其余幂等、回读、对账都卡在「服务端 / 框架给不给口」上。

把这事说清楚,不是削弱本文,恰恰是它最诚实的地方—— 因为 R8 的解药从来不是「写得更漂亮」,是「第二个观测者到底是谁」。 不说清,reconcile 就会退化成跟 toast('任务已完成') 一样的自指:自己证明自己办成了。

2.2.5 续跑契约:检查点是事实源,task 是投影(V1.9 新增)

// 进程重启 / 链恢复:以检查点为唯一事实源,task 只是它的投影
// ★ 谁先写谁说了算;绝不能「检查点一份、闭包变量一份」各记各的
function resume(task: Task): { stop: true; value: any } | { stop: false; task: Task } {
  const cp = checkpoint.latest(task.id);
  
  if (!cp) return { stop: false, task }; // 首跑
  
  if (cp.state === 'confirmed') { // 已确认:投影可追平,正常续跑
    return { 
      stop: false, 
      task: { 
        ...task,
        done: cp.done, 
        pending: cp.pending,
        confirmVersion: cp.confirmVersion 
      } 
    };
  }
  
  // intent 态:远端状态未知 → 绝不自动续跑发写,交给用户确认
  return { 
    stop: true, 
    value: degrade(
      { ...task, done: cp.done, pending: cp.pending },
      { id: cp.stepId } as Step,
      '上一次操作可能已发出,请先确认后再继续'
    )
  };
}

点题:检查点落盘之后,task.done / task.pending 必须立刻从同一份派生快照回写(§2.2 主循环那两行)。 漏这一步,下一轮 for (const step of task.pending) 拿到的是 stale 解构值, 检查点里 done=[A]、循环里还当 A 没做 → 续跑重发,×2 照旧发生。这就是 V1.9 补上的最后一毫米。


三、探针扫描与因果链

3.1 R4 范式绑架 —— 强命中

操作级判据:这条链有没有一步是「云侧不可用时也能走完」的?没有。

链的「业务写操作」,没有一步是云侧不可用还能推进的——出票、扣款、锁库存全得等云侧。 唯一例外是熔断这一刀:它不救活写操作,只在闭闸期给链一个 「不再傻等、不再重发」的边界,把无限挂起砍成有终点的降档。

这说明 R4 的解药不在「让写操作离线成」(做不到), 而在「给失败一个可控的形状」——正对应 §5.1 第三刀「换一条路」。

3.2 R8 自指闭锁 —— 整机半命中,操作级强命中

裸奔版最后那句 toast('任务已完成'),凭据是「循环正常退出了」; 而循环正常退出的前提,是每一步都「没抛异常」——异常早被兜底分支吞掉了。 用执行方自己的状态证明任务完成,闭环里没有第二个观测者。

▸ R2 → R8 的并刀判据(本篇仅此一处合并)R2「独立异构通道缺失」与本篇 R8「自指闭锁」在操作级坍缩成同一条接缝: 校验与转换同源的唯一暴露面,就是「完成度靠执行方自己报」。 故 R2 不单列,归 R8 承载。这是颗粒度裁断,不是改名: 一旦出现「异构对账通道客观存在、却仍读同一份快照」的场景,须把 R2 拆回单列,不可继续借 R8 的壳。

3.3 R6 假兜底 —— 整机弱命中,操作级强命中

整条链只有一个兜底——最后弹一句「任务失败」。这不是兜底,是把问题推回给用户。 兜底是分级还是一把梭?一把梭 → 强命中。 链越长,这把梭越钝。

3.4 R7 无异构通道 —— 半命中

云段 / 端段怎么切,只有一条判据——这一步的副作用是否「可回滚、可本地化」:

  • 可落端侧:查(缓存的航班列表)、比(本地比价)、提醒、生成待办、填表单草稿——断网也值钱;
  • 必须留云侧:出票、扣款、锁库存、改订单——没网就别装成完成,进『待确认』;
  • 切错了才是事故:把「扣款」降级到端侧假装成功,那是造 R8,不是容错。

degrade() 里的 runLocalFallback 就是这条线的入口,它兜的只能是「无副作用、能本地化」的那一半。

3.5 R9 跨层完美同一 —— 操作级弱命中(现状)

资金 / 授权动作,若指望「模型足够聪明就不会错放」,等于用有限模型覆盖无限异常。 加固版的解药,正是把这一步换成可信 UI 硬闸门(§2.2 的 assertPrecondition):

  • 闸门立住 + 回读命中 = 真隔离;
  • 卡在等确认 = 『待确认』态,绝不标『已完成』(六问第 5 问的通过条件)。

一旦触发,就是灾难级。所以本篇的验收第 5 问不设「凑合过」,只认这两档。

3.6 因果链:这盏绿灯是怎么亮起来的

云侧受限 / 网络抖动
↓ 无超时上限 → 傻等
用户手动重试 / 系统自动重试
↓ 无幂等键 → 写操作重复生效
订单 ×2、扣款 ×2
↓ 无检查点 → 断点无法续
只能从头重跑(再烧一遍 token、再扣一次款)
↓ 异常被兜底分支吞掉
返回码为 0、循环正常退出
↓ 无独立对账 → 报「任务已完成」
用户到现场才发现:什么都没有
↑ 最阴的一刀在这条线之外:
[出票/扣款若没过资金闸门,前面四把刀全装上也会 ×2]
→ 资金类副作用必须单拎:先确认、后发写、确认版本进检查点(§2.2.1)
↑ V1.9 补上的三跳(都在代码里,不是注释):
[超时未捕获 → 崩出链外] 没 catch 时 degrade 根本走不到,§2.2.3
[检查点非事实源 → 续跑重发] task 没回写时 done 丢步,§2.2.5
[idemKey 漂移 → 去重失效] retry 重新 bump 时键变了,§2.2.1 铁律 2

3.7 CMP 三层在操作级的健康度

层母篇(整机)【整机维度档位】本篇(单条链)说明
C 主干底座极稳稳Agent 框架、分布式底座不背这个锅
M 收容机制半稳(漂移)漂移规划与调度全依赖云侧与场景分布
P 冗余通道弱弱单条链上几乎没有真冗余,只有最后一句报错;补 P 靠 §2.2.4 的能力归属

结论:链断,断不在底座,断在「没人给这条链修冗余」; 而修冗余的第一问不是「写什么代码」,是「第二个观测者谁给」。


四、灵魂拷问:加这些动作,慢了多少、贵了多少

这是最容易被打回的一问。裸奔版唯一的优势就是快——多一层锚是不是就把体验拖垮了?

加固动作额外开销量级换来什么弱网下的真实代价
幂等键一次散列 + 入参 + 服务端去重查一次链路正常 < 10ms不重复下单;键恒定才兜得住超时重试服务端不可达 → 退化『待确认』,不扣
检查点每步结构化写(两阶段)单步 < 50ms断点能续、且续的是真·已完成本地写稳、云同步可迟;先落意向、回读后才确认
熔断滑动窗口内存计数,闭闸期零网络(严格零依赖)忽略不傻等到超时⚠️ 半开探测那一下是真请求——别把「零依赖」宣传成「零开销」
调用后回读校验一次只读查询正常 < 100ms抓到「200 但业务没成」弱网下 3–8s 甚至超时;它治的是「别扣第二次」,不是提速
超时捕获一次 try/catch + 一次意向检查点可忽略崩出链外 → 转待确认没有这行,前面所有兜底在超时那一刻集体失效
合计(10 步链)—正常约 0.5–1 秒避免一次重复支付 / 断链重跑弱网里最慢的是回读,价值是上限可控

量级判断:一条 10 步 Agent 链的总耗时通常在数秒到数十秒量级 (含多次云侧推理与外部写操作)。链路正常时,0.5–1 秒的加固成本占比通常不到几个百分点。

而一次重复支付的代价:退款流程的时间成本 + 一次真实的资损 + 一次对产品信任的消耗。 这笔账的分子分母,不在一个量级上。

一句话把账说正:上表是链路正常时的增量开销;弱网才是这套动作的战场。 那时回读与半开探测本身就是最长路径。 所以别拿它当「性能优化」卖——它换的不是延迟更低,是别再悄悄地扣第二次,是上限可控。谁拿「弱网更慢了」来杠,杠不动这一句。


五、砍三刀 + 四阶段落地

5.1 砍三刀

第一刀(砍成功率数字): 「复杂任务成功率超 90%」是全局平均。分母里的失败若有一次是支付错账或授权外溢,这个 9 分就不算 9 分。

第二刀(砍「系统会自动兜底」): 系统兜的是进程级崩溃(杀后台、回收内存、重启);它兜不了业务级半完成(钱扣了、单没出)。 把「进程还活着」当成「任务没丢」,是典型的跨层幻觉。

第三刀(砍「重试就是容错」): 没有幂等的重试,是同通道空转——越重试越错。 重试是「在原来的路上再走一次」,容错是「换一条路,或者明确降档」。 真换路,先问 §2.2.4 那张表——路在谁手里。 而换路的第一条纪律是 §2.2.1 铁律 2:重试不许换键。

5.2 四阶段落地(时间窗 / 强依赖 / 诚实补丁)

阶段时间窗核心动作强依赖诚实补丁
一 · 观测0–1 个月给每步打点:stepId、耗时、结果、是否重试、是否走 degrade—打点有开销与隐私面,只记结构化元数据,不记用户内容
二 · 断点1–3 个月幂等键(键恒定) + 两阶段检查点服务端须支持幂等去重幂等接口常在合作方手里;对方没有,退而用「操作账本 + 出账前回读」。本地检查点会丢最近一步,须「先落意向、回读后才确认」
三 · 熔断3–6 个月超时上限 + 滑动窗口 + 半开探测阶段一的耗时 / 失败分布阈值太松没用、太紧误伤正常链,初版宁晚熔,按数据再调;半开探测有真实请求代价
四 · 降档6 个月起把 ∅_safe 从「崩溃兜底」升级成「优雅降档的产品承诺」前三阶段 + 端侧降档产品化降档必须能解释「哪步成了、哪步没成、需要你确认什么」(§2.2.3 的 confirmWhat);没有独立对账就只给『待确认』

四阶段强依赖,不能跳: 没有阶段一的分布,阶段三的阈值就是拍脑袋; 没有阶段二的检查点(且 task 跟着回写,§2.2.5),阶段四的降档就没有「已完成清单」可交付; 而阶段二的命脉,是服务端给不给那个幂等口(§2.2.4)——给不了,就别吹「已兜底」。


六、可证伪验收清单(六问)

这六问,今晚就能拿自己的链挨个问一遍。 任何一问答「会」或「不知道」,那条链就还亮着绿灯幻觉。

  1. 幂等:某个写操作超时后重试,会不会产生第二笔真实订单? → 必须答「不会」:idemKey 从 intent 检查点读回同一个,服务端去重生效。(§2.2.1 铁律 2)
  2. 独立观测:你的「任务完成」是执行方自己汇报的, 还是有一个独立对账维度? → 再追一句:那双眼睛谁给? 没有 → 最多『已提交,待确认』,别说『已完成』。(§2.2.4)
  3. 熔断:云侧限流时,这条链是傻等到超时,还是有明确的熔断阈值? → 且超时路径必须进 degrade,不能靠 catch 漏掉崩出去。(§2.2.3)
  4. 断点:链断在第 5 步,恢复后是从第 5 步续,还是「从头再说一遍」? → 以检查点为事实源(resume,§2.2.5);若停在 intent 态,宁可拦住问用户,也不自动续发写。
  5. 硬闸门(三态,不是过 / 不过):
    • 模型判断放行 → 没过;
    • 用户已确认 + 回读命中 → 真隔离;
    • 卡在等确认 → 『待确认』态,不算过。 → 闸门只拦「没确认」,别拿版本号误杀首次。(§2.2.1)
  6. 降档可解释:降级发生时,你告诉用户的是「失败了」, 还是「哪几步成了、哪步没成、需要你确认什么」? → 必须有 confirmWhat 字段,不能只给 needConfirm: true。(§2.2.3)

七、诚实清单与边界重申(本篇自己的空圈)

  • 本文阈值、超时、窗口参数都是建议初值,不是标准值,也不是华为官方口径;
  • ∅_safe 是本框架内的定义(安全降级状态),不是行业通用术语——对外沟通须先解释;
  • 「合计 0.5–1 秒」「占比不到几个百分点」是链路正常时的工程量级判断, 不是实测数据;弱网下回读本身即可能成为最长路径(§四),请以自己链上的打点分布为准;
  • 严格零依赖(连网络都不要)的是「熔断 + 硬闸门」; 断网仍可交付的是「端侧降档(无副作用)」; 幂等、回读、对账仍依赖服务端 / 框架给口,拿不到就按 §2.2.4 的退路走, 别把『待确认』包装成『已完成』;
  • 本文只给「应用侧如何在框架之上自建兜底」,不涉及框架内部实现, 也不假设系统已经提供这些能力;
  • 本文写作时点为 2026-11,数据以 HDC 2026 及最新公开信源为准;
  • 尚未运行时验证的项(本篇自己的空圈,不藏):
    1. 版本双轨流转(thisVer 首跑生、重试读回、回读后推进)尚未在鸿蒙运行时跑通验证;
    2. 超时 → degrade 分支(含 resume 对 intent 态的拦停)同上;
    3. 服务端是否真正认 idemKey 并做唯一约束,是整条链能否防 ×2 的地基——本文无法替合作方签字。

边界:不提供代码级漏洞挖掘,不评价产品商业成败,不代表华为官方结论。 母篇的判词「收容做得很漂亮,容错才是深水区」在这里依然成立—— 本篇是把「深水区」里的一处,写成能下手的施工图。


八、本篇的相对位置(增量归属)

现象层(行业已有):熔断、幂等键、检查点、退避、半开探测、 outbox/inbox 事件溯源的输出箱 / 输入箱模式——这些是成熟工程实践; 母篇点出的「端云绑架」也是公开讨论。本篇不抢这些功劳。

本篇的框架层增量:

  1. 把母篇的架构判词下沉成一条链上的可检查动作—— 五处空圈(超时 / 幂等 / 检查点 / 完成判定 / 资金闸门) 逐一定位,并标清能力归属(§2.2.4);
  2. R8 的「层级敏感」发现:同一个 R8 自指闭锁, 在整机层面判「半命中」,下沉到单条链的操作层面升格为强命中—— 因为链上没有任何外部校验点,而那个「外部点」往往不在应用侧手里;
  3. 版本双轨(V1.9):把「用户确认版本」与「本轮意图版本」拆成两条线, 并给出 idemKey 跨超时重试恒定的铁律——这是把「防重放」从口号变成可验证契约;
  4. 检查点即事实源(V1.9):task 只是投影,续跑从检查点重建, intent 态绝不可自动续发写——堵死「续跑重发」这条最阴的缝;
  5. 可证伪六问:把「这条链有没有真冗余」变成六个能当场自测的问题, 第 2 问追「第二双眼睛谁给」,第 5 问走三态,第 6 问落到 confirmWhat 字段。

仍未验证:这六问尚未在真实第三方团队上做过独立复现; 落地效果也没有真实企业的硬指标数据。 它证明了这套动作「可以用」,还没证明它「一定管用」—— 尤其是 §2.2.4 里那四个「等口」的动作,能不能落地,取决于生态给不给路。


附录 A · 母篇 → 本篇的映射

母篇要素本篇对应
R4 端云协同范式绑架(强命中)§3.1 链的可靠性 = 云侧可用性 × 网络稳定性;解药是「给失败可控形状」
R8 自指闭锁(整机:半命中)§3.2 操作级升为强命中(链上无外部校验点);含 R2 并刀判据
R6 假兜底(整机:弱命中)§3.3 操作级升为强命中(一把梭兜底)
R7 无异构通道(整机:弱命中)§3.4 无「云段 + 端段」拆分设计,附切分判据
R9 本体论死锁(整机:强命中 | 操作级:弱命中·现状)§3.5 资金 / 授权硬闸门缺失;闸门立住 + 回读命中即转「已隔离」
开发者目标一:长任务链熔断与降级§2.2 三道锚 + §2.2.4 能力落点 + §5.2 四阶段
∅_safe 安全空集§2.2.3 degrade() 优雅降档(含 confirmWhat)
元公式 D_max 判词§5.1 第一刀:平均值代替尾部
砍三刀§5.1
—— V1.9 新增 ——§2.2.1 版本双轨 | §2.2.2 两阶段检查点 | §2.2.5 检查点即事实源

注:R9 一行按「整机 / 操作级」双档标注,避免跨篇读者忽略层级差异。


附录 B · 事实与数据来源

  • HarmonyOS 7 与 Agent 架构:华为开发者大会 HDC 2026(2026-06-12,东莞松山湖), 余承东发布 HarmonyOS 7,三大核心升级为 Agent 亲和系统架构、 鸿蒙智能体框架 2.0、系统智能体小艺 (百度百科「HarmonyOS 7」「Agent 亲和系统架构」等公开条目)。
  • 复杂任务成功率超 90%:鸿蒙智能体框架 2.0 公开口径(同上)。
  • 小艺 2100+ 系统能力、500+ 伙伴精选 Skill、2000+ 鸿蒙智能体: HDC 2026 现场报道(雷科技等公开报道)。
  • SDK 26:100+ Kit、8 万 + API:华为开发者官网《HarmonyOS 7 (API 26) 新能力一览》。
  • Agent 开发范式(@Agent / AgentSession / A2A): 公开技术教程(CSDN,2026-08),含鸿蒙 AgentSession 用法及 A2A 等业界协议对照, 本文仅作范式参照,不以此给鸿蒙能力背书。
  • 超丝滑方舟引擎(性能大模型,启动 +22%、跳转 +25%):HDC 2026 公开数据。
  • 星河互联架构 250MB/s、分布式软总线 8ms 级连接:公开资料与母篇。
  • 星盾安全(信通院增强级端云协同 AI 安全认证;AI 风险识别「卓越级」):公开资料。
  • Agent 长任务链工程实践(状态管理 / 幂等 / 检查点 / 熔断降级):公开技术文章(2026-09 至 2026-11,多篇工程复盘)。 本文的工程参数建议取自其共性做法,数值为本文建议初值,非其原始值。

以上数据对应的原始链接与最新口径,请以华为官方、信通院最新发布为准。 本篇未对鸿蒙系统的内部兜底实现做任何断言。


附录 C · 审稿记录(本篇不藏刀)

轮次来源发现处理落点
外部审稿 · 第一刀同行挑刺assertPrecondition 首轮 currentVer=null 误杀(死循环)采纳,改写为「唯一硬拦 = 未确认;续跑才比上轮版本」§2.2.1
外部审稿 · 第二刀同行挑刺withTimeout 无 try/catch,超时崩出链外,degrade 走不到采纳,补 catch + 喂熔断 + 先落 intent 检查点§2.2.3
外部审稿 · 第三刀同行挑刺指「幂等键与闸门版本不同步」诊断采纳,修复驳回:压平成一个数会吞确认语义、复活首轮误杀;改为版本双轨§2.2.1
V1.9 · 第一刀自审task.done / task.pending 未从检查点快照回写,续跑丢步重发采纳,派生即回写 + resume() 以检查点为事实源§2.2.5
V1.9 · 第二刀自审超时重试 bumpVersion 导致 idemKey 漂移,服务端去重失效采纳,thisVer 从 intent 检查点读回、仅回读后推进§2.2.1 铁律 2
V1.9 · 第三刀自审§2.2.2 引言重复两遍已清理§2.2.2

原则:审稿人也得被审稿。第三刀的方向是对的(接缝真实存在),但它的修复会把第一刀刚修好的东西拆回去—— 所以本篇记录的是「哪处是真洞、哪处是误判、为什么拒」,而不是「谁挑的都照单全收」。 这本身,就是空圈自反在这一稿里的落点。

────────────────────────────────────────

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐