跳到主要内容

幂等性设计

核对日期:2026-05-09。

1. 定义与边界

幂等性(Idempotency)指同一个操作在相同业务语义下执行一次或多次,最终可观察结果一致。Agent 系统中的幂等性重点覆盖工具副作用、队列重试、API 重试、回放调试和人工审批后的继续执行。

幂等不是“不重试”,也不是“所有操作都天然安全”。它需要业务键、去重存储、状态机和副作用边界共同保证。

2. 为什么重要

Agent 经常会因为模型超时、工具超时、队列重复投递、客户端重试而重复执行某一步。如果这一步是查询,影响较小;如果是创建订单、退款、发邮件、删除数据,就可能造成严重事故。

3. 核心机制

幂等键应由业务语义决定:

idempotency_key = tenant_id + operation + business_object_id + semantic_step_id

示例:

{
"operation": "ticket.create",
"idempotency_key": "tenant_a:ticket.create:run_01:step_4",
"request_hash": "sha256:...",
"status": "succeeded",
"result_ref": "ticket_123",
"created_at": "2026-05-09T10:00:00Z"
}

处理流程:

4. 架构模式

模式适用场景注意点
客户端幂等键对外 API,客户端会重试服务端仍要校验 request hash。
服务端业务键Agent 内部步骤需要稳定 step id。
数据库唯一约束创建类操作错误处理要返回既有结果。
Outbox/Inbox跨服务消息适合事件驱动和补偿。

5. 工程实现

工具网关幂等包装:

def call_tool_idempotently(tool_name, payload, key):
existed = idem_store.get(key)
if existed and existed.request_hash == hash_payload(payload):
return existed.result
if existed:
raise IdempotencyConflict("same key with different payload")

idem_store.reserve(key, request_hash=hash_payload(payload))
try:
result = tool_client.call(tool_name, payload)
idem_store.mark_success(key, result)
return result
except Exception as exc:
idem_store.mark_failed(key, retryable=is_retryable(exc))
raise

6. 生产实践

  • 幂等记录的 TTL 要覆盖客户端和队列最大重试窗口。
  • 对“处理中”的幂等键设置租约,避免 worker 崩溃后永久卡住。
  • 对同一幂等键但不同请求体返回冲突,而不是悄悄复用结果。
  • 幂等键和 trace id 关联,便于排查重复执行。
  • 对外部不支持幂等的 SaaS,在本地工具网关做预占和补偿。

7. 常见反模式

  • 用随机 UUID 作为每次重试的幂等键,等于没有幂等。
  • 只在 API 层做幂等,worker 和工具层仍然会重复副作用。
  • 幂等键不包含租户,造成跨租户冲突或信息泄漏。
  • 不保存结果,只保存“执行过”,导致重试方无法拿到一致响应。
  • 把所有失败都缓存,导致临时错误无法恢复。

8. 评测方法

  • 重复请求测试:同一请求发送 2 到 10 次,最终只产生一次副作用。
  • 并发测试:多个 worker 同时处理同一 key,只有一个成功执行。
  • 冲突测试:同一 key 不同 payload 应返回冲突。
  • 崩溃测试:副作用前后分别 kill 进程,验证恢复策略。

9. 安全与治理

  • 幂等记录可能包含业务对象引用,要按租户隔离。
  • 不把完整敏感 payload 存入幂等表,使用 hash 和受控引用。
  • 高风险工具调用强制要求幂等键;缺失则拒绝执行。
  • 回放模式默认禁用真实副作用,只验证幂等路径和 mock 结果。

10. 权威资料

11. 二次精修:幂等键分层

Agent 的幂等性要按“请求、任务、工具、副作用”分层设计。一个全局 key 不够,因为同一 Agent run 内可能有多个可重试步骤。

层级幂等键来源存储位置去重结果
API request客户端 key 或业务请求 hashAPI 幂等表返回首次响应
Agent taskrun_id + step_index任务表不重复执行同一步
Tool calltool_name + normalized_args + business_idtool call ledger返回已确认结果
External side effect业务单号、支付单号、工单号下游系统下游保证唯一
Notificationevent_id + channel + recipient通知表不重复通知用户
CREATE TABLE idempotency_ledger (
scope TEXT NOT NULL,
idempotency_key TEXT NOT NULL,
status TEXT NOT NULL,
request_hash TEXT NOT NULL,
response_ref TEXT,
expires_at TIMESTAMP NOT NULL,
PRIMARY KEY (scope, idempotency_key)
);

12. 幂等执行流程

13. 与重试、回放、审计的关系

  • 重试必须依赖幂等键,否则“提高成功率”会变成重复下单、重复退款、重复发信。
  • 回放环境应使用只读工具替身,或强制所有副作用工具命中 ledger 的历史结果。
  • 审计日志要记录 request hash,发现同一 key 携带不同参数时应拒绝而不是覆盖。
  • 评测要构造重复投递、worker 崩溃后重试、下游超时但实际成功等样本。
  • 安全治理要限制幂等键中出现 PII,建议使用业务 ID 加 HMAC,而不是明文用户信息。

14. 验收指标

指标目标
Duplicate Side Effect Rate0
Idempotency Conflict Rate可观测,异常升高告警
Retry Success Without Duplicate高于 99%
Ledger Lookup Latency P95不成为主链路瓶颈
Expired Key Replay Blocked高风险业务必须拦截

15. 补充权威资料