异步任务(SEP-1686):长跑工作的「先调用、后取结果」


文档摘要

异步任务(SEP-1686):长跑工作的「先调用、后取结果」 本节摘要:真实的 Agent 工作要花几分钟到几小时:CI 运行、深度研究综合、批量导出。同步工具调用会掉线、超时或冻住 UI。SEP-1686 于 2025-11-25 合入,新增 Tasks 原语:任何请求都可被增强为 task,结果可稍后拉取或经状态通知流式获取。漂移提示:Tasks 在 2026 上半年仍是实验性的,SDK 表面仍围绕规范设计中。 学习目标 阅读完本节,你应当能够: 判断何时把工具从同步提升为任务增强(服务端工作 >30 秒)。 走完任务生命周期: → → / / 。 持久化任务状态,使崩溃不丢在途工作。 正确轮询 并取 。 一、问题与直觉 一个 工具跑一个多分钟的抽取管线。

异步任务(SEP-1686):长跑工作的「先调用、后取结果」

本节摘要:真实的 Agent 工作要花几分钟到几小时:CI 运行、深度研究综合、批量导出。同步工具调用会掉线、超时或冻住 UI。SEP-1686 于 2025-11-25 合入,新增 Tasks 原语:任何请求都可被增强为 task,结果可稍后拉取或经状态通知流式获取。漂移提示:Tasks 在 2026 上半年仍是实验性的,SDK 表面仍围绕规范设计中。

学习目标

阅读完本节,你应当能够:

  1. 判断何时把工具从同步提升为任务增强(服务端工作 >30 秒)。
  2. 走完任务生命周期:workinginput_requiredcompleted / failed / cancelled
  3. 持久化任务状态,使崩溃不丢在途工作。
  4. 正确轮询 tasks/status 并取 tasks/result

一、问题与直觉

一个 generate_report 工具跑一个多分钟的抽取管线。同步模型下三条路:

  1. 把连接开三分钟——远程传输掉线、客户端超时、UI 冻住。
  2. 立即返占位符,要客户端轮询自定义端点——破坏 MCP 统一性。
  3. 发后不管——无结果。

都不好。SEP-1686 加了第四条:任务增强。任何请求(典型是 tools/call)可被标记为 task,服务端立即返一个 task id,客户端轮询 tasks/status,完成时取 tasks/result,服务端状态跨重启存活。

二、从零实现

任务增强

一个请求通过设 params._meta.task.required:true(或 optional:true,服务端决定)成为 task。服务端立即响应:

{ "jsonrpc": "2.0", "id": 1, "result": { "_meta": { "task": {"id": "tsk_9f7b...", "state": "working", "ttl": 900000} } } }

ttl 是服务端保留状态的承诺;ttl 过后任务结果被丢弃。

每工具 opt-in

工具注解可声明 task 支持:

  • taskSupport:"forbidden"——本工具始终同步,快工具安全。
  • taskSupport:"optional"——客户端可请求任务增强。
  • taskSupport:"required"——客户端必须用任务增强。

generate_report 会是 required,notes_search 会是 forbidden

状态

working -> input_required -> working (经 elicitation 循环) working -> completed working -> failed working -> cancelled

状态机是只追加的:一旦 completed/failed/cancelled,任务即终态。

方法

  • tasks/status {taskId}——返回当前状态与进度提示。
  • tasks/result {taskId}——阻塞,或未完成则返 404。
  • tasks/cancel {taskId}——幂等;终态忽略。
  • tasks/list——可选;枚举活跃与最近完成的任务。

流式状态变化

服务端支持时,客户端可订阅状态通知:

server -> notifications/tasks/updated {taskId, state, progress?}

流式而非轮询的客户端 UX 更好。轮询始终作为最小表面被支持。

持久状态

规范要求声明 task 支持的服务端持久化状态:ttl 内的崩溃不应丢已完成结果。存储从 SQLite 到 Redis 到文件系统皆可。本节脚手架用文件系统。

