Agent 框架层出不穷,到底哪个值得长期投入?

LangGraph 讲 Checkpoint,OpenAI 讲 ThreadRun,A2A 讲 Task,AG-UI 讲 Event,Deep Agents 又引入 TodoSubagentVirtual Filesystem。名字越来越多,API 越来越像一套套独立世界观。

框架名词在变,但底层问题始终围绕任务、上下文、步骤、事件、状态和产物展开。 如果把这些名词往下拆,会发现它们其实都在回答同一个底层问题:

一个 Agent 任务,如何被启动、携带上下文、持续观测、中断恢复,以足够低的使用成本完成执行,并最终产生产物?

换成协议视角,这个问题可以说得更直接:

一个生产级 Agent Protocol 应该包括什么?为什么这些协议对象会比具体框架 API 更稳定?

我不想每换一个 Agent 框架,就重新学习一套对象体系。我更关心的是,那些跨框架反复出现的稳定边界是什么。

框架会更迭,协议对象会换名字,但生产级 Agent 系统要解决的问题不会消失:

本文的目标不是介绍某一个框架怎么用,而是以 Agent Protocol 为主线,把 Agent Runtime 拆成一组可协议化的对象、操作和状态机。

这里先把边界说清楚:本文所说的 Agent Protocol 不是某一个具体标准,不等于 A2A、AG-UI、LangChain Agent Protocol 或任意单一规范;它指的是 Agent Runtime 对外暴露的一组稳定对象、生命周期操作和状态迁移。具体协议标准和框架 API 是证据,不是本文主线。

我前面几篇 Agent 实践文章中,如何快速创建领域Agent - OneAgent + MCPs 范式 讨论的是如何把 Manus / Claude Code 式 Loop Agent 带进企业业务场景;从Claude Code到 OneAgent:如何做好上下文工程 讨论的是长任务 Agent 如何通过 Plan / Offload / Isolate / Retrieve / Reduce / Cache 管理上下文。本文再往下抽一层:这些实践背后,哪些对象和边界会沉淀为 Agent Runtime 的稳定协议语言?

协议告诉我们外部世界需要什么契约,Runtime 告诉我们内部如何实现这些契约。Harness 则保证这些 Runtime 能力已经被打包成足够易用的默认体验。理解这层关系后,再看新框架时,就能快速判断:

  • 它只是换了一套 API 名字,还是解决了一个真实的 Runtime 问题?
  • 它强化的是执行模型、状态管理、工具协议,还是流式事件?
  • 它是暴露底层能力,还是把一整套长任务 Agent 能力封装成开箱即用的 harness?
  • 它的设计是长期趋势,还是阶段性流行?

我认为:

  1. Agent Runtime 的核心不是模型调用,而是任务生命周期管理
  2. Thread / Run / Step / Event / Artifact / Checkpoint 会成为跨框架的稳定对象
  3. 执行模型不会统一:Runtime Loop 承载方式和编排协议会长期分层演进
  4. 真正区分玩具 Agent 和生产 Agent 的,是状态持久化、中断恢复、可观测性和可评测性
  5. 值得看的不是某个框架 API,而是协议边界和 Runtime 抽象

读这篇文章前,请先理解 6 个对象

对象人话解释它回答的问题
Thread / Session一段长期上下文这是谁的哪段任务?
Run / Task一次具体执行这次具体跑了什么?
Step执行中的一个可观测步骤哪一步调用了模型、工具或子 Agent?
Event执行过程中的进展变化现在发生了什么?
ArtifactAgent 产出的正式结果结果在哪里,由哪次执行产生?
Checkpoint可以恢复的执行快照失败或中断后从哪里继续?

这 6 个对象,是理解 Agent Runtime Protocol 的入口。

围绕这 6 个对象,生产级 Agent Protocol 至少还要表达 stream / interrupt / resume / cancel / retry 这些生命周期操作。后文所有框架对比、Runtime 分析和 Harness 讨论,都应回扣到这组对象与操作:它们分别解决任务创建、上下文携带、步骤执行、事件观察、中断恢复、产物沉淀和评测审计的问题。

1. 先定义 Agent Protocol 的边界

1.1 三层概念:标准、对象、Runtime 能力

讨论 Agent Protocol 时,最容易把三层东西混在一起:

层级例子解决的问题
具体协议标准A2A、AG-UI、LangChain Agent Protocol、AITP、ACP不同系统如何通信,如何描述任务、消息、事件和产物
通用协议对象Thread、Run、Step、Event、Artifact、Checkpoint外部世界如何稳定理解一次 Agent 任务
Runtime 实现能力状态持久化、中断恢复、可恢复流、权限控制、可观测性Runtime 内部如何兑现这些对象和状态机

本文重点讨论第二层:通用协议对象。具体协议标准和框架实现只作为证据,用来说明这些对象正在跨系统收敛。

1.2 Runtime Protocol:外部世界如何理解一个 Agent

Agent Runtime Protocol 是 Agent Runtime 暴露给外部世界的契约。它回答的不是”模型如何思考”,而是:

  • 如何启动一次任务 :创建 Thread、Task、Run,或发送一条 Message
  • 如何携带上下文 :历史消息、文件、结构化数据、参与者、能力声明
  • 如何观察进展 :状态变更、流式事件、Artifact 增量、Trace
  • 如何中断和恢复 :需要输入、需要授权、取消、重试、继续执行
  • 如何拿到结果 :最终消息、Artifact、结构化输出、错误信息

一句话:Protocol 是 Runtime 的外部边界,Runtime 是 Protocol 的内部实现

因此讨论 Agent Runtime 时不应该只讨论内部编排,也要讨论它被什么协议对象驱动,以及它向外承诺什么状态机。换句话说:Runtime 是内部能力,Protocol 是外部可依赖的边界

1.3 Runtime:模型调用之外的执行系统

Agent Runtime 是 Agent 的执行环境,负责:接收输入 → 调用 LLM → 执行工具 → 管理状态 → 产出结果。

不同框架对 Runtime 的定义边界不同:LangGraph 包含了从编排到持久化的完整栈;OpenAI Assistants 把整个 Runtime 藏在服务端;AutoGen 更强调多 Agent 对话组织。但它们都必须回答同一组问题。

更精确地说,Agent Runtime 不是”一次模型调用”,而是模型调用之外的那层执行系统。它至少要管理五类事情:

  • 生命周期:一次任务如何开始、运行、暂停、恢复、结束
  • 上下文:哪些消息、文件、状态、外部资源对当前执行可见
  • 调度:下一步调用模型、工具、子 Agent,还是等待人类
  • 控制面:权限、Guardrail、取消、超时、预算、并发限制
  • 数据面:状态快照、事件流、Trace、Artifact、成本数据如何流动

这也是为什么 Responses API 不是 Runtime,而 OpenAI Agents SDK 是更高层 Runtime:前者主要给你模型和工具调用能力,后者开始接管循环、工具执行、Handoff、Session、Guardrail、Tracing 等运行时职责。

1.4 最小生命周期:一个 Agent 任务到底经历了什么

一次任务进入生产环境后,会依次经过创建、领取、执行、暂停或取消,再提交终态。

Thread/Session 描述长期上下文,Run 描述一次具体执行。超时、取消、Trace、成本、权限审批和最终结果都需要绑定到明确的 Run

Protocol 对象Runtime 含义典型来源
Agent / Assistant可被调用的能力提供者A2A Agent Card、OpenAI Assistant、LangGraph assistant
Thread / Context多轮上下文边界OpenAI Thread、AITP Thread、A2A Context
Task / Run一次执行边界A2A Task、OpenAI Run、LangGraph Run
Message / Part输入输出内容单元A2A Message/Part、AITP Message
Artifact任务产物A2A Artifact、文件、报告、代码 diff
Event进展增量SSE event、status update、artifact update
Checkpoint / State可恢复状态LangGraph Checkpoint、State Snapshot

WORKING -> CANCELED 之间可能隔着三台机器:取消请求落到 API-2Run 实际由 Worker-7 执行,后者又派生了三个子 Agent。一条状态箭头没有说明信号怎样找到它们,也没有说明迟到结果如何被拒绝。

下面用 LangGraph Agent Server 作参照,把一次请求经过的持久化、调度、执行和事件传递边界画出来。这不是所有 Runtime 必须照搬的实现。

Client
  │ POST /threads/{thread_id}/runs

API Server ── 创建 Run、保存输入和状态 ──► PostgreSQL

  └── 发送唤醒信号 ──► Redis / Message Broker


                         Queue Worker
                              │ 领取 Run、获得 lease、加载 graph

                              ├──► LLM / Tool / Subagent
                              ├──► PostgreSQL:checkpoint、状态、artifact
                              └──► Redis PubSub:event、cancel signal、heartbeat


                                            API Server ── SSE ──► Client

请求不是先完整上传到 Redis,再由每个进程复制一份状态。API Server 先创建可持久化的 Run;消息系统只负责叫醒 Worker、传递取消信号和转发实时事件,Worker 再根据 run_id 到数据库读取完整输入。Redis 丢掉一条临时通知不应该等于丢掉任务,SSE 断开也不应该等于任务消失。

Run 执行相关的信息会出现在三个位置,但只有一处能承担故障恢复:

状态位置保存什么不应该承担什么
持久化事实源ThreadRun、输入、状态机、Checkpoint、父子任务关系、取消版本依赖某个进程存活的临时执行对象
临时协调层队列唤醒、PubSub、流式事件、heartbeat、短期租约元数据用户数据和唯一一份 Run 状态
Worker 本地状态当前图实例、协程句柄、本地 CancellationToken、尚未提交的结果跨故障恢复所需的唯一状态

一次 Run 会经过下面几个阶段。

  1. API Server 校验请求,创建 Run,把输入和初始状态写入持久化存储。只有这一步成功,客户端才拿到稳定的 run_id
  2. Worker 从队列领取任务并获得一次执行租约。多实例环境需要保证同一次 RunAttempt 只归一个 Worker 所有;Agent ServerPostgreSQL MVCC 约束这一点,而不是靠一把长时间持有的分布式锁。
  3. Worker 执行模型、工具和子 Agent,在步骤边界保存 Checkpoint,同时发布事件。实时事件可以走临时 PubSub;如果协议承诺断线补收,还要额外持久化事件片段。已完成的状态提交不能只存在事件流里。
  4. 执行需要人类输入时进入 INPUT_REQUIRED;收到用户取消时先进入 CANCEL_REQUESTED。前者等待 resume,后者要求整个任务树停止产生新工作。两者都不等于直接杀掉某条 HTTP 连接。
  5. 完成、失败或取消时,Worker 以带版本条件的写入提交终态。提交失败或版本已经变化,就丢弃这份迟到结果,不能把它覆盖到已经取消的 Run 上。

