任务已经取消了,钱还在往外跑——你遇到的情况,本质是"取消了任务"不等于"撤销了支付授权"。
打个比方:你叫停了一辆正在送货的卡车,但没收回司机手里的钥匙,司机到了目的地还是能开门卸货。任务停了,代理手里的那把签名钥匙可能还活着。
为什么停了任务,付款还在继续
AI 代理的支付能力,来自它持有的一把"会话钥匙"(session key)。这把钥匙的权限和任务是独立的。
任务取消只是停止了"让代理做什么"的指令流,但钥匙本身还在链上注册着,没被撤销。如果代理的代码里没有检查"任务是否已取消"就继续执行之前的授权,或者你在取消任务时没有顺手撤销钥匙,它就还能继续签名付款。
核心问题就一个:你停的是计划,不是权限。
三步立即停止待处理付款
步骤 1:撤销代理的支付授权(最快)
[做什么] 立刻让那把钥匙失效,不管代码怎么跑,钥匙不能用就付不了款。
[怎么做] 取决于你用的钱包工具:
Nevermined:Dashboard 里点一下撤销,或者调
DELETE /api/v1/delegation/{delegationId}接口。没有缓存、没有宽限期,撤销立即生效,任何在途的校验/结算请求都会返回DELEGATION_INACTIVE。(来源:Nevermined 官方文档)CHIPI SDK:调用
revokeSession()方法,这会发起一笔链上交易把会话标记为已撤销。可以查返回的txHash确认上链状态。(来源:CHIPI SDK 文档)通用规则:在 Dashboard 或后台管理里找到"会话管理"或"支付授权"页面,把对应代理的授权记录删除或禁用。
[完成标准] 查看会话状态,显示为 revoked 或 inactive。如果代理正在执行付款,会收到授权失效的报错(如 DELEGATION_INACTIVE)。
步骤 2:通过生命周期钩子拦截(如果你的框架支持)
如果你用 x402 协议,可以在不撤销钥匙的情况下,通过钩子拦截特定任务的付款请求。
[做什么] 在代码层面拦截正在运行的付款流程,让已取消任务的请求在付款前被中止。
[怎么做] 用 x402 的客户端钩子或 MCP 钩子:
client.onBeforePaymentCreation(async ({ taskId, amount }) => {
// 检查这个任务是否已被取消
if (await isTaskCancelled(taskId)) {
return { abort: true, reason: "Task was cancelled" };
}
});或者 MCP 客户端的 onPaymentRequired 钩子,在工具调用触发付款前拦截:
mcpClient.onPaymentRequired(async ({ toolName, paymentRequired }) => {
if (blocklist.has(toolName) || taskCancelled) {
return { abort: true };
}
});(来源:x402 官方文档)
[完成标准] 已取消任务触发付款时,日志里出现 abort: true 记录,付款没有被提交。
步骤 3:核对钱包余额变化
[做什么] 确认撤销已生效,没有漏网之鱼。
[怎么做]
查代理钱包的交易记录,看撤销操作的时间点之后有没有新的扣款
如果没有,说明拦截成功
如果还有,说明代理可能用了另一把没撤销的钥匙,或者支付请求在撤销前已经提交上链了
高危提醒:已签名的交易是拦不住的。 如果代理在撤销之前已经用钥匙签了一笔交易,只是还没来得及广播,你撤销钥匙之后它仍然可以把那笔已签名的交易发出去。撤销只阻止新签名,不追回已签名的支票。如果你发现撤销之后还有扣款,去查那笔交易的时间戳,可能是在撤销之前签的。
核验收尾
在 Dashboard 里确认会话状态从
active变为revoked或inactive查看钱包交易记录,撤销时间点之后没有新的付款
如果用了钩子,日志里能看到
abort相关记录
核验渠道: 任务取消后触发一次测试付款(如果安全的话),确认返回的是授权错误而不是付款成功。



