#AI Agent#MCP#DevOps

长运行工具调用:Operation、Poll 与 Cancel 的终态协议

初始请求超时后,工具可能仍在服务端运行;发出取消也不等于副作用已停止。本文为单次长运行工具调用建立 operation 身份、轮询水位、取消竞态和唯一终态接受点。

本文要点

  • 主题聚焦:AI Agent、MCP、DevOps
  • 适合人群:独立开发者、全栈工程师、AI 应用开发者
  • 核心价值:快速理解背景、实践路径、常见误区和工程建议
作者 @admin·发布于 2026年7月13日·更新于 2026年7月20日

上传分析、生成报表或批量变更可能运行十分钟。若客户端在 30 秒后只得到超时,它并不知道 Server 没开始、仍在处理,还是已经完成但响应丢失。重新调用会制造第二个操作;点击取消后立即把本地节点标成失败,又可能让稍后到达的成功结果悄悄触发下游步骤。

MCP 超时、重试与幂等说明单次请求何时可重试,Agent 长任务工作流覆盖跨步骤 Agent 的检查点。本篇把边界缩到一个长运行工具调用:如何获得 operation 身份、等待、补充输入、取消,并把唯一终态交给调用节点。

先协商能力,再提交 operation

MCP Tasks 在 2025-11-25 规范中引入,而且目前仍标为 experimental。客户端必须按固定协议版本做 capability negotiation;Server、Client 或该工具未声明支持时,不能假设 tasks/get、tasks/cancel 存在,应使用该工具明确发布的同步上限或拒绝长任务。Google AIP-151 的 long-running operation 提供了另一种 operation 资源形态;两者字段不同,适配层不能把相似 URL 当成同一协议。

执行器保存 toolOperation.v1:callNodeId、请求摘要、工具与 descriptor 版本、主体、operation/task ID、协议适配器版本、提交幂等键、poll cursor、服务端状态、输入轮次、取消 generation、过期时间和最终结果摘要。初次提交状态为 SUBMITTING。只有服务端返回可查询 ID,或以同一提交键查询到已存在 operation,才进入 WORKING;连接在两者之前断开则进入 SUBMISSION_UNKNOWN,必须先按键查询,不能生成新键盲重试。

text
SUBMITTING -> WORKING <-> INPUT_REQUIRED
SUBMITTING -> SUBMISSION_UNKNOWN -> WORKING | NOT_FOUND_SAFE
WORKING | INPUT_REQUIRED -> CANCEL_REQUESTED
WORKING | INPUT_REQUIRED -> TERMINAL_OBSERVED
TERMINAL_OBSERVED -> FETCHING_RESULT -> ACCEPTED
CANCEL_REQUESTED -> CANCELLED_ACCEPTED | TERMINAL_OBSERVED

MCP Task 的状态包含 working、input_required、completed、failed 与 cancelled。本地附加状态不应伪装成协议状态。INPUT_REQUIRED 暂停自动 poll,把服务端请求、operation ID、输入 schema 摘要和期限交给Agent 人工审批门;回复必须绑定本次 input round。poll 按 Server 建议间隔并加抖动,受总等待预算、最大 QPS 和过期时间约束;HTTP 202 只说明请求已接受处理,并不证明业务完成。

Cancel 是请求,不是逆向完成

发出 cancel 时先以 CAS 提升 cancelGeneration 并记录 CANCEL_REQUESTED,再发送协议请求。按 MCP Tasks 合同,合法的 tasks/cancel 必须在响应前把 Task 转为不可逆的 cancelled;因此成功响应本身就是取消终态证据。若 Task 已先进入 completed 或 failed,Server 必须以 -32602 拒绝取消,客户端随后读取既有终态,不能改写为 cancelled。一旦取消赢得竞态,即使底层执行后来完成,Task 也必须保持 cancelled;可能残留的外部效果另记 EFFECT_RECONCILIATION_REQUIRED,不能把迟到完成接纳为协议成功。Agent 运行时状态机只消费该事实。

tasks/get 只返回 Task 状态;看到 completed、failed 或 cancelled 后还存在结果获取阶段。MCP 的 tasks/result 才返回原请求本应返回的结果或 JSON-RPC error;对非终态调用它还会阻塞。执行器对 completed/failed 必须取得并验证该结果,再进入唯一接受点 acceptTerminal。事务同时匹配 call node、request digest、Task ID、工具版本、execution epoch、cancel generation、终态和 result digest,随后写 terminal receipt 与唯一 ready outbox。cancelled 可由成功 cancel 响应接纳;若结果在删除前可取则附在审计 receipt,但绝不能当成功 payload。Agent 工具输出防线继续验证返回内容。

operation 过期或 get 返回 404 时要区分 NEVER_CREATED、EXPIRED_WITH_RECEIPT 和 UNKNOWN。只有服务端以提交键证明从未创建,才允许重新提交;已过期但有完成 receipt 可继续接受;其余进入人工对账。客户端断开只停止本地等待,除非合同明确声明,否则不能自动等价为服务端 cancel。

让每个竞态都进入测试

故障注入覆盖:Server 创建后丢失初始响应、两个 poller 乱序返回、input_required 重放、完成与取消同时到达、取消 ACK 丢失、tasks/get 完成后 tasks/result 丢失或截断、旧 execution epoch 回调、Task ID 错误复用、过期前后 404,以及 poll 429/503。断言每个 call node 最多一个 terminal receipt、结果未取回时 completed 不推进、成功取消后迟到完成不推进,所有 UNKNOWN 都可按 Task 或提交键查询。

门禁要求一万组时序排列的终态分歧为 0;重复提交产生第二个 operation 为 0;poll 放大不超过配置 QPS;取消确认 p99 与 UNKNOWN 对账时限分别低于 60 秒和 15 分钟;100% 下游推进能回到 terminal receipt。上线先只为无副作用的报表工具记录 shadow operation,再让 5% 长任务使用新适配器。回滚时停止新建 operation、提升 execution epoch,并让旧执行器仅接管同一 operation 账本中的在途项;不能切回“超时就重调”。实验性 MCP Tasks 合同变化时,按协议版本禁用对应 adapter,保留查询和对账能力直到所有旧 operation 终结。

Related

相关推荐