INPUT_REQUIREDCANCEL_REQUESTED 必须显式进入状态机:

SUBMITTED ──► PENDING / QUEUED ──► RUNNING ──► COMPLETED

                                      ├──► INPUT_REQUIRED ──► RUNNING
                                      ├──► CANCEL_REQUESTED ──► INTERRUPTED / CANCELED
                                      ├──► FAILED
                                      └──► TIMED_OUT

用户按下取消到任务进入终态之间存在时间差。模型请求可能仍在网络中,工具可能正在写外部系统,子 Agent 也可能运行在另一台机器上。此时前端显示取消已受理,调度器停止创建新工作,审计记录仍未结束的调用和副作用。

取消也不是让每个节点都查询一次 Redis。持有该 RunWorker 收到取消通知后更新本地 CancellationToken,执行循环在以下安全边界检查它:

  • 进入下一个节点或下一轮 ReAct Loop
  • 调用模型、工具之前和返回之后
  • 创建子 Agent 之前
  • 写入 CheckpointArtifact 或最终答案之前

关键写入需要携带 Worker 启动时读取的 run_versioncancel_epoch。如果取消操作已经把版本从 7 推进到 8,数据库就拒绝版本 7 产生的模型结果、工具结果和最终答案。PubSub 缩短通知延迟,条件更新负责拒绝迟到提交。

这仍然不能自动撤销外部副作用。任务在取消前已经发出的邮件、创建的订单、提交的代码不会因为 Run 变成 CANCELED 而消失。工具边界还要提供超时、幂等键、事务或补偿动作。生产系统能够承诺的是停止创建新工作、阻止迟到结果提交、记录无法撤销的副作用,而不是让每个远程调用在同一毫秒物理停止。

故障恢复沿用同一套边界。Worker 定期上报 heartbeat;租约过期后,清扫任务把 Run 重新入队,新 Worker 从最近的持久化 Checkpoint 继续。这里保证的是“一次尝试只由一个 Worker 持有”,不等于外部副作用天然具备端到端 exactly-once。如果所有计算节点同时宕机,只要持久化事实源仍在,服务恢复后就能重新调度;如果数据库和备份也一起丢失,任何协议都无法凭空恢复执行历史。

生命周期与后文章节

生命周期阶段主要协议对象后文对应部分
创建任务Agent / Thread / Run执行模型、Runtime Loop
携带上下文Thread / Message / Workspace状态管理、Workspace / Sandbox
执行步骤Step / Tool Call / Subagent task执行模型、工具协议、多 Agent 协作
观察事件Event / Trace / State Snapshot流式输出、可观测性
中断恢复Checkpoint / Interrupt / Resume状态管理、中断恢复、错误恢复
产生产物Artifact / Workspace file状态管理、流式输出、Harness
评测审计Step / Event / Artifact / Trace可观测性与可评测性

1.5 现有协议已经在向同一组对象收敛

下面这张表不是为了横向堆框架名词,而是作为证据:不同标准和框架正在围绕 Thread、Run、Step、Event、Artifact、Checkpoint 这些对象收敛。

协议/规范核心对象主要关注点对 Runtime 的启发
LangChain Agent ProtocolThread、Run、Store、Command、OpenAPI spec用框架无关 API 服务化生产 AgentRuntime 要暴露可创建、搜索、更新、流式运行和发送命令的标准资源
A2AAgent Card、Task、Message、Part、Artifact、Streaming Event独立 Agent 系统之间互操作Task 状态机和 Artifact 是跨 Agent 协作的核心
AITPThread、Actor、Capability、Transport跨信任边界的 Agent 交互和交易Thread 是最低公共接口,Capability 承载结构化能力
ACPAgent metadata、REST endpoint、Message、SSE跨框架、跨组织 Agent 通信协议要简单到能用 HTTP 直接接入,同时支持异步长任务
AG-UIRun event、Message event、Tool event、State deltaAgent 与前端 UI 的事件协议前端需要的不只是最终答案,而是标准化事件流
OpenAI AssistantsAssistant、Thread、Message、Run、Run Step托管式 Agent 执行Thread/Run/Step 是生产 Runtime 的基础资源模型
LangGraph Server APIThread、Run、Stream Mode、State Update可恢复流和状态观测Runtime 协议需要同时支持 run stream 和 thread stream
Deep AgentsTodo、Subagent task、Virtual filesystem、Backend、Skill复杂任务 Agent HarnessRuntime 之上还需要面向长任务的 planning、delegation、workspace 和 skill 协议对象
OpenTelemetry GenAITrace、Span、Event、Attributes跨框架可观测性语义Protocol 不只面向业务调用,也面向观测系统

这些标准并没有完全收敛,但它们已经共同指向一个事实:Agent Protocol 的中心不再是单次 chat completion,而是 长生命周期、可观测、可评测、可恢复、可协作的任务对象

1.6 本文使用哪些框架作为证据

后文会多次出现框架对比表。它们不是主线,而是证据:用来观察不同实现如何落到同一组协议对象上。

框架全称核心定位版本基准
LangGraphLangGraph + LangGraph Platform图执行引擎 + Agent Server1.2.x
Deep AgentsDeep Agents SDK(built on LangGraph)面向复杂任务的 Agent Harness2026.06
OpenAIAssistants API + Responses API + Agents SDK托管式 Agent Runtime2025.04
AutoGenAutoGen 0.4(Core + AgentChat)多 Agent 对话框架0.4.x
Claude SDKClaude Agent SDK(Anthropic)代码执行 Agent0.1.x

Part 1:创建任务与执行步骤:Agent 如何跑起来

这一部分对应任务生命周期里的“创建任务”和“执行步骤”:一个外部请求如何变成 Run,Run 又如何被拆成 Step、Tool Call、Subagent task 和状态事件。先看 Runtime Loop 被谁承载,再看 loop 内部哪些动作会被提升为协议状态。

2. 执行模型 (Execution Model)

2.1 通用概念

执行模型定义了 Agent 计算如何被编排:什么是执行的基本单元、单元之间如何调度、控制流由谁决定。放到协议视角,它还定义了一个外部请求如何变成内部执行:一条 Message 如何创建 Task/Run,一次 Run 如何拆成多个 Step,每个 Step 如何产生状态、事件和产物。

子概念

  • 执行单元 (Execution Unit):一次不可分割的计算步骤——一个 LLM 调用、一次工具执行、一个决策节点
  • 调度模型 (Scheduling):执行单元的排列方式——顺序、并行、条件分支
  • 控制流 (Control Flow):谁决定下一步做什么——显式的图边、LLM 的推理、代码逻辑

2.2 两层模型:Loop 承载方式与编排协议

讨论 Agent 执行模型时,最容易混淆的是把不同层级的东西放在一起比较。更清晰的做法是拆成两层:

  • Runtime Loop 承载方式:谁拥有主循环,控制流被放在哪种运行时容器里
  • 编排协议模式:主循环内部哪些语义对象被显式化,哪些 Action 副作用会进入 Runtime 状态机

Graph、Code、Managed 属于第一层,回答 loop 的承载容器;ReAct、Plan-and-Execute、Conversation-style coordination 属于第二层,回答 loop 内部的主导语义对象。Conversation 和 Graph / Code / Managed 放在同一层会制造误判,它更适合作为广义 Agent loop 上的一种消息协作契约。

执行模型应拆成两层看:Loop 承载方式决定循环在哪里,编排协议决定循环内部哪些语义被显式建模。

Loop 层: 图式 Runtime 区别于 Code Runtime 在于它使用构建二叉树的方式来构建条件和边,不过以图式 Runtime 为代表的 LangGraph 的节点函数、条件边和工具调用仍然由代码实现,这些代码被放进图运行时里,控制流被结构化为节点、边、状态和 checkpoint。它的价值在于给复杂分支、并行、恢复和观测提供稳定运行时边界,是一种基于 Code 的 DSL(Domain Specific Language)。 Managed 则代表着用户将 runtime 托管给平台。

编排协议层: ReAct 可以看成最小 Agent loop:Observation 进入上下文,模型完成 Reasoning,再选择 Action,最后把 Result 写回上下文继续推进。这里的 Action 可以是普通业务工具,也可以是带 Runtime 语义的工具,例如更新计划、发送消息、路由、handoff、请求人类确认。

Plan-and-Execute 的关键是把 Plan / Todo / Step / Progress 提升为显式状态。计划依然可以由 ReAct 的 update_plan()update_todo() 触发,但 Runtime 会把这些副作用纳入进度展示、checkpoint、恢复、审计和评测。

Conversation-style coordination 的关键是把 Participant / Message / Route / Handoff / Speaker 提升为显式状态。transfer_to_agent() 可以表现为一次工具调用,同时触发 active agent、权限边界、上下文可见性和 trace 归属的状态迁移。它的核心语义来自持续参与者之间的消息协议,而非一次性调用对象。

这也解释了为什么 Agent 可以作为工具存在。子 Agent 被一次性调用并返回结果时,更接近 capability invocation;多个 Agent 以持续身份参与同一段消息协议,订阅、响应、修正彼此的消息时,更接近 conversation-style coordination。差异来自运行时角色:一次性能力调用,或持续参与者交互。

这里还有 Runtime 和 Framework 之间的层:Agent Harness。它不是主线之外的新概念,而是 Protocol/Runtime 能力产品化后的应用层。LangChain 官方把 Deep Agents SDK 归为 harness:它基于 LangGraph runtime 封装高层电池包,把 planning、todo、subagents、filesystem、context management、HITL、streaming、memory、permissions 组合成一个开箱即用的复杂任务 Agent。

Harness 的价值是易用性:它把原本需要开发者自己组装的 Runtime 能力,预先打包成一套默认可用的工作方式。Deep Agents 的优势就在这里——你不需要从零设计 todo list、subagent task、virtual filesystem、backend 和 permission model,就能获得一个接近 Claude Code 使用体验的长任务 Agent。

Claude Agent SDK 走的是另一种路线:它直接复用 Claude Code 二进制能力,因此可以获得成熟的代码 Agent 体验、文件操作、权限模型和工具链集成;对应的限制是,它的执行环境、工具边界、可移植性和可观测性会更强地绑定到 Claude Code 的产品形态。

我在 从Claude Code到 OneAgent:如何做好上下文工程 里把规划工具、子智能体、虚拟文件系统和长 Prompt 放在同一组能力中,因为它们不是零散技巧,而是 Harness 把 Runtime 能力产品化后的默认工作方式。在协议视角,这些能力会进一步被拆成 Todo / Subagent task / Workspace / Skill / Event 等可观察对象。

