“榫卯”框架的构想–关于 Agent 执行底座的一些思考

近期为了求职, 我开始学习 Agent 开发. 在这个过程中我逐渐意识到, 在我接触到的许多 Agent 框架中, 仍然存在一些共同的局限:

  1. 状态与执行过程难以稳定地重现
  2. 长流程任务的中断与恢复不够自然
  3. 对分布式执行和跨节点协作的支持不够统一
  4. 扩展模型,运行环境和工具的方式比较分散
  5. 可观测性通常停留在文本日志层面
  6. 可靠性,隔离性与性能之间的取舍缺少统一描述

这些问题并不意味着现有框架没有价值. 恰恰相反, 它们说明 Agent 正在从一次性的调用, 逐渐变成需要长期运行,持续协作并且能够承担真实副作用的计算过程. 因此, Agent 需要的不只是更好的模型调用接口, 也需要更可靠的执行底座.

这使得我想起了一年前为了支持抢票状态机脚本而产生的一个想法: 分布式状态机. 经过一段时间的技术选型和思考, 我开始设想一种面向 Agent,追求可重现执行,可恢复和可分布式执行的框架, 并暂时将它命名为“榫卯”.

“榫卯”这个名字来自传统木构建筑中的连接方式. 我希望不同的计算模型,运行环境和能力组件, 能够通过清晰的语义边界组合在一起, 同时又不必把所有内容都耦合进同一个内核.

分布式状态机的理念

Agent 可以从状态机的视角来理解: 它拥有任务进度,上下文和记忆等状态, 也拥有已经发生的事件和仍在等待的操作, 并根据输入,规则以及模型的判断不断产生新的行为. 这里的状态机更接近对可观察执行过程的描述, 而不是要求所有 Agent 都采用同一种编程模型. 这种视角为我们描述执行过程提供了一个比较清晰的起点.

常见的状态机实现往往在单一进程中运行. 如果能够把其中一部分可独立执行的动作交给不同节点, 那么一个 Agent 就可以获得跨进程,跨设备协作的能力. 这与 Agent Swarm 所强调的协作关系有相似之处, 但仅仅分发动作并不会自动形成可靠的 Agent Swarm, 还需要进一步处理任务边界,消息传递,失败恢复以及副作用等问题.

分布式系统本身并不天然保证确定性. 相反, 网络延迟,消息重复,节点故障和并发调度都会带来新的不确定性. 因此, 我们需要把可重现性和可恢复性作为明确的设计目标: 在相同的输入,执行历史以及兼容的代码和组件版本下, 系统应当能够得到一致的状态演化结果; 对于可以恢复的故障, 则应当依据清楚的语义继续执行.

计算模型

如果设计只停留在分布式状态机, 那么它仍然只是某一种计算模型的分布式实现. 但无论是 Agent 还是一般的分布式系统, 都可能需要不同层次的计算模型, 例如 Λ Calculus,Actor,状态机,数据流或其他模型.

这些模型各自有不同的表达方式, 但它们通常都需要处理一些相似的问题: 状态如何变化, 任务如何协作, 何时产生副作用, 以及执行过程如何暂停和恢复.

因此, 我希望设计一个不把某种计算模型硬编码在内核中的底座. 上层模型可以使用各自的结构和语义表达任务, 底层则提供相对统一的执行,通信,状态和生命周期抽象. 这就是我对多层 IR 的初步理解.

这里的 WASM Component Model 不是榫卯的语义内核, 而是一种重要的执行载体. WASM 的执行模型与 Component Model 可以共同为工具,插件以及部分计算模型提供可移植的执行格式,清晰的接口组合和能力受限的沙盒边界. 榫卯负责说明一次组件调用在状态,外部效果,生命周期和恢复过程中意味着什么, WASM 运行时则负责在宿主提供的能力边界内承载这段代码. 具体的计算模型仍然需要拥有自己的表达方式, 并通过明确的接口与底座交互.

榫卯试图统一的语义