def save_task(task): path = f"/tmp/lesson-13-tasks/{task.id}.json" atomic_write(path, json.dumps(task.__dict__)) # 跨重启存活 def load_all_tasks(): return [Task(**json.loads(read(p))) for p in glob("/tmp/lesson-13-tasks/*.json")]

取消语义

tasks/cancel 幂等。任务在执行中时,服务端尝试停止(检查执行器协作式取消);若已终态,请求是 no-op。

崩溃恢复

服务端进程重启时:

  1. 加载所有持久化的任务状态。
  2. 把进程已死的 working 任务标记为 failed,错误码 CRASH_RECOVERY
  3. 在 ttl 内保留 completed/failed/cancelled

异步任务 + 采样

任务本身可调 sampling/createMessage。长跑研究任务就是这么工作的:服务端的任务线程按需采样客户端模型,同时客户端 UI 把任务显示为 working 配周期进度更新。

为什么这是实验性的

SEP-1686 在 2025-11-25 出货,但更广的路线图列出三个开放问题:持久订阅原语、子任务(父子任务关系)、结果 TTL 标准化。预期规范在 2026 全年演进。生产代码应只把 Tasks 当常见情况稳定,并对未来子任务的 SDK 变更加守卫。

三、框架对比

维度 同步工具 任务增强(SEP-1686)
连接占用 全程 仅立即返回
超时风险
跨重启 ttl 内存活
取消 幂等 tasks/cancel
适合 <30 秒 分钟~小时级

💡 心法:taskSupport:required 用在 >30 秒的工具;forbidden 用在快工具;状态机只追加,终态后一切 no-op。生产持久化用 SQLite/Redis,别用裸文件系统。

四、可复用产物

本节产出 outputs/skill-task-store-designer.md——给定一个长跑工具(研究、构建、导出),它设计任务存储(状态形状、ttl、持久性)、选对 taskSupport 标志、画进度通知。

code/main.py 实现一个持久任务存储(文件系统后端)与一个后台线程跑的 generate_report 工具。客户端调工具立即拿 task id,worker 更新进度时轮询 tasks/status,完成时取 tasks/result。取消可用;崩溃恢复通过杀 worker 线程再重载状态模拟。

五、练习

  1. 跑完整流:运行 code/main.py,启动一个 generate_report 任务,轮询 status,再取结果。

  2. 中途取消:运行中加一个 tasks/cancel 调用,验证 worker 遵守它且状态变 cancelled

  3. 模拟崩溃恢复:杀 worker 线程,重启加载器,观察 CRASH_RECOVERY 失败模式。

  4. 换 SQLite:把存储扩展到 SQLite,持久性收益相同,但查询选项打开(列出会话 X 的所有任务)。

  5. 读路线图:读 MCP 2026 路线图贴,找出最可能影响来年 SDK API 设计的那个 Tasks 相关开放问题。

本节要点回顾

  1. 同步工具扛不住长跑:掉线/超时/冻 UI;SEP-1686 用任务增强(立即返 task id,后取结果)解决。
  2. 任务增强:_meta.task.required/optional,服务端立即返 {id, state, ttl}
  3. taskSupport 三态:forbidden(快工具)、optionalrequired(长跑工具)。
  4. 状态机只追加:workinginput_required(经 elicitation 回 working)→ completed/failed/cancelled 终态。
  5. 四方法:tasks/status 轮询、tasks/result 取/404、tasks/cancel 幂等、tasks/list 可选。
  6. 流式 vs 轮询:notifications/tasks/updated 推送 UX 更好;轮询是最小表面。
  7. 持久状态必需:ttl 内崩溃不丢;存储 SQLite/Redis/文件系统皆可。
  8. 崩溃恢复:working 且进程死 → failed + CRASH_RECOVERY;终态在 ttl 内保留。
  9. 任务可调采样:长跑研究任务靠任务线程按需采样客户端模型。
  10. 实验性:子任务、持久订阅、TTL 标准化三个开放问题,2026 全年演进,生产代码加守卫。

下一节,我们看 MCP Apps——把交互式 UI(ui://)作为第四种内容块,让服务端能在 host 里渲染富组件。


发布者: 作者: Rohit Gupta 转发
评论区 (0)
U