换成本文的六对象主线,可以这样对应:

Harness 体验对象回扣到的协议对象说明
Todo / PlanStep / Event把长任务进度变成可观察、可恢复的步骤
Subagent taskRun / Step / Artifact把委派任务变成可追踪的子执行和结果
Virtual filesystem / WorkspaceArtifact / Checkpoint把中间结果、文件和最终产物沉淀到可恢复状态
SkillTool / Artifact / Metadata把可复用能力包变成 Runtime 可发现的能力
Permission / HITLInterrupt / Resume / Event把高风险动作放入中断恢复状态机

易用性也会带来约束。封装越强,默认路径越清晰,框架替你做的决策也越多。因此使用这些成熟框架的时候,手里有源码能够覆写乃至重写很有必要,不然复杂的业务场景很难被都满足。相比强绑定二进制产品形态的路线,生产环境我更推荐使用 Deep Agents,原因也在于此。

所以评价一个 Agent 框架,既要看底层 Runtime 能力,也要看这些能力是否容易被正确使用。Runtime 解决能不能做,Harness 解决开发者能不能低成本做好;二进制复用型 SDK 进一步解决成熟体验复用问题,同时也带来更强的平台约束。

Harness 把 Runtime 能力打包成默认可用的长任务 Agent 体验,解决“能不能做”之外的“能不能低成本做好”。

2.3 跨框架映射

概念LangGraphOpenAI AssistantsAgents SDKAutoGenClaude SDK
执行单元Node(函数/Runnable)Run StepAgent turnAgent message handlerAgent turn
调度模型Graph(DAG + 循环)服务端托管循环Python 控制流对话协议(轮转/选择)代码驱动循环
控制流条件边 / Command服务端决定(不透明)Handoff / 代码分支Selector / RoundRobin工具结果驱动 LLM
并行执行Send API(fan-out/fan-in)不支持不支持GroupChat 内并行不支持
执行容器Thread + RunThread + RunRunner 上下文Runtime + TeamSession

2.4 Runtime Loop:Agent 的隐藏主循环

很多 Agent 框架表面 API 差异很大,但内部都存在一个主循环:

while not done:
    messages = load_context()
    model_output = call_llm(messages, tools)
    if model_output.tool_calls:
        tool_results = execute_tools(model_output.tool_calls)
        append_results(tool_results)
        continue
    if model_output.handoff:
        transfer_to_next_agent()
        continue
    if model_output.needs_human:
        interrupt()
        break
    return final_output

Runtime Loop 在内部决定下一步调用模型、执行工具、切换 Agent、等待人类还是返回结果;协议外部则需要把这些分支稳定表达成 Task / Run 状态。

框架差异主要在于这个循环由谁拥有:

拥有者代表特点
开发者拥有循环Responses API、Claude Client SDK灵活,但状态、重试、工具执行都要自己写
SDK 拥有循环OpenAI Agents SDK、Claude Agent SDK上手快,工具执行和事件流由 SDK 托管
图引擎拥有循环LangGraph循环被拆成节点、边、Checkpoint 和 Pregel-style SuperStep
服务端拥有循环OpenAI Assistants最省心,但控制权和可观测性最少

判断一个框架是不是 Runtime,不要看它是否能调模型,而要看它是否拥有这个循环。

Deep Agents 的位置很特殊:它不重新发明 Runtime Loop,而是把 LangGraph 的 durable execution、streaming、checkpointing、人机协作能力包装成一个默认可用的 harness。对协议设计来说,这意味着外部对象仍然是 Thread/Run/Event/Artifact,但内部多了 todo list、virtual filesystem、subagent task、skill、backend 这些更贴近复杂任务的中间对象。

Task/Run 状态机需要把每轮执行后的可观察状态暴露给客户端:

RUNNING ──► COMPLETED

   ├──► INPUT_REQUIRED ──► RESUME ──► RUNNING
   ├──► CANCEL_REQUESTED ──► INTERRUPTED / CANCELED
   └──► FAILED / TIMED_OUT

A2A 把这类状态显式放进 TaskOpenAI 把它放进 RunLangGraph Server 则通过 Thread/Run stream 暴露生命周期事件。对象名不同,但协议都需要向客户端回答同一个问题:这次执行现在处于什么状态,客户端下一步能做什么?

2.5 事件驱动 Runtime

AutoGen Core 展示了另一条路线:把 Agent 执行看成事件驱动系统。Agent 不再只是”被调用的函数”,而是订阅 Topic、接收 Message、发布 Message 的 Actor。

这种模型的价值在于:

  • 解耦 :发送方不需要知道谁会处理消息
  • 并发 :多个 Agent 可以订阅同一个 Topic 并行响应
  • 分布式 :Runtime 可以演进成跨进程、跨机器的消息总线
  • 弹性 :失败的 Agent 可以独立重启,不必拖垮整个工作流

但代价也明显:调试困难、消息顺序复杂、状态一致性变差。适用于大规模(超过 10个 Agent 协作)多 Agent 系统。

2.6 Workspace / Sandbox:执行环境也是状态

新一代 Agent Runtime 开始把”工作区”作为一等概念。OpenAI Agents SDK 的 Sandbox agents、Claude Agent SDK 的文件工具和权限模式,本质上都在回答同一个问题:Agent 执行时能读写哪些外部资源?

Deep Agents 把这一点推得更彻底:它默认提供 virtual filesystem,并支持 StateBackend、FilesystemBackend、StoreBackend、CompositeBackend 等可插拔 backend。也就是说,文件不只是工具调用的副作用,而是 Agent 管理上下文、沉淀中间结果、组织长任务产物的核心状态层。

Workspace 和普通上下文不同:

类型例子生命周期风险
Prompt Context消息、系统提示词单次模型调用泄漏、污染
Runtime StateCheckpoint、Session 变量跨步骤/跨请求版本不一致
Workspace State文件、代码仓库、浏览器页面跨工具调用破坏性副作用
External State数据库、工单、支付系统Runtime 外部真实业务影响

因此,生产 Runtime 不能只管理”对话历史”,还要管理工作区隔离、文件变更审计、权限审批和副作用回滚。

2.7 设计决策分析

执行模型的设计决策要分两层看。第一层是 Runtime Loop 承载方式,它决定控制权、状态、恢复和观测主要由谁负责:

Loop 承载方式容易做到困难做到典型场景
图式 Runtime分支、并行、可视化、断点调试简单的线性对话(过度建模)复杂工作流、审批流、研报生成
代码式 Runtime灵活、学习曲线低、调试直观持久化、断线恢复、可视化简单 Agent、脚本任务
托管式 Runtime零运维、开箱即用自定义执行逻辑、成本控制快速原型、客服 Bot

第二层是 编排协议模式,它决定 loop 内部哪些语义被 Runtime 正式承认:

编排契约显式建模对象典型触发形式Runtime 需要管理什么
ReAct Tool LoopTool Call / Observation / ResultLLM 选择工具工具执行、结果回写、错误作为数据
Plan-and-ExecutePlan / Todo / Step / Progress工具调用或调度器触发计划持久化、进度更新、计划修正、阶段恢复
Conversation-style coordinationParticipant / Message / Route / Handoff / Speaker工具调用或消息路由触发发言顺序、路由、权限切换、上下文可见性、trace 归属
Manager-WorkerTask / Subtask / Assignment / Result工具调用或调度器触发子任务分派、上下文隔离、结果汇总、失败重试

2.8 本章结论

执行模型回答“一个 Run 如何被调度”。后面的状态、工具、流式、中断和观测能力,都是围绕这条 Runtime Loop 展开的。

执行模型不会统一。Loop 承载方式回答主循环放在哪里,编排协议模式回答哪些 Action 副作用会被 Runtime 提升为状态对象。复杂工作流适合图式 Runtime,简单任务适合代码式 Runtime,快速原型适合托管式 Runtime;ReAct、Plan-and-Execute、Conversation-style coordination 可以运行在不同 Runtime 之上,也可以在同一个 Runtime 内叠加。

作为开发者,关键不是押注某一种 loop,而是让状态管理、工具调用、流式输出独立于具体执行模型。这样从代码式 Runtime 切到图式 Runtime,或从 ReAct 切到 Plan-and-Execute 时,其他能力仍然可以复用。— 虽然对于 LangGraph来说都可以做。


Part 2:保存状态、中断恢复与重试:Agent 如何活得久

这一部分对应任务生命周期里的“携带上下文”“中断恢复”和“失败重试”:Run 执行到一半时哪些状态必须保存,暂停后如何继续,失败后如何保留已有进度。状态管理是基础,中断恢复和错误恢复都是它向外延伸出来的生产能力。

3. 状态管理:生产级 Agent 的分水岭

3.1 通用概念

状态管理定义了 Agent 执行过程中的可变数据如何表示、持久化、版本化和恢复。协议视角下,状态管理还要决定哪些状态可以被外部看见:Thread history、Task status、Artifact、State Snapshot、Trace metadata,分别暴露给不同类型的客户端。

子概念

  • 状态表示 (State Schema) :数据的形状——类型化的结构(TypedDict)、消息列表、JSON blob
  • 状态持久化 (Persistence) :数据存到哪——内存、数据库、服务端托管
  • 状态版本化 (Versioning) :能否查看/回滚历史——快照链、消息追加、无版本
  • 状态作用域 (Scope) :数据对谁可见——全局、Agent 级、Channel 级
  • 增量更新 (Update Mechanism) :如何修改状态——Reducer 函数、直接覆盖、追加消息

3.2 持久化光谱

各框架在状态持久化上的立场差异巨大,形成了一个光谱:

状态持久化从“进程内临时状态”到“服务端托管状态”形成一条光谱,生产 Agent 必须明确自己站在哪一段。

3.3 跨框架映射