到这里需要先澄清, 榫卯并不打算把所有计算模型写成同一种语言, 也不打算用一套统一的接口取代所有上层框架. 这里的“统一”更接近于定义一组最小的共同概念和约束, 再让不同计算模型说明自己的行为如何与它们对应. 如果某些特性无法无损地对应, 这种差异也应该被明确保留下来, 而不是被抽象层悄悄抹去.

我目前认为, 最值得统一的是以下几组语义:

  1. 状态与演化语义: 一个任务当前知道什么,已经完成什么,正在等待什么, 以及输入和事件如何推动状态变化
  2. 事件与因果语义: 任务,消息,决策和结果之间哪些必须存在先后与依赖, 哪些可以并发, 它们又如何等待,汇合或产生新的任务
  3. 外部效果语义: 哪些行为只是内部计算, 哪些行为会读取或改变外部世界, 以及系统如何表达效果已经完成,尚未确认或需要补偿
  4. 生命周期与故障语义: 任务的开始,等待,取消,失败,重试,恢复,人工接管和完成分别意味着什么, 在这些变化之后哪些责任仍然存在
  5. 身份与历史语义: 逻辑任务,组件和单次执行实例如何彼此区分, 重试,恢复,迁移和版本变化后哪些身份关系仍然成立, 以及哪些历史需要被保留以支持观察,回放和审计
  6. 能力与执行边界语义: 一个执行单元可以访问哪些资源,承担哪些权限和约束, 当它在本地,沙盒或远程节点运行时, 哪些差异必须暴露, 哪些含义应当保持不变

其中, 状态,因果,效果和生命周期更接近执行模型的核心; 时间,资源,权限和位置则是贯穿这些核心语义的约束. 例如, 超时不仅是一个时间问题, 它还会改变任务的生命周期, 甚至影响一个外部效果是否仍然由当前任务负责. 因此, 它们不适合被看成彼此孤立的功能开关.

这些语义共同构成一种执行契约. 上层可以选择不同的计算模型, 底层也可以使用不同的运行环境, 但它们需要对共同部分给出清楚的解释: 哪些状态必须保留, 哪些事件形成因果关系, 哪些操作属于外部效果, 失败或迁移后哪些责任仍然存在. 只要这些约定没有改变, 暂停,恢复或更换节点就不应该悄悄改变任务的含义. 至于某种计算模型独有的行为, 则可以作为它自己的扩展语义继续存在.

这里还需要划出一条边界: 榫卯要统一的是执行事实, 而不是业务目标或智能策略. 任务为什么值得完成,Prompt 如何组织,某个领域中的“预订”具有什么业务意义, 仍然可以由上层编排或具体组件决定; 榫卯只要求这些决定在执行过程中能够被清楚地表达为状态,事件,效果和能力边界.

因此, 榫卯的核心并不是把所有东西都做成同一种模型, 而是让不同模型拥有可以相互连接的共同部分, 同时保留不能被简单统一的差异. 这也是“榫卯”这个名字对我来说最重要的含义.

多层 IR 设计

你可能知道 LLVM 的 MLIR. 我设想的多层 IR 并不是要简单复制 MLIR, 而是借鉴“不同层次的语义可以逐步转换”的思想, 让不同计算模型能够共享一部分基础设施.

一个可能的概念划分如下:

  1. Upper IR: 描述业务逻辑,任务关系以及较高层的语义拓扑
  2. Dist IR: 描述数据依赖,控制依赖,生命周期和副作用边界
  3. Kernel IR: 描述更基础的执行,通信和状态操作

上层 IR 可以表达更接近 Agent 或业务的概念, 下层 IR 则负责提供稳定的执行语义. 这种划分的目标不是保证所有图灵完备的计算模型都能被完全,无损地转换, 而是尽可能保留那些与状态,通信,恢复和副作用有关的关键语义.

不过, IR 只是承载和转换语义的方式, 本身并不会自动产生正确的语义. 应当先说明哪些行为需要被保留,哪些差异不能被隐藏, 再讨论这些内容是否适合由多层 IR 表达. 否则, 多层 IR 很容易变成一组名称不同但边界仍然模糊的中间结构.

Kernel IR 和 Dist IR 是这个方向中最需要谨慎研究的部分. 它们既要足够通用, 又不能因为过度抽象而失去可理解性和可验证性. 具体的原语和转换规则, 需要在后续的理论研究与实践中逐步确定.

