
RAG 应从原始来源开始,而不是从分块开始
2026年8月1日指南

当模型工作超过 HTTP 生命周期时,用回执、幂等、终态、重试与计费组成可运营的写入协议。
记忆提取不是普通数据库插入。客户端超时后,模型供应商仍可能已经接受任务;队列可能重复投递;worker 也可能在提交记录后、确认消息前崩溃。如果 API 把这一切伪装成一次同步请求,客户端就无法判断应该重试、等待还是报警。
可靠的写入协议必须把“已接受”和“已完成”分开。HTTP 请求创建唯一命令身份并返回回执;持久任务拥有执行过程;终态事件拥有最终结果。
假设客户端提交推断记忆并等待五秒,供应商调用用了六秒。第五秒客户端看到超时,第六秒 worker 提交了两条记忆。如果客户端没有稳定命令身份就重试,系统可能再次推理并产生重复;如果完全不重试,用户又会以为写入丢失。
协议必须让这些状态可区分:
| 状态 | 它能证明什么 | 客户端的安全动作 |
|---|---|---|
| Accepted | 命令已经持久记录 | 保存回执并观察事件 |
| Pending | 目前没有 worker 持有有效租约 | 等待;修复任务或分发器可以重新认领 |
| Running | 一个 worker 持有未过期租约 | 不要创建第二条命令 |
| Succeeded | 规范记录及必要状态已经提交 | 读取结果 |
| Failed | 自动执行到达不可继续的错误 | 检查错误;必要时显式授权重试 |
FishMem Cloud 会验证请求、绑定已认证工作区、计算规范化命令哈希、声明幂等键、预留额度,并创建一条 memory_infer 操作任务。只有完成这些步骤后才分发工作。HTTP 返回 202,是因为系统已经接受对命令的责任,而不是因为工作已经结束。
任务负载携带结构化作用域、推理输入、幂等身份和托管用量授权,即使原始 HTTP 请求早已消失也能执行。成功完成后,持久任务里的敏感原始输入会被命令指纹和审计、重放所需的最小结果证据替代。
幂等键不是“以后帮我去重”的提示,而是规定一个调用意图只有一个身份。
哈希应覆盖语义命令字段,而不是传输噪音。作用域、推理模式、消息内容和记忆选项会改变命令;请求编号、连接时间和重试计数通常不会。
Cloudflare Queue、定时任务或其他分发器可以唤醒 worker,但投递消息不能是任务存在的唯一证据。消息会重复、延迟或耗尽。持久任务需要记录尝试次数、状态、租约所有者、租约过期时间、下次尝试、终态错误和最终结果。
worker 通过比较并交换的语义认领任务。worker 崩溃后,另一个 worker 可以接管过期租约;队列消息没到时,定时修复会找到 pending 任务重新分发。两条路径最终都汇聚到同一个操作身份。
重新调用模型可能得到不同事实。在任何规范写入发生前,这种变化也许可以接受;发生部分提交后就不安全。FishMem 核心日志会先冻结稳定记录 ID 与待执行变更计划,再完成各类投影。重试时重放相同计划,而不是产生第二种解释。
操作日志分别跟踪规范状态和投影状态。如果记录已经提交但向量写入失败,重试会为现有记录修复向量,不会再添加一次记忆。
客户端不应依赖读取 worker 日志来判断结果。Event API 提供持久任务的隐私安全投影,包含状态、尝试次数、时间、错误与结果引用。SDK 可以提供等待完成的便利方法,但任何保留事件 ID 的客户端都能直接观察底层资源。
错误类型要稳定到足以驱动决策:
托管推理不能让任务状态和资金状态各说各话。FishMem 在入队前预留所需额度;终态成功时只结算一次;终态失败时释放预留并在请求账本记录退款。人工重试必须在执行前重新授权,旧失败任务不是对未来额度的无限领取权。
这样可以避免三种结果:没有运行却收费、成功提交后又退款,以及模糊重试造成重复收费。
| 失败 | 自动重试? | 原因 |
|---|---|---|
| 供应商在返回结果前超时 | 有上限,且命令仍安全时 | 可能是暂时错误;幂等任务控制重复 |
| 结构化输出无效 | 仅按明确提取策略 | 重复提示未必能修复语义不匹配 |
| 额度不足 | 否 | 需要新的授权或套餐变更 |
| 投影写入失败 | 是 | 修复已有规范记录 |
| 幂等冲突 | 否 | 调用方用一个身份提交了两条命令 |
infer=false 是同步确定性写入,因为调用方已经提供要保存的记录;infer=true 默认异步,因为模型工作可能超出 HTTP 生命周期并独立失败。混合两条路径,要么会让确定性写入承担不必要复杂度,要么会让推断写入假装同步完成。