概念LangGraphOpenAI AssistantsAgents SDKAutoGenClaude SDK
状态表示TypedDict + Channel 级 ReducerThread(消息列表 + 元数据)RunContext(Python 对象)ChatCompletionContext + 共享状态对话历史(隐式)
持久化Checkpointer(PG/Redis/SQLite)服务端托管(不透明)无(手动 save_state/load_state无内置无内置
版本控制Checkpoint 链(parent_id,类 Git)Thread 消息历史(追加制)
状态作用域Channel 级(每个字段独立 Reducer)Thread 级Agent 级Agent/Team 级Session 级
增量更新Annotated[list, add_messages] 等 Reducer追加消息直接修改追加消息直接修改

3.4 状态分层:不要把所有东西都叫 Memory

Agent 领域最容易混淆的词是 Memory。更清晰的做法是把状态拆成五层:

层级典型名称内容主要问题
ConversationMessages / Thread用户、模型、工具消息上下文窗口、裁剪、摘要
Run StateState / Context当前执行的结构化变量类型、Reducer、并发更新
CheckpointSnapshot / Savepoint某一步之后的完整可恢复状态存储、版本、回滚
ArtifactFile / Report / Code diffAgent 产出的外部结果生命周期、权限、可追溯
Semantic MemoryLong-term Memory跨会话沉淀的用户偏好或知识检索、污染、遗忘

很多框架说自己支持 Memory,实际只支持其中一层。生产设计必须先问清楚:要保存的是对话、运行状态、可恢复快照、文件产物,还是长期记忆?

这和前文讨论的上下文工程是同一个问题的两个视角。从Claude Code到 OneAgent:如何做好上下文工程 里我从模型可用性的角度拆成 Plan、Offload、Isolate、Retrieve、Reduce、Cache;这里则从 Runtime Protocol 的角度拆成 Conversation、Run State、Checkpoint、Artifact、Semantic Memory。前者回答“怎样让模型在长任务中不迷失”,后者回答“哪些状态必须被 Runtime 稳定保存、恢复和暴露”。

3.5 Session、Thread、Run 的关系

  • Session/Thread :长期上下文边界,回答”这是谁的哪段任务”
  • Run :一次执行边界,回答”这次具体跑了什么”
  • Step :最小可观测执行单元,回答”哪一步调用了模型或工具”
  • Checkpoint :恢复边界,回答”失败后从哪里继续”
  • Artifact :产物边界,回答”结果在哪里、由哪次执行产生”

OpenAI Assistants 把 Thread 和 Run 显式暴露出来;LangGraph 把 Thread 作为 configurable.thread_id,把 Run 隐含在一次 invoke/stream 中;Agents SDK 更强调 Runner 和 Session。名字不同,但边界是相同的。

如果所有 Runtime 都能基于统一 Agent Protocol 表达 Thread -> Run -> Step -> Artifact 这条链路,那么控制台、前端、评测系统、审计系统就不需要理解每个框架的内部状态结构。

3.6 并发会话与并发 Run:Thread 不是锁,Run 才是执行边界

并发会话处理的关键,是不要把 Thread / Session 和 Run 混成一个概念。Thread / Session 是长期上下文边界,Run 是一次执行边界;同一个用户可以有多个 Thread,同一个 Thread 也可能在短时间内收到多个 Run 请求。

生产 Runtime 必须明确一个问题:同一个 Thread 上是否允许多个 Run 同时执行? 不同选择会导向不同的状态一致性策略:

策略行为优势代价典型场景
串行队列同一 Thread 的 Run 按顺序排队执行语义最稳定,消息顺序清晰延迟增加,长任务会阻塞后续输入多轮对话、客服、需要强上下文连续性的任务
拒绝新 RunThread 已有运行中 Run 时直接返回 conflict / busy实现简单,避免状态冲突用户体验生硬,需要前端解释和重试后台任务、审批流、一次只允许一个执行的场景
取消并覆盖新 Run 到来时取消旧 Run,用最新输入重新执行交互体验直接,适合“以最后一次为准”旧 Run 的部分进度和副作用需要可追溯或可回滚搜索、草稿生成、用户频繁改需求的交互
分叉新 Run从同一个 Checkpoint 分叉出多个 Run 并行执行适合 A/B 测试、方案比较、探索式任务需要清晰标记分支、Artifact 归属和最终采纳关系Prompt 对比、策略实验、研究任务
乐观并发Run 开始时记录 state version,提交时检查是否冲突并发度高,适合低冲突写入冲突检测和合并逻辑复杂多 Agent 并行写不同 state channel

这些策略没有绝对优劣,关键是把语义放进协议和 Runtime 状态机里。客户端需要知道新 Run 是被排队、拒绝、取消旧任务、创建分支,还是等待冲突解决;观测系统也要能把每个事件、Artifact 和错误归属到具体 Run。

并发写状态时,Runtime 至少要处理五类冲突:

  • 消息顺序冲突 :两个 Run 同时向同一个 Thread 追加消息,最终历史如何排序
  • 状态版本冲突 :两个 Run 基于同一份 State Snapshot 修改同一个字段,谁覆盖谁
  • Artifact 归属冲突 :多个 Run 生成同名文件或报告,哪个是正式产物
  • Workspace 副作用冲突 :多个 Run 同时改同一份代码、浏览器页面或外部系统资源
  • 事件流归属冲突 :前端同时订阅多个 Run 时,如何用 run_id、step_id、event_id 恢复和去重

因此,Thread 不应该被简单当成一把全局锁。更稳的设计是:Thread 承载上下文,Run 承载执行,Checkpoint 承载版本,Event 承载进展,Artifact 承载产物;并发控制策略则明确写进 Run 创建语义和状态迁移规则。

3.7 状态迁移与 Schema 演进

持久化一旦进入生产,就会遇到 Schema 演进问题:今天保存的 Checkpoint,三个月后代码升级还能不能恢复?或者说历史执行记录还能不能打开继续了?

生产 Runtime 需要考虑:

  • 状态版本号 :每个快照记录 schema version
  • 迁移函数 :加载旧快照时转换到新结构
  • 兼容窗口 :保留多久的旧状态可恢复
  • 失败策略 :迁移失败时是终止、降级,还是创建新 Run

这也是服务端托管状态和自建 Checkpoint 的核心差异:托管方案隐藏迁移复杂度,但也隐藏了控制权;自建方案控制力强,但必须承担 schema 演进成本。

3.8 设计决策分析

LangGraph 的 Checkpoint 模型是目前最完整的状态管理方案:

  • 每个节点执行后自动快照(不需要手动调用 save)
  • 快照具备链式结构,支持”时间旅行”(即任意节点回滚、重放)
  • Content-addressed blob 存储,类似 git 的存储方式,大状态只存一次
  • 允许运行时修改 Agent 的上下文信息,这个相当牛意味着可以运行时让 Agent 自进化

代价是:学习曲线陡峭,Reducer 函数的语义需要理解,Checkpoint 存储占空间。

OpenAI Assistants 的 Thread 模型走了另一个极端:

  • 你不需要(也无法)管理状态——服务端全包
  • 状态只能通过追加消息来修改,不能直接改内部状态
  • 没有回滚——你只能创建新 Thread

代价是:零控制权。调试困难,无法做”如果当时走了另一条路”的分析。

AutoGen / Claude SDK / Agents SDK 基本没有内置持久化,把这个问题留给开发者。对于短生命周期的 Agent 这没问题,但一旦需要跨请求保持状态(如人机协作工作流、事后评测、版本管理等),就必须自己搭建。

3.9 本章结论

状态管理回答“Run 执行到一半时,哪些东西必须被保存,以及多个 Run 同时发生时如何保持一致”。它承接上一章的 Runtime Loop,也直接支撑后面的中断恢复、错误回滚、并发会话和执行回放。

状态持久化是区分“玩具”和“生产”的分水岭。没有持久化的 Agent 无法在进程崩溃后恢复,无法支持真正的 Human-in-the-Loop,无法调试“为什么 Agent 走了这条路”,也无法从同一个状态分叉执行不同策略。并发 Run 进一步要求 Runtime 明确队列、拒绝、取消覆盖、分叉和乐观并发等策略。

真正难的不是保存,而是恢复。恢复要求状态 schema、工具副作用、外部资源、权限上下文都能重新对齐;只把 messages 存进数据库,并不等于具备生产级状态管理。


4. 中断与恢复:Human-in-the-Loop 的真正基础设施

4.1 通用概念

interrupt/resumecancelrollback 都会停止当前执行,但它们保留的状态和允许的后续动作不同。

  • interrupt / resume 保留继续执行的意图,任务在等一个值、一次审批或一份授权。
  • cancel 撤销继续执行的意图,任务要停止创建新工作并进入终态。
  • rollback 不只停止执行,还丢弃这次 Run 产生的内部状态;外部副作用仍要单独补偿。
对象Runtime 需要记录什么
中断点哪个节点、工具审批或业务条件触发暂停
中断状态状态快照是否已经持久化,是否依赖原进程继续存活
中断载荷向人类暴露的问题、待审批动作和候选项
返回路由输入对应的 ThreadRuninterrupt_id
取消传播当前 Worker、并行分支和远程子 Agent 的停止状态

4.2 跨框架映射

概念LangGraphOpenAI AssistantsAgents SDKAutoGenClaude SDK
中断触发interrupt() / interrupt_before / interrupt_afterrequires_action(仅工具审批)Guardrail 拦截HandoffTerminationclient.interrupt()
中断状态Checkpoint(完整快照 + pending_writes)服务端 Thread(不透明)无持久化对话历史(手动 save)无持久化
中断载荷任意 JSON(interrupt(payload)tool_calls 列表Guardrail 错误信息HandoffMessage
恢复机制Command(resume=value)submit_tool_outputs()代码手动恢复重新 run_stream(task=input)query()
多点中断支持(多节点设置 interrupt_before不支持不支持不支持不支持

4.3 中断/恢复通用流程

不管框架如何实现,中断/恢复的通用流程是一样的:

Agent 执行 ──► 到达中断点 ──► 保存执行状态 ──► 向前端暴露中断载荷


                                               人类查看/决策


Agent 恢复 ◄── 从快照加载状态 ◄── 接收人类输入 ◄── 前端提交

ask and wait 如果只保存在内存里,进程退出时,中断点和待提交载荷会一起丢失;部署、扩容或故障后,输入也无法路由回原来的执行点。

LangGraph 把中断载荷写入 Checkpoint,再通过 Command 把恢复值送回中断点:

# 节点内主动中断,传递任意载荷
def review_node(state):
    decision = interrupt({
        "question": "要发布这篇文章吗?",
        "draft": state["draft"],
        "options": ["发布", "修改", "丢弃"]
    })
    # decision 是人类通过 Command(resume=...) 传入的值
    if decision == "发布":
        return {"status": "published"}
# 人类回复
graph.invoke(Command(resume="发布"), config)

4.4 LangGraph interrupt() 到底做了什么

interrupt() 不是每经过一个节点就查询一次 Redis,也不是把正在运行的 Python 栈冻结到数据库。节点第一次调用它时,内部先查看当前任务的 scratchpad 里有没有对应的 resume 值:有就直接返回;没有就抛出 GraphInterrupt。图引擎捕获这个特殊控制信号,把中断载荷和图状态交给 Checkpointer,本次执行到此结束。

恢复时,调用方使用相同的 thread_id 再次执行图,并传入 Command(resume=value)LangGraphCheckpoint 加载状态,重新进入发生中断的节点;当代码再次走到同一个 interrupt() 时,才从 scratchpad 取出 resume 值并返回。

resume 会从中断节点开头重新执行,不会从调用 interrupt() 的那一行 Python 代码原地续跑。

def review_node(state):
    audit_log("ready_for_review")  # resume 后会再次执行
    approved = interrupt({"draft": state["draft"]})
    publish()                       # 只有批准后才执行
    return {"approved": approved}

因此 interrupt() 之前的副作用必须幂等,或者被拆到已经完成并保存 Checkpoint 的前一个节点。多个动态中断还要保持调用顺序稳定,否则旧 Checkpoint 中保存的第一个恢复值,可能在新代码里落到另一个中断点上。

4.5 四种名字相近、行为不同的控制动作

interrupt 出现在四类 API 中,但它们停止的对象、保留的状态和允许的后续动作并不相同。

动作目的运行时行为后续动作
节点内 interrupt(payload)业务审批或补充输入抛出 GraphInterrupt,保存图状态和载荷相同 thread_id + Command(resume=...)
interrupt_before / interrupt_after调试断点在节点前后暂停,依赖 CheckpointerNone 继续到下一个断点
runs.cancel(action="interrupt")用户终止部署中的 Run停止执行该 RunWorker,状态变为 interrupted,保留已完成 Checkpoint检查、审计,或从某个快照分支执行
runs.cancel(action="rollback")放弃本次 Run 的内部痕迹停止执行,删除该 Run 及其 Checkpoint,线程状态回到运行前无法再恢复或检查该 Run

节点内 interrupt() 是“我还要继续,但需要一个值”;取消接口的 action="interrupt" 是“这次 Run 不再继续,但把现场留下”。后者保留内部状态,不代表已经发出的邮件、订单或远程请求会被回滚。

4.6 跨进程取消不是逐节点查 Redis

API Server 和执行任务的 Worker 不在同一个进程时,取消需要一条控制链:

POST /runs/{run_id}/cancel

        ├──► 持久化 CANCEL_REQUESTED,推进 cancel_epoch
        └──► Redis / Broker 通知 run_id 对应的 Worker


                             本地 CancellationToken


                         安全边界停止 + 带版本条件提交终态

LangGraph Agent Server 使用 Redis string + PubSub 把取消请求路由给持有该 RunWorker。因此取消请求落到任意一个无状态 API Server 都可以处理,不需要命中创建任务时的那台机器。Redis 在这里是控制信号的快速通道,Run 和用户数据仍以持久化存储为准。

PubSub 通知可能晚于模型或工具返回。Worker 在创建子任务、写入 Checkpoint 和提交终态前检查本地令牌,关键写入再携带 cancel_epoch 做条件更新;数据库中的版本已经变化时,本次写入直接失败。

底层模型客户端或工具支持取消时,可以进一步终止网络请求;不支持时,只能等待调用返回,再丢弃结果。直接杀进程可以更快,却会留下未关闭资源、半完成写入和难以判断的外部副作用,通常只适合作为超时后的最后手段。

4.7 设计决策分析

方案优势劣势
LangGraph:通用 interrupt + Command任意节点、任意载荷、完整状态保存需要 Checkpointer,学习成本高
OpenAI:requires_action简单,服务端托管状态只能审批工具调用,不能主动问用户问题
AutoGen:HandoffTermination用 Handoff 统一了人机和 Agent 间交互状态需手动保存,恢复不是从断点继续
Claude SDK:interrupt()极简——发信号停止没有恢复,只能重新开始

4.8 本章结论

原生 interrupt() 处理一张图内部的暂停和恢复。部署中的用户取消还要持久化 CANCEL_REQUESTED、通知对应 Worker、更新本地取消令牌,并用条件写拒绝迟到结果;子 Agent 跨出当前服务后,这些动作还必须被序列化成跨服务协议。


5. 错误恢复:Agent 应该先把错误当数据看

5.1 通用概念

错误恢复定义了 Agent 执行过程中发生故障时,Runtime 如何检测、表示和处理错误。

子概念

  • 错误检测 (Detection) :在哪一层发现错误——工具执行、LLM 调用、状态更新
  • 错误表示 (Representation) :错误以什么形式存在——Exception、错误数据、状态标记
  • 恢复策略 (Recovery Strategy) :如何处理错误——重试、回滚、跳过、交给 LLM
  • 部分进度保留 (Partial Progress) :失败时已完成的步骤是否保留

5.2 跨框架映射

概念LangGraphOpenAI AssistantsAgents SDKAutoGen
错误表示Exception → pending_writesRun status = failedPython ExceptionException in message
重试RetryPolicy(per-node 配置)自动(不透明)手动手动
回滚Checkpoint 回滚N/A(服务端托管)N/AN/A
部分进度Checkpoint 保留Thread 消息保留丢失对话保留
错误传播可配置(error-as-data 或 raise)事件通知抛给调用者消息传给 GroupChat

5.3 两种错误哲学

Error-as-Exception (传统)                Error-as-Data (Agent 原生)
 
工具调用 ──► 失败 ──► 抛异常             工具调用 ──► 失败 ──► 返回错误信息


              框架/开发者 try/catch                      LLM 看到错误信息
              决定重试/放弃                              LLM 自主决定下一步
                                                       (重试/换工具/告知用户)

Agent Runtime 更适合把可理解的工具错误作为数据返回给模型,而不是默认打断执行。 即 Error-as-Data,因为LLM 有足够的推理能力来处理工具错误。这个假设在旗舰级别的模型上是成立的——它们能理解”API 返回 429 限频”并决定等待后重试。

5.4 LangGraph 的 Checkpoint 回滚

LangGraph 是唯一支持 Checkpoint 回滚的框架:

  • 节点 A 执行成功 → 自动保存 Checkpoint A
  • 节点 B 执行失败 → 异常被记录到 pending_writes
  • 重新 invoke 时 → 从 Checkpoint A 恢复,只重试节点 B
  • 已完成的节点 A 不会重新执行

这对长时间运行的工作流至关重要。一个 10 步的 Agent 在第 8 步失败了,你不需要重跑前 7 步。

5.5 本章结论

错误恢复回答“失败是否会抹掉已有进度”。它同样依赖状态管理:没有 Checkpoint,失败只能重跑;有 Checkpoint,Runtime 才能保留已完成步骤并只重试失败部分。

Agent Runtime 应默认采用 Error-as-Data。Agent 的核心价值是自主决策,工具错误也应该优先作为可理解的数据交给模型处理;只有模型无法处理的系统级故障,才应该作为 Exception 向上抛。

Checkpoint 回滚是生产环境的明确缺口。长任务执行到后半段失败时,是否能从最近稳定状态恢复,直接决定这个 Runtime 能否承载真实业务流程。


Part 3:连接工具与观察事件:Agent 如何连接外部世界

这一部分对应任务生命周期里的“执行外部动作”和“观察事件”:Runtime 如何调用外部能力,并把执行进展暴露给外部系统。工具协议处理输入侧能力接入,流式事件处理输出侧进展同步。

6. 工具协议:最可能先标准化的一层

6.1 通用概念

工具协议定义了 Agent 如何发现、调用和处理外部能力。

子概念

  • 工具定义 (Tool Definition):描述工具的名称、参数、返回值——通常用 JSON Schema
  • 工具调用 (Tool Invocation):调用的请求/响应格式和传输方式
  • 工具结果 (Tool Result):返回给 Agent 的数据格式
  • 工具发现 (Tool Discovery):Agent 如何知道有哪些工具可用
  • 错误处理 (Error Handling):工具调用失败时的行为

6.2 跨框架映射

概念LangGraphOpenAIAutoGenClaude SDK
定义格式@tool + JSON SchemaFunction Calling JSON SchemaFunctionTool + JSON SchemaTool(JSON Schema)
调用约定ToolNode 自动执行requires_action → 客户端执行Agent 内部直接调用Agent 内部直接调用
结果格式ToolMessageFunction output(字符串)FunctionExecutionResultToolResult
发现机制构建时 bind_tools()创建 Assistant/Response 时指定创建 Agent 时注册创建时 allowed_tools
错误处理可配置:handle_tool_errors=True错误作为 output 返回 LLM异常转为错误消息错误在结果中

6.3 工具协议独立分层

工具协议的关键问题在于工具能力能否从执行模型里解耦出来。

紧耦合的做法是:

  • 用 LangGraph 时,工具必须适配 LangChain Tool
  • 用 OpenAI 时,工具必须适配 Function Calling 格式
  • 用 Claude SDK 时,工具必须适配它自己的工具定义
  • 切换框架时,工具层跟着重写

更合理的做法是:

  • 工具定义统一使用结构化 schema
  • 工具调用统一表达为请求和响应
  • 工具结果统一转成 Agent 可理解的消息
  • 执行框架只负责编排,不直接拥有工具实现

6.4 MCP:工具层标准化的典型形态

从 Runtime Protocol 的视角看,MCP (Model Context Protocol)把工具发现、工具定义、工具调用、资源读取、Prompt 模板等能力抽象成一组客户端和服务端之间的协议对象。Host / Client / Server 的分层,让 Agent Runtime 可以通过统一连接方式接入外部能力,而不必为每个工具单独写框架绑定。

MCP 对象对应工具协议能力Runtime 意义
Tool工具定义、参数 schema、调用结果让外部能力以统一 schema 暴露给 Agent
Resource可读取的上下文资源把文件、文档、数据库记录等变成可发现上下文
Prompt可复用提示模板把任务模板和工具使用方式沉淀为可调用能力
Client / Server传输与能力发现边界解耦 Runtime 和具体工具实现

MCP 标准化的是“Agent 能调用什么、如何发现和调用”;Runtime Protocol 还要继续表达 Thread / Run / Step / Event / Artifact / Checkpoint / Interrupt 这些任务生命周期对象。MCP 可以成为 Runtime 的工具层和上下文接入层,但完整 Runtime 仍然需要自己管理执行循环、状态持久化、流式事件、中断恢复和观测语义。

MCP 的长期价值在于把工具生态从框架内部抽出来。一个 MCP Server 可以同时服务 Claude、IDE、桌面应用、后台 Agent 或自建 Runtime;Runtime 只需要实现 MCP Client/Host 侧适配,就能复用同一组工具、资源和 Prompt。这正是工具协议最可能先标准化的原因:工具层边界清晰,输入输出结构化,和底层 loop 承载方式解耦。

这也是 如何快速创建领域Agent - OneAgent + MCPs 范式 的核心判断:企业里不会存在全知全能的 God Agent,但可以用一个强基础 Agent 连接 MCP0与各种提供上下文的 MCP,把领域知识、存量服务和工具发现变成可组合的工具生态。本文把这个判断放进 Runtime Protocol 里看,就是“工具发现、工具定义、工具调用、资源读取”会先于完整 Agent Runtime 形成标准化边界。

6.5 Error-as-Data vs Error-as-Exception

工具调用失败时,有两种根本不同的处理策略:

策略行为代表
Error-as-Data错误信息作为工具结果返回给 LLM,由 LLM 决定如何处理OpenAI(错误在 output 中)、LangGraph (handle_tool_errors=True)
Error-as-Exception错误作为异常抛出,执行中断,由框架/开发者处理传统编程模式

Error-as-Data 是更好的默认策略。原因:

  • LLM 能看到错误信息,可以自主决定重试、换工具、或告知用户
  • 不需要开发者为每种错误写 try/catch
  • 更接近人类使用工具的方式——工具出错了,你会看看错误信息然后决定下一步

这类设计的核心是:错误仍然是一个合法的工具结果,不是直接打断 Runtime 的异常。

6.6 Runtime 控制面:权限、Guardrail、预算

工具一旦能产生真实副作用,Runtime 就必须有控制面。控制面负责约束 Agent 能做什么、何时必须停下来、谁可以批准继续。

生产 Runtime 至少需要这些控制点:

控制点作用典型触发时机
Permission限制工具、文件、网络、外部系统访问工具调用前
Guardrail检查输入/输出是否违反安全或业务规则模型调用前后
Human Review让人类审批高风险动作写文件、发请求、提交订单前
Budget限制 token、成本、步骤数、执行时间Run 开始和每个 Step 后
Cancellation允许用户或系统终止执行长任务、误操作、超时

OpenAI Agents SDK 把 Guardrails、Human-in-the-loop、Tracing 做成 Runtime 能力;Claude Agent SDK 暴露 permissions 和 hooks;LangGraph 通过 interrupt/checkpoint 组合实现审批和恢复。它们指向同一个趋势:Agent Runtime 不只是执行器,还是一个安全边界。

6.7 本章结论

工具协议回答“Runtime 如何连接外部能力”。它与执行模型解耦:同一个 Tool API 应该能被图式、代码式、托管式 Runtime 复用,而不是绑定在某个框架的 wrapper 里。

工具层是最可能先标准化的部分。JSON Schema 已经成为事实标准,MCP 进一步把工具发现、资源读取和 Prompt 模板从框架内部抽出来,让外部能力能被不同 Runtime 复用。

一旦工具能产生真实副作用,控制面就必须进入 Runtime。权限、Guardrail、人类审批、预算和取消不是外围功能,而是 Agent Runtime 面向真实系统时的安全边界。


7. 流式输出:不是 token 打字机,而是任务事件流

7.1 通用概念

流式输出定义了 Agent 执行的增量结果如何传递给消费者。协议视角下,流式输出不是”边生成边打印 token”,而是 Runtime 把一次 Task/Run 的状态变化、消息增量、工具进展、Artifact 增量和自定义事件统一编码成事件流。

子概念

  • 传输协议 (Transport) :SSE、WebSocket、异步生成器、轮询
  • 粒度控制 (Granularity) :Token 级、节点/步骤级、消息级
  • 可恢复性 (Resumability) :断连后能否从断点继续接收
  • 多通道 (Multi-channel) :能否同时传递不同类型的事件

生产级流式输出不是 token 打字机,而是状态、消息、工具、产物、错误和 Trace 组成的任务事件流。

7.2 跨框架映射

概念LangGraph PlatformOpenAI AssistantsAgents SDKAutoGenClaude SDK
传输SSESSE / 轮询Python AsyncGenPython AsyncGenPython AsyncGen
粒度9 种 StreamMode 可组合固定事件类型StreamEvent消息级事件级
可恢复支持Thread streamRun stream 需开启持久化)不支持不支持不支持不支持
自定义事件get_stream_writer()不支持不支持不支持不支持
子图/子 Agentstream_subgraphs=TrueN/A不支持Topic 订阅N/A

7.3 Server vs Library:流式能力的分水岭

流式输出的复杂程度与 Runtime 的部署形态直接相关:

形态传输可恢复典型
Library(进程内)Python AsyncGenerator不需要(进程内不会断连)Agents SDK、Claude SDK、AutoGen
Server(跨网络)SSE / WebSocket必须考虑(网络会断)LangGraph Platform、OpenAI Assistants

LangGraph Deployment 把实时传输和断线补收拆成了两件事。运行中的输出通过 Redis PubSubWorker 转给 API Server,普通 join_stream 不会补发订阅前的输出;创建 Run 时开启 stream_resumable=true,服务端才会持久化流片段,客户端随后用 Last-Event-ID 补收。Thread stream 也支持按最后事件 ID 恢复。

PubSub 是实时通道,不是事件日志。只接上 SSE + Redis PubSub,能做到水平扩容后的实时转发,做不到断线期间的完整回放。协议一旦承诺可恢复流,必须再回答事件片段存在哪里、保存多久、如何去重。

7.4 SSE 的句柄边界:指向 Run,不指向连接

SSE 很容易让人把一次连接当作资源本身。前端打开 EventSource,服务端拿到一个 Response,设计里就可能出现 streamId -> response object 这样的表。第一版能跑,页面刷新、反向代理断线、服务水平扩展以后就会露出问题:句柄绑在连接上,连接一断,句柄也失去意义,后台任务还在跑,前端却没有一个稳定对象可以重新订阅。

更稳的边界是让句柄指向业务执行对象:

POST /tasks
-> taskId / runId
 
GET /runs/{runId}/events
-> 订阅该 Run 的事件流
 
POST /runs/{runId}/cancel
-> 取消该 Run

这里的 runId 像一个受控句柄。创建接口登记 Run、状态机、事件日志和取消能力;消费方拿 runId 订阅事件、查询快照、取消任务。SSE 只是其中一种传输绑定;开启可恢复流后,断线客户端才能用 Last-Event-ID 回到持久化的事件片段上。

内部仍然可以有连接表,但它应该是短命的订阅关系:

runId -> persisted stream chunks (optional) / state snapshot / cancel state
runId -> subscribers[]

这个边界适合长任务、可恢复订阅、多观察者、取消和审计。一个导出任务、一次搜索 Run、一段动画讲解生成,都应该先有稳定的 Run,再把 SSE 挂到它身上。

普通通知通道不必这么做。如果连接断开就代表业务结束,没有后台状态、没有重放、没有取消、没有快照,直接用当前用户的 SSE 通道会更简单。只有创建和消费需要分离时,句柄才值当。任务先创建,客户端随后订阅、断线重连、取消或查快照。

落地时有几件事不能省。runId 不要可猜;每次订阅、查询、取消都要校验权限;开启可恢复流时,终态后的事件片段和快照要有 TTL;水平扩容时这些片段不能只放在单机内存里;长连接需要心跳,不然网关可能安静地切断连接。

SSE 服务可以句柄化,但句柄应该落在 Run/Task 这种业务执行对象上,不落在某条 HTTP 连接或 Response 对象上。连接只是观察者,Run 才是被观察、被取消、被恢复的资源。

7.5 本章结论

流式输出回答“外部系统如何实时看见 Run 的进展”。它把状态、消息、工具调用、Artifact 增量和错误统一成事件流,是 Runtime 面向前端、控制台和审计系统的主要出口。

流式能力与部署形态高度相关。进程内 Agent 可以用 AsyncGenerator;跨网络部署后,客户端断线、服务端继续执行、之后补收事件会反复发生,SSE 和可恢复流就不再是可选项。

别把 streaming 写成 token 打字机。若接口承诺断线恢复,事件片段要能持久化、能按 Last-Event-ID 补收;SSE 的句柄落在 Run/Task 上,连接只负责订阅。


Part 4:协作、审计与评测:Agent 如何被理解

这一部分对应任务生命周期里的“跨 Agent 分工”和“评测审计”:多个 Agent 如何围绕同一任务协同,外部系统又如何理解一次执行的质量。多 Agent 关注分工边界,可观测性和可评测性关注反馈闭环。

8. 多 Agent 协作:最碎片化,也最不该过早押注

8.1 通用概念

多 Agent 协作定义了多个 Agent 如何共同完成一个任务。协议视角下,多 Agent 的本质不是”多个 prompt 互相聊天”,而是多个 Runtime 或多个 Agent 能否基于共同对象交换任务、消息、能力和产物。

子概念

  • 通信模式 (Communication) :Agent 间如何传递信息——直接发送、发布/订阅、共享状态
  • 委派模型 (Delegation) :任务如何分配——Handoff 接力、层级分工、投票决策
  • 状态共享 (State Sharing) :Agent 间能否看到彼此的状态——共享 / 隔离
  • 拓扑结构 (Topology) :Agent 的组织形式——线性、星型、网状、层级

8.2 四种多 Agent 编排模式

下面四种是协作模式,不是框架能力边界。LangGraph 作为图式 Runtime,可以通过节点、边、状态和 Send 等机制承载子图嵌套、Handoff 接力、群聊选择和发布-订阅等控制流;OpenAI Agents SDK、AutoGen Core 等框架只是把其中某些模式做成了更原生的使用表面。

多 Agent 协作没有统一模型。子图、Handoff、群聊选择和发布订阅是四类编排语义;具体框架的差异在于哪种语义被做成一等 API,哪种需要用更底层的图、消息或工具机制表达。

8.3 跨框架映射

概念LangGraphAgents SDKAutoGenClaude SDK
通信模式Sub-graph / Send API / Deep Agents taskHandoff(transfer_to_agentGroupChat + pub/subN/A
委派模型嵌套图 / 条件路由 / Subagent taskHandoff toolSelector / RoundRobin / SwarmN/A
状态共享Channel 级(可配置映射)共享上下文共享对话N/A
拓扑任意(图可表达任何拓扑)线性 Handoff 链星型(Selector)/ 顺序N/A
并行执行Send API(map-reduce)不支持支持不支持
分布式LangGraph Platform 管理不支持GrpcWorkerAgentRuntime不支持

8.4 设计决策分析

模式优势劣势适用场景
子图嵌套类型安全、状态隔离可控、可复用需要提前定义图结构固定工作流中的子任务分工
Subagent task任务委派自然、上下文隔离、可复用专长需要设计子 Agent 能力边界研究、代码、复杂任务分解
Handoff 接力简单直观,LLM 决定何时交棒无并行,线性执行客服转接、分工明确的流水线
群聊选择最灵活,适合开放式协作难以调试,选择器可能震荡头脑风暴、多角色讨论
发布-订阅解耦、可扩展、支持分布式复杂度高,调试困难大规模 Agent 集群

8.5 中断能传播多远,取决于子 Agent 是什么

“取消主 Agent 时,怎样取消每一个子 Agent”没有一个只靠递归调用就能成立的答案。先要看这些子 Agent 是否仍在同一个 Runtime 边界内。

运行边界子任务是什么原生中断能力还缺什么
同一张 CompiledGraph 内的子图同一次图执行里的嵌套节点子图默认继承父图 Checkpointer;子图里的 interrupt() 会向顶层传播中断前副作用幂等、并行中断按 interrupt_id 恢复
同一部署中的独立 Run由队列中另一个 Worker 执行的子任务服务端能按 run_id 路由恢复或取消显式记录父子 Run,取消时遍历任务树
RemoteGraph 或其他远程服务HTTP/gRPC 创建的另一项任务本地 GraphInterrupt 无法穿过网络自动暂停远端进程把中断、恢复和取消序列化成协议消息,两端都持久化关联 ID

通过 HTTP 创建的独立 Run 不会接收父进程里的 GraphInterrupt。父任务必须持久化下面这些关联字段,才能把恢复值和取消命令路由到远端:

root_run_id
└── run_id / parent_run_id
    ├── child_run_id / child_thread_id
    ├── interrupt_id
    ├── status
    └── cancel_epoch

interrupt_id 让一份人类回复回到准确的暂停点;root_run_idparent_run_id 让调度器找到整棵任务树;cancel_epoch 用来拒绝树上任何旧版本的迟到提交。这些 ID 如果只放在父 Agent 的上下文里,父进程一挂,恢复和取消都会失去路由依据。

根任务取消时,调度器先把根 Run 标记为 CANCEL_REQUESTED 并推进版本,再查询所有非终态后代,对每个独立子 Run 发送幂等取消命令。活着的子任务在安全边界停止;已经完成的子任务保留结果;失联的子任务在租约超时后回收。根任务只有在子任务全部进入终态,或超时后被明确标记为 orphaned,才能结束收拢过程。

取消无法让所有子 Agent 同时物理停止。收到取消后,调度器拒绝创建新子任务和提交旧版本结果;存活的子任务最终进入终态,失联任务则在超时后标记为 orphaned。已经发生的外部副作用进入审计记录,并在工具支持时执行补偿。

8.6 本章结论

对大多数业务来说,先把单 AgentThreadRunStateToolEventArtifact 边界做好,再引入必要的 HandoffSubagent task,比一开始设计复杂群聊拓扑更稳。子任务跨出当前进程以后,父子 Run 关系和控制协议应当先于协作拓扑落地,否则系统能派活,却收不回来。


9. 可观测性与可评测性:看见问题与评价质量

9.1 通用概念

可观测性定义了 Agent 执行过程如何被追踪、记录和调试;可评测性定义了如何基于这些观测数据对 Agent 质量进行评价、归因和持续优化。

二者的关系

  • 可观测性偏运行时:Trace、Event、State Snapshot 帮助开发者在运行时定位问题、理解因果、回放状态。
  • 可评测性偏事后:基于可观测数据形成质量指标、Badcase 分析、对比实验、反馈闭环,进而驱动 Prompt、工具、编排策略的自优化。

没有可观测性,评测就缺乏数据基础;没有可评测性,可观测数据只能用于调试,无法形成质量改进闭环。生产级 Agent Runtime 需要同时提供两者:既能看见“它怎么跑的”,也能评价“它跑得好不好”。

子概念

  • Tracing :分布式追踪——每个步骤的输入/输出、耗时、因果关系
  • Logging :事件日志——Agent 运行过程中的关键事件记录
  • Metrics :量化指标——延迟、Token 消耗、成本、成功率
  • Debugging :调试能力——步进执行、状态回放、条件断点

9.2 跨框架映射

概念LangGraphOpenAIAutoGenClaude SDK
TracingLangSmith(付费产品)内置 Traces(不透明)无内置无内置
事件日志stream_mode="events"/"debug"Run Steps APIConsole + stdlib loggingEvent stream
Token 统计Callback 回调Usage 对象Usage trackingResponse 中的 usage
执行回放Checkpoint historyThread 消息历史不支持不支持
成本追踪LangSmithOpenAI Dashboard手动手动

9.3 Trace 的最小语义模型

OpenAI Agents SDK 的 Tracing 设计给了一个很好的参照:Trace 表示一次端到端工作流,Span 表示其中一个有开始和结束时间的操作。一个 Agent Runtime 的 Trace 至少应该表达:

Span 类型对应 Runtime 动作关键字段
Run Span一次完整执行run_id、session_id、status、cost
Agent Span某个 Agent 被激活agent_id、instructions_version、tools
Generation Span一次 LLM 调用model、prompt_tokens、completion_tokens
Tool Span一次工具调用tool_name、arguments、result、is_error
Handoff SpanAgent 间交接source_agent、target_agent、reason
Guardrail Span安全/业务规则检查rule_name、pass/fail、action
Interrupt Span人类介入点payload、resume_value、latency

这比普通日志强很多,因为它保留了父子关系和因果链。你不只是知道”调用了工具”,而是知道它属于哪次 Run、由哪个 Agent 触发、消耗多少、失败后是否重试、最终是否影响输出。

9.4 三类观测数据

Agent Runtime 的可观测性不能只看 Trace,还要同时看事件和状态:

类型解决的问题示例
Trace为什么这次执行走到这里LLM 调用、工具调用、Handoff、Guardrail
Event Stream现在正在发生什么token、progress、custom event、interrupt
State Snapshot当时系统处于什么状态checkpoint、messages、pending writes

Trace 更适合事后分析,Event Stream 更适合前端实时展示,State Snapshot 更适合恢复和调试。生产 Runtime 应该三者打通:事件能定位到 Span,Span 能定位到 Checkpoint,Checkpoint 能恢复出当时状态。

Trace 解释因果,Event Stream 展示实时进展,State Snapshot 支持恢复和调试;三者打通后才能支撑评测闭环。

9.5 设计决策分析

可观测性是所有框架中最薄弱的维度。具体问题:

  1. 没有标准的 Trace 格式:LangSmith 有自己的 Trace 格式,OpenAI 有自己的 RunStep 格式,两者不互通。Agent 执行的 Trace 需要一个类似 OpenTelemetry 的开放标准。

  2. Tracing 和框架绑定太深:LangSmith 只能追踪 LangChain/LangGraph 的执行。如果你的工作流混用了多个框架,没有统一视图。

  3. 调试能力严重不足:只有 LangGraph 的 Checkpoint History 能做真正的”时间旅行调试”(回到任意一步查看当时的状态)。其他框架只能看日志。

9.6 可评测性:从可观测到质量闭环

可评测性是可观测性的下游。一个具备可评测性的 Runtime 应该能回答:

  • 质量指标 :准确率、召回率、Pass Rate、Token 成本、延迟、用户满意度
  • 归因分析 :某次失败是 Prompt 问题、工具问题、状态管理问题,还是编排策略问题
  • 对比实验 :同一任务在不同策略下的表现差异(A/B 测试、Prompt 变体、工具链变体)
  • 反馈闭环 :评测结果如何驱动 Prompt 更新、工具优化、编排策略调整
  • Badcase 管理 :失败案例的结构化记录、分类、复现和追踪

当前框架的可评测能力普遍较弱。多数框架只提供 Trace 和 Event,但不提供:

  • 标准化的质量指标定义
  • 自动化的 Badcase 归因
  • 对比实验的协议支持
  • 评测结果到配置的自动反馈

这导致可观测数据主要停留在“调试用”,难以形成“质量改进闭环”。无论是自己建还是框架提供能力,都需要下面的:

  • 评测协议 :定义质量指标、评测数据集、对比实验的标准接口
  • 归因工具 :从 Trace 自动推断失败根因
  • 反馈机制 :评测结果能自动驱动 Prompt/工具/策略的调整
  • Badcase 库 :结构化失败案例,支持复现和追踪

9.7 本章结论

可观测性与可评测性回答“如何看见并评价一次 Run”。它收束前面的 Step、Event、State Snapshot、Artifact 和 Error,把 Runtime 执行过程变成可调试、可审计、可优化的数据。

Agent 需要同时具备可观测性和可评测性。可观测性需要 OpenTelemetry-like 的 Span、Trace、Event、State Snapshot、Artifact Link 和 Cost Attribution;可评测性需要 Metric Schema、Evaluation Dataset、Badcase Schema、Experiment Protocol 和 Feedback Loop。

生产级 Runtime 必须把两者打通:可观测数据应该能直接用于评测,评测结果应该能驱动 Prompt、工具和编排策略更新,形成“看见问题 → 评价质量 → 归因分析 → 优化策略”的闭环。


10. Agent Protocol 对象如何落到 Runtime 能力

如果用协议主线串起来,前面的生命周期和八个维度可以归结为一张映射表:

Protocol 对象/操作外部契约Runtime 需要实现的能力对应章节
Agent Card / Metadata告诉别人我是谁、会什么、怎么调用Agent 注册、能力描述、权限声明、版本管理2、6、8
Thread / Context承载多轮上下文和参与者会话管理、历史保存、上下文裁剪、参与者隔离3
Message / Part表达用户、Agent、工具的通信内容多模态输入、结构化数据、文件引用、消息追加3、6
Task / Run表达一次可管理的执行持久队列、RunAttempt、租约、状态机、超时、预算、重试2、4、5
Step / Run Step表达执行内部的可观测步骤LLM 调用、工具调用、Handoff、Guardrail 记录2、9
Event Stream表达进展增量SSE、Last-Event-ID、事件持久化、多通道流7
Interrupt / Input Required表达需要人类或外部系统继续Checkpoint、resume、审批、授权、表单输入4
Cancel / Cancel Requested提交取消请求,并区分 CANCEL_REQUESTED 与最终 CANCELED持久化取消状态、控制信号、CancellationToken、版本栅栏1、4
Run Relationship表达根任务、父任务和远程子任务的归属任务树、级联取消、定向恢复、孤儿任务回收8
Artifact表达任务产物文件管理、产物版本、增量产出、可追溯链接3、7、9
Todo / Plan表达长任务的显式计划任务分解、进度跟踪、计划更新、上下文压缩2、8
Workspace / Backend表达 Agent 可读写的工作区virtual filesystem、shell、store、权限、隔离2、3、6
Skill表达可复用能力包动态加载、权限控制、子 Agent 复用、脚本/参考资料6、8
Trace / Span表达执行因果链观测埋点、成本归因、状态关联、审计9
Error表达失败和下一步可能动作Error-as-Data、异常边界、回滚、重试策略5

前端、控制台、评测系统和审计系统依赖的是稳定的 Run、事件、产物和错误对象,而不是 Runtime 内部的类名。缺少这些对象时,一次执行无法被跨系统查询、恢复和审计。

10.1 一个好的 Agent Runtime Protocol 应该满足什么

  1. 任务对象一等化:不能只有 request/response,必须有可查询、可取消、可恢复的 Task/Run
  2. 上下文对象一等化:Thread/Context 不能只是 messages 数组,还要承载参与者、能力和元数据
  3. 步骤对象一等化:Run 内部的 LLM 调用、工具调用、Handoff、Guardrail、Subagent task 都应该能被表达为 Step/Run Step
  4. 事件流标准化:token、状态、工具、Artifact、错误都应该是同一条事件流上的不同事件
  5. 产物对象一等化:长任务的结果不应只塞进最终文本,而要成为可引用的 Artifact
  6. 中断是状态,不是异常INPUT_REQUIREDAUTH_REQUIRED 这类状态应该进入协议状态机
  7. 发现与能力声明分离:Agent metadata 负责发现,Capability 负责表达可选增强能力
  8. 协议绑定可替换:同一语义对象可以绑定到 REST、SSE、JSON-RPC、gRPC 或消息队列
  9. 观测语义内建:Trace/Span/Event ID 应该从协议层贯穿到 Runtime 内部
  10. 通知可以丢,任务不能丢PubSub 丢失后,新的 Worker 仍能从持久化 Run 状态判断任务应该执行、取消还是恢复
  11. 独立子任务必须保存归属关系:每个子 Run 写入 root_run_idparent_run_id;否则父进程退出后,取消、恢复和审计都会失去路由依据

10.2 Protocol 与 Runtime 的边界

Protocol 不应该规定模型怎么思考,也不应该规定内部必须用 Graph、Actor 还是 Code Loop。它应该规定:

  • 哪些资源可以被创建、查询、更新、取消
  • 每个资源有哪些稳定状态
  • 客户端如何订阅变化
  • 人类或其他 Agent 如何补充输入
  • 产物和错误如何被表达
  • 观测系统如何关联一次执行

Runtime 则负责:

  • 如何选择模型和工具
  • 如何调度步骤
  • 如何保存和迁移状态
  • 如何隔离工作区
  • 如何处理副作用
  • 如何把内部细节映射回协议对象

最好的协议是低约束的,最好的 Runtime 是高内聚的:协议只定义外部可依赖的语义边界,Runtime 在边界内保持实现自由。


11. 跨维度分析:设计决策的持久性判断

以下是我个人的一些判断。

11.1 哪些设计决策会持久?

设计决策持久性理由
Graph 是唯一最优 Runtime 形态流行代码式 Runtime、图式 Runtime、托管式 Runtime 会按场景并存;混合模式正在出现
Handoff 是多 Agent 标准流行太简单,无法处理并行和复杂拓扑
Conversation 是独立底层执行模型流行它更像运行在不同 Runtime 之上的编排协议,不应和 Graph / Code / Managed 平级
Checkpoint 链式版本控制可能持久概念有价值(类 Git),但实现可能简化
状态持久化是核心能力持久没有持久化的 Agent 无法用于生产
Error-as-Data 优于 Error-as-Exception持久Agent 需要自主推理错误,不是抛异常然后崩溃
SSE 是流式标准持久HTTP 原生、浏览器原生、自带重连机制
Server-managed Runtime 是生产必需持久但形态未定——可以是 Platform 也可以是自建

11.2 行业收敛趋势

正在收敛的

  • Agent 任务对象(Task / Run)
  • Agent 上下文对象(Thread / Context)
  • Agent 步骤对象(Step / Run Step / Tool Call)
  • Agent 事件流(SSE + 标准事件类型)
  • Agent 产物对象(Artifact / File / Structured Output)
  • 工具定义格式(JSON Schema)
  • 工具调用协议
  • 流式传输协议(SSE)
  • 错误处理哲学(Error-as-Data)

没有收敛的

  • Runtime Loop 承载方式(图式 Runtime / 代码式 Runtime / 托管式 Runtime 并存)
  • 编排协议模式(ReAct / Plan-and-Execute / Conversation-style coordination / Manager-Worker 并存)
  • 状态管理(Checkpoint / Thread / 手动管理并存)
  • 多 Agent 协作(各框架完全不兼容)
  • 可观测性标准(各自为战)

2 年内,Agent Protocol 会先在 Thread / Task / Run / Step / Message / Artifact / Event / Checkpoint 这些外部对象上收敛,工具层会继续标准化,流式层会统一到 SSE + 可恢复流,但 Runtime Loop 承载方式、编排协议和多 Agent 协作不会统一——因为它们解决的问题空间太大,不存在一个”最优解”。相对来说,Graph 可以认为是编排协议的一个超集。

11.3 作为开发者,重点关注什么?

方向建议理由
Agent Protocol 对象模型重点投入Thread、Run、Step、Artifact、Event、Checkpoint 会成为跨框架通用语言
工具协议抽象重点投入工具定义、调用、结果处理的设计模式跨框架可迁移
状态管理抽象重点投入无论哪个框架,状态持久化的设计模式是通用的
Harness 易用性判断重点投入开箱即用程度决定团队能否低成本把 Runtime 能力真正用起来
Error-as-Data 模式理解并应用改变你写 Agent 的方式,不依赖框架
特定框架的执行模型谨慎投入深入 1-2 个即可,重点理解 why,不是记 API
多 Agent 模式观望太碎片化,等标准出现再深入不迟
可观测性关注 OpenTelemetry 方向Agent Tracing 标准化是迟早的事

11.4 如果我从零设计 Agent Runtime Protocol

维度我的选择理由
协议对象Agent / Thread / Run / Step / Message / Event / Artifact / Checkpoint这些是外部系统真正依赖的稳定边界
执行模型混合:图式 Runtime 做复杂工作流,代码式 Runtime 做简单任务,编排协议按场景选择复杂工作流需要显式分支、并发控制和 Checkpoint;简单任务保留普通函数入口
任务调度持久化 Run + 短期队列信号 + lease/heartbeat任务不会因消息丢失而消失,Worker 宕机后可以重新领取
状态管理持久化事实与临时协调分层,自动 per-step Checkpoint数据库负责恢复,消息系统负责低延迟通知,不让 Redis 成为唯一状态
工具协议统一 Tool API + Adapter不再写框架特定的 Tool wrapper
流式输出SSE + 持久化事件片段 + Last-Event-ID客户端重连时携带 Last-Event-ID,服务端补发遗漏事件;存储不绑定某一种消息系统
中断/恢复通用 interrupt(payload, interrupt_id) + resume(interrupt_id, value)让输入回到准确的暂停点,不把恢复和取消混成一个动作
取消cancel(run_id, cancel_epoch) + 协作式检查 + 提交栅栏通知负责尽快唤醒 Workercancel_epoch 已变化时,数据库拒绝迟到结果和终态写入
错误恢复Error-as-Data 默认,系统错误才 raise工具业务错误以结构化结果返回执行循环,运行时异常则把当前 RunAttempt 标记为失败
多 AgentSubgraph 做紧耦合,父子 Run + 消息协议做跨服务协作图内中断交给 Runtime,跨服务暂停和取消交给显式协议
可观测性OpenTelemetry Span 作为一等原语每个节点执行自动生成 Span,不依赖特定平台
控制面权限、Guardrail、预算、取消内建写文件、发请求或创建订单前检查权限、预算和取消状态,并记录审批结果与外部副作用 ID
工作区Workspace/Sandbox 一等化文件、浏览器、代码仓库都属于 Runtime 状态

11.5 “用哪个框架”不重要,重点是“我需要什么 Runtime 能力”

Agent 框架还会继续变化。今天是 LangGraph、OpenAI Agents SDK、AutoGen、Claude Agent SDK,明天可能会出现新的图式 Runtime、新的编排协议、新的多 Agent 协作框架和新的托管式 Runtime。每个框架都会带来新的对象名、新的 API 形状和新的最佳实践。

但生产级 Agent 系统真正绕不开的问题一直稳定:一次执行如何创建、取消、重试和结束;哪些历史、文件、状态和权限对当前执行可见;失败、中断、升级后系统还能不能恢复;前端、评测和审计系统如何知道 Agent 正在做什么;最终产物如何被保存、引用、追溯和复用;Agent 什么时候可以真的改文件、发请求或下订单。

如果只盯着框架 API,很容易被短期流行牵着走;如果先建立 Runtime Protocol 的概念模型,就能反过来审视框架:它是否稳定表达 Thread / Run / Step / Event / Artifact / Checkpoint,是否具备真正的状态持久化和可恢复事件流,是否把工具层从框架绑定中抽出来,是否能支撑调试、审计、成本归因和质量评估。

对我来说,理解 Runtime Protocol 的价值,是把知识从“框架熟练度”提升到“系统设计判断力”。框架值得学,但不要只学框架;框架终究只是对现实问题的抽象。


附录 A:术语对照表

通用概念英文LangGraphOpenAI AssistantsAgents SDKAutoGenClaude SDK
执行上下文Execution ContextThread + RunThread + RunRunnerRuntime + TeamSession
执行单元Execution UnitNodeRun StepAgent turnMessage handlerAgent turn
状态快照State SnapshotCheckpointThread stateN/Asave_state()N/A
状态持久化器State PersisterCheckpointer服务端托管N/A手动N/A
工具定义Tool Definition@tool / BaseToolFunction@function_toolFunctionToolTool
工具调用结果Tool ResultToolMessageFunction outputTool outputFunctionExecutionResultToolResult
中断点Interrupt Pointinterrupt()requires_actionGuardrailHandoffTerminationinterrupt()
恢复指令Resume CommandCommand(resume=)submit_tool_outputs手动代码run_stream(task=)query()
流式事件Stream EventStreamPartSSE EventStreamEventMessageEvent
子 AgentSub-AgentSubgraphN/AHandoffNested TeamTask tool
执行追踪Execution TraceLangSmith TraceRun StepsSDK TracesConsole logN/A
错误结果Error Resulterror-as-data / raiselast_errorException错误消息Hook 通知

附录 B:各框架参考链接

LangGraph

Deep Agents

OpenAI

AutoGen

Claude Agent SDK

相关标准与协议