与现有系统的关系

榫卯并不是要重新发明 Agent 编排,持久化执行或组件系统, 也不是要把它们全部替换掉. 现实中的系统往往同时覆盖其中几种能力, 因此下面的划分只是说明各自通常更关心什么, 而不是为它们划出绝对的边界:

  1. Agent 编排更关心“任务要做什么”, 例如如何规划步骤,选择工具以及协调不同角色
  2. 持久化执行更关心“任务中断后如何继续”, 例如如何保存进度,记录历史以及恢复执行
  3. 组件系统更关心“不同代码如何组合和隔离”, 例如如何描述接口,传递数据以及划分能力边界
  4. 分布式运行时更关心“任务在哪里以及如何被执行”, 例如如何安排节点,传递消息和处理故障

榫卯希望回答的是: 这些问题能否围绕同一套状态,因果,效果,生命周期和能力边界语义被统一描述. 这样, 上层 Agent 可以继续使用自己的编排方式, 组件可以继续使用自己的语言和接口, 而任务在暂停,恢复,迁移或跨节点执行时仍然拥有一致的含义.

从这个角度看, 榫卯与它们并不是简单的平行竞争关系. 对 Agent 编排来说, 榫卯不负责决定采用怎样的 Prompt,规划策略或角色关系, 而是为编排结果提供可以暂停,恢复和分布式执行的语义; 对持久化执行来说, 榫卯不只是关心“把进度保存下来”, 还要说明不同计算模型中的状态,外部效果,身份和能力边界究竟意味着什么; 对组件系统来说, 榫卯关心的是接口之外的生命周期,状态,协作和故障. Component Model 可以描述“一个组件能够调用什么”, 而榫卯还需要描述“这次调用在整个任务中意味着什么”. 对分布式运行时来说, 榫卯也不负责消除网络和节点之间的现实差异, 而是定义任务换了执行位置以后, 哪些性质仍然需要成立.

这也意味着, 在概念上先把榫卯理解为一份贯穿这些系统的执行语义和兼容边界, 可能比立刻把它定义成一个包办所有能力的框架更准确. 它最终可以由一个独立运行时承载, 也可以和已有的编排框架,持久化执行系统或组件运行时结合. 具体采用哪种形态, 并不是本文现在需要预设的结论.

例如, 对一个抢票任务来说, Agent 编排可以决定先查询再预订, 持久化执行可以保存每一步的历史, 组件系统可以承载查询和预订能力, 分布式运行时可以把不同动作交给不同节点. 榫卯需要关心的, 则是“预订”究竟是怎样的效果,何时算作完成,失败后如何继续, 以及任务迁移后这些含义是否仍然成立.

可观测性与可恢复性

我希望这套架构能够把“看见 Agent 做了什么”和“让 Agent 在故障后继续做下去”视为同一个问题的两个方面.

可观测性

很多 Agent 系统的日志往往是一段连续的文本流, 很难直接看出任务之间的依赖关系,状态变化和副作用边界. 如果执行过程本身带有计算模型的语义, 那么观测结果就不应只有日志文本, 还应该能够呈现任务拓扑,状态迁移以及不同层次的执行事件.

可观测性回答的是“系统刚才做了什么”, 而回放回答的是“系统能否根据已有历史再次走过同一过程”. 两者彼此相关, 但并不完全相同.

对于 LLM 来说, 输出结果通常无法依靠再次调用来稳定重现. 因此, 在合适的执行边界上记录与决策有关的输入,输出和外部结果, 可以让系统在回放时使用原有的执行历史, 从而在定义好的边界内重建一致的运行轨迹. 这里追求的是“可重放的执行过程”, 而不是声称 LLM 本身已经变成了确定性程序.

回放也不等于重新执行所有外部操作. 对于外部效果, 更准确的做法是重建它的历史结果和责任状态, 而不是在回放过程中再次触碰真实世界.

与此同时, 执行历史中可能包含 Prompt,用户数据和外部系统的返回结果. 因此, “能够记录”并不意味着“应该无限制地记录”, 这些历史同样需要受到权限,隐私和生命周期边界的约束.

