一把 key 上的幂等:让六后端里的每次调用都能安全重放
本文讲解在多后端 LLM API 聚合场景下,如何通过客户端幂等键与去重存储设计,确保重试和续跑不会导致重复计费。涵盖幂等键生成、传递、存储与清理策略,以及跨后端调用时的注意事项。
在聚合多个 LLM 后端时,一次用户请求可能因为超时、网络抖动或上游限流而被重试或续跑。如果缺少幂等控制,同一个逻辑操作可能被多次执行,导致重复扣费或重复处理。本文讨论如何通过客户端幂等键与去重存储设计,让每次调用都能安全重放。
为什么需要客户端幂等键
聚合站通常不会在多个后端之间做请求去重,因为不同后端的响应格式、计费方式和错误语义不同。去重责任落在客户端:客户端需要为每个逻辑操作生成唯一标识(幂等键),并在重试时复用同一个键。这样,服务端或客户端存储就能识别重复请求,避免重复落账。
幂等键的生成原则
- 唯一性:每个逻辑操作(如一次用户提问)生成一个全局唯一的键,例如 UUID v4 或基于业务 ID 的哈希。
- 稳定性:同一个逻辑操作在重试、续跑或跨进程传递时,键必须保持不变。
- 不可预测性:避免使用可枚举的键,防止恶意重放。
- 与业务关联:键可以包含业务标识(如用户 ID、会话 ID),便于排查和清理。
在请求中传递幂等键
通常通过 HTTP 头(如 Idempotency-Key)或请求体字段传递。聚合站应将此键透传给后端,或至少记录在聚合层的日志中。如果后端支持幂等键(部分 API 支持),可以直接利用;若不支持,则依赖聚合层或客户端的去重存储。
去重存储的设计
去重存储的核心是记录“键 -> 处理状态与结果”。设计时需考虑:
- 存储位置:客户端本地(如内存、SQLite)或服务端(如 Redis、数据库)。客户端存储简单但多设备不同步;服务端存储可跨设备但增加延迟。
- 键的粒度:以幂等键为唯一索引,存储请求摘要、响应状态、响应体(或引用)、时间戳。
- 状态机:记录“进行中”、“成功”、“失败”等状态。重试时若键已存在且状态为成功,直接返回缓存结果;若为进行中,可等待或返回冲突;若为失败,根据策略决定是否重试。
- 并发控制:使用锁或原子操作防止同一键并发写入。
- 过期与清理:设置合理的 TTL(如 24 小时),避免存储无限增长。清理策略应结合业务重试窗口。
重试与续跑的流程
- 客户端生成幂等键,查询去重存储。
- 若键不存在,写入“进行中”状态,发起请求。
- 请求成功,更新状态为“成功”并存储结果;失败则更新为“失败”并记录错误。
- 重试时复用同一键,若状态为“成功”直接返回结果;若为“进行中”可轮询或等待;若为“失败”则重新发起并更新状态。
- 续跑(如流式响应中断)时,同样使用原键,并根据已接收的部分内容决定是否重新请求或从断点继续。
跨后端调用的注意事项
- 后端差异:不同后端对相同请求的响应可能不同,幂等键应绑定到具体后端,避免用同一个键跨后端重试导致结果不一致。
- 计费幂等:聚合站按官方价 ×1.3 扣费,贡献 key 按 ×1.1/×1.2 返 USDC。去重存储应确保同一幂等键只产生一次计费事件。
- 错误分类:区分可重试错误(如超时、限流)和不可重试错误(如参数错误)。仅对可重试错误使用幂等重试。
- 日志与审计:记录幂等键与请求的关联,便于对账和排查重复扣费。
小结
客户端幂等键与去重存储是聚合站多后端调用安全重放的基础。通过唯一、稳定的键和状态化的存储,结合合理的过期与并发控制,可以有效避免重试和续跑导致的重复落账。设计时需注意跨后端差异和计费一致性,确保每次调用都能安全重放。