可恢复性

一个长流程任务最怕在中途失败后丢失进度, 更怕已经产生的外部操作无法确认或重复执行. 因此, 可恢复性不仅意味着保存内存状态, 还意味着保存任务进度,执行历史以及外部副作用的状态和不确定性.

在历史足够完整且代码和组件版本兼容时, 系统可以据此恢复 Agent 的逻辑状态和已经完成的步骤. 某些运行时也可能提供状态快照, 作为恢复的一种辅助方式, 但快照并不能自动涵盖网络连接,外部服务和其他宿主状态.

Agent 的 Tool Call 可能改变真实世界. 对于这类操作, Saga 更适合被理解为一组有顺序的业务补偿动作, 而不是对现实世界进行真正的“逆向回滚”. 有些副作用可以补偿, 有些只能通过查询,对账或人工介入处理. 因此, 框架需要尽可能让这些动作具备清晰的边界, 并在跨节点恢复时避免重复或失去所有权.

对于外部世界的操作, 榫卯能够管理的是执行意图,执行结果以及后续的补偿过程, 而不能单方面保证每个动作只发生一次, 也不能保证每个动作都可以撤销. 承认这种不确定状态, 本身也是可靠执行语义的一部分.

组件化扩展

为了让内核与扩展能力保持相对解耦, 我希望把 WASM Component Model 作为需要隔离或跨语言组合的执行单元的主要载体, 而不仅是一种插件格式.

WIT 可以用来描述组件之间的接口契约, Canonical ABI 则规定不同语言之间如何交换这些接口中的值. 这为插件,工具和计算模型提供了较为清晰的组合方式.

在这个构想中, 一个 WASM 组件实例既可以作为一个节点, 也可以成为某个节点内部的执行单元. 同一份执行契约也可以由可信的本地代码或远程服务承担, 但对于不完全可信,需要跨语言运行或需要明确资源边界的逻辑, WASM 应当成为优先选择. 这并不要求调度,持久化和恢复机制本身都运行在 WASM 中, 也不要求一个完整的 Agent 必须被封装成单个组件. 从这个意义上说, 榫卯可以是 WASM-first, 但不必是 WASM-only.

这种方式并不意味着组件之间一定共享内存, 也不自动保证接近原生的性能. 实际开销会受到数据表示,调用频率,运行时和边界设计的影响, 需要后续通过实践验证.

同样, “可以编译到 WASM”也不等于“可以直接作为组件使用”. 不同语言对 WASI,Component Model,异步和资源类型的支持程度并不相同. 我更希望它最终支持一组具有成熟工具链的语言, 而不是在一开始承诺任意语言都能无缝接入.

组件化也为独立升级和动态装载提供了可能, 但这需要接口兼容,版本管理以及运行中状态的处理. 这些属于后续需要单独论证的问题.

异构设计

狭义的分布式通常把节点理解为不同的机器. 但对 Agent 来说, 节点也可以是同一设备中的线程,沙盒,运行时或进程, 也可以是远程设备,服务乃至另一个 Agent.

在这个构想中, “节点”并不特指一台物理机器, 而是一个能够承载部分执行过程,拥有一定状态并受到能力边界约束的执行单元.

这种尺度上的差异, 让 Agent 的执行环境呈现出一种层次化和异构化的特征. 一个任务可以在本地完成, 也可以被交给远程节点或其他 Agent; 对上层任务来说, 这些执行位置可以通过统一的语义来描述.

不过, 不同节点并不是完全等价的. 它们在延迟,可靠性,权限,资源和故障范围上都有差异. 因此, “无感的分布式”更应该意味着上层不必承担底层通信细节, 而不是忽略这些差异.

如果未来 AGI 或具身智能成为现实, 可被调度的节点可能进一步延伸到物理世界中的设备和实体. 这是一种值得想象的远景, 但并不是当前框架成立所必需的前提.

能力边界与沙盒

引入 WASM 后, 在采用能力控制的运行时中, Agent 的部分逻辑,工具和扩展组件可以运行在一个具有明确边界的执行环境中. 组件不会天然获得宿主环境的全部权限, 而是通过宿主显式提供的能力访问文件,网络,模型或其他资源. 这样可以降低扩展代码对宿主造成意外影响的范围, 也为审计和追踪提供边界.

对于榫卯来说, 这层沙盒不仅用于隔离代码, 也可以成为能力和外部效果的边界. 当组件需要访问宿主资源时, 系统可以明确知道它请求了什么能力, 并把这次访问放回整个任务的状态,历史和生命周期中理解. 因此, WASM 的沙盒能力与榫卯的执行语义并不是彼此独立的两部分, 而是分别从执行机制和任务含义两个方向描述同一个边界.

但沙盒不是绝对安全的保证. 如果宿主直接暴露了不受约束的文件,网络或进程能力, 那么即使代码运行在 WASM 中, 沙盒也无法替代这些权限控制. 宿主提供了什么能力,如何限制资源,如何处理运行时错误, 同样决定了系统的安全性和稳定性. 因此, WASM 更适合作为能力隔离的一层基础, 而不是替代完整的安全模型.

形式化验证

如果希望系统具备较高的可靠性, 就不能只依赖大量测试, 还需要研究哪些性质可以被形式化描述和验证.

我目前感兴趣的方向包括:

  • 分布式执行与补偿过程中的一致性性质
  • 执行历史与恢复过程的正确性
  • 不同 IR 之间转换时的语义保持
  • 组件边界,权限和资源访问的约束
  • 通信协议中的安全性与活性

这里的目标不是证明 LLM 的回答永远正确, 而是尽量证明 Agent 的执行边界,状态演化和故障处理不会违反预先定义的约束. 至于哪些性质真正值得验证, 以及采用怎样的理论和工具, 还需要通过后续研究逐步明确.

网络协议

在网络层面, 系统需要面对可靠传输,身份认证,消息顺序,超时,重试和取消等问题. 现有的 RPC 与传输协议可以提供重要的基础能力, 但它们本身并不等于完整的分布式执行语义.

本地执行也可能存在进程,线程和沙盒之间的通信边界. 至于是否采用共享内存,零拷贝或其他优化方式, 应该根据实际的工作负载和性能测试决定, 而不应成为架构成立的前提.

对未来的展望

在我目前的预期里, 只要未来的智能系统仍然需要管理状态,调用外部能力并在不同计算资源之间协作, 那么这里讨论的许多问题就仍然存在.

短期来看, 这套思想可以用于思考更可靠的 Agent 长流程,工具调用和多 Agent 协作. 更长远地看, 它也可能与 Agent OS,具身智能以及其他分布式计算系统产生联系.

我希望用户能够在一个设备上发起任务, 让另一个设备或服务承担具体操作, 并且在任务暂停,迁移或恢复时仍然保留清晰的执行语义. 这并不意味着未来的 Agent 没有边界, 而是希望这些边界能够被明确描述,组合和管理.

即使暂时不讨论 AI 和 LLM, 其中关于状态,执行历史,组件边界和异构协作的思想, 也可能对某些分布式计算场景有参考价值. 但它是否能够成为通用基础设施, 仍然需要长期的理论和实践验证.

总结

以上内容仍然只是“榫卯”框架的基本构想, 不是完整的技术设计. Kernel IR 应该包含哪些原语, 多种计算模型如何共享执行语义, 执行历史与补偿机制如何配合, 以及不同节点之间如何安全地迁移任务, 都还需要进一步研究.

本文并不试图让 LLM 本身变得确定, 也不承诺所有外部操作都能精确回滚, 更不试图一次解决所有分布式计算问题. 榫卯当前最重要的问题, 是确定哪些执行语义值得被统一, 以及这些语义能否在 Agent 编排,持久化执行,组件边界和不同运行环境之间保持一致. 也就是说, 下一步首先要明确最小的执行契约, 而不是急于确定 Kernel IR 的全部原语或某一种运行时的最终形态.

我希望先把这套思想作为一个问题框架保留下来: 让 Agent 的不确定性停留在可管理的边界内, 让状态,行为和副作用能够被观察,恢复和组合. 具体的实现方式,协议选择和形式化模型, 将在后续的文章和实践中分别讨论.