跳转至

Jianmu 产品与架构概览

本文面向产品经理、业务负责人、合作方,以及希望快速理解 Jianmu 的非核心开发人员。它不打算解释每个模块怎么实现,而是回答几个更直接的问题:Jianmu 是什么、为什么这样设计、它适合解决什么问题、和主流 Agent 框架有什么不同。

目录

  1. Jianmu 是什么
  2. 1.1 一句话定位
  3. 1.2 Jianmu 关注的不是“让 LLM 调工具”
  4. 1.3 三个核心设计目标:复杂编排、自治运行、长时运行
  5. 1.4 从核心目标到 Runtime 模块

  6. 为什么需要 Jianmu

  7. 2.1 从最简单的 Agent 开始
  8. 2.2 Agent 进入真实业务后会发生什么
  9. 2.3 Jianmu 解决的是 Agent Runtime 问题
  10. 2.4 什么时候应该用 Jianmu

  11. Jianmu 的整体产品架构

  12. 3.1 产品架构总图
  13. 3.2 三个 Runtime 支柱:Structured / Reactive / Durable
  14. 3.3 运行内核:Runner / Node / State
  15. 3.4 生命周期与持久化:Suspend / Resume / Checkpoint / Effects / Termination
  16. 3.5 治理:Guard / Approval / Sandbox / Permission
  17. 3.6 观测与扩展:Event / Telemetry / Hook
  18. 3.7 能力层:Model / Tool / Skill / Memory / Context / MCP / RAG
  19. 3.8 多智能体:Swarm

  20. 运行内核:Runner、Tree、Node 与 State

  21. 4.1 行为树承载的 Agent 循环
  22. 4.2 Runner:Event-driven Tick
  23. 4.3 Node / Tree / Preset:Agent Loop 与 Tree Skill 的共同基石
  24. 4.4 State / Port Binding:节点之间如何共享数据

  25. 生命周期与持久化:Suspend、Resume、Checkpoint、Effects、Termination

  26. 5.1 等待不是异常:Suspend / Resume
  27. 5.2 什么时候应该停止:Termination 也是 Runtime 语义
  28. 5.3 恢复不只是恢复状态:Effects、Commit Boundary 与 Reconciliation
  29. 5.4 一个完整任务示例

  30. 治理:Guard、Approval、Sandbox 与 Permission

  31. 6.1 人如何进入 Agent 的执行闭环
  32. 6.2 Guard / Approval / Sandbox
  33. 6.3 Hook、Guard、Approval 的边界

  34. 观测与扩展:Event、Telemetry 与 Hook

  35. 7.1 为什么长期运行的 Agent 不能是黑盒
  36. 7.2 Event Bus:Runtime 里发生了什么
  37. 7.3 Telemetry:从事件到完整运行轨迹
  38. 7.4 Hook:在不修改主循环的情况下进入执行过程
  39. 7.5 从观察到干预:Hook 能改变什么
  40. 7.6 为什么这一层决定了 Jianmu 能不能真正产品化

  41. 能力层:Model、Tool、Skill、Memory、Context、MCP 与 RAG

  42. 8.1 Model:Provider、Retry / Fallback 与 Streaming
  43. 8.2 Tool / MCP:连接外部世界
  44. 8.3 Skill:把经验沉淀成能力
  45. 8.4 Tree Skill:企业确定性的主要沉淀方式
  46. 8.5 Context / Memory / RAG:模型看到什么、系统记住什么、外部取回什么

  47. 多智能体:Swarm

  48. 9.1 多 Agent 不等于“多个模型互相聊天”
  49. 9.2 Subagent、Agent Team 和 Swarm:同一个 Runtime 的不同自由度
  50. 9.3 Agent 是有生命周期的执行体
  51. 9.4 每个 Agent 都有自己的身份、状态、任务与 Mailbox
  52. 9.5 通信本身就是 Runtime 的一部分
  53. 9.6 消息就是事件:Agent 如何互相唤醒
  54. 9.7 Direct / Group / Topic:Swarm 中的通信网络
  55. 9.8 去中心化协作:没有必须掌控全局的总指挥
  56. 9.9 Liquid Topology:组织结构随着任务动态变化
  57. 9.10 Agent 创建 Agent:协作网络可以自己生长
  58. 9.11 长时 Swarm:生命周期、Mailbox、Snapshot 与恢复
  59. 9.12 Swarm 如何处理重复执行、并发与幂等
  60. 9.13 Jianmu 的“去中心化”到底指什么

  61. 从能力沉淀到持续改进

    • 10.1 从一次成功执行到可复用能力
    • 10.2 Capability Loop:执行 → 验证 → 沉淀 → Skill → 复用
    • 10.3 从运行证据到候选能力
    • 10.4 验证、晋升与回滚
    • 10.5 从能力积累到持续改进 / RSI
  62. Jianmu 与主流 Agent 框架的设计取向

    • 11.1 不同框架在解决同一个问题
    • 11.2 LangGraph:State Graph 与 Durable Execution
    • 11.3 AgentScope:Agent-centric Application Framework
    • 11.4 AutoGen:Event-driven Multi-Agent Runtime
    • 11.5 Jianmu:Behavior Tree as Agent Runtime
    • 11.6 为什么 Jianmu 选择行为树
  63. Jianmu 已经长出了哪些产品形态

    • 12.1 TUI Chat
    • 12.2 Tree Studio
    • 12.3 Swarm Studio
    • 12.4 Seedbot / 业务 Agent
    • 12.5 同一个 Runtime,不同产品形态
  64. Jianmu 与 Agent Engineering 的演进

    • 13.1 Harness Engineering:可靠执行环境
    • 13.2 Loop Engineering:自治执行闭环
    • 13.3 Structured Orchestration:复杂控制结构
    • 13.4 Jianmu 为什么会自然汇聚到这些问题
  65. 总结:Jianmu 的设计哲学

    • 14.1 Agent 是有生命周期的执行体
    • 14.2 模型负责判断,Runtime 负责让事情继续发生
    • 14.3 稳定的部分结构化,不确定的部分交给模型
    • 14.4 等待、失败、人介入和恢复都应该是正常运行状态
    • 14.5 Tree Skill 让能力积累,Swarm 让多个执行体持续协作
    • 14.6 Jianmu 的边界:它是 Runtime,不是所有问题的答案

1. Jianmu 是什么

本章用途:先把 Jianmu 说清楚。

1.1 一句话定位

Jianmu 是一个以行为树承载 Agent Loop 的 Runtime,主要面向复杂编排、自治运行和长时任务。

它解决的是 Agent 在真实业务里会遇到的问题:一次行动循环怎么持续推进,任务做到一半要等人怎么办,程序重启后怎么继续,一个 Agent 不够时怎么协作,以及一套已经跑通的做法怎么沉淀成可复用、可治理的 Tree Skill。

Jianmu 的定位不放在 agentic workflow 那一层。它的底层仍然是现代 Agent:模型可以观察环境、判断下一步、调用工具、读取反馈并继续行动。Jianmu 做的是把这个 ReAct 内核循环放进行为树里,由事件驱动 Runner 持续 tick;再通过 Tree Skill 和治理层,把稳定下来的行为变成可复用、可审计、可干预、可恢复的企业级能力。

可以把大模型和 Jianmu 的关系简单理解成:

大模型负责判断下一步做什么,Jianmu 用事件驱动的行为树 tick 让这个判断持续、可控地变成行动。

1.2 Jianmu 关注的不是“让 LLM 调工具”

最简单的 Agent 并不难做。给模型一些工具,让它根据用户问题选择工具、读取结果、继续推理,就已经可以完成不少任务。真正麻烦的是任务变长、流程变复杂以后,Agent 该怎么运行。

比如一个订单处理 Agent,可能先要查订单和库存,再判断风险;遇到异常要换一条处理路径;涉及退款时要等人工审批;审批可能十分钟后才回来;中间某个外部接口还可能失败,需要重试或者降级。如果任务进一步拆给多个 Agent,它们还要互相发消息、等待结果,并知道各自做到哪里。

Jianmu 把处理现实中复杂执行所需要的能力建模成了完整且自洽的 Runtime。模型、Tool、Skill 都可以接进来,但任务状态、行为树 tick、等待与恢复、多 Agent 协作、安全控制等问题,不需要每个业务重新用 Prompt 和胶水代码拼一遍。

1.3 三个核心设计目标:复杂编排、自治运行、长时运行

Jianmu 的设计重点可以归纳成三个方向。

复杂编排

模型越来越强后,很多日常任务并不需要提前写成一张完整 Workflow。一个 ReAct Agent 自己看信息、调工具、读结果、继续判断,已经可以完成不少工作。

但真实业务里的 Agent 运行久了以后,问题会变多。它会遇到重试、降级、等待、审批、回调、子任务和多 Agent 协作。靠模型每一轮临场规划,前期很快;到了复杂场景,执行逻辑就容易散在 Prompt、工具代码和业务判断里。

Jianmu 使用行为树作为 Agent Runtime 的 Loop 内核。行为树最早用于游戏 AI 和机器人领域,是一种将决策逻辑与执行逻辑统一表示的树形模型。与传统流程图不同,行为树中的节点不仅表示一个步骤,还可以表示条件选择、顺序执行、并行执行、循环、重试等控制行为。

机器人执行任务的行为树示例

图:用行为树拆解“将物体从 A 点搬运到 B 点”任务。

相比通用的图结构,复杂流程在节点和跳转增多后容易形成难以阅读的“面条图”;而树结构天然具有层级结构,可以逐层拆解复杂度,使整体结构更容易理解和维护。

关键在于,Jianmu 的底层循环仍然是 Agentic 的。模型可以持续判断、选择工具、读取结果并继续行动;行为树负责构建这个 ReAct 循环,让它可以被 Runner 推进、暂停、恢复和观察。复杂业务编排主要放在 Tree Skill 这一层,同样使用 Node / Tree 表达结构,但面向的是稳定业务能力,而不是把内层 Agent Loop 写得很复杂。

自治运行

自治系统指的是不依赖外部人工输入、能自觉感知外部环境变化而作出行动的系统。

Jianmu 把行为树的 tick 执行和事件机制结合起来。Agent 不需要靠外部输入一遍遍手动触发:状态发生变化、收到新消息、异步任务完成,或者之前等待的外部结果回来后,Runtime 可以继续推进执行。

长时运行

Jianmu 围绕 Agent 构建了完整的生命周期。任务可能很快完成,也可能中间等待外部系统、人工审批或其他 Agent。Jianmu 会管理任务状态和执行进度,并通过 checkpoint、挂起与恢复等机制,让任务在中断之后能够继续推进,而不是只能从头再来。

行为树在这里提供稳定的执行结构,Runtime 则负责状态、事件和恢复。两者共同构成了 Jianmu 的长时运行能力。

1.4 从核心目标到 Runtime 模块

前面三个目标会自然落到几组 Runtime 模块上。

如果把 Jianmu 展开成一棵 Runtime 设计树,大致可以这样看。

flowchart LR
    ROOT["Jianmu Agent Runtime"]

    EX["运行内核<br/>Runner · Node/Tree · State"]
    DU["生命周期与持久化<br/>Suspend / Resume · Checkpoint<br/>Effects · Termination"]
    GO["治理<br/>Guard · Approval · Sandbox · Permission"]
    OB["观测与扩展<br/>Event · Telemetry · Hook"]
    CA["能力层<br/>Model · Tool · Skill · Memory<br/>Context · MCP · RAG"]
    SW["多智能体<br/>Swarm"]

    ROOT --> EX
    ROOT --> DU
    ROOT --> GO
    ROOT --> OB
    ROOT --> CA
    ROOT --> SW
核心目标 主要依赖模块
复杂编排 Tree Skill(基于 Node / Tree)
自治运行 行为树承载的 ReAct Loop、Runner、Event、State、Model、Tool
长时运行 Suspend / Resume、Checkpoint、Effects、Termination

企业化需要的确定性主要由 Tree Skill 承担。Tree Skill 使用同一套 Node / Tree 表达能力,把稳定业务做法组织成可复用、可审计、可测试、可版本管理和可回滚的能力。

除了这三条主线,Jianmu 还需要治理、观测、能力接入、经验复用和多智能体协作等支撑模块。它们不是新的核心目标,而是让这三个目标能够在真实系统里成立。

2. 为什么需要 Jianmu

本章用途:从普通 Agent 的能力边界出发,说明为什么当任务变复杂以后,光有模型、Prompt 和 Tool 还不够。

2.1 从最简单的 Agent 开始

一个最简单的 Agent,通常可以理解成三样东西:模型、Prompt 和 Tool。

用户提出任务后,模型判断要不要调用工具;拿到工具结果后,再决定下一步,直到给出答案。对于一次性、短流程的任务,这种方式已经很好用。

比如:

  • 查一个订单状态;
  • 根据几份资料生成总结;
  • 调一个接口查询库存;
  • 根据用户要求生成一份报表。

这类任务有一个共同点:生命周期很短,执行过程也比较简单。

很多时候,一个 ReAct 循环,甚至一段普通业务代码,就够了。Jianmu 并不是为了替代这些简单方案。

问题出现在任务开始变长以后。

原本的一次模型调用,可能变成十几步执行;原本只有一个工具,后来需要调用多个业务系统;原本一次请求内就能完成,后来开始出现等待、审批、回调、失败重试和多 Agent 协作。

这时候,Agent 的难点会慢慢从“模型下一步想什么”,转移到“这件事到底怎么持续跑下去”。

2.2 Agent 进入真实业务后会发生什么

真实业务很少是一条从头走到尾的直线。

还是以一个订单异常处理 Agent 为例。

它可能先查询订单信息,然后检查库存和支付状态。如果只是普通异常,可以自动处理;如果金额较大,需要人工审批;如果库存系统暂时不可用,要过一会儿再试;如果问题涉及物流,还需要把一部分任务交给另一个 Agent;等对方返回结果以后,再决定最终怎么处理。

于是几个很现实的问题会同时出现。

流程会越来越复杂。

分支、重试、降级、并行任务、等待条件不断增加。如果这些逻辑全部堆在一段 Prompt、一个 while 循环或者一张不断扩大的流程图里,早期可能还能维护,后面会越来越难看清楚“现在为什么走到这里”。

任务会停下来。

Agent 不可能一直占着线程等待。它可能要等人工审批、用户补充信息、外部系统回调,甚至等另一个 Agent 几分钟以后才返回结果。

这时候系统需要知道:为什么停、停在哪里、等什么,以及条件满足以后从哪里继续。

执行会失败。

真实的工具调用会超时,接口会报错,进程会重启,模型也可能给出不符合预期的结果。

如果任务已经执行了很多步骤,中途出错后全部从头开始,不但浪费成本,还可能把已经执行过的真实操作再执行一次。

有些动作不能让 Agent 自己决定。

查数据和发起退款不是一回事。读一个文档和删除一批数据也不是一回事。

当 Agent 开始操作真实业务系统,就需要权限、审批、预算、频率限制、执行隔离,以及一套能看清楚“它刚才到底做了什么”的记录。

一个 Agent 也可能不够。

复杂任务经常天然包含不同角色:有人负责分析,有人负责查资料,有人负责执行,有人负责检查结果。

这时问题又会变成:这些 Agent 怎么创建、怎么发消息、怎么等待彼此、一个 Agent 挂掉以后怎么办,以及整个团队的状态怎么保存。

最后还有一个更长期的问题:

同样的事情,为什么每次都要重新想一遍?

如果某套处理流程已经被反复验证过,系统应该能把它留下来,下一次直接复用,而不是每次重新让模型规划一遍。

这些问题放在一起看,就会发现它们并不属于某一个 Prompt,也不属于某一个模型。

它们属于 Agent 的运行过程本身。

2.3 Jianmu 解决的是 Agent Runtime 问题

Jianmu 就是在这个位置上出现的。

它不替模型负责“变聪明”,也不要求所有业务都改成一种固定写法。它主要负责模型做出决定以后,整个 Agent 任务怎么被组织、推进、暂停、恢复和约束。

可以把一套完整的 Agent 系统粗略拆成两部分:

模型 / Prompt / RAG
        ↓
   决定下一步做什么
        ↓
----------------------
        ↓
      Jianmu
        ↓
怎么执行、怎么等待、怎么恢复、怎么协作、怎么受控
        ↓
Tool / Skill / 外部系统 / 其他 Agent

上半部分更偏“智能”,下半部分更偏“运行”。

Jianmu 主要做的是后者。

这也是为什么 Jianmu 更适合被理解成 Agent Runtime,而不只是一个行为树库或者一套 Agent SDK。

行为树是它组织复杂控制逻辑的核心结构,但 Jianmu 真正提供的是围绕这个结构的一整套运行能力:状态管理、事件驱动、挂起与恢复、checkpoint、Tool 和 Skill、多 Agent、Guard、Sandbox、Telemetry 等。

这些能力单独看都不神秘。真正重要的是,它们被放在同一个运行模型里以后,很多原本需要业务层自己处理的问题就有了统一的语义。

比如:

  • 等人工审批和等外部回调,本质上都可以看作“任务暂时挂起”;
  • 工具执行失败和子任务失败,都可以进入统一的重试或降级路径;
  • 单 Agent 和多 Agent 都有明确的生命周期;
  • 任务状态和执行进度可以一起保存,而不是只保存一段聊天记录。

所以,Jianmu 想解决的并不是“怎么更快做出一个 Demo Agent”,而是另一个阶段的问题:

当 Agent 已经能做事以后,怎么让它在复杂、真实、会中断的环境里继续把事情做完。

2.4 什么时候应该用 Jianmu

不是所有 Agent 都需要 Jianmu。

如果需求只是一次模型调用、几个简单 Tool,或者一条很短的固定流程,直接使用模型 SDK、普通代码、成熟的 ReAct Agent 或任务队列,往往更简单。

Jianmu 真正开始体现价值,通常是在 Agent Loop 本身变复杂以后。比如任务逐渐出现:

  • 多层分支、Retry、Fallback 和并行控制;
  • 异步任务、外部回调、等待用户或审批;
  • 一个任务跨越多次请求、进程重启甚至更长时间;
  • 高风险动作需要 Guard、Approval、Sandbox 和审计;
  • 外部副作用不能因为恢复而被重复执行;
  • 多个 Agent 需要有独立生命周期并持续协作;
  • 已经跑通的做法希望沉淀为 Tree Skill,而不是每次重新规划。

可以粗略理解成:

单轮问答 / 简单 Tool Calling
→ 普通 SDK 往往足够

简单、固定的线性流程
→ 代码 / DAG 往往更直接

行为树 Agent Loop + 等待 + HITL + 恢复
→ 开始进入 Jianmu 擅长的范围

长时自治 + 真实副作用 + 多 Agent + Tree Skill 沉淀
→ Runtime 的价值会越来越明显

但这里有一个很重要的现实:真实生产环境往往比 Demo 复杂得快得多。

一个原本看起来只是“LLM 调三个 Tool”的功能,上线以后很容易继续出现:权限怎么控制、接口超时怎么办、用户中途取消怎么办、金额太大谁审批、服务重启以后怎么恢复、动作到底有没有执行成功、多个任务并发会不会重复、出了问题怎么追踪。

这些需求通常不是一次性全部出现,而是随着产品真正接触用户和业务,一层一层长出来。

所以“什么时候需要 Jianmu”的门槛,并不一定是系统已经复杂到肉眼可见的程度。很多真实业务一旦要求可靠、持续、可控地执行,其实很快就会跨过这个门槛。

Jianmu 不是为了把简单 Agent 改造成 Workflow,而是为了在 Agent Loop 变长以后,让运行、等待、恢复和能力沉淀都有明确位置。

3. Jianmu 的整体产品架构

本章用途:先看全貌。这里讲每一层为什么存在,不深入模块实现。

3.1 产品架构总图

如果只从产品角度看,Jianmu 可以分成几层:最上面是具体产品和业务应用,中间是 Agent 本身,下面是负责持续运行的 Runtime。Runtime 内部再拆成几组相对稳定的模块,负责执行推进、生命周期、治理、观测扩展、能力接入和多智能体协作。

flowchart TB
    APP["产品 / 业务应用<br/>TUI Chat · Tree Studio · Swarm Studio · Seedbot · 业务系统"]

    AGENT["Agent / Agent Swarm<br/>理解任务 · 做出判断 · 协作分工"]

    subgraph RUNTIME["Jianmu Agent Runtime"]
        EX["运行内核<br/>Runner · Node/Tree · State"]
        DU["生命周期与持久化<br/>Suspend / Resume · Checkpoint<br/>Effects · Termination"]
        GO["治理<br/>Guard · Approval · Sandbox · Permission"]
        OB["观测与扩展<br/>Event · Telemetry · Hook"]
        CA["能力层<br/>Model · Tool · Skill · Memory<br/>Context · MCP · RAG"]
        SW["多智能体<br/>Swarm"]
    end

    WORLD["外部能力与业务世界<br/>模型服务 · 工具服务 · 知识库 · 人工审批 · 业务系统"]

    APP --> AGENT
    AGENT --> RUNTIME
    CA --> WORLD

    EX --> DU
    EX --> GO
    EX --> OB
    EX --> CA
    EX --> SW
    GO -.约束动作.-> CA
    OB -.运行记录.-> APP
    DU -.保存进度.-> EX

这张图里,最值得注意的是 Agent 和 Runtime 被分开了。

Agent 更像“做决定的人”,负责理解任务、判断下一步、选择工具或 Skill,必要时把任务交给其他 Agent。

Runtime 负责让事情持续跑下去。它要知道现在执行到哪里,什么时候该继续 tick,为什么暂停,出错以后怎么办,程序重启以后怎么恢复,以及多个执行体之间怎么协调。

Jianmu 的 Runtime 把 Agent 的 ReAct 式行动循环放进行为树里运行。模型仍然负责判断和选择,行为树负责控制执行路径,状态和事件负责让这个循环可以暂停、恢复和继续。

所以 Jianmu 更接近现代 Agent Runtime,而不是一套 agentic workflow builder。workflow 更像提前定义好路径,再让模型填充局部判断;Jianmu 的内核循环仍然是 Agent 在观察、判断、行动和读取反馈,只是这个循环被行为树组织起来,并由事件驱动机制推进。

Tree Skill 位于更上层。它处理的是另一件事:当某段 Agent 行为已经稳定下来以后,把它整理成一棵可复用的树。企业场景要的确定性,主要就落在这里。模型仍然可以处理不确定判断,但已经验证过的步骤、边界、审批和失败处理,可以通过 Tree Skill 固定下来。

所以 3.1 先按产品模块看全貌。下一节再把这些模块背后的运行语义抽象成 Structured、Reactive 和 Durable 三个支柱。

3.2 三个 Runtime 支柱:Structured / Reactive / Durable

Jianmu Runtime 里最核心的东西,可以先不按代码模块看,而是看成三个支柱。

支柱 解决的问题 Jianmu 里的主要做法
Structured Control 稳定业务能力越来越复杂以后,执行逻辑怎么保持清楚 Tree Skill、层级子树、Retry、Fallback、Wait 等控制结构
Reactive Execution Agent 怎么在有变化时继续跑,而不是靠人工反复触发 Event-driven Runner、Behavior Tree Tick、消息与状态变化唤醒、Suspend / Resume
Durable State 任务跨等待、跨中断以后,怎么知道之前做到哪里 State、Context、Checkpoint、Memory、执行状态恢复

这三个东西不是互相独立的功能。

比如一个退款任务正在等审批:行为树知道当前流程走到“审批”这一步;Runtime 把任务挂起,不再无意义地循环;Checkpoint 保存当前状态;等审批结果回来以后,一个事件重新唤醒任务,然后从原来的位置继续。

如果只有 Behavior Tree,没有事件和状态恢复,它更像一个结构清楚的流程执行器。

如果只有事件循环,没有结构化控制,Agent 可以一直运行,但复杂流程还是容易慢慢堆成大量判断和胶水代码。

如果只有状态持久化,也只能回答“之前保存了什么”,不能自然回答“接下来该从哪一步继续”。

Jianmu 想做的是把这三件事放进同一个执行模型里。底层循环仍然是 Agent 在感知、判断、行动、观察结果;只是这个循环不直接写成一段不可控的 while loop,而是通过事件驱动的 Runner 和行为树 tick 承载起来。

这也对应了前面提到的三个设计重点:

  • 复杂编排主要落在 Tree Skill;
  • 自治运行主要来自 event-driven Runner 和 Behavior Tree tick;
  • 长时运行依赖 Reactive Execution 和 Durable State 一起工作。

3.3 运行内核:Runner / Node / State

运行内核是 Jianmu 最内层的一组模块。Runner 负责在事件到来时推进 Runtime,Node 承载行为树中的具体行为并构成 Tree,State 保存任务当前状态。

flowchart LR
    R["Runner<br/>推进 tick / 处理唤醒"] --> N["Node/Tree<br/>承载行为与控制结构"]
    N --> S["State<br/>保存任务状态与节点数据"]
    S --> R

Runner、Node 和 State 不是三块彼此独立的功能。Runner 每次被事件唤醒时会 tick 行为树,Node 根据当前输入和状态执行,执行结果再写回 State。State 的变化又可能触发下一次唤醒。自治运行的基本循环就在这里形成。

Node / Tree 这一层也为 Tree Skill 提供表达基础。内核循环用它构建 ReAct 或 Plan-Execute;到了能力层,Tree Skill 再用同一套结构承载更复杂的分支、重试、降级、子流程和能力复用。

3.4 生命周期与持久化:Suspend / Resume / Checkpoint / Effects / Termination

生命周期与持久化处理任务如何跨时间存在。真实任务不会总是一口气跑完,它可能要等外部系统、等人工审批、等异步结果,也可能在中途遇到进程重启和网络故障。

flowchart TB
    D["Durable Execution"]

    D --> CKPT["Checkpoint<br/>保存现场"]
    D --> SUSP["Suspend<br/>暂停执行"]
    D --> TERM["Termination<br/>明确结束原因"]
    D --> EFF["Effects<br/>记录外部副作用"]

    CKPT --> RES["Resume"]
    SUSP --> RES
    RES --> CONT["Continue Execution<br/>继续执行"]

Checkpoint 负责保存现场,Suspend 负责把任务暂停在一个明确的等待点。等待条件回来以后,Resume 接住之前保存的状态,让任务继续执行。

Termination 给结束一个明确原因。一个长时任务不能只有“还在跑”和“成功了”两种状态,也需要知道它是被用户取消、被策略终止、超时结束,还是因为错误无法继续。

Effects 处理已经影响外部世界的动作。比如发起退款、发送消息、写入业务系统,这类动作一旦跨过边界,就不能只靠“节点有没有执行过”来判断。Runtime 需要记录这些副作用,避免恢复和重试时把同一件事做两遍。

3.5 治理:Guard / Approval / Sandbox / Permission

治理让自治运行有边界。Agent 可以自己推进任务,但进入真实业务以后,不能默认所有动作都可以直接执行。

flowchart LR
    ACT["准备执行动作"] --> PERM["Permission<br/>是否具备权限"]
    PERM --> GUARD["Guard<br/>根据上下文判断风险"]
    GUARD -->|可直接执行| EXEC["执行"]
    GUARD -->|需要确认| APP["Approval<br/>人工审批"]
    GUARD -->|需要隔离| BOX["Sandbox<br/>隔离执行"]

Permission 描述 Agent 拥有什么权限,更像一组边界事实。Guard 是运行时的判断点,它会结合权限、上下文、动作类型和业务策略,判断这次动作能不能做。

Approval 和 Sandbox 是常见处理结果。需要人确认的动作会进入 Approval,任务可以挂起,等审批结果回来以后再恢复。高风险代码或外部执行可以放进 Sandbox,减少对宿主环境的影响。

这样设计的目的很直接。安全控制不应该散落在每个 Tool 和每段业务代码里,Runtime 需要在执行链路上给出统一边界。

3.6 观测与扩展:Event / Telemetry / Hook

观测与扩展层记录 Runtime 中发生了什么,并给外部系统留下观察和介入的入口。

flowchart LR
    R["Runtime 执行过程"] --> P["关键执行点<br/>Runner / Node / Model / Tool"]

    P --> H["Hook<br/>外部逻辑接入"]
    H --> P

    P --> E["Event<br/>发出运行时信号"]
    E --> T["Telemetry<br/>组织成运行轨迹"]

    T --> O["Trace / Metrics / Logs<br/>调试、审计、监控"]

Event 偏向运行时语义,是 Runtime 发出的离散信号。比如节点开始、工具调用完成、任务挂起、审批创建、任务恢复等。它回答的是 Runtime 里发生了什么。

Telemetry 偏向观测系统。它会把一次运行中的事件、耗时、错误、工具调用、模型调用和上下文信息组织成可查看、可分析、可审计的轨迹。它回答的是这次运行完整经历了什么。

Hook 解决外部系统如何在关键点接进来。产品可以在模型调用前补充上下文,在工具执行前做额外检查,在任务挂起时更新 UI,或者把某些事件同步到业务系统。Hook 可以进入执行链路,但它不应该变成任意改写 Runtime 语义的万能入口。

3.7 能力层:Model / Tool / Skill / Memory / Context / MCP / RAG

Runtime 自己不会凭空完成业务,它需要连接真正的能力。能力层负责把模型、工具、知识、上下文和可复用做法接进 Jianmu。

Model 负责理解、生成和判断。Tool 负责真正接触外部世界,比如查数据库、调用接口、运行代码、访问业务系统。MCP 让外部工具和资源可以用统一方式接入。

Context 把当前任务需要的信息组织给模型。Memory 和 RAG 提供不同来源的历史经验和外部知识。Skill 则把已经验证过的做法沉淀下来,让后续 Agent 可以直接调用。

可以简单理解成:

Model 负责判断
Tool / MCP 负责行动
Context / Memory / RAG 负责提供信息
Skill 负责把一套做法留下来
Runtime 负责让整个过程持续运行

这几个部分刻意没有绑死在一起。同一棵执行树可以换模型,同一个 Skill 可以被不同 Agent 调用,Tool 可以来自本地代码、MCP 或业务系统。这样业务能力不会全部粘在某一个 Agent Prompt 里。

3.8 多智能体:Swarm

多智能体层的 Swarm 把同一套 Runtime 思路扩展到多个 Agent 的协作场景。

在 Jianmu 里,Agent 不只是一次模型调用。它有自己的任务、状态、能力和生命周期。对于简单任务,可以只有一个 Agent;任务复杂以后,也可以组织成 Agent Team,或者进一步进入 Swarm。

单 Agent 和多 Agent 共用同一套 Runtime 思路。一个 Agent 在等用户输入,和另一个 Agent 在等同伴返回消息,本质上都可能处于“现在没有条件继续,需要等待事件”的状态。一个 Agent 需要保存执行进度,一个团队同样需要保存成员、消息和协作进度。

所以 Jianmu 的多 Agent 不是单独外挂的一套聊天机制,而是把 Agent 当作可以被 Runtime 管理的执行体。Swarm 负责让多个这样的执行体能够创建、通信、等待彼此,并共同完成任务。

后面的第 9 章会展开 Swarm、消息和动态协作。这里先保留一个判断:

一个 Agent 不够时,Jianmu 可以增加新的执行体,而不是把所有复杂度继续塞进一个 Agent 里。

4. 运行内核:Runner、Tree、Node 与 State

本章用途:解释 Jianmu Agent 怎么跑起来。这里先看 Runtime 如何被事件唤醒、如何推进行为树、节点如何执行动作,以及 State 如何参与每一轮执行。

4.1 行为树承载的 Agent 循环

先不看代码,一个 Jianmu Agent 跑起来以后,仍然是一个典型的 Agent 循环。它感知外部变化,读取当前状态,让模型或规则判断下一步,执行工具或 Skill,再把结果写回状态。

Jianmu 的差别在于,这个循环由行为树构建和承载,不再是一段裸的 ReAct while loop。换句话说,Jianmu 的内核循环可以理解为行为树构建的 ReAct:Reason、Act、Observe 和继续执行这些环节,落在行为树的节点、组合节点和状态传播上。

flowchart LR
    E["事件 / 输入"] --> S["更新状态"]
    S --> T["行为树 tick"]
    T --> R["Reason<br/>模型 / 规则判断"]
    R --> A["Act<br/>Tool / Skill / Agent"]
    A --> O["Observe<br/>结果 / 外部反馈"]
    O --> U["更新 State / 节点状态"]
    U --> T
    U --> W["等待下一次事件"]
    W --> E

这里的“事件”不只是用户发来一句话。

它也可能是:

  • 一个异步 Tool 执行完成;
  • 外部接口返回结果;
  • 用户补充了之前缺失的信息;
  • 审批结果到达;
  • 另一个 Agent 发来消息;
  • 某个业务状态发生变化。

事件到达以后,Runtime 会重新推进执行。行为树根据当前状态决定这次 tick 应该走到哪里,节点再去调用模型、Tool、Skill 或其他 Agent。动作产生新的结果,这些结果又会改变 State 和节点状态,后续事件再推动下一轮执行。

所以 Jianmu 里的 Agent 更接近一个持续响应变化的执行体,而不是“收到请求以后从头执行一遍固定函数”。

4.2 Runner:Event-driven Tick

Runner 负责回答一个很具体的问题:什么时候推进这棵行为树。

传统行为树常见于游戏 AI 和机器人系统。那里的行为树通常被外部主循环按固定频率 tick,比如每一帧 tick 一次,或者按照一个固定周期轮询。世界在持续变化,主循环也持续推进树。

Jianmu 面对的不是这种运行环境。一个企业 Agent 大量时间都在等外部世界:等 Tool 完成、等用户补充信息、等审批结果、等回调、等另一个 Agent 发来消息。如果还按照固定频率轮询 tick,Runtime 就会在很多没有新信息的时刻反复推进同一棵树。

Jianmu 的 Runner 采用 event-driven tick。

没事件时,不推进;有事件时,再唤醒 Runner,继续 tick 行为树。

这些事件可以来自:

  • 用户输入;
  • Tool 执行完成;
  • 外部系统回调;
  • 审批结果返回;
  • State 发生变化;
  • 另一个 Agent 发来消息;
  • 定时任务或调度器触发。
sequenceDiagram
    participant R as Jianmu Runtime
    participant T as Behavior Tree
    participant X as Async Tool / External System

    R->>T: tick
    T->>X: 发起异步任务
    T-->>R: 当前节点 RUNNING
    Note over R: 没有新事件,等待
    X-->>R: 任务完成,发出 wake-up
    R->>T: 再次 tick
    T->>T: 根据新结果继续执行

这就是 event-driven tick 的核心含义。

行为树本身仍然保留 RUNNING、SUCCESS、FAILURE 这些节点状态,但 Runner 不再像传统行为树那样靠固定频率轮询 RUNNING 节点。一个节点如果正在等待异步结果,可以保持 RUNNING;Runner 暂时停下来。等结果回来,一个事件重新唤醒 Runner,再从当前状态继续 tick。

这点看起来只是调度方式不同,但它对长时 Agent 很关键。

传统轮询 tick 更适合持续在线、世界每一刻都在变化的场景。Jianmu 的 event-driven tick 更适合企业任务:大部分时候没有必要算,真正应该继续的时候,往往是因为外部世界送来了新事实。

事件驱动还有一个好处:Agent 的时间不需要和某个 HTTP 请求绑在一起。

一次 Web 请求可以结束,但任务本身还活着。后面新的事件到达时,再把这个任务继续唤醒。

这也是“长时运行”和“一个接口请求跑很久”的区别。

4.3 Node / Tree / Preset:Agent Loop 与 Tree Skill 的共同基石

Runner 解决“什么时候 tick”,Node / Tree 解决“tick 的时候执行什么”。

Node 是具体执行单元,可以是一次模型判断、一次 Tool 调用、一次状态检查、一次等待,也可以是一个 Skill 或另一个 Agent。

调用模型
执行 Tool
等待异步任务
调用 Skill
创建另一个 Agent

Tree 把这些 Node 组织起来。

Node / Tree 在 Jianmu 里主要用在两处。

第一处是 Runner 里的 Agent Loop。Jianmu 默认的内核循环可以理解为行为树构建的 ReAct,也可以扩展成 Plan-Execute 等其他循环形式。

ReAct Loop
├── Reason
├── Act
├── Observe
└── Continue / Stop

Plan-Execute Preset
├── Plan
├── Execute
└── Review

第二处是 Tree Skill。Tree Skill 也用 Node / Tree 来表达一套能力,但它面向的是更稳定的业务做法。

Tree Skill
├── 查询订单
├── 风险检查
├── Approval
├── 执行动作
└── 结果确认

所以 Node / Tree 不是“复杂 workflow”的同义词。它们一方面用于构建 Runner 中的 ReAct、Plan-Execute 等现代 Agent 循环,另一方面用于构建 Tree Skill。复杂编排主要体现在 Tree Skill 这一层。

4.4 State / Port Binding:节点之间如何共享数据

Behavior Tree 解决“谁执行、先后关系是什么”,但一棵树真正跑起来以后,还需要另一条线:节点之间的数据怎么流动。

如果所有节点都随意读写一个无结构字典,简单任务当然能跑,但复杂以后很容易出现字段类型不一致、历史数据被覆盖、临时状态残留到下一轮等问题。

所以 Jianmu 希望 Agent 的运行状态有明确结构和数据契约,而不是靠每个节点之间的口头约定。

这里的 Typed State,指的是 State 里的关键字段有明确类型、含义和更新规则。节点不能随便往共享字典里塞字段,而是要知道自己读什么、写什么、写进去以后怎么合并,以及这个字段能活多久。

简单说,Typed 解决的是这类问题:

这个字段是什么类型?
哪个节点会写它?
写入时是覆盖还是追加?
这个值是长期状态,还是一次调用里的临时状态?

其中有两个特别重要的语义。

Reducer 决定一个新值写进来以后,是覆盖旧值,还是按照约定方式合并。比如消息历史通常更像“追加一条”,而不是“把整个历史替换掉”。这样“数据怎么合并”本身就是 State 的规则,不必散落在每个业务节点里。

Ephemeral 则解决“这个状态能活多久”。有些数据应该贯穿整个任务,有些只属于当前 run、当前 step 或当前模型调用。生命周期结束以后自动清理,能避免临时数据污染后续执行。

持久业务状态
→ 任务继续时仍然存在

Run 级临时状态
→ 新一轮运行时复位

Step 级临时状态
→ 下一步执行时复位

Call 级临时状态
→ 下一次模型调用时复位

这和第 5 章的生命周期思想是一致的:状态不仅有值,也有自己的生命周期。

Port Binding 进一步让 Node 不必绑死某个业务字段名。节点只声明自己需要什么输入、产生什么输出,再把这些逻辑端口映射到当前业务 State。

flowchart LR
    A["Node A<br/>逻辑输出"] --> S["Typed State"]
    S --> B["Node B<br/>逻辑输入"]
    PA["Port Binding"] -.-> S

于是同一个 Node 或子树可以在不同业务里复用,而不用因为 State 字段名字不同就重写内部逻辑。

所以这一层最重要的结论是:

Behavior Tree 负责控制流,Typed State / Port Binding 负责数据流。

两者结合以后,Jianmu 的树才不仅是一组有层级关系的节点,而是一套有明确数据契约、可以持续运行和恢复的执行结构。

节点可以共享状态,但共享不等于随便改。

5. 生命周期与持久化:Suspend、Resume、Checkpoint、Effects、Termination

本章用途:解释 Jianmu Agent 如何跨越等待、中断和外部副作用继续存在。长时运行不只是把状态存下来,还要知道什么时候暂停、怎样恢复、为什么结束,以及已经影响外部世界的动作如何处理。

5.1 等待不是异常:Suspend / Resume

Jianmu 里有两种很容易混淆的“等”。

第一种是 Runtime 内部自己能等的东西,比如一个异步节点还在执行。这个时候 Agent 仍然处在运行周期里,只是 Runner 暂时没有必要继续 tick。

第二种是需要把控制权交回给外部世界的等待,比如:

  • 需要人工审批;
  • 需要用户补充信息;
  • 需要某个外部系统代为执行,然后之后再把结果送回来。

这种情况下,Jianmu 会把任务正式挂起,也就是 Suspend。

目前 Runtime 原生支持三类挂起:

挂起类型 典型场景 等什么回来
审批等待 退款、删除、发布、高风险操作 批准 / 拒绝结果
用户输入等待 信息不完整,需要用户补充 用户提供的数据
外部执行等待 把动作交给外部系统处理 外部执行结果

挂起时,Runtime 会记录这次为什么暂停、对应哪个请求、需要什么数据才能恢复。对于需要把任务交还给宿主应用的场景,Jianmu 会在挂起点保存 checkpoint,然后把一个 suspended 结果返回给上层。

上层产品就可以正常结束当前请求。

例如 Web 页面可以显示:

订单退款任务
状态:等待财务审批
退款金额:¥12,800
[批准] [拒绝]

此时 Agent 并不是“报错退出”,任务也不是消失了。

它只是停在一个明确的状态上。

等审批结果回来以后,上层把结果交还给 Runtime,Jianmu 再执行 Resume,从之前保存的位置继续。

flowchart LR
    A["执行到审批节点"] --> B["创建 Suspension"]
    B --> C["保存当前状态和执行位置"]
    C --> D["返回宿主:suspended"]
    D --> E["等待人工 / 用户 / 外部系统"]
    E --> F["结果回来"]
    F --> G["Resume"]
    G --> H["从原流程继续执行"]

这里最重要的一点是:Jianmu 不把等待人、等待系统当成异常。

真实业务本来就会停下来。问题不在于“怎么避免暂停”,而在于暂停以后还能不能清楚地知道:

  • 为什么停;
  • 停在哪;
  • 等谁;
  • 等什么数据;
  • 数据回来以后怎么继续。

Jianmu 把这些信息放进 Runtime 的挂起/恢复协议里,而不是让每个业务自己再写一套 pending_status、回调表和恢复逻辑。

Checkpoint 在这里也不只是“保存几个变量”。

Jianmu 保存的是两个维度:一边是业务和运行状态,一边是行为树当前的执行状态。恢复以后,不只是“记得之前订单号是多少”,还要知道当前 Sequence / Selector 执行到了哪个子节点,哪些步骤已经跑过,接下来应该从哪里继续。这个区别很重要,只保存聊天记录或者业务字段,并不等于恢复了一个正在执行的 Agent。

5.2 什么时候应该停止:Termination 也是 Runtime 语义

长时运行很容易让人产生一个误解:

Agent 越自治,就应该越能一直跑下去。

其实正好相反。

一个真正可靠的 Runtime,不只是要知道什么时候继续,还必须知道什么时候不应该继续。

比如下面这些情况,语义完全不同:

外部接口还没返回
→ 等待,之后继续

需要用户补充信息
→ Suspend,拿到输入以后 Resume

模型暂时遇到可重试的服务错误
→ 当前尝试可以结束,宿主以后可能重新启动

API Key 错误
→ 继续 Retry 没有意义,应该明确终止

Agent 已经超过最大循环次数
→ 应该停止,而不是无限思考

Token Budget 已经耗尽
→ 应该停止,而不是继续花钱

用户明确拒绝审批
→ 当前高风险执行路径应该结束

如果所有这些情况最后都只变成一个:

Status.FAILURE

上层产品其实很难知道接下来该怎么办。

是立刻重试?

是提示用户改配置?

是等一会再启动?

还是这次任务已经明确结束?

所以 Jianmu 在 Runtime 里保留了 Termination Record 这类终止语义。

它不只是记录“失败了”,还会记录为什么结束,以及宿主后续应该如何理解这次结束。

目前 Runtime 已经会区分一些典型原因,例如:

provider_error
provider_retry_exhausted
model_call_failed
hook_error
max_iterations_exceeded
budget_exceeded
approval_rejected
tool_denied
...

产品层不需要记住这些内部字符串,真正需要理解的是:结束本身也有类型。

例如模型 Provider 的错误可以分成两类。

第一类是用户可以直接修复、继续重试也没有意义的错误:

API Key 无效
余额不足

这类错误应该明确告诉宿主:

不要继续傻跑,先让用户解决配置或账户问题。

第二类是本次模型调用层的重试已经耗尽,但底层问题仍可能只是暂时性的:

服务临时不可用
网络持续超时
Provider 短时故障

这时候当前 Run 可以结束,但一个更高层的 Host 或调度系统以后仍然可以选择重新启动。

所以 Jianmu 更希望把:

节点返回 FAILURE

和:

整个 Agent 执行为什么终止

分开理解。前者是 Behavior Tree 里的局部控制语义。后者是 Runtime 生命周期语义。

从产品角度看,这会让 Agent 的状态更容易解释:

Running      → 正在工作
Waiting      → 暂时没事做,等事件
Suspended    → 控制权交给外部,之后可以 Resume
Completed    → 正常完成
Terminated   → 这次执行明确结束,并且有原因

这里最重要的一点是:

长时运行不等于永不停止。好的 Runtime 不仅知道怎么继续,也知道什么时候应该有理由地结束。

这和 Suspend / Resume 正好构成一对。

Suspend 回答:

“我现在不能继续,但以后还要回来。”

Termination 回答:

“这一次运行不应该再继续了,原因需要被保留下来。”

5.3 恢复不只是恢复状态:Effects、Commit Boundary 与 Reconciliation

前面总图里已经提到 Effects。这里需要把它和另外两个词放在一起看。

Effects 指 Agent 对外部世界产生的副作用。比如退款、发消息、写数据库、创建工单、发布内容。它们和内部 State 不一样,一旦发生,就不一定能通过恢复 checkpoint 撤回来。

Commit Boundary 是副作用真正跨出 Runtime、进入外部系统的边界。越过这条边界之前,系统还可以做 Guard、Approval、参数校验和取消;越过以后,Runtime 就必须把“外部世界可能已经改变”当成事实来处理。

Reconciliation 是恢复时的对账动作。当 Runtime 不确定某个 Effect 到底有没有成功时,不能靠猜,也不能简单重试,而是要向外部系统确认真实状态,再决定复用结果、补回 Receipt,还是重新执行。

三者的关系可以简单理解成:

Effect
→ 要改变外部世界的动作

Commit Boundary
→ 这个动作真正越过系统边界的点

Reconciliation
→ 结果不确定时,恢复前先和外部世界对账

Checkpoint 回答的是:

Agent 内部做到哪里了?

但只要 Agent 开始真正改变外部世界,还必须回答另一个问题:

这个动作到底已经发生了吗?

假设 Agent 调用支付系统退款。最麻烦的情况不是接口明确失败,而是:支付系统其实已经退款成功,但返回结果之前网络中断,Runtime 随后重启。

如果恢复以后只看到“退款节点还没完成”,然后把这个节点重新执行一次,就可能造成重复退款。

所以对付款、退款、发消息、发布内容、修改数据库、创建资源这类副作用,恢复不能简单等价于:

没看到成功
→ 再做一次

Jianmu 用 Governed Effect / Commit Protocol 把真正改变外部世界的动作放到一个明确的提交边界上:

flowchart LR
    P["Proposal<br/>准备做什么"] --> V["Validation<br/>允许做吗"]
    V --> R["Prepared<br/>留下提交意图"]
    R --> E["External Execution<br/>改变外部世界"]
    E --> C["Receipt<br/>取得外部回执"]
    C --> D["Committed<br/>确认已提交"]

这里最重要的是 Commit Boundary。

在越过这条边界之前,系统还可以做 Guard、Approval、业务校验;越过以后,Runtime 就必须把“这个动作是否已经发生”当成一等问题,而不能只看行为树节点有没有返回 SUCCESS。

如果已经有可信 Receipt,恢复时应该复用已经发生的结果,而不是重新产生副作用。真正困难的是结果不确定的情况:Runtime 知道动作已经准备执行,甚至请求可能已经发出,但没有拿到足够可信的最终结果。这时候应该进入 Reconciliation:先向外部系统确认事实,再决定下一步。

本地:这笔退款结果不确定
          ↓
向支付系统查询真实状态
          ↓
   ┌──────┴──────┐
   ↓             ↓
已经退款       确认未退款
   ↓             ↓
补回 Receipt    才允许重新执行

跨网络和外部系统的一致执行不能只依赖“这个函数调用过一次”,而需要把稳定的动作身份、幂等能力、Commit Record、Receipt 和 Reconciliation 组合在一起,让 Runtime 在重试和恢复时仍然保持一致的副作用语义:

不要因为 Runtime 重试或重启,把同一个业务决定再次作用到外部世界。

因此 Jianmu 的长时恢复实际上有两个维度:

Checkpoint
→ 我内部做到哪里了?

Governed Effect / Receipt
→ 外部世界已经发生了什么?

只有两边都能回答,恢复才不仅是“程序继续跑”,而是业务意义上的继续执行。

5.4 一个完整任务示例

把前面的机制放到一个完整例子里会更直观。

假设我们做一个“异常退款处理 Agent”。用户给它一个任务:

检查订单 A1024 为什么没有正常完成,如果符合退款条件就处理退款。

第一步:接到任务

宿主应用创建任务,Jianmu 初始化 Agent 的状态和行为树。

Agent 首先读取订单信息。模型或规则判断需要查询订单、支付和库存状态,于是调用对应 Tool。

任务状态:运行中
当前阶段:读取订单信息

第二步:外部工具异步执行

订单接口很快返回,但支付系统查询需要一点时间。

行为树里的异步节点发起请求后处于 RUNNING。这时候 Runtime 不需要疯狂轮询,而是等待异步任务完成后的 wake-up。

支付结果回来以后,节点发出信号,Runner 再推进一次行为树。

第三步:根据结果选择路径

现在状态里已经有订单、支付和库存信息。

Agent 判断:用户确实支付成功,但订单因为库存异常没有履约,满足退款条件。

行为树进入退款分支。

这里的好处是,退款相关逻辑可以封装在一个独立子树里,而不是继续堆在最外层流程上。

第四步:执行前经过 Guard

退款 Tool 准备执行金额为 12,800 元的退款。

Guard 发现这笔金额超过了自动执行阈值,因此不允许直接调用,而是要求人工审批。

此时系统并不是让模型继续“想办法”,而是明确进入审批状态。

第五步:任务挂起

Runtime 创建审批相关的 Suspension,并保存 checkpoint。

当前 Web 请求可以结束,产品界面显示:

任务:异常退款处理
订单:A1024
建议操作:退款 ¥12,800
原因:支付成功,但订单未履约
状态:等待审批

Agent 此时不占着一个循环不停运行。

它就停在这里。

第六步:半小时后,人完成审批

财务人员点击“批准”。

审批结果被写回,宿主使用这次审批对应的请求标识恢复任务。

Runtime 从 checkpoint 恢复业务状态和行为树执行状态,然后继续之前的退款流程。

已经完成的订单查询、支付查询和风险判断不需要重新做一遍。

第七步:越过 Commit Boundary,真正执行退款

审批通过以后,退款 Tool 才真正有资格改变外部世界。

对于这种不可逆动作,更完整的 Runtime 路径不是“失败就直接再调一次”,而是先形成一个稳定的 effect identity,记录准备提交的退款动作,再调用支付系统。

Effect Proposal
   ↓
Validation / Approval 已通过
   ↓
Prepared
   ↓
调用支付系统退款
   ↓
拿到 Receipt
   ↓
Committed

如果支付系统明确返回失败,行为树可以按照业务策略走 Retry / Fallback 或人工处理。

但如果出现的是“请求可能已经成功,只是结果丢了”,就不能盲目重试。恢复时应该先根据 effect id / 业务单号向外部系统 Reconcile,确认真实退款状态以后再决定下一步。

这也是为什么 Checkpoint 和 Effect Recovery 要分开:Checkpoint 告诉 Runtime 流程走到退款这里了,Effect Record 则负责回答钱到底退没退。

第八步:完成并留下结果

退款成功后,Agent 更新任务状态,并生成最终结果给用户。

订单 A1024 已完成退款。
退款金额:¥12,800
审批人:XXX
退款结果:成功

Telemetry 则保留整个过程中重要的 Runtime 事件,方便之后查看任务什么时候开始、为什么挂起、什么时候恢复、调用过哪些能力、最终在哪里结束。

整个过程可以概括成:

flowchart TD
    A["接收任务"] --> B["查询订单 / 支付 / 库存"]
    B --> C["异步任务完成,唤醒 Runtime"]
    C --> D["判断退款条件"]
    D --> E["进入退款子流程"]
    E --> F["Guard 检查"]
    F -->|需要审批| G["Suspend + Checkpoint"]
    G --> H["人工审批"]
    H --> I["Resume"]
    I --> P["Effect Proposal / Prepared"]
    P --> J["执行退款"]
    J -->|明确失败| K["Retry / Fallback / 人工"]
    J -->|结果不确定| R["Reconciliation"]
    R -->|确认未执行| J
    R -->|确认已执行| CMT["补回 Receipt / Committed"]
    J -->|成功并有 Receipt| CMT
    CMT --> L["更新状态并完成任务"]

6. 治理:Guard、Approval、Sandbox 与 Permission

本章用途:解释 Agent 自治运行时边界在哪里。Jianmu 允许 Agent 持续推进任务,但权限、审批、隔离和人工介入必须进入 Runtime 的执行链路,而不能散落在每个 Tool 或业务回调里。

这里的 Runtime 指完整的 Jianmu Agent Runtime,包括运行内核、生命周期、治理、观测和能力层。Runner / Node / State 只是其中的运行内核,Guard、Approval、Sandbox 和 Permission 属于 Runtime 的治理层。

6.1 人如何进入 Agent 的执行闭环

很多人一说“自治 Agent”,第一反应是尽量不要人参与。

但在真实业务里,这通常不现实,也不一定安全。

有些事情模型自己做没有问题,比如整理资料、查询状态、生成草稿;有些事情即使模型判断得很有把握,也仍然应该经过人确认,比如退款、发布、删除、付款或者修改关键业务数据。

所以 Jianmu 里的 HITL(Human-in-the-Loop)更接近一种正常的执行节点,而不是失败后的兜底。

一个典型流程可以是:

Agent 自动处理
   ↓
准备执行高风险动作
   ↓
Guard 判断:需要人工确认
   ↓
任务 Suspend
   ↓
产品界面展示审批信息
   ↓
人批准 / 拒绝
   ↓
生命周期层 Resume
   ↓
继续执行对应分支

这里要分清的是 Runtime 内部不同模块的分工。

Guard 属于治理层,负责判断:这件事能不能直接做,还是必须先问人。

Suspend / Resume 属于生命周期层,负责处理:既然要问人,那任务怎么停下来,之后又怎么接回去。

这样做以后,HITL 不需要被写成一堆业务特判。

而且产品层可以真正利用这个机制做交互。

比如三类 Suspension 可以对应不同 UI:

  • 审批:显示风险说明、关键参数、批准/拒绝按钮;
  • 用户输入:显示表单,让用户补充字段;
  • 外部执行:显示“处理中”,等系统回调。

多 Agent 场景里的消息等待则由 Agent Runtime 处理,产品层同样可以把“正在等待哪个角色返回结果”呈现出来,但它不是这里所说的第四种 Suspension。

这也是为什么 Jianmu 把 Runtime 和宿主产品分开。

Runtime 不应该决定按钮长什么样,也不应该假设交互一定发生在命令行、网页还是 IM 里。它只需要明确告诉上层:现在任务为什么停了,以及恢复时需要什么。

上层产品怎么把这件事呈现给用户,可以完全不同。

同一个 Agent 因此可以跑在 TUI、Tree Studio、Swarm Studio 或业务系统里,而不需要为每种 UI 重写一套运行逻辑。

6.2 Guard / Approval / Sandbox

当 Agent 只做信息整理时,安全问题还比较简单。

一旦它开始真的执行动作,情况就完全不同了。

比如下面这些动作,风险显然不一样:

查询库存        → 风险低
生成退款建议    → 风险较低
发起 50 元退款  → 可能允许自动执行
发起 5 万元退款 → 需要审批
执行未知代码    → 需要隔离环境
批量删除数据    → 可能直接禁止

Jianmu 不希望把这些判断全部交给模型。

模型可以给建议,但“这个动作到底能不能执行”应该由更明确的机制控制。

这里主要有三层。

Guard 负责做执行前判断。

它可以根据策略、预算、调用频率或业务规则,返回几种结果:直接允许、拒绝,或者要求确认。

Approval 负责需要人参与的那部分。

如果 Guard 判断这个动作不能直接执行,Runtime 就可以把任务挂起,等人批准或拒绝,再继续对应流程。

Sandbox 负责执行隔离。

有些动作允许执行,但不应该直接运行在宿主机器或主业务环境里。Sandbox 解决的是“在哪里执行更安全”。

所以这三个东西的关系可以一句话说清:

Guard 决定能不能做,Approval 解决谁来确认,Sandbox 决定在哪里做。

这套机制的重点不是追求“绝对安全”,而是把风险控制从 Prompt 里拿出来。

如果只是告诉模型:

“请谨慎操作,不要执行危险动作。”

这当然有用,但它仍然是一条自然语言要求。

真正进业务以后,系统还需要更硬的边界:哪些 Tool 能用、哪些动作必须确认、预算是多少、代码在哪里执行、出了问题能不能追踪。

Jianmu 的目标就是把这些边界放进 Runtime 的执行链路,而不是只依赖模型自己记得遵守规则。

把这一章放在一起看,Jianmu Agent 内部其实同时存在几条不同的线:

Behavior Tree   → 控制流:谁先执行、失败以后走哪里
Node / Preset   → 执行结构:ReAct、Plan-Execute 等模式怎么落到树上
Typed State     → 数据流:节点之间共享什么、怎么合并、能活多久
Port Binding    → 数据契约:节点的逻辑输入输出怎么映射到业务状态
Model           → 动态判断与生成
Tool            → 原子外部动作
Skill           → 可复用任务能力
Long-term Memory→ 跨任务知识
Checkpoint      → 当前任务恢复
Guard / Approval→ 给真实执行加边界

所以如果只记一句,可以记成:

Tree 管控制流,State / Port 管数据流,Model / Tool / Skill 提供能力,Memory / RAG / Context 管信息进入模型的方式,Checkpoint 管任务恢复,完整的 Agent Runtime 再把这些模块放进同一条可持续、可治理、可恢复的执行链路里。

单独看,每一项都不新鲜。

真正重要的是,它们被放在同一个 Runtime 里以后,Agent 不再只是“模型会不会调工具”,而开始拥有明确的控制结构、数据契约、能力边界和恢复语义。

6.3 Hook、Guard、Approval 的边界

有了 Hook 以后,一个很容易出现的误解是:

“既然 before_tool_call 可以看到和修改参数,那安全检查是不是也都写 Hook 就行?”

我不建议这样理解。

Hook、Guard、Approval 虽然都会“进入执行过程”,但解决的问题不同。

可以直接用这张表记:

机制 核心问题 是否应该承担安全边界
Event Bus 刚刚发生了什么? 否
Telemetry 整个运行过程是怎么发生的? 否
Hook 我能否在稳定边界观察或扩展执行? 一般不作为核心安全边界
Guard 这个动作允许执行吗? 是
Approval 这个动作需要谁确认? 是,人参与决策
Sandbox 即使执行,它应该在哪里执行? 是,执行隔离

Hook 的主要目标是扩展性。

Guard 的主要目标是策略约束。

Approval 的主要目标是责任和确认。

Sandbox 的主要目标是隔离。

例如一个高风险 Tool:

删除生产数据

可以有一个 Hook 记录它的参数,也可以有 Hook 给审计系统发通知。

但真正决定:

“这个动作不允许执行。”

应该是 Guard。

如果策略要求人工确认:

“只有管理员批准才允许执行。”

应该进入 Approval。

最终命令即使被允许,也可能应该在受限 Sandbox 里执行。

所以合理的链路更接近:

flowchart LR
    A["Agent 产生动作"] --> H["Hook\n扩展 / Transform"]
    H --> G["Guard\n策略检查"]
    G -->|需要确认| P["Approval"]
    G -->|允许| S["Sandbox / Executor"]
    P -->|批准| S
    S --> E["Event / Telemetry"]

这里 Hook 很强,但它不应该因为“能修改参数”就变成所有治理逻辑的归宿。

否则一个产品忘了注册 Hook,安全边界就消失了。

这也是为什么本章前面把 Guard / Approval / Sandbox 作为 Runtime 的明确能力,而没有把它们当普通插件。

7. 观测与扩展:Event、Telemetry 与 Hook

本章用途:解释一个正在长期运行的 Agent,外部系统怎么知道它正在发生什么,怎么把这些运行事实组织成可理解的 Trace,又怎么在不修改 Agent 主循环的情况下,把产品和业务逻辑接进执行过程。

前面几章主要站在 Agent 内部看 Runtime:

Behavior Tree 怎么组织执行
ReactiveRunner 怎么持续运行
State / Checkpoint 怎么恢复
Tool / Skill 怎么提供能力
Guard / Approval 怎么控制风险

但一个 Runtime 真正进入产品以后,还会多出另一类问题:

UI 怎么知道 Agent 现在在做什么?
出了问题以后怎么还原刚才的执行过程?
模型调用了多少次、Tool 花了多久?
业务系统怎么订阅 Agent 的生命周期?
模型调用前能不能补一段 Context?
Tool 参数能不能在统一位置做适配?
运行结果怎么投影到不同产品界面?

这些问题都不能靠 Behavior Tree 本身解决。

如果 Runtime 只负责“把任务跑起来”,但外部看不到、接不进去、也没有稳定扩展点,那么它很容易变成一个黑盒。

Jianmu 现在用三套互相配合、但职责不同的机制来处理这件事:

Event Bus
  → Runtime 里发生了什么

Telemetry
  → 这些事情串起来以后,完整运行轨迹是什么

Hook
  → 我能不能在指定边界观察或修改执行数据

再加上前面讲过的 Guard / Approval,就形成了一条从“看见”到“影响”再到“治理”的链路。

可以先建立一个很粗的产品心智模型:

flowchart LR
    R["Jianmu Runtime"] --> E["Runtime Events\n发生了什么"]
    R --> T["Telemetry\n运行轨迹"]
    H["Hooks\n观察 / Transform"] <--> R

    E --> UI["UI / Studio / External System"]
    T --> TRACE["Trace / Metrics / Eval"]
    H --> EXT["Product / Business Extension"]

这三者都和“运行过程”有关,但不能混为一谈。

7.1 为什么长期运行的 Agent 不能是黑盒

一个只回答一句话的 LLM 应用,黑盒问题没有那么严重。

用户问:

北京今天多少度?

系统回答:

27°C。

只要结果正确,很多时候用户并不关心中间发生了什么。

但 Agent 一旦真的开始做事,情况就完全不同了。

比如一个编码 Agent 连续运行了二十分钟,最后告诉你:

“任务完成了。”

这时候真正需要知道的可能是:

它看了哪些文件?
改了哪些文件?
调用了多少次模型?
执行了哪些 Shell 命令?
测试到底跑过没有?
中间失败过几次?
为什么选择了这个修复方案?
有没有等待用户确认?
最终结果属于原始 Run,还是某次 Resume?

如果这些东西都看不到,“任务完成”四个字其实没有太大可信度。

长时 Agent 更是如此。

一个任务可能:

10:00 开始
10:03 调用 Tool
10:05 等待外部系统
11:20 收到 callback
11:21 继续运行
11:25 请求人工审批
14:00 用户批准
14:01 Resume
14:06 完成

对这种任务来说,“最终输出”只占整个运行过程很小的一部分。

真正的产品对象已经变成了一次持续存在的 Run。

因此 Runtime 至少需要让外部回答四类问题。

第一类是状态问题:

Agent 现在是 Running、Waiting、Suspended 还是 Completed?

第二类是过程问题:

刚才经过了哪些 Node、Model Call 和 Tool Call?

第三类是诊断问题:

失败发生在哪里,错误是什么,前后发生了什么?

第四类是扩展问题:

我自己的产品逻辑怎么接进来,而不用 fork Runtime 主循环?

这就是为什么可观测性不是“上线以后顺便加个日志”。

对于长时 Agent,它本身就是 Runtime 设计的一部分。

一个长期运行的 Agent,不仅要能继续跑,还要能让外部知道它为什么在跑、跑到哪里,以及刚刚发生了什么。

7.2 Event Bus:Runtime 里发生了什么

最基础的一层是 Event。

Runtime 每推进一步,其实都在不断发生离散事件:

一次 Run 开始了
一个 Tick 开始了
一个 Model Call 发出了
一个 Tool 开始执行了
一个 Tool 返回了
Agent 被 Suspend 了
Checkpoint 保存了
Agent Resume 了
一条消息到达了
一个 Agent 被创建了
任务结束了

如果这些事实只存在于函数调用栈里,那么外部产品必须直接耦合 Runtime 内部代码才能知道它们。

Jianmu 的思路是:把重要运行事实显式变成 Event。

这些 Event 不是普通日志,而是带有执行上下文的结构化运行事实。这样 UI 收到“Tool 完成”时,不只是看到一条文本,而是可以知道它属于哪次 Run、哪个 Agent、哪个执行位置,并把它投影成真正的产品状态。

Runtime 发生变化
      ↓
结构化 Event
      ↓
TUI / Studio / Audit / Business Backend

这里 Event Bus 并不负责“界面应该长什么样”。

它只提供一个稳定事实:

Runtime 发生了什么。

UI 自己决定怎么解释。

TUI 可以把事件画成 waterfall。

Tree Studio 可以把事件投影成节点状态。

Swarm Studio 可以把 Agent 生命周期和消息事件投影成聊天状态。

外部审计系统也可以只关心 Tool 和 Approval 相关事件。

这就是 Event Bus 最重要的价值:生产者和消费者解耦。

Runtime 不需要知道有多少个消费者,也不需要为了每个产品写一套专用 callback。

                 ┌── TUI
                 ├── Tree Studio
Runtime Event ───┼── Swarm Studio
                 ├── Audit
                 └── Business Backend

在 Swarm Runtime 里还有 Agent 级事件总线,用于 agent_created、agent_paused、message_received 等多 Agent 生命周期和消息事件;其中部分生命周期事件还会桥接到 Runtime 级事件体系。

所以从产品角度看,可以把它们统一理解成:

Jianmu 尽量把重要运行变化变成可订阅的结构化事件,而不是要求上层应用去猜 Runtime 内部发生了什么。

不过 Event 只回答了一件事:

刚刚发生了什么?

如果要回答:

这一整个任务到底是怎么跑过来的?

还需要 Telemetry。

7.3 Telemetry:从事件到完整运行轨迹

Event 是一个个离散事实。

Telemetry 更关心这些事实之间的上下文关系。

例如,下面这些事件单独看都很好理解:

model.call.started
model.call.completed

tool.call.started
tool.call.completed

llm.usage

但真正分析一次运行时,我们还需要知道:

这个 Model Call 属于哪次 Run?
这个 Tool Call 是哪次模型判断触发的?
它们是不是属于同一个节点?
这个调用下面还有没有 Child Span?
总共花了多少 Token?
整条链用了多久?

Telemetry 关注的不是某一个事件,而是这些事件之间的关系。

产品层可以把区别简单记成:

Event Bus
→ 刚刚发生了什么?

Telemetry
→ 这些事情串起来以后,整个 Run 是怎么发生的?

例如一次执行可以被还原成:

Run
├── Agent Step
│   ├── Model Call
│   ├── Tool Call
│   └── Tool Call
├── Approval Wait
├── Resume
└── Completed

再叠加耗时、Token 使用、错误和上下游关系,就得到真正可用于 Trace、调试、性能分析、成本统计和 Eval 的运行轨迹。

所以 Event Bus 和 Telemetry 没有被简单合成一个概念:前者强调实时运行事实,后者强调跨模块、跨步骤的可观测链路。

从产品角度看,Telemetry 最终支撑的是几类很实际的能力:

Trace
调试
性能分析
Token / Cost 统计
故障诊断
Eval 数据
运行历史

尤其是第 10 章会继续讲的 Capability Loop 和 RSI。

系统如果未来想根据真实执行结果改进 Skill,第一步不是“让模型自我反思”,而是先有足够可靠的运行证据。

没有可观测的执行,就很难有可信的评估;没有可信的评估,就很难谈安全的自动改进。

7.4 Hook:在不修改主循环的情况下进入执行过程

Event 和 Telemetry 解决的是“看见”,但产品真正接入 Runtime 以后,还会出现另一类需求:

能不能在几个稳定边界上接入自己的逻辑,而不去修改 Agent 主循环?

比如:

  • 模型调用前补充产品自己的 Context;
  • 模型返回后做统一处理;
  • Tool 调用前适配业务参数;
  • Tool 返回后把结果投影成统一 observation;
  • Agent 状态变化时同步 UI 或外部系统。

如果每出现一个这类需求都去改 Runner、LLM Node 或 Tool Executor,最后不同产品会各自拥有一份略有差异的 Runtime,核心执行语义也会慢慢分叉。

Hook 的价值就在这里:Runtime 保持稳定,产品逻辑通过明确的扩展边界接进来。

从产品角度,Hook 可以粗略分成两种语义。

Observe Hook 只观察运行过程,例如记录、同步 UI、发送通知、收集额外指标。它的重点是:

让我知道 Runtime 走到这里了。

Transform Hook 则允许在明确的调用边界修改即将继续传递的数据,例如模型输入、模型结果、Tool 参数或 Tool 结果。

flowchart LR
    C["Context"] --> H1["Hook"] --> M["Model"]
    M --> H2["Hook"] --> R["Model Result"]
    R --> H3["Hook"] --> T["Tool"]
    T --> H4["Hook"] --> O["Tool Result"]

这里最重要的不是具体有哪些 Hook 名字,而是修改能力有明确边界。Hook 可以扩展模型和 Tool 的调用链,但不应该变成一个可以任意重写 Runtime 状态机的万能入口。

7.5 从观察到干预:Hook 能改变什么

Hook 让 Jianmu 不只是 Observable,也变得可以被产品扩展。

比如一个代码 Agent 运行期间,用户手动修改了文件。产品可以在下一次模型调用前,把“文件已经发生变化”补进 Context,而不用让 Runtime 本身理解 IDE 文件变化是什么。

Runtime 原始 Context
        ↓
产品 Hook 补充外部变化
        ↓
Model

再比如,不同 Tool 可能返回完全不同的原始对象,但产品希望 Agent 后续看到统一的 observation。这个转换也可以放在 Tool 调用边界,而不必把同一套适配逻辑复制进每个 Tool。

Raw Tool Result
      ↓
产品 Hook
      ↓
Normalized Observation
      ↓
Agent 后续执行

这类设计的核心原则是:

扩展点可以进入执行链路,但核心执行语义仍然属于 Runtime。

Hook 可以观察 Suspend,也可以让 UI 随之更新;但真正决定任务如何 Suspend / Resume 的仍然是 Runtime。Hook 可以调整 Tool 参数,但真正决定这个动作是否允许执行的仍然应该是 Guard。

这样产品可以持续增加自己的逻辑,又不需要把 Jianmu Core 变成每个业务系统的定制代码。

7.6 为什么这一层决定了 Jianmu 能不能真正产品化

到这里再看第 12 章会讲到的几个产品,会发现一个共同点:

产品层看到的并不是 Runtime 内部对象本身,而是 Runtime 对外暴露出来的事件、Trace 和扩展边界。

TUI Chat 为什么能显示:

当前 Run
Tool 调用
Approval
文件变化
Token Usage
Trace Waterfall

因为 Runtime 不是一个只返回最终字符串的函数。

Tree Studio 为什么能把正在运行的树节点实时画成 Running / Success / Failure?

因为执行状态能够被投影出来。

Swarm Studio 为什么能展示 Agent 生命周期、消息和协作状态?

因为这些变化本身就是 Runtime 中的结构化事件。

同样,产品为什么能在不修改 Jianmu Core 的情况下做:

Tool observation projection
外部文件变化提示
working-view compaction
Inspector request capture
自定义日志 / 指标

因为 Hook 给了产品稳定的扩展入口。

因此从产品架构的角度,可以把 Jianmu Runtime 粗略分成两面。

第一面是执行内核:

Structured
Reactive
Durable

解决:

Agent 怎么正确地跑。

第二面可以理解成 Runtime 的 Control / Integration Plane:

Event
Telemetry
Hook
Governance

解决:

外部怎么知道它在跑、怎么接入它、怎么扩展它、怎么约束它。

这里的 “Control / Integration Plane” 是产品层的心智模型,不是说 Jianmu 代码里正式存在一个同名模块。

把两边放在一起看:

flowchart TB
    PRODUCT["TUI / Studio / Business System / Eval"]

    subgraph CONTROL["Runtime Control & Integration Plane"]
        EVENT["Event Bus"]
        TELE["Telemetry / Trace"]
        HOOK["Hook"]
        GOV["Guard / Approval / Sandbox"]
    end

    subgraph CORE["Execution Kernel"]
        STRUCT["Structured Control\nBehavior Tree"]
        REACT["Reactive Execution\nEvent-driven Runner"]
        DURABLE["Durable State\nCheckpoint / Resume"]
    end

    PRODUCT <--> CONTROL
    CONTROL <--> CORE

这张图也解释了为什么“可观测性”这个词其实还不够。

如果只有 Telemetry,外部只能看。

有 Event Bus,外部可以实时订阅运行事实。

有 Hook,外部产品还可以在明确边界进入执行过程。

有 Guard / Approval,真正的干预又有安全和责任边界。

所以这一层更完整的描述应该是:

可观测、可扩展、可干预,同时保持治理边界。

这对 Agent 产品尤其重要。

因为长期 Agent 不可能永远生活在一个框架自己的 Demo 里。

它最终要接进:

IDE
IM
业务后台
审计平台
监控系统
Eval Pipeline
企业权限体系
其他 Agent

如果每接一个产品都要修改 Runtime 主循环,框架很快就会失去统一语义。

所以 Event、Telemetry 和 Hook 的价值,不只是“开发体验更方便”。

它们让 Jianmu 可以保持一个相对稳定的执行内核,同时允许越来越多产品和业务系统接进来。

如果把这一章压缩成一句话,就是:

Jianmu 不只希望 Agent 能运行,还希望一个正在运行的 Agent 可以被看见、被追踪、被产品接入,并在明确边界上被扩展和干预。

这也是 Runtime 从“执行引擎”走向真正产品基础设施时必须补上的一层。

8. 能力层:Model、Tool、Skill、Memory、Context、MCP 与 RAG

本章用途:解释 Runtime 调用什么能力,以及这些能力如何被组织、复用和沉淀。运行内核负责推进,生命周期层负责持续存在,能力层负责让 Agent 真正理解、判断、行动和积累经验。

8.1 Model:Provider、Retry / Fallback 与 Streaming

模型是 Agent 最重要的动态判断来源之一,但 Jianmu 不希望控制逻辑和某一家模型服务绑在一起。

所以模型调用被放在独立的一层:上面的 Tree 和 Node 只表达“这里需要一次模型能力”,下面的 Provider 再负责把这次调用送到具体模型服务。

flowchart LR
    N["Agent / LLM Node"] --> M["统一 Model 层"]
    M --> P["Provider A"]
    M --> Q["Provider B"]
    M --> X["其他 Provider"]

这样同一棵 Tree、同一个 Skill 可以更换模型,而不需要把执行结构一起重写。

这层还统一处理模型调用最常见的可靠性问题。

Retry 面向短时故障。超时、限流或服务暂时不可用时,可以在模型层做有限重试,而不是让每个 Agent 节点各自实现一套错误处理。

Fallback 面向受控降级。主模型持续不可用时,可以切换到预先配置的备用模型。这里的 Fallback 是模型基础设施的降级,不等于 Behavior Tree 里的业务 Fallback:前者是在完成同一次模型调用,后者可能意味着整个业务方案已经换了一条路径。

Primary Model
   ↓ 短时故障
Retry
   ↓ 仍不可用
Fallback Model
   ↓
成功 / 明确结束

Streaming 也不只是界面上的“逐字输出”。Agent 的流式响应还可能包含结构化 Tool Call,因此模型层需要保证增量传输结束后,上层仍然得到完整、一致的模型结果,再继续后续执行。

模型调用产生的 Token 使用量等信息也可以在这一层统一进入 Telemetry。

所以可以把这层理解成:

Node 决定什么时候需要模型,Context 决定给模型看什么,Model 层负责把模型能力稳定、可替换、可降级、可流式地接进 Runtime。

8.2 Tool / MCP:连接外部世界

模型能想,但它自己不会真的去改数据库、查订单、发邮件或者调用业务接口。

这些真正产生外部效果的能力,都通过 Tool 接进来。

Jianmu 对 Tool 的理解比较直接:Tool 是 Agent 和外部世界之间的一层明确接口。

它可以是:

  • 一个 Python 函数;
  • 一个 HTTP API;
  • MCP 暴露出来的工具;
  • 一个数据库查询;
  • 一个外部服务;
  • 一段需要在 Sandbox 里执行的代码。

Tool 本身只负责“这件事怎么做”。

至于什么时候做、失败以后怎么办、是否需要人工确认、结果回来以后下一步走哪里,这些不应该全部塞进 Tool 里面,而是交给 Runtime、Behavior Tree 和 Guard 来处理。

这个分工很重要。

否则业务做久以后,很容易出现一种情况:每个 Tool 里面都偷偷带着一点流程逻辑、权限逻辑、重试逻辑和状态逻辑,最后谁也说不清真正的业务流程藏在哪里。

在 Jianmu 里,更希望保持这样的关系:

Behavior Tree 决定这次 tick 怎么推进
Model 决定动态问题怎么判断
Tool 负责真正执行动作
Guard 决定动作能不能直接执行
Runtime 负责等待、恢复和状态推进

这样 Tool 可以保持相对简单,也更容易被多个 Agent 或 Skill 重复使用。

8.3 Skill:把经验沉淀成能力

Tool 解决的是“一个动作怎么做”,Skill 解决的是“这一类事情通常怎么做”。

比如:

  • query_order 是 Tool;
  • “处理一个异常订单”更像 Skill。

后者可能需要先查订单,再查支付,再判断风险,必要时审批,最后决定退款还是人工处理。它已经不是一次原子调用,而是一套完整能力。

所以 Jianmu 里的 Skill 不是简单的 Prompt 别名。

一个 Skill 可以有自己的输入、输出、说明、允许使用的工具和执行方式。Agent 调用 Skill 时,拿到的是一段已经组织好的能力,而不是一句模糊的“你想办法把这件事做了”。

从产品角度看,Skill 的意义在于:能力开始有名字、有边界,也可以被重复使用。

比如产品里可以逐渐形成:

订单异常分析
退款处理
合同检查
日报生成
舆情汇总
竞品调研
发布前检查

这些东西不再全部藏在某个 Agent 的 System Prompt 里,而是可以被单独管理。

这也是 Jianmu 后面做 Skill Catalog 的原因:Agent 真正长期使用以后,最有价值的不一定是某一次回答,而是积累下来的这些能力。

对企业场景来说,Skill 还有另一层意义。它把“这类事情怎么做”从某个 Agent 的 Prompt 里拿出来,变成一个可以命名、管理和治理的对象。Prompt Skill 保留灵活性,Tree Skill 则进一步提供结构化确定性。

8.4 Tree Skill:企业确定性的主要沉淀方式

Skill 在 Jianmu 里可以有不同的执行方式。

前面第 4 章讲过,行为树在 Jianmu 里有两个层次:一个是 Runtime 内核里的 Agent Loop,一个是能力层里的 Tree Skill。两者不是先后递进关系,也不是两套不同 DSL。Agent Loop 和 Tree Skill 都使用 Node / Tree 表达结构,也都由 ReactiveRunner 推进执行。

复杂编排主要发生在 Tree Skill 这一层。内核循环解决的是现代 Agent 怎么持续 Reason、Act、Observe;Tree Skill 解决的是一套稳定业务能力怎么被组织成可以复用、治理和审计的树。

有些任务变化很大,更适合让模型根据说明临场完成。比如“根据这些材料写一份竞品分析”,很难提前把每一步都固定下来。

这类能力可以保留比较灵活的 Prompt Skill。

但还有一些能力,最开始也许靠模型探索,后来执行方式已经越来越稳定。

比如经过多次执行以后,我们发现“异常退款处理”基本都会走这几步:

查询订单
   ↓
查询支付
   ↓
判断退款条件
   ↓
风险检查
   ↓
必要时审批
   ↓
执行退款
   ↓
确认结果

这时候继续每次都让模型重新规划一遍,就没有太大意义。更好的做法是把已经稳定的部分从临场判断里拿出来,变成一棵真正可以运行的树。

Jianmu 可以把这套成熟做法沉淀成 Tree Skill。以后其他 Agent 遇到同类问题,可以直接调用这棵树。

Tree Skill 的价值不只是更省 Token。

更重要的是,它把一套已经验证过的执行方式固定成了真正可以运行的结构。企业系统需要的确定性,主要就来自这一层。

模型仍然可以参与其中,比如负责分类、判断或生成内容;但那些已经明确的步骤、重试规则、审批路径和失败处理,不需要每次重新猜。它们进入 Tree Skill 以后,就可以被测试、审计、评审、版本化和回滚。

可以把这个过程理解成:

第一次:模型探索怎么做
        ↓
多次执行:发现比较稳定的做法
        ↓
整理成 Skill
        ↓
进一步结构化为 Tree Skill
        ↓
后续任务直接复用

这也是为什么 Jianmu 里的 Skill 和行为树关系很紧。

同一套 Node / Tree 和 ReactiveRunner,在 Runtime 内核里服务于 Agent Loop,在能力层里服务于 Tree Skill。内核循环保持轻量,主要表达 ReAct 或 Plan-Execute 这样的现代 Agent 循环;复杂编排、企业确定性和能力复用,主要落在 Tree Skill。

8.5 Context / Memory / RAG:模型看到什么、系统记住什么、外部取回什么

Context、Long-term Memory 和 RAG 都和“给模型提供信息”有关,但解决的是几类不同的问题。

Context 回答:

模型这一刻应该看到什么?

当前任务、历史消息、Tool 结果、检索内容、Skill 说明和业务 State,不可能每次全部塞进模型。Context 的作用是从这些信息里组织出当前这一轮真正需要的工作集。

Long-term Memory 回答:

这次任务结束以后,哪些信息以后还值得记住?

比如用户长期偏好、已经确认过的事实、跨会话仍然有用的背景知识。Jianmu 把长期记忆当成可替换的能力层:可以使用语义记忆后端,也可以使用更轻量的存储,并按用户、Agent、Thread 或业务范围隔离。

关键不在于“把所有聊天都永久存下来”,而在于有选择地记录,并在需要时重新检索进 Context。

RAG 回答:

当前任务需要哪些外部知识?

它更像知识接入方式,而不是 Agent 自己的长期记忆。产品文档、业务规则、历史工单、代码库和知识库里的材料,可以通过 RAG 检索出来,再进入当前 Context。这样模型看到的是和本轮任务有关的材料,而不是一整套外部知识库。

所以可以简单记成:

State            = 当前 Runtime 里的事实是什么
Context          = 模型现在看什么
Long-term Memory = 跨任务以后还要记得什么
RAG              = 从外部知识里取回什么

它们之间的关系大致是:

flowchart TB
    S["Typed State\n当前运行事实"] --> C["Context\n本轮模型工作集"]
    M["Long-term Memory\n跨任务知识"] --> C
    R["RAG\n外部知识检索"] --> C
    C --> L["Model"]

这个区分很重要:保存聊天历史不等于长期记忆;长期记忆被检索出来以后,也不意味着每一条都应该进入模型当前 Context。至于 Checkpoint,它属于第 5 章的生命周期与持久化层,处理的是任务中断以后怎么恢复,不属于能力层的信息供给机制。

9. 多智能体:Swarm

本章用途:解释 Jianmu 的多智能体为什么不是“多开几个模型”,而是一组有独立身份、状态和生命周期的 Agent,在同一个 Runtime 中通过消息持续协作,并在任务执行过程中动态形成组织结构。

Jianmu 的多智能体有一句最重要的定调:

Jianmu 的多智能体不是让多个模型互相聊天,而是让多个有独立身份、状态和生命周期的 Agent,在同一个 Runtime 中持续协作。

如果只看表面,多 Agent 很容易被理解成:让几个 LLM 扮演不同角色,然后轮流说话。

但 Jianmu 想做的不是这个层次。

在 Jianmu 里,每个 Agent 都是一个真正运行着的执行体;消息不是几次函数调用之间顺手传递的参数,而是 Runtime 要管理的对象;Agent 之间也不要求永远由一个 Manager 统一分工。随着任务变化,新的 Agent 可以被创建,新的通信关系可以出现,原有成员可以暂停、恢复或退出,整个协作网络会跟着任务一起变化。

这也是这里所说的 Swarm 和 Liquid Topology。

9.1 多 Agent 不等于“多个模型互相聊天”

最简单的多 Agent 往往长这样:

Researcher 说一句
      ↓
Coder 说一句
      ↓
Reviewer 说一句
      ↓
再回到 Researcher

这种方式当然也是多智能体,而且很多任务已经够用。

但从 Runtime 角度看,它更像一个多角色对话流程。每个“Agent”可能只是一次模型调用,真正掌握流程的是外面的 orchestrator。

Jianmu 的 Swarm 不一样。

一个 Agent 被创建以后,会有自己的身份、角色、任务、状态、Mailbox 和 Runner。它可以独立执行,可以暂时没有事情可做,可以收到消息以后再被唤醒,也可以暂停、恢复、失败、重启或被终止。

换句话说,Jianmu 里的 Agent 不是:

一个角色名 + 一段 Prompt

而更接近:

Agent
├── 我是谁:Identity / Role
├── 我要做什么:Task
├── 我现在知道什么:State
├── 别人给我发了什么:Mailbox
├── 我怎么执行:Behavior Tree / ReactiveRunner
└── 我现在处于什么阶段:Lifecycle

于是多个 Agent 放在一起以后,问题就不再只是“下一轮谁说话”。

真正的问题变成了:

  • 哪些 Agent 现在存在;
  • 谁正在运行,谁在等待;
  • 一条消息应该发给谁;
  • 收到消息以后是否应该立即唤醒;
  • Agent 中途失败以后怎么办;
  • Runtime 重启以后,哪些消息已经处理过;
  • 一个 Agent 能不能自己创建新的 Agent;
  • 整个协作结构能不能在执行过程中变化。

这才是 Jianmu Swarm 真正处理的问题。

9.2 Subagent、Agent Team 和 Swarm:同一个 Runtime 的不同自由度

“多 Agent”这个词把很多组织方式放在了一起。对 Jianmu 来说,更重要的不是给它们分三个完全独立的系统,而是理解:它们可以建立在同一个 Multi-Agent Runtime 上,只是开放的组织自由度不同。

Subagent:受约束的父子拓扑

最简单的是 Subagent。

            Main Agent
           /     |     \
          ↓      ↓      ↓
       Agent A Agent B Agent C

主 Agent 掌握整体任务,把子任务分给下面的 Agent;子 Agent 主要完成被分配的工作,再把结果交回父 Agent。

这种模式的好处是非常直观:谁负责拆任务、谁创建谁、结果回到哪里都比较明确。对于大量“一个主任务拆成几个子任务”的场景,这已经足够。

在 Jianmu 里,不需要为了使用这种简单模式换一套 Runtime。只要把协作规则限制在父子关系里,就可以得到一个更可控的 Subagent 系统。

Agent Team:受约束的固定协作拓扑

再往上可以是一个预先组织好的 Agent Team。

         Manager / Team Protocol
          /       |        \
         ↓        ↓         ↓
   Researcher   Coder    Reviewer

成员、角色和主要协作关系可以在任务开始前确定。Researcher、Coder、Reviewer 都有自己的状态、Mailbox 和生命周期,但不一定允许成员在运行中随意扩张团队或改变全部通信关系。

这种模式保留了多 Agent 的长期状态、异步协作和恢复能力,同时让成员数量、调用路径和成本更容易预测。

Swarm:允许拓扑在运行中变化

真正的 Liquid Swarm 会进一步放开这些约束。

Agent A ─────→ Agent B
   │             │
   ↓             ├────→ Agent D
Agent C ←────────┘
   │
   └──────────→ Agent E

这里不要求所有消息都经过 Manager,也不要求任务开始前就知道最终会出现几个 Agent。Agent 可以根据局部信息直接建立新的协作关系,也可以在 Runtime 允许的范围内创建新的角色。

所以三者更适合被理解成一条自由度梯度:

形态 组织自由度 典型约束 可预测性
Subagent 低 父子关系、主 Agent 分派 高
Agent Team 中 固定成员、固定角色、受控通信 较高
Liquid Swarm 高 可动态创建、动态通信、动态拓扑 更依赖 Runtime 治理
更固定、更可预测
        ↑

Subagent
   ↓
Fixed Agent Team
   ↓
Dynamic Team
   ↓
Liquid Swarm

        ↓
更自治、更灵活

这里有一个很重要的产品判断:

Swarm 是 Jianmu 多智能体能力的上限,不是使用门槛。

Jianmu 提供动态创建、消息路由、生命周期和液态拓扑,并不意味着每个产品都应该把这些自由度全部打开。生产系统完全可以根据成本、风险和可控性,把成员数量固定下来、限制谁能创建 Agent、限制通信范围,只使用 Subagent 或固定 Team。

很多真实业务反而应该从更受约束的形态开始,只在确实无法提前设计协作关系的部分释放动态性。

这和 Jianmu 在单 Agent 层的设计是一致的:稳定的部分结构化,不确定的部分留出自治空间。 到了多 Agent 层,同样可以理解成:稳定的组织关系提前固定,真正需要动态协作的部分才交给 Swarm 在运行时形成。

9.3 Agent 是有生命周期的执行体

要做 Swarm,第一件事不是“让 Agent 会发消息”,而是先让 Agent 真正成为 Runtime 里的长期对象。

在 Jianmu 里,Agent 有明确的生命周期。

stateDiagram-v2
    [*] --> Created: create / spawn
    Created --> Running: start
    Running --> Paused: pause
    Paused --> Running: resume
    Running --> Running: message / wake / continue
    Running --> Failed: unrecoverable error
    Failed --> Running: restart policy
    Running --> Stopped: kill
    Paused --> Stopped: kill
    Failed --> Stopped: kill
    Stopped --> [*]

这个设计看起来很基础,但区别很大。

如果所谓“创建一个 Agent”只是调用一次 LLM,那么调用结束以后它也就没了。下一轮再调用时,实际上是另一次请求。

而在 Jianmu 里,一个 Agent 可以:

  • 被创建并注册到 Runtime;
  • 自动开始执行,也可以由外部手动推进;
  • 暂停一段时间;
  • 收到新消息后继续运行;
  • 因异常触发重启策略;
  • 被其他 Agent 或宿主终止;
  • 在 Runtime snapshot 恢复后重新存在。

这意味着 Swarm 里的“成员”是真正有时间跨度的。

某一刻 Agent B 没有事情做,并不意味着 B 不存在;它可能只是在等下一条消息。

所以 Jianmu 的多智能体首先是一个生命周期管理问题,然后才是一个“多个模型怎么协作”的问题。

9.4 每个 Agent 都有自己的身份、状态、任务与 Mailbox

生命周期解决“Agent 活不活着”,接下来还要解决“这个 Agent 到底是谁”。

Jianmu 会为每个 Agent 保存自己的 Profile 和运行状态。产品层可以把它理解成每个 Agent 都有一张自己的工作卡片:

Agent B
├── id: agent_b_...
├── role: logistics_specialist
├── task: 调查订单 A1024 的物流异常
├── parent: Agent A
├── state: 当前任务状态
├── mailbox: 收到但尚未处理的信息
├── groups / topics: 当前加入的协作网络
└── runtime status: running / paused / ...

这里最关键的是 Mailbox。

如果 Agent 只是同步调用,A 调 B 时可以直接把参数传进去,B 返回结果就结束。

但 Swarm 里的 Agent 是异步、持续存在的。

A 给 B 发消息时,B 可能正在运行别的任务,也可能刚好处于空闲状态。消息不能因为“对方现在没在函数调用栈里”就丢掉。

所以每个 Agent 都需要自己的消息入口,并且 Runtime 要知道:

  • 哪些消息已经到达;
  • 哪些已经被处理;
  • 当前消费到哪个位置;
  • 是否还有未读消息;
  • 新消息是否应该把 Agent 唤醒。

这让 Agent 从“被调用的函数”变成了更接近长期运行服务的东西。

9.5 通信本身就是 Runtime 的一部分

这是 Jianmu Swarm 很重要的一个设计点。

在简单多 Agent 系统里,所谓通信可能只是:

result_a = agent_a.run(task)
result_b = agent_b.run(result_a)

这里其实没有真正的通信系统,只是 orchestrator 把 A 的返回值传给了 B。

Swarm 不够用。

因为当 Agent 独立运行以后,一条消息从 A 发给 B,至少会涉及这些事情:

A 发消息
   ↓
Runtime 确认目标
   ↓
写入 Message Store
   ↓
投递到 B 的 Mailbox
   ↓
记录消息序号和消费状态
   ↓
唤醒 B
   ↓
B 把消息同步进自己的 State / Context
   ↓
继续执行

也就是说,通信不是 Agent 外面的一段胶水代码,而是 Runtime 自己要负责的基础设施。

Jianmu 的 AgentRuntime 会统一处理消息路由、Mailbox 投递、事件、Agent 生命周期和调度。

这样做有一个很直接的好处:Agent 不需要知道对方现在是否“在线”。

它只需要把消息交给 Runtime。

对方什么时候处理、是否需要唤醒、消息有没有被消费、失败以后怎么处理,都是 Runtime 的事情。

这和真实的人协作其实有点像。发一封邮件时,我们不会要求对方必须此刻正坐在电脑前;邮件系统负责把消息保存下来,对方之后再处理。

Swarm 想长期运行,就必须有类似的语义。

9.6 消息就是事件:Agent 如何互相唤醒

Jianmu 单 Agent 的核心是事件驱动。

到了 Swarm,这个设计自然延伸成:一个 Agent 发出的消息,可以成为另一个 Agent 的事件。

sequenceDiagram
    participant A as Agent A
    participant R as AgentRuntime
    participant M as Message Store / Mailbox
    participant B as Agent B

    A->>R: send_message(B, content)
    R->>M: 保存并投递消息
    R->>B: wake
    B->>M: 同步未读消息
    M-->>B: incoming messages
    B->>B: ReactiveRunner 继续执行

单 Agent 是:

外部世界发生变化
        ↓
      Event
        ↓
    唤醒 Agent
        ↓
     Agent 行动

Swarm 则多了一层:

Agent A 行动
     ↓
   Message
     ↓
成为 Agent B 的事件
     ↓
唤醒 Agent B
     ↓
Agent B 行动

再往后,B 的行动又可能唤醒 C、D。

于是整个 Swarm 可以理解成:

多个事件驱动的 Agent Runtime,通过消息不断改变彼此的执行状态。

这比“多个 Agent 轮流说话”更接近 Jianmu 的真实运行方式。

Agent 没有新消息、没有异步任务、也没有其他需要处理的工作时,可以保持空闲;一旦消息到达,Mailbox 变化会推动它重新运行。

9.7 Direct / Group / Topic:Swarm 中的通信网络

Swarm 如果只有“父 Agent 给子 Agent 派任务”,最后还是很容易退化成一棵组织树。

Jianmu 的 Runtime 支持三种不同的消息路由方式。

方式 含义 适合什么情况
Direct 精确发给某个 Agent 我明确知道应该找谁
Group 发给一个组里的所有成员 一组 Agent 需要同步某件事
Topic 发给所有订阅某个 Topic 的 Agent 我关心的是“谁对这个信息感兴趣”,而不是具体是谁

Direct 很容易理解。

例如 Risk Agent 知道 Logistics Agent 的 ID,可以直接询问:

Risk Agent ──“这个订单是否已经发货?”──→ Logistics Agent

Group 更像团队频道。

例如几个正在处理同一个订单的 Agent 都加入 order:A1024 组,重要状态可以一次同步给所有人。

Topic 则更有 Swarm 的味道。

比如 Agent A 发现一个潜在高风险事件,只需要向 risk Topic 发布:

                topic:risk
              /     |      \
             ↓      ↓       ↓
        Risk A   Risk B   Monitor

发送方不需要提前知道所有接收者是谁。

新的 Agent 只要订阅这个 Topic,就可以进入这条信息流;取消订阅以后就离开。

这意味着 Agent 之间的通信关系本身也可以动态变化。

9.8 去中心化协作:没有必须掌控全局的总指挥

Jianmu Swarm 里可以有父子关系,也可以有负责统筹的 Agent,但不要求一定存在一个掌握全局、决定所有下一步的 Manager Agent。

这是“去中心化”最核心的含义。

一个 Agent 可以根据自己的局部信息做决定:

  • 我要不要联系另一个 Agent;
  • 我要联系谁;
  • 要不要创建新的角色;
  • 要不要加入某个 Group;
  • 要不要订阅一个 Topic;
  • 当前任务是否已经完成。

例如:

Root Agent
    │
    ├────→ Logistics Agent
    │           │
    │           └────→ Payment Agent
    │
    └────→ Risk Agent
                │
                └────────→ Logistics Agent

最开始 Root Agent 只创建了 Logistics 和 Risk。

但 Logistics 在调查过程中发现问题和支付有关,于是它自己创建了 Payment Agent。

随后 Risk 又直接向 Logistics 询问信息。

整个过程中,不需要每一条信息都走:

子 Agent → Root → 另一个子 Agent

Runtime 负责通信秩序,但它不替 Agent 决定应该和谁合作。

Runtime 管秩序,Agent 自己决定怎么协作。

9.9 Liquid Topology:组织结构随着任务动态变化

如果只说“去中心化”,还不足以描述 Jianmu 的 Swarm。

另一个关键点是 Liquid Topology。

所谓“液态”,说的是:组织结构不是任务开始前就完全固定的,而是执行过程中根据需要形成。

例如一个任务刚开始时,可能只有一个 Agent:

A

A 发现需要物流专家:

A ──→ B

B 又发现需要支付专家:

A ──→ B ──→ C

与此同时 A 创建了风险 Agent D:

A ──→ B ──→ C
 \
  └──→ D

随后 D 发现 B 手里的物流信息对自己有用,于是直接联系 B:

A ──→ B ──→ C
 \    ↑
  └──→ D

最终网络长成什么样,不一定能在任务开始前画出来。

因此这里有一个很重要的判断:

在 Liquid Swarm 里,组织结构本身就是任务执行的结果。

传统工作流通常先把节点和边画好,然后数据沿着这张图流动。

Jianmu 的 Swarm 可以在运行中改变“有哪些 Agent”“谁和谁通信”“谁订阅什么信息”。

也正因为如此,它更适合那些很难提前把协作结构完全设计好的开放任务。

9.10 Agent 创建 Agent:协作网络可以自己生长

Liquid Topology 能成立,一个很关键的能力就是:Agent 可以创建 Agent。

这不是说所有任务都应该无限创建 Agent。

它真正解决的是:系统运行到一半时,才发现需要一个之前没有准备好的执行角色。

比如一个市场调研 Agent 最开始只负责收集行业资料。

做到一半发现需要检查一家公司的财务风险,它可以创建一个 financial_analyst Agent;财务 Agent 又发现需要核实海外监管信息,再创建一个 regulation_researcher。

Market Agent
    │
    └──→ Financial Agent
              │
              └──→ Regulation Agent

这些 Agent 不是工程师提前在 Workflow 里写死的三个节点,而是运行过程中出现的。

在 Jianmu 里,这类 Runtime 操作本身可以作为 Tool 暴露给 Agent:创建 Agent、列出当前 Agent、暂停、恢复、终止、发送消息、加入 Group、订阅 Topic。

因此 Agent 不只是业务能力的使用者,也可以在 Runtime 允许的范围内改变自己的协作环境。

当然,这件事越动态,工程上越难控制。

所以 Jianmu 不是只提供 create_agent() 就结束了,还要继续解决生命周期、消息、重复创建、恢复等问题。

9.11 长时 Swarm:生命周期、Mailbox、Snapshot 与恢复

一个 Swarm 如果只跑几十秒,很多问题都可以先忽略。

但如果它要跑很久,甚至中间跨越等待、重启和故障,事情就复杂了。

假设一个 Swarm 里现在有 8 个 Agent:

  • 3 个正在执行;
  • 2 个在等其他 Agent 的消息;
  • 1 个被暂停;
  • 1 个刚刚收到消息还没处理;
  • 1 个因为异常正在重启。

这时候进程突然重启。

恢复不能只是说:

“好,我记得之前有 8 个 Agent。”

还需要知道:

  • 每个 Agent 的 Profile 和任务是什么;
  • 每个 Agent 的 State 是什么;
  • 哪些 Agent 原来是 paused / auto mode;
  • 每个 Mailbox 已经消费到哪个消息序号;
  • 当前加入了哪些 Group;
  • 订阅了哪些 Topic;
  • Message Store 里还有哪些消息;
  • 恢复以后哪些 Agent 应该重新启动。

所以 Jianmu 的 Swarm snapshot 保存的是整个 Runtime 的状态,而不只是几段对话记录。

Swarm Snapshot
├── Agent A
│   ├── Profile
│   ├── State
│   ├── Mailbox Cursor
│   ├── Groups / Topics
│   └── Lifecycle State
├── Agent B
│   └── ...
├── Agent C
│   └── ...
└── Message Store

恢复时,Runtime 会重新建立 Agent Host、State、Runner 和路由关系,并恢复消息存储,再让需要自动运行的 Agent 继续工作。

这也是为什么前面一直强调:

通信本身必须属于 Runtime。

如果消息只存在某几个 Agent 的 Prompt 里,或者只在函数调用过程中短暂存在,那么整个 Swarm 根本没有办法真正恢复。

9.12 Swarm 如何处理重复执行、并发与幂等

动态多 Agent 要真正长期运行,Runtime 不能假设“一切只会发生一次”。重试、恢复和并发都可能让同一个意图再次出现,所以 Jianmu 把这类问题直接纳入 Swarm 的运行语义,而不是要求每个 Agent 自己记得“千万别重复”。

最典型的是 Agent 创建。

Agent A 需要一个 Risk Agent,但创建成功以后,它在拿到返回结果之前发生超时。恢复后如果把“创建 Risk Agent”再做一次,就可能得到两个重复角色。

Jianmu 为这类创建提供稳定的复用标识。Runtime 可以识别:

这不是一个新的创建意图,而是之前那次创建的重试。

于是返回已经存在的 Agent,而不是再次扩张协作网络。

消息发送同样如此。发送方可能已经把任务交给另一个 Agent,却在确认结果之前重启。通过稳定的消息去重语义,重复发送可以被识别和抑制,避免一条业务意图在恢复以后变成两份任务。

创建 Agent
→ stable reuse identity
→ 重试时复用已有 Agent

发送 Message
→ stable dedupe identity
→ 重试时避免重复投递同一意图

再往下,Runtime 还要管理 Mailbox 的消费位置、消息顺序、Agent 生命周期和 Snapshot 恢复。这样一个 Swarm 重启以后,不只是“把 Agent 都重新建出来”,还能够知道哪些消息已经处理、哪些执行体应该继续、哪些操作已经有过结果。

并发则是另一类问题。多个 Agent 可以同时运行、同时发消息、同时发现需要某种能力。Jianmu Runtime 负责把基础设施层的并发秩序管理好,包括消息投递、Mailbox 消费、生命周期推进和重复操作控制。

至于业务本身的并发冲突,例如两个 Agent 同时争抢最后一份库存、同时修改同一笔交易,则应该继续交给业务规则、Guard、Governed Effect 或外部系统自己的事务语义处理。

这个边界很重要:

Jianmu 负责让 Swarm 的执行基础设施具备可恢复、可去重、可持续的语义;业务世界里的资源竞争,则在明确的治理和事务边界上解决。

所以重复执行、并发和幂等不是 Jianmu Swarm 留给使用者自行处理的“已知问题”,而是多 Agent Runtime 本身必须承担的一部分。

9.13 Jianmu 的“去中心化”到底指什么

最后需要把一个边界说清楚。

Jianmu 的 Swarm 是协作逻辑和 Agent 决策层面的去中心化,并不是说整个基础设施完全没有中心。

当前架构里仍然有统一的 AgentRuntime:

                    AgentRuntime
          ┌────────────┼────────────┐
          ↓            ↓            ↓
      消息路由      生命周期       Snapshot
          │            │            │
          └───────┬────┴────┬───────┘
                  ↓         ↓
             Agent A ↔ Agent B
                ↕        ↘
             Agent C ↔ Agent D

AgentRuntime 负责的是基础设施:

  • 谁现在存在;
  • 消息怎么投递;
  • Mailbox 怎么消费;
  • Agent 怎么启动、暂停、恢复和终止;
  • Group / Topic 的成员关系;
  • Runtime 怎么 snapshot 和恢复。

这个统一 Runtime 负责的是基础设施秩序,不等于系统必须存在一个替所有 Agent 做决定的“中央大脑”。在开放的 Liquid Swarm 里,下一步做什么、联系谁、是否需要新的角色,以及协作网络最后长成什么样,都可以由 Agent 根据任务和局部信息动态决定。

但这里还要再强调一个边界:去中心化是 Jianmu 提供的协作能力,不是强制所有产品采用的组织形式。

同一个 Runtime 完全可以被约束成:

Subagent
→ 只允许父 Agent 分派与创建

Fixed Team
→ 成员和角色预先确定

Controlled Dynamic Team
→ 只允许特定角色扩张或建立新通信

Liquid Swarm
→ 在治理边界内动态形成拓扑

产品可以通过固定成员、限制 Agent 创建权限、限制通信范围、设置预算和 Guard,把组织自由度收紧到自己能接受的范围。需要更高成本可预测性时,就少开放动态能力;任务本身难以提前分解时,再逐步释放更多自治空间。

所以更准确的说法是:

Jianmu 用统一 Runtime 管理消息、生命周期、恢复和治理,并允许产品在“固定层级协作”到“动态液态 Swarm”之间选择合适的组织自由度。

这也是 Jianmu 所说的“去中心化”真正想表达的东西:Runtime 有统一秩序,但协作决策不必全部集中在一个 Manager 身上。

如果把这一章压缩成一句话,就是:

Jianmu 提供的是一个统一的多 Agent Runtime:简单场景可以收敛成 Subagent 或固定 Agent Team,复杂开放任务则可以逐步释放动态创建、动态通信和液态拓扑,直到形成长期运行的 Swarm。

10. 从能力沉淀到持续改进

本章用途:说明一套有效流程如何从“一次成功执行”变成可复用 Skill,并进一步进入持续改进:运行产生证据,证据推动候选修改,候选经过验证、晋升和回滚,再重新投入真实执行。

Agent 真正长期运行以后,会自然出现一个问题:

这次任务做成了,下一次还要不要从头再想一遍?

如果答案永远是“要”,那系统虽然会做事,却很难真正积累能力。

一个 Agent 第一次处理异常订单时,可能需要模型临场分析:先查什么、哪些信息有用、什么时候应该审批、失败以后怎么处理。这个过程可以很灵活,甚至带有不少试错。

但如果类似任务已经做过很多次,而且其中大部分步骤已经比较稳定,那么这些经验就不应该永远只存在于某一次对话、某一段 Trace 或某个开发者的脑子里。

Jianmu 希望把这类经验逐渐变成可以再次调用的 Skill。

所以前面几章讲的是“Agent 怎么把一次任务跑完”,这一章开始讨论另一个时间尺度的问题:

Agent 做过的事情,怎么变成它以后会直接使用的能力。

10.1 从一次成功执行到可复用能力

先看一个最简单的例子。

第一次让 Agent 处理“订单支付成功但没有履约”的问题,它可能这样工作:

理解用户问题
   ↓
查订单
   ↓
发现信息不够
   ↓
再查支付
   ↓
判断可能需要退款
   ↓
查退款规则
   ↓
发现大额退款需要审批
   ↓
发起审批
   ↓
执行退款
   ↓
确认结果

第一次这样跑完全合理,因为系统还不知道这类问题最合适的处理方式是什么。

但当相似任务出现十次、五十次以后,我们可能会发现:

  • 订单状态和支付状态几乎每次都要查;
  • “是否符合退款条件”是一个相对稳定的判断步骤;
  • 大额退款必须经过审批;
  • 退款失败通常要重试或转人工;
  • 最后一定要确认真实退款结果,而不能只看 Tool 调用是否发出。

这时候已经出现了一套比较稳定的结构。

真正值得沉淀的不是某一次具体结果:

订单 A1024 最后退款成功

而是背后的做法:

这类订单异常,一般应该怎么处理?

这就是从“执行结果”走向“能力”的第一步。

不过,一次成功执行不能直接等于一个 Skill。

因为一次成功可能只是碰巧成功。模型临场选择的路径也可能包含很多只适用于当前任务的细节。

所以从执行里沉淀能力时,需要区分两类东西。

第一类是稳定结构:

  • 哪些步骤几乎总是需要;
  • 哪些前置条件必须满足;
  • 哪些失败有固定处理方式;
  • 哪些动作必须经过审批;
  • 输入和输出应该长什么样。

第二类是仍然需要动态判断的部分:

  • 当前用户到底想解决什么;
  • 当前异常属于哪一类;
  • 一段文本应该如何理解;
  • 多个候选方案里哪一个更合适。

前一类适合固化到 Tree、Tool、约束和输入输出契约里;后一类仍然可以留给模型。

所以能力沉淀并不是“把模型去掉”,而是把那些已经不需要每次重新猜的东西固定下来。

最后,一个成熟的能力可能变成:

异常退款 Skill
├── 输入
│   ├── order_id
│   └── 可选的用户补充说明
├── 稳定流程
│   ├── 查询订单
│   ├── 查询支付
│   ├── 判断退款条件
│   ├── 风险检查
│   ├── 必要时审批
│   └── 执行并确认退款
├── 动态判断
│   └── 模型负责异常分类和必要的文本理解
├── 约束
│   └── 大额退款不得自动放行
└── 输出
    ├── result
    ├── reason
    └── transaction_id

到这一步,它就不再只是某次任务的 Trace,而开始成为一个有边界的能力资产。

Jianmu 现有 Skill 系统正是用来承载这种资产。Skill 可以声明自己的名字、说明、输入、输出、依赖工具、执行方式和约束;比较灵活的部分可以用 Prompt Skill,已经稳定的控制结构则可以变成 Tree Skill。

10.2 Capability Loop:执行 → 验证 → 沉淀 → Skill → 复用

如果把上面的过程拉长看,它其实不是一条单向流水线,而是一个循环。

flowchart LR
    A["执行真实任务"] --> B["观察结果与 Trace"]
    B --> C["验证哪些做法真正有效"]
    C --> D["提取稳定结构"]
    D --> E["沉淀为 Skill / Tree Skill"]
    E --> F["后续 Agent 直接复用"]
    F --> G["产生更多执行数据"]
    G --> B

这里我把它称为 Capability Loop。

它和普通“保存一个 Prompt 模板”最大的区别,是中间多了一个很重要的环节:验证。

一个流程被执行过,不代表它值得复用;一个流程成功过,也不代表它应该被推广到所有类似任务。

所以更合理的路径是:

做过
  ↓
做成过
  ↓
多次验证确实有效
  ↓
再沉淀

验证可以很简单,也可以很严格。

早期产品里,它可能只是开发者或业务人员检查几次执行 Trace,确认这套流程足够稳定。

再往后,可以有专门的测试集:

正常订单
大额退款
支付状态异常
接口超时
审批拒绝
退款结果丢失

一个候选 Skill 只有在这些场景里表现足够稳定,才进入正式能力库。

这点对 Agent 系统尤其重要,因为“能力复用”本身是一种放大器。

如果沉淀的是一个好流程,后续任务都能受益;如果沉淀的是一个错误流程,后续任务也会稳定地重复这个错误。

所以 Capability Loop 不是:

成功一次 → 自动记住

而更接近:

执行
  ↓
观察
  ↓
验证
  ↓
确认哪些部分值得留下
  ↓
形成 Skill
  ↓
重新投入执行

Jianmu 的 Skill 机制让最后一步真正可以落回 Runtime:沉淀下来的能力可以被后续 Agent 发现和调用,再次进入真实任务。

因此能力不是只写在文档里,而是会重新进入 Agent 的运行闭环。

过去的成功执行
       ↓
   形成 Skill
       ↓
新的 Agent 任务
       ↓
直接调用 Skill
       ↓
产生新的运行结果
       ↓
继续验证和改进

这也是为什么第 8 章里说 Skill 更像“能力资产”。

资产的意义不只是存下来,而是之后还会被使用,并且使用结果还能继续反过来修正它。

10.3 从运行证据到候选能力

能力开始积累以后,下一步很自然:系统能不能根据真实运行结果,主动发现“这套 Skill 还有哪里可以改”?

最稳妥的做法不是让模型直接重写正式能力,而是先把运行过程中留下的 Trace、失败案例、验证结果当成证据。

真实任务
   ↓
运行结果 / Trace
   ↓
发现反复出现的问题
   ↓
提出一个候选修改

候选可以来自人,也可以由 Agent 根据这些证据自动提出。无论是谁提出,关键都在于它首先只是 Candidate,不是新的正式能力。

对于结构化 Skill,Jianmu 还可以利用树、节点、输入输出和约束本身做检查:候选结构是否合法、依赖是否完整、是否仍然满足基本契约。这样一部分明显错误的修改可以在真正投入评估前就被挡下来。

这一步最重要的产品原则是:

提出修改 ≠ 接受修改。

系统可以越来越主动地提出能力改进,但“想到一个新版本”和“这个版本值得被使用”必须是两件事。

10.4 验证、晋升与回滚

候选版本真正困难的地方,不是“能不能生成”,而是有没有资格替代当前版本。

所以 Jianmu 把候选和正式能力分开。一个候选至少要经过重新执行和评估,确认它真的带来提升,同时没有明显引入新的安全、成本或回归问题。

flowchart LR
    C["Candidate"] --> V["Validation / Evaluation"]
    I["Current Version"] --> V
    V --> G{"Gate"}
    G -->|Reject| R["保留当前版本"]
    G -->|Accept| N["New Version"]
    N --> A["Activation"]
    A -->|出现问题| B["Rollback"]

这里有两个非常重要的边界。

提出修改 ≠ 接受修改。

模型或者 Agent 可以提出 Candidate,但不能因为“看起来更好”就直接覆盖正式能力。

接受修改 ≠ 正式上线。

一个候选即使通过验证,也可以先形成新版本,再由产品决定什么时候激活;如果后续真实运行发现问题,还应该能够回滚到之前的稳定版本。

所以持续改进不是一个“自动改 Prompt”的动作,而是一条受治理的能力发布链:

Evidence
   ↓
Candidate
   ↓
Validation / Evaluation
   ↓
Gate
   ↓
Version
   ↓
Activation
   ↓
必要时 Rollback

这套关系也给未来的自动晋升留下了清楚边界:系统可以逐步提高自动化程度,但能力是否成为正式版本、何时进入真实运行,始终可以被治理。

10.5 从能力积累到持续改进 / RSI

这里说的持续改进,不一定要求重新训练底层模型。

对于 Agent 来说,还有一条很实际的路线:模型本身可以不变,但它长期使用的 Skill、执行结构和能力版本不断变化。

昨天
Model + Skill v1

今天
Model + Skill v2

以后
Model + 更多经过验证的能力

于是 Jianmu 里出现了三个不同的时间尺度:

行为树管一次任务内部的结构,Runtime 管 Agent 在时间上的生命周期,Skill 管能力在多次任务之间的积累。

如果再把前面的 Evidence、Candidate、Validation、Gate、Version 和 Rollback 接起来,就形成一个持续改进循环:

flowchart LR
    T["真实任务"] --> E["运行证据"]
    E --> P["提出能力修改"]
    P --> V["验证 / 评估"]
    V --> G{"Gate"}
    G -->|Reject| T
    G -->|Accept| N["新能力版本"]
    N --> T

它和“模型反思一句,下次注意”最大的区别,是改进对象可以是一份结构化、可执行、可验证、可回滚的能力。

这也是 Jianmu 对 RSI 最重要的连接点:Agent 的长期成长不必只存在于模型参数或一段越来越长的 Prompt 里,也可以体现在能力资产本身的变化上。

执行产生证据,证据推动能力变化,新的能力再回到真实执行中接受检验。

当这条链持续运行时,Agent 才开始从“每次完成任务”走向“在完成任务的过程中逐渐积累做事的方法”。

11. Jianmu 与主流 Agent 框架的设计取向

本章用途:不做“谁有谁没有”的功能清单,而是比较 LangGraph、AgentScope、AutoGen 和 Jianmu 面对相似问题时,分别选择了什么核心抽象和设计重点。

先说结论:Jianmu 和这些框架解决的问题并没有完全错开。

LangGraph 已经把 durable execution、checkpoint、HITL 和长时运行做得很成熟;AgentScope 有完整的 Agent、Tool、Memory、State、Pipeline 和多 Agent 能力;AutoGen Core 本身就是事件驱动的多 Agent Runtime,并且原生强调消息、Topic、Subscription 和分布式 Agent。

所以如果这一章写成:

Jianmu 有长时运行,别人没有
Jianmu 有 HITL,别人没有
Jianmu 有多 Agent,别人没有

那基本是不成立的。

Jianmu 真正不同的地方,是它选择了另一套运行内核:

用事件驱动 Runner 推进行为树 tick,把 Agent Loop 本身放进行为树里运行;再把稳定下来的行为沉淀成 Tree Skill。

这是一种架构选择,不是一张功能勾选表。

本章的比较口径主要参考截至 2026 年 8 月各框架官方文档,重点看它们公开强调的核心抽象和设计中心,而不是比较某个版本里恰好有没有某个 API。

11.1 不同框架在解决同一个问题

如果把今天几个主流 Agent 框架放在一起看,会发现大家其实都在面对几乎同一批问题:

  • 模型怎么调用 Tool;
  • 多步骤任务怎么组织;
  • 状态放在哪里;
  • 中间失败以后怎么继续;
  • 人怎么介入;
  • 多 Agent 怎么协作;
  • 一个任务怎么跨越分钟、小时甚至更长时间运行;
  • 出问题以后怎么知道刚才发生了什么。

真正不同的是:每个框架选择了什么作为最基本的组织单位。

可以先用一张很粗的表理解:

框架 更核心的抽象 最自然的思考方式 设计重点
LangGraph State + Node + Edge / StateGraph 当前是什么状态,下一步走哪个节点 Stateful orchestration、Durable Execution、HITL
AgentScope Agent / ReActAgent + Message + Application Components 怎么快速构建一个能力完整的 Agent 应用 Agent 能力、工具、Memory、工作流、工程生态
AutoGen Agent + Message + Runtime + Topic / Subscription 哪个 Agent 收到什么事件,然后怎么响应 Event-driven Multi-Agent、消息通信、分布式 Runtime
Jianmu Behavior Tree + Reactive Runtime + State 哪个事件唤醒 Agent,这次 tick 走到哪里 行为树 Agent Loop、长时恢复、Tree Skill 沉淀、Swarm

这张表不是在说四个框架只能做表里那件事。

LangGraph 当然可以做多 Agent;AutoGen 也可以写确定性 Workflow;AgentScope 也有 Pipeline、Routing 和 Handoff;Jianmu 也不是只能写 Behavior Tree。

它只是说明:当一个系统逐渐复杂以后,每个框架最希望开发者用什么方式去理解这份复杂度。

这点比功能数量更重要。

因为一个框架真正长期影响代码结构的,往往不是“有没有 Tool API”,而是:

当任务越来越复杂时,你会把新增的复杂度放到哪里?

是加一个 Node 和 Edge?

是再增加一个 Agent?

是增加一种消息订阅关系?

还是让 Agent Loop 在行为树里运行,再把稳定下来的做法沉淀成 Tree Skill?

这就是不同框架的设计取向开始真正分开的地方。

11.2 LangGraph:State Graph 与 Durable Execution

LangGraph 和 Jianmu 的问题空间重叠很深:两者都认真处理状态、长时执行、Checkpoint 和 HITL,而不只是做一个聊天 Agent SDK。

LangGraph 最自然的心智模型是:

State + Node + Edge。

业务复杂度主要被表达成状态更新和节点之间的转移关系。对于天然就是状态机或流程图的问题,这种方式非常直接;它也有完整的 Durable Execution 和 Subgraph 能力,所以不能把 LangGraph 简化成“只能画一张大图”。

Jianmu 和它真正的差异,不在于谁有没有恢复、HITL 或子流程,而在于默认把 Agent Loop 放在哪里。

LangGraph
→ 更强调状态如何流转

Jianmu
→ 更强调事件如何唤醒行为树,行为树如何推进 Agent Loop

例如 Retry、Fallback、Wait 和局部恢复,在 Jianmu 里更倾向成为行为树 tick 过程中的局部控制语义,而不是继续增加全局状态转移关系。

LangGraph 更适合把“状态如何流转”作为第一等概念;Jianmu 更希望把“事件如何驱动行为树 Agent Loop”作为第一等概念。

11.3 AgentScope:Agent-centric Application Framework

AgentScope 更接近一个围绕 Agent 本身 组织完整应用能力的框架:Model、Tool、Memory、Skill、State,以及多 Agent 协作,都从“怎么快速构建一个能力完整的 Agent”出发。

Jianmu 的起点不太一样。它更早追问的是:

这个 Agent Loop 要怎么长期运行?
什么事件会触发下一次 tick?
行为树当前走到哪里?
稳定下来的做法怎么变成 Tree Skill?

所以两边都可以做 ReAct、多 Agent、Memory 和 Skill,差别并不是“谁有谁没有”。

AgentScope 更把 Agent 作为开发体验的中心;Jianmu 更把 Agent 背后的事件驱动 Runtime 和行为树 tick 放在中心。

简单 Agent 应用里,前者的高层抽象会很直接;当控制逻辑、等待、恢复和长期运行开始占据主要复杂度时,Jianmu 的设计取向会更明显。

11.4 AutoGen:Event-driven Multi-Agent Runtime

AutoGen 和 Jianmu 的重叠主要发生在事件驱动多 Agent Runtime这一边。它同样把 Agent、Message、Runtime、Topic / Subscription 放在很核心的位置,所以“事件驱动 Agent + 消息通信”并不是 Jianmu 独有的能力。

AutoGen 更自然的思考方式是:

Agent 收到 Message / Event
      ↓
执行自己的处理逻辑
      ↓
继续产生 Message / Event
      ↓
其他 Agent 被触发

Jianmu 的 Swarm 外层也有相似思想,但它在单个 Agent 内部又放了一层 Behavior Tree + Reactive Runtime。每个 Agent 被事件唤醒以后,推进的是自己的行为树 tick,而不是一段散落在 Prompt 和业务代码里的循环。

所以可以简单理解成:

AutoGen 更强调 Agent 之间如何通过消息和事件形成系统;Jianmu 同时强调 Agent 之间的事件协作,以及每个 Agent 内部由行为树承载的 Agent Loop。

如果问题的核心就是大规模消息驱动、多 Agent 通信或分布式 Actor Runtime,AutoGen 的取向会非常自然;Jianmu 更关心的是如何把这种多 Agent 协作和单个 Agent 的长期行为树循环放进同一个 Runtime 模型。

11.5 Jianmu:Behavior Tree as Agent Runtime

把前三个框架看完以后,Jianmu 的位置就比较清楚了。

Jianmu 不是因为发现:

“大家都没有 Agent Runtime。”

才出现的。

恰恰相反,Agent Runtime 这件事已经有很多成熟答案。

Jianmu 做的选择是:

如果 Agent 真的要长期运行,那么它的 Loop 能不能由 Behavior Tree 来承载,并由事件驱动的 Runner 持续推进?

这就是 Jianmu 最根本的架构判断。

它的主干可以压缩成:

flowchart TB
    EVENT["Event / Message / External Change"] --> RUNNER["ReactiveRunner"]
    RUNNER --> TREE["Behavior Tree"]
    TREE --> DECIDE["Model / Rule"]
    TREE --> TOOL["Tool / Skill"]
    TREE --> WAIT["Wait / Suspend / HITL"]
    DECIDE --> STATE["State"]
    TOOL --> STATE
    WAIT --> STATE
    STATE --> RUNNER

其中 Behavior Tree 不是 UI 上的一张图,而是 Agent Loop 的执行语义本身。

它负责:

  • Sequence;
  • Selector / Fallback;
  • Retry;
  • Condition;
  • Wait;
  • Decorator;
  • Subtree;
  • 节点状态传播。

ReactiveRunner 再负责:

  • 什么时候 tick;
  • 没有事情时怎么等待;
  • 异步节点完成以后怎么唤醒;
  • 外部交互时怎么 Suspend / Resume;
  • 状态和 checkpoint 怎么连接。

再往外扩:

  • Tree Skill 把稳定子树变成可复用、可治理的企业能力;
  • Swarm 把多个 Agent Runtime 连成动态协作网络;
  • Guard / Approval / Sandbox 给执行加边界。

所以 Jianmu 的整体不是:

Behavior Tree Library
+
LLM API

而更像:

Agent Loop                → Behavior Tree Tick
Reactive Execution        → ReactiveRunner / Event
Durable State             → State / Checkpoint
Enterprise Determinism    → Tree Skill
Multi-Agent Runtime       → Swarm
Governance                → Guard / Approval / Sandbox

Behavior Tree 是运行内核,Tree Skill 是沉淀出口。一个解决“这次怎么跑”,一个解决“稳定做法怎么进入企业系统”。

11.6 为什么 Jianmu 选择行为树

那么问题就来了:

已经有 StateGraph、Agent Framework、Event-driven Runtime,为什么还要再选择 Behavior Tree?

答案不是“行为树比它们高级”。

更准确地说,是 Jianmu 对未来 Agent 的复杂度来源做了一个判断:

当 Agent 从 Demo 进入长期运行以后,复杂度会越来越多地出现在 Loop 的运行语义里,而不只是 Prompt 和 Tool 数量。

比如一个任务最开始可能只有:

Plan
 ↓
Tool
 ↓
Answer

后来开始增加:

失败要 Retry
Retry 失败要 Fallback
高风险动作要 Approval
外部回调要 Wait
某些分支需要并行
某段成熟做法要变成 Tree Skill
某个子流程还要独立复用

这时候 Jianmu 希望这些控制关系本身有明确语义。

1. 层级结构是默认能力

Behavior Tree 天然是树。

一个子流程可以直接收进一个子树:

Order Handling
├── Validation
├── Payment
│   ├── Normal
│   └── Recovery
└── Fulfillment

开发者可以只看当前层,也可以继续展开里面的细节。

Graph 当然也有 Subgraph,可以做到类似的层级封装。区别不是“能不能”,而是 Behavior Tree 从一开始就把层级控制当成默认组织方式。

2. Retry / Fallback 是控制语义,不只是跳转关系

例如:

Retry(3)
└── Call Payment API

或者:

Fallback
├── Primary Model
├── Backup Model
└── Human

这类结构对行为树来说非常自然。

它不需要每次重新解释“失败以后下一条边到底指向哪里”。

3. RUNNING 是一等状态

传统一次性函数最熟悉的是:

成功 / 异常

但长时 Agent 大量时间其实处于:

还没完成。

异步任务没回来、人还没审批、另一个 Agent 还没回复。

Behavior Tree 本身就有 RUNNING 这一执行状态,所以“现在还不能结束”天然属于控制模型,而不是额外塞进去的异常分支。

Jianmu 再把这一点和事件驱动 Runtime 接起来:

RUNNING
  ↓
没有新事件就等待
  ↓
事件到达
  ↓
继续 tick

这是 Behavior Tree 和 Reactive Runtime 组合起来以后才真正有价值的地方。

4. Tree Skill 承担企业确定性

如果某一段树反复验证以后已经比较稳定,就可以进一步沉淀成 Tree Skill。

于是:

运行中的行为树
   ↓
稳定子树
   ↓
Tree Skill

中间不需要把它重新翻译回一段自然语言 Prompt。

这也是企业化最关键的一步。Runtime 里的行为树可以保留 Agent 的动态循环,Tree Skill 则把已经稳定的做法变成可测试、可审计、可版本管理、可回滚的资产。

这对 Jianmu 后面的 Capability Loop 和 RSI 也很重要。

5. 行为树并不要求模型退出控制

这里也容易产生一个误解:

用 Behavior Tree,是不是就变成传统规则系统,不智能了?

不是。

树只负责承载和约束 Agent Loop。

叶子节点里面仍然可以是:

LLM 判断
ReAct Loop
Tool Call
RAG
另一个 Skill
另一个 Agent

所以 Jianmu 真正追求的是:

稳定的部分结构化,不确定的部分继续交给模型。

而不是把所有决策都提前写死。

这也是 Jianmu 最适合的那类任务:

既不能完全固定
也不能完全靠模型临场发挥

前面第 2.4 节已经说明了什么时候值得使用 Jianmu。放在框架比较里,更重要的是记住:这些框架大量能力其实彼此重叠,真正长期影响系统结构的是它们选择了什么作为核心抽象。

LangGraph 更偏 State Graph,AgentScope 更偏 Agent-centric Application Framework,AutoGen 更偏消息与事件驱动的多 Agent Runtime;Jianmu 则选择用 Behavior Tree 承载每个 Agent 的 Loop,再用 Reactive Runtime、持久状态、Tree Skill 和 Swarm 把它扩展成长期运行系统。

Jianmu 的问题不是“别人有没有这些能力”,而是:

Behavior Tree 能不能成为复杂、自治、长时 Agent 的自然 Loop 内核?

12. Jianmu 已经长出了哪些产品形态

本章用途:看看同一个 Runtime 目前已经支撑了哪些不同的使用方式和产品形态。

前面几章一直在讲 Runtime、Behavior Tree、Skill 和 Swarm。

到了这一章,可以换一个更产品的视角:

这些底层能力最后到底长成了什么东西?

Jianmu 目前已经不是只有一个 Python API。

同一套 Runtime 已经长出了几种很不一样的产品形态:

TUI Chat      → 单 Agent 工作台
Tree Studio   → 行为树设计与调试工具
Swarm Studio  → 多 Agent 协作空间
Seedbot       → 真实渠道里的业务 Agent

它们看起来差别很大。

一个像终端里的 AI 助手,一个像可视化流程编辑器,一个像多智能体聊天工作台,一个直接接进钉钉这样的真实业务渠道。

但底下复用的东西高度一致:

flowchart TB
    TUI["TUI Chat"]
    TREE["Tree Studio"]
    SWARM["Swarm Studio"]
    BOT["Seedbot / 业务 Agent"]

    TUI --> CORE["Jianmu Runtime"]
    TREE --> CORE
    SWARM --> CORE
    BOT --> CORE

    CORE --> BT["Behavior Tree"]
    CORE --> STATE["State / Checkpoint"]
    CORE --> SKILL["Skill"]
    CORE --> TOOL["Tool / Guard / Sandbox"]
    CORE --> MULTI["AgentRuntime / Swarm"]

所以这一章真正想说明的不是“Jianmu 有四个 Demo”,而是:

Runtime 已经开始和具体产品形态解耦。

同一个执行内核,可以被不同的 UI、渠道和交互方式包起来。

12.1 TUI Chat

TUI Chat 是最接近“直接和一个 Jianmu Agent 一起工作”的产品形态。

它运行在终端里,但并不是一个只有输入框和输出框的聊天窗口。

现在的界面里已经能同时看到:

  • 对话历史;
  • Agent 当前任务进度;
  • 文件变化;
  • 代码内容;
  • 流式输出;
  • Approval;
  • Ask User;
  • Runtime 状态。

从产品角度看,它更像一个 Agent Workbench。

用户不是只在等模型“回复一句话”,而是在看一个执行体工作的全过程。

例如一个编码 Agent 开始处理任务以后,界面可能经历:

用户提出任务
   ↓
Agent 开始运行
   ↓
查看文件
   ↓
修改代码
   ↓
准备执行高风险操作
   ↓
Approval Bar 出现
   ↓
用户批准
   ↓
Agent Resume
   ↓
继续执行并完成

这里很能体现前面第 5 章讲的一个设计:宿主产品不需要自己重新实现 Suspend / Resume。

Runtime 告诉 TUI:

现在任务挂起了
原因:需要审批
需要展示这些参数

TUI 负责把它变成 Approval Bar。

如果挂起原因是需要用户补充信息,就显示 Ask User Bar。

所以 UI 和执行语义是分开的。

这个分离很重要,因为以后换成 Web、IM 或业务后台时,Runtime 不需要跟着重写。

TUI Chat 还有另一个价值:它把 Runtime 的可观测性直接暴露给了用户。

普通聊天产品通常只展示:

用户消息
模型回复

而 Agent 真正复杂以后,中间发生了什么往往比最后一句回复更重要。

例如:

调用了哪个 Tool?
有没有改文件?
Token 用了多少?
在哪一步被挂起?
哪次运行是 Resume 出来的?
Tool 为什么失败?

TUI 现在已经有 session persistence、trace 文件和 trace waterfall 等能力,可以把一次运行拆成 run → step → model/tool/child span 来看。

这使它不只是“聊天界面”,也是一个开发和调试 Jianmu Agent 的入口。

因此 TUI Chat 代表的是 Jianmu 的第一种产品形态:

把 Runtime 包装成一个人可以直接操作、观察和干预的单 Agent 工作台。

12.2 Tree Studio

如果说 TUI Chat 是“使用 Agent”,那么 Tree Studio 更接近“设计 Agent 的执行结构”。

Tree Studio 是 Jianmu 的可视化 Behavior Tree 编辑器。

用户可以在画布上拖拽:

Sequence
Selector
Parallel
Loop
AgentLLMNode
ToolExecutor
SkillNode
...

然后把它们组织成一棵真正可以运行的行为树。

最关键的是:画布不是一张只用于展示的图。

Tree Studio 保存下来的树定义会被后端编译成真正的 Jianmu Behavior Tree,再交给 Agent / Runtime 执行。

也就是说:

画出来的结构
      ↓
Tree Definition
      ↓
编译成 Behavior Tree
      ↓
ReactiveRunner 真正执行

所以 Tree Studio 更像一个 Runtime 的“可视化控制面”。

这和很多 Workflow Builder 有一个细微但重要的区别。

它不是把 Jianmu 的执行结果画出来,而是直接在编辑 Jianmu 的控制结构。

例如产品同事想表达:

优先调用主模型
失败就调用备用模型
再失败就转人工

在 Tree Studio 里可以直接设计成:

Fallback
├── Primary Model
├── Backup Model
└── Human Handling

如果主模型再需要最多重试三次:

Fallback
├── Retry(3)
│   └── Primary Model
├── Backup Model
└── Human Handling

这就是 Behavior Tree 作为产品交互方式的价值:一些原本藏在代码里的控制语义,可以直接被看见。

Tree Studio 还有一个很关键的出口:导出 Tree Skill。

一个流程在画布里设计、运行、调试稳定以后,可以导出为标准 Skill 目录,包括 SKILL.md 和对应的树定义。

于是产品路径可以变成:

设计流程
   ↓
运行调试
   ↓
确认稳定
   ↓
导出 Tree Skill
   ↓
其他 Agent 直接复用

这和第 10 章的 Capability Loop 是直接连在一起的。

Tree Studio 因此不只是“低代码编排器”。

它还可以成为:

从行为树 Agent Loop 走向企业能力沉淀的入口。

未来如果 Jianmu 的自动改进能力继续往前发展,Tree Studio 也天然适合展示:

Skill v1
   ↓ 修改
Skill v2

具体改了哪个节点?
哪个分支被新增?
哪个 Retry 参数发生变化?

所以 Tree Studio 代表的是 Jianmu 的第二种产品形态:

把运行中的 Behavior Tree 和沉淀后的 Tree Skill 变成可以被设计、观察、调试和治理的产品对象。

12.3 Swarm Studio

Swarm Studio 对应的是 Jianmu 第 9 章那套多智能体 Runtime 的产品化。

如果直接把底层 AgentRuntime 暴露给用户,产品体验会很抽象:

spawn
send_message
subscribe_topic
mailbox
snapshot
wake

这些都是 Runtime 概念,不是普通用户愿意直接操作的东西。

Swarm Studio 做的事情,是把它翻译成一个更接近人类协作软件的界面。

它的产品模型可以简单理解成:

Agent Profile
      ↓
Workspace Agent
      ↓
Conversation

Agent Profile 是一个可复用的专家模板。

比如:

物流专家
财务专家
法律专家
产品经理
代码 Reviewer

把 Profile 放进某个 Workspace 以后,它变成真正参与当前工作的 Workspace Agent。

多个 Agent 再进入 Conversation 协作。

因此用户看到的是:

“我有一组专家,他们在一个工作空间里共同处理事情。”

而底层 Runtime 看到的是:

Agent identity
Mailbox
Message routing
Lifecycle
Wake-up
State

两层被产品界面隔开了。

Swarm Studio 也没有把所有通信简化成“一个群聊”。

例如 Agent 可以直接私聊另一个 Agent。

这种私聊会形成独立的 Side Thread,而不是在主群里偷偷传一段不可追踪的上下文。

私聊结束后,还要明确决定:

这条信息要不要同步回主对话?

这件事看起来很细,但它实际解决的是多 Agent 系统里非常容易出现的信息断层。

比如:

财务 Agent 私下问了法律 Agent 一个问题
法律 Agent 给了关键结论
但这个结论没有回到主任务

如果通信只是“模型之间随便聊”,这类信息很容易丢。

Swarm Studio 通过显式的 Channel / Side Thread / Sync-back 语义,让协作关系能够被产品看到和追踪。

另外,Swarm Studio 现在也会持久化:

  • Agent Profile;
  • Workspace Agent;
  • Conversation;
  • Message;
  • Agent 状态;
  • 对话记忆;
  • History Snapshot。

这意味着刷新页面或者关闭某一轮交互以后,“团队”不需要从零开始重新生成。

这和第 9 章讲的长期 Swarm 是一致的。

所以 Swarm Studio 真正想产品化的不是:

“多开几个聊天机器人。”

而是:

让一组长期存在、身份明确、可以互相通信的 Agent,拥有一个人类可以进入和观察的协作空间。

这也是 Jianmu 的 Swarm 从 Runtime 走向产品的第一种比较完整的形态。

12.4 Seedbot / 业务 Agent

TUI Chat、Tree Studio、Swarm Studio 都很“Jianmu”。

用户能明显看到 Agent、Tree 或 Swarm 的存在。

但真实业务落地还有另一种情况:用户根本不应该知道底下用了 Jianmu。

Seedbot 就更接近这种形态。

它目前主要面向 DingTalk 渠道。

用户看到的体验可能只是:

在钉钉里给机器人发一条消息
        ↓
机器人处理任务
        ↓
在钉钉里回复

但后端实际经历的是:

flowchart LR
    A["DingTalk / Channel"] --> B["Inbound Message"]
    B --> C["Session"]
    C --> D["Jianmu Agent Runtime"]
    D --> E["Skill / Tool / Guard / Sandbox"]
    E --> F["Outbound Message"]
    F --> A

Seedbot 会负责渠道层的事情:

  • 收消息;
  • 维护 Session;
  • 把渠道用户映射到会话;
  • 把 Agent 最终结果发回渠道;
  • 提供 gateway 和 debug 接口。

而 Agent 怎么执行,仍然复用 Jianmu 的核心能力:

  • Behavior Tree / Reactive Runtime;
  • Typed State / Checkpoint;
  • Skill / Tool;
  • Guard / Constraints;
  • Context 与运行时依赖。

这说明一个很重要的产品边界:

Jianmu 不要求最终产品长得像 Jianmu。

Runtime 可以完全藏在一个普通业务产品后面。

例如同样的模式可以继续被用于:

企业 IM Bot
客服 Agent
物流异常处理 Agent
结算 Agent
内部知识助手
运维 Agent
业务后台里的自动任务

用户只看到自己熟悉的渠道和业务界面。

只有开发者知道底下是一个 Jianmu Agent 在持续运行。

Seedbot 因此更像一个参考答案:

怎样把 Jianmu 从框架能力接进一个真实渠道和业务配置体系。

这和做 Demo 的区别很大。

Demo 通常只需要证明:

Agent 能不能完成任务?

真实业务还要处理:

消息从哪里来?
用户是谁?
Session 怎么保存?
回复发到哪里?
配置怎么管理?
Guard 怎么接业务规则?
服务挂了以后怎么办?

Seedbot 就处在 Runtime 和这些真实应用问题的交界处。

12.5 同一个 Runtime,不同产品形态

把四个产品放在一起看,会发现它们其实是在回答四个完全不同的问题。

产品形态 用户最关心的问题 Jianmu 暴露出来的核心能力
TUI Chat Agent 现在在做什么,我怎么和它一起工作 Agent Runtime、HITL、Trace、Session
Tree Studio 这个 Agent 的控制逻辑怎么设计和调试 Behavior Tree、State、Skill
Swarm Studio 一组 Agent 怎么持续协作 AgentRuntime、Mailbox、Lifecycle、Message
Seedbot / 业务 Agent 怎么把 Agent 接进现有业务和渠道 Runtime、Skill、Tool、Guard、Session

这说明 Jianmu 的产品边界并不应该只定义成“一个 Agent 开发框架”。

更准确地说,它正在形成一个下面这样的结构:

                   ┌── TUI Chat
                   │
Jianmu Runtime ────├── Tree Studio
                   │
                   ├── Swarm Studio
                   │
                   └── Business Agent / Seedbot

Runtime 是共用的。

产品层决定用户看到什么。

对于开发者,可能最重要的是 Tree、State 和 Trace。

对于普通员工,可能只需要一个聊天窗口。

对于管理多 Agent 的操作者,可能需要 Workspace、Agent Profile 和 Conversation。

对于最终业务用户,甚至连“Agent”这个词都不需要出现。

这种分层还有一个现实意义:Jianmu 的内核能力不需要和某一个 UI 的产品成败绑死。

例如 Tree Studio 可以继续演化成面向开发者的可视化 IDE;Swarm Studio 可以演化成多 Agent 协作工作台;Seedbot 可以演化出多个行业应用。

它们可以共用 Runtime,但产品定位完全不同。

反过来,Runtime 里新增一个真正通用的能力,比如:

更可靠的 Suspend / Resume
新的 Skill 类型
更好的 Trace
更完整的 Swarm Snapshot
新的 Guard 策略

也可能同时被多个产品入口复用。

这就是“平台”和“应用”开始分离的地方。

所以这一章最后可以把 Jianmu 的产品结构压缩成一句话:

Jianmu Core 负责让 Agent 可靠地运行,Studio 负责让人看见和控制这种运行,业务应用则负责把 Runtime 接进具体场景。

这几种产品看起来不像同一个东西,但它们其实共享同一套底层判断:

Agent 不应该只存在于一次模型调用里,而应该成为可以被运行、观察、干预、组合和长期托管的执行体。

13. Jianmu 与 Agent Engineering 的演进

本章用途:把 Jianmu 放回近一段时间 Agent 工程的发展里看。这里是行业坐标,不拿外部概念反过来定义 Jianmu。

前面几章一直是在 Jianmu 内部看问题。

这一章换一个视角:为什么最近越来越多 Agent 系统,最后都会开始讨论 Runtime、Harness、Loop、Orchestration、Evals、Memory、Sandbox 这些看起来“不像模型”的东西?

原因其实很直接。

当模型能力还不够强时,大家最关心的是:

Prompt 怎么写?
模型选哪个?
上下文怎么塞?

但当模型已经能规划、调用工具、写代码、自己修正以后,系统真正容易出问题的地方开始往外移动:

模型知道该做什么
        ↓
但环境准备好了吗?
工具可靠吗?
权限边界在哪里?
失败以后怎么继续?
上下文满了怎么办?
什么时候应该停?
人怎么介入?
多步骤控制怎么组织?

于是 Agent Engineering 的重点逐渐从“把一次模型调用调好”,扩展到:

怎样给模型搭一个可以长期行动、获得反馈、恢复状态并受约束的执行系统。

近一段时间行业里出现的 Harness Engineering、Agent Loop、Durable Execution、Agent Runtime 等讨论,本质上都在回答这个问题的不同部分。

这里先说明一个边界。

本章把这些问题整理成三类:

Harness Engineering
Loop Engineering
Structured Orchestration

它们不是严格按年份依次替代的“三代 Agent 技术”,也不是行业统一的正式分类。

尤其 Structured Orchestration 是本文为了描述“复杂执行结构如何被明确组织”而使用的概括性名称。

更准确地说,这三类问题会同时存在,而且彼此重叠:

flowchart TB
    H["Harness Engineering\n环境、工具、状态、安全、反馈"]
    L["Loop Engineering\n观察、决策、行动、反馈、继续/停止"]
    O["Structured Orchestration\n分支、Retry、Fallback、Wait、并行、子流程"]

    H --> R["Agent Runtime Engineering"]
    L --> R
    O --> R

Jianmu 并不是先看到这些词,再照着它们设计。

更像是做复杂 Agent 的过程中,先后碰到了同一批工程问题,最后发现自己的架构和行业正在讨论的这些方向自然汇合了。

13.1 Harness Engineering:可靠执行环境

“Harness”这个词原本就有“把某个能力固定住、接上周围设施,让它可以稳定工作的装置”这种意思。

放到 Agent 里,也可以用很直白的话理解:

模型是发动机,Harness 是发动机真正装进车以后周围那一整套东西。

如果只有模型,最简单的系统可能是:

User
 ↓
LLM
 ↓
Answer

但一个真正工作的 Agent 往往需要:

                 Model
                   │
        ┌──────────┼──────────┐
        ↓          ↓          ↓
      Tools      Context     Memory
        │          │          │
        ├────── Environment ──┤
        │          │          │
     Sandbox     State      Files
        │          │          │
        └──── Guard / Approval ┘
                   │
              Trace / Eval

这些东西共同决定模型到底能不能可靠工作。

2026 年 OpenAI 在总结 Codex 的实践时直接用了 Harness Engineering 这个词,重点也不是“再训练一个更聪明的模型”,而是设计环境、工具、文档、Guardrail、验证和反馈循环,让 Agent 能够稳定地完成端到端工作。

Anthropic 在讨论 long-running agent harness 时也强调了类似问题:一个任务一旦跨越多个 context window,就必须想办法把进度、环境和可交接的信息留给下一轮执行,否则模型每次都像一个刚上班、什么都不知道的新工程师。

所以 Harness Engineering 比“长时运行”更宽。

长时运行是其中很重要的一部分,但 Harness 还包括:

  • Agent 能看到什么;
  • Agent 能用什么工具;
  • 文件和代码环境是什么;
  • 哪些动作允许执行;
  • 哪些动作需要审批;
  • 状态如何保存;
  • 失败如何被观察;
  • 如何验证任务真的完成;
  • 上一次执行留下了什么可继续利用的东西。

从这个角度回头看 Jianmu,会发现很多看起来分散的能力,其实都属于 Harness:

Typed State       → 把运行事实留住
Checkpoint        → 让任务可以恢复
Context           → 决定模型这一轮看到什么
Tool              → 给模型行动能力
Skill             → 给模型可复用能力
Sandbox           → 控制代码在哪里执行
Guard             → 判断动作能不能做
Approval          → 让人进入高风险决策
Telemetry / Trace → 让执行过程可观察

这些模块单独看都不是“智能”。

但它们决定了智能能不能真正落地。

一个很典型的例子是代码 Agent。

模型可能已经知道应该:

找到 bug
→ 修改文件
→ 跑测试
→ 看失败
→ 再修

但如果 Harness 没有准备好,事情会迅速变成:

文件路径找不到
测试环境缺依赖
shell 没权限
命令执行没有隔离
测试结果没回到模型
上下文太长丢失前面的判断
执行中断以后无法继续

模型再聪明也很难解决一个根本不存在的执行环境。

所以近一段时间 Agent 系统越来越像传统软件工程,这不是倒退。

恰恰相反,是因为模型开始真的能够承担工作以后,软件工程里那些原本由人默默处理的问题,必须被显式交给 Harness。

对于 Jianmu 来说,Harness Engineering 最对应的不是某一个模块,而是整套 Durable Runtime 思想:

不要只给模型几个 Tool,而要给 Agent 一个能长期生活和工作的执行环境。

这和第 5 章讲的长时运行直接连在一起。

Agent 可以等待、挂起、恢复、收到新事件再继续;状态和审批不会因为一次请求结束就消失。

所以“Long-running”更像 Harness 最容易被用户感受到的结果之一,而不是 Harness 的全部定义。

13.2 Loop Engineering:自治执行闭环

如果 Harness 解决的是:

Agent 在什么环境里工作?

那么 Loop Engineering 解决的是:

Agent 怎么持续自己往前走?

Agent 和普通 LLM 调用最明显的区别,就是它不是一次输入、一次输出。

一个最基本的 Agent Loop 可以写成:

观察当前状态
    ↓
决定下一步
    ↓
执行动作
    ↓
看到动作结果
    ↓
更新判断
    ↓
继续 / 完成 / 请求人介入

Anthropic 对 Agent 的一个很实用的定义,就是模型在一个自我驱动的循环里 plan、act、observe、adjust,直到任务完成或者需要人介入。

OpenAI 在 Agents SDK 和 Codex 的工程说明里也都把 loop 当成 Agent 的核心运行方式:模型可以连续多轮调用 Tool、接收执行结果,再决定下一步,直到满足退出条件。

所以“自治”不是:

模型第一次就把完整计划想对。

真正的自治更接近:

模型可以根据环境反馈不断重新决定下一步。

这两者差别很大。

例如一个 Agent 想解决测试失败:

先猜原因
  ↓
改代码
  ↓
跑测试
  ↓
发现不是这个问题
  ↓
看新的错误信息
  ↓
换一种修改
  ↓
再次验证

如果系统只允许模型一次性输出一个 20 步计划,然后机械执行到底,它反而很难自治。

因为真实环境会不断给新信息。

所以 Loop 的核心不是“循环调用 LLM”这么简单。

真正需要设计的是:

  • 每一轮给模型什么状态;
  • Tool 结果怎么返回;
  • 哪些变化应该触发下一轮;
  • 什么算任务完成;
  • 什么情况下应该 Retry;
  • 什么情况下应该停止;
  • 什么情况下应该问人;
  • 如何避免无限循环;
  • 上下文越来越长时怎么办;
  • 一轮执行失败以后从哪里继续。

这就是为什么可以把它叫 Loop Engineering。

一个 naive loop 很容易写:

while not done:
    response = model(state)
    result = execute(response.action)
    state.update(result)

真正困难的是 not done、state、execute 和异常路径。

Jianmu 的自治运行,本质上也可以放到这个坐标里理解。

但它没有把 Loop 写成一个裸 while True。

它把循环落到了事件驱动 Runner 和 Behavior Tree tick 上:

flowchart LR
    E["Event / State Change"] --> W["Wake"]
    W --> T["Behavior Tree Tick"]
    T --> D["Model / Condition 决策"]
    D --> A["Tool / Skill / Action"]
    A --> S["State Update"]
    S --> Q{"还有工作吗?"}
    Q -->|有| T
    Q -->|没有,等事件| E
    Q -->|需要外部输入| H["Suspend"]
    H --> E

这里有两个特点。

第一,Loop 是事件驱动的。

没有事情发生时,Agent 不需要不停问模型:

“现在有新情况吗?”

它可以停下来。

等 Tool 完成、用户回复、审批通过、其他 Agent 发消息,再被 Runtime 唤醒。

第二,Loop 的每一轮都是一次行为树 tick。

下一步允许做什么、某个失败怎么处理、什么时候应该等待,都在这次 tick 中由 Behavior Tree 给出控制语义。

模型仍然可以在骨架里的动态节点做判断。

所以 Jianmu 对 autonomy 的理解不是:

让模型拥有无限自由

而是:

Runtime 让 Agent 可以持续行动
+
Model 根据反馈动态决策
+
Behavior Tree 给行动过程提供结构和边界

这也是为什么第 1 章里说:

模型负责判断下一步做什么,Jianmu 用事件驱动的行为树 tick 让这个判断持续、可控地变成行动。

Loop Engineering 对应的正是这句话里的“持续”。

13.3 Structured Orchestration:复杂控制结构

Agent 能持续循环以后,很快还会遇到第三类问题:

循环里面的控制逻辑越来越复杂怎么办?

最开始,一个 Agent 可能只有:

Think
 ↓
Tool
 ↓
Observe
 ↓
Think

后来业务开始增加规则:

主方案失败重试 3 次
还是失败就走备用方案
高风险动作先审批
某些外部任务需要等待 callback
两个查询可以并行
一部分流程必须完成以后另一部分才能开始
某一段成熟做法以后还要沉淀成 Tree Skill

如果所有控制都继续塞进一个 ReAct Prompt 里,模型就必须同时负责两件事:

理解任务本身
+
记住整个系统的控制规则

任务越长,第二部分越容易变成负担。

因此 Agent 工程里一直存在 workflow / graph / routing / handoff / evaluator-optimizer 这些结构化编排方式。

Anthropic 在早期总结 Agent architecture 时,就明确区分了两类系统:

Workflow → 预定义代码路径控制执行
Agent    → 模型动态决定自己的过程和 Tool 使用

但真实产品通常不会真的二选一。

很多系统最终会变成:

Loop 有明确运行语义,语义判断仍然交给模型。

例如:

Sequence
├── 数据准备
├── LLM 判断异常类型
├── Fallback
│   ├── 自动处理
│   └── 人工处理
└── 验证结果

这里第二步是 Agentic 的,整体控制结构又是确定的。Jianmu 关心的正是这种混合形态:Agent Loop 不能失去动态判断,但稳定控制关系也不能一直放在 Prompt 里。

所以本章用 Structured Orchestration 来概括这一类工程问题。

为什么不用“Graph Engineering”?

因为 Graph 是一种非常重要的实现方式,但不是唯一的结构化编排方式。

结构化控制可以用:

  • 普通代码;
  • State Machine;
  • DAG;
  • State Graph;
  • Behavior Tree;
  • Workflow DSL;
  • Actor / Message Protocol;
  • 多种结构混合。

真正的问题不是“有没有画 Graph”,而是:

哪些控制关系应该从 Prompt 里拿出来,进入 Runtime 的行为树 tick;哪些稳定做法应该进一步沉淀成 Tree Skill?

这正是 Jianmu 和很多 Agent 框架选择开始分开的地方。

LangGraph 的回答偏向:

State + Node + Edge

AutoGen Core 的回答偏向:

Agent + Message + Event + Subscription

而 Jianmu 的回答是:

Behavior + Composite + Decorator + Status

也就是 Behavior Tree。

Behavior Tree 对 Jianmu 最有吸引力的地方,不只是“能画成树”,而是它已经给很多常见控制问题提供了局部语义:

Sequence
Fallback
Retry
Parallel
Condition
RUNNING
Subtree

例如:

优先自动完成任务
如果失败,走人工流程

可以直接表达成:

Fallback
├── Automatic Handling
└── Human Handling

再例如:

主接口失败最多重试三次

可以局部变成:

Retry(3)
└── Primary API

这些控制关系被放在节点附近,而不需要散落在很多全局跳转条件里。

这就是第 11 章所谓:

Jianmu 把“行为树如何推进 Agent Loop”作为更靠近核心的概念。

Structured Orchestration 还有另一个意义:给 autonomy 设一个可理解的形状。

如果完全没有结构,Agent 的每一步都由模型重新决定,灵活性很高,但系统也更难预测和验证。

如果所有路径全部提前写死,模型几乎没有自主空间,系统也就不再像 Agent。

Jianmu 想处在中间:

稳定的控制关系 → Tree
不确定的语义判断 → Model
明确的原子动作 → Tool
成熟的做法 → Tree Skill

所以 Structured Orchestration 对应的是 Jianmu 设计目标里的“复杂编排”。

它不是为了让流程看起来更复杂,而是为了让复杂度有地方可放。

13.4 Jianmu 为什么会自然汇聚到这些问题

把前三节放在一起,就可以重新看 Jianmu 的三个早期核心目标:

复杂编排
自治运行
长时运行

它们和前面的三类 Agent Engineering 问题确实有很强的对应关系:

Jianmu 最初关注的问题 更大的 Agent Engineering 视角 Jianmu 里的主要承载方式
长时运行 Harness / Durable Runtime State、Checkpoint、Context、HITL、Guard、Sandbox
自治运行 Loop Engineering Event-driven Runner、Behavior Tree Tick、Model/Tool feedback loop
复杂编排 Structured Orchestration Behavior Tree、Decorator、Retry、Fallback、Subtree

但这张表不能理解成一一等号。

Harness 不只负责长时运行;Structured Orchestration 也会影响 Loop;State 同时属于 Harness 和控制逻辑。

这只是帮助理解 Jianmu 为什么会走到今天这套架构。

最开始可能只是觉得:

Agent 的流程复杂以后,需要 Behavior Tree。

但一棵树真正开始执行以后,很快就会出现:

节点要异步等待
   ↓
需要 ReactiveRunner
   ↓
等待过程中要保存状态
   ↓
需要 Checkpoint
   ↓
有人要审批
   ↓
需要 Suspend / Resume
   ↓
真实 Tool 有风险
   ↓
需要 Guard / Sandbox

然后一个 Agent 还不够:

多个 Agent 要协作
   ↓
需要消息
   ↓
消息要唤醒 Agent
   ↓
需要 Mailbox 和 Lifecycle
   ↓
系统要长期存在
   ↓
需要 Swarm Snapshot / Recovery

再往后,任务做得越来越多:

成熟做法不能每次重新规划
   ↓
需要 Tree Skill
   ↓
Tree Skill 还希望持续改进
   ↓
需要 Trace / Eval / Version / Gate / Rollback

所以 Jianmu 后来变得“重”,不完全是因为想把功能做全。

更重要的原因是:只要接受“Agent 是一个长期运行的执行体”这个前提,很多 Runtime 问题会一个接一个自然出现。

这也解释了为什么 Jianmu 最终比“行为树 Agent 框架”这个名字覆盖得更广。

Behavior Tree 仍然是 Loop 内核。

但仅仅有 Tree,解决不了:

任务如何跨时间存在
Agent 如何被事件唤醒
人如何进入执行过程
消息如何可靠传递
执行如何恢复
能力如何沉淀
副作用如何治理

这些最后都属于 Runtime。

所以如果今天重新给 Jianmu 一个更工程化的定位,我会把它概括成:

Jianmu 在做的是 Agent Runtime Engineering。

它用事件驱动 Runner 和 Behavior Tree tick 解决 Agent Loop 怎么运行的问题,用状态与恢复解决时间问题,再用 Tree Skill 和 Swarm 把 Runtime 扩展到能力积累与多智能体协作。

可以画成:

flowchart TB
    M["Model Intelligence"] --> RUNTIME

    subgraph RUNTIME["Jianmu Agent Runtime"]
        BT["Behavior Tree Tick\nAgent Loop"]
        LOOP["Reactive Runner\nEvent-driven Autonomy"]
        DURABLE["Durable State\nLong-running & Recovery"]
        SKILL["Tree Skill\nEnterprise Determinism"]
        SWARM["Swarm\nMulti-Agent Collaboration"]
        GOV["Governance\nGuard / Approval / Sandbox"]
    end

这也让 Jianmu 和“模型能力”的关系更清楚。

Jianmu 并不试图替模型变聪明。

模型能力增强以后,Jianmu 反而应该让更多动态判断回到模型。

Runtime 真正应该保留的是那些模型再聪明也不能只靠 Prompt 保证的东西:

状态
生命周期
权限
执行边界
持久化
消息语义
恢复语义
可观测性
稳定控制结构

因此一个更强的模型,并不会让 Runtime 消失。

很多时候恰恰相反:模型越能自主行动,系统越需要一个可靠 Harness、清楚的 Loop 和明确的执行边界。

从这个角度看,Jianmu 的三个设计目标并不是三个孤立功能:

复杂编排
自治运行
长时运行

它们最终汇聚到同一个问题:

当模型开始从“回答问题”变成“持续行动”以后,谁来负责行动过程本身?

Jianmu 给出的答案是 Runtime。

所以这一章最后可以用一句话把 Jianmu 放回 Agent Engineering 的演进里:

模型让 Agent 能做决定;Harness 给它可靠的工作环境;事件驱动 Runner 和行为树 tick 让 Agent Loop 可以持续运行;Tree Skill 把稳定下来的做法沉淀成企业可用的确定性能力。Jianmu 想做的,是把这些能力收进同一个 Agent Runtime。

14. 总结:Jianmu 的设计哲学

本章用途:把全文压缩成几条真正值得记住的设计判断。

前面十章已经讲了很多东西:Behavior Tree、ReactiveRunner、State、Checkpoint、HITL、Skill、Swarm、Guard、Studio,也比较了 LangGraph、AgentScope 和 AutoGen。

如果最后只记住一堆模块名,这篇文档其实没有完成任务。

Jianmu 真正想表达的不是:

我们又做了一个 Agent Framework,里面功能很多。

而是一套对 Agent 的基本判断。

最核心的起点只有一个:

Agent 不应该被看成一次模型调用,而应该被看成一个可以持续存在、持续行动、持续积累能力的执行体。

一旦接受这个前提,后面的很多设计其实都会自然出现。

14.1 Agent 是有生命周期的执行体

最简单的 LLM 应用通常是一次请求:

输入
 ↓
模型
 ↓
输出

任务结束,请求也结束。

但真实 Agent 经常不是这样。

它可能:

  • 做一半等一个接口;
  • 等人审批;
  • 等另一个 Agent 回复;
  • 暂停几个小时以后再继续;
  • 中途失败并重启;
  • 一直在线,持续接收新任务。

所以对 Jianmu 来说,一个 Agent 更接近:

Agent
├── Identity
├── State
├── Task
├── Context
├── Mailbox
├── Behavior Tree
└── Lifecycle

它会被创建,会运行,会等待,会被唤醒,会暂停,会恢复,也会终止。

这也是整套架构最重要的变化。

如果 Agent 只是一轮请求,那么很多东西都可以放在应用代码里临时处理。

但当 Agent 真的跨时间存在以后:

状态要保存
消息不能丢
审批不能丢
执行位置要恢复
副作用不能重复
生命周期要有人管理

这些问题就不再是 Prompt 能解决的了。

它们需要 Runtime。

所以 Jianmu 的第一个设计判断可以写成:

先把 Agent 当成长期存在的执行体,再讨论它有多聪明。

14.2 模型负责判断,Runtime 负责让事情继续发生

Jianmu 并不希望把模型的判断能力重新写回规则系统。

模型最有价值的地方仍然是处理那些难以提前枚举的问题:

用户到底想做什么?
现在发生了什么?
下一步最值得尝试什么?
这个异常属于哪一类?
这些信息应该怎么理解?

这些问题应该尽可能交给模型。

但模型不应该同时承担所有运行时责任。

比如:

这条 Tool 调用是不是已经执行过?
现在应该继续跑还是等待事件?
审批结果有没有持久化?
重启以后应该从哪里恢复?
消息已经消费到哪个位置?
这个动作有没有权限执行?

这些问题如果也靠模型“记得”,系统会非常脆弱。

所以 Jianmu 一直在做一层职责分离:

Model
负责理解、推理、判断、生成

Runtime
负责状态、时间、执行、恢复、消息和边界

这也是全文反复出现的那句话:

模型负责判断下一步做什么,Jianmu 用事件驱动的行为树 tick 让这个判断持续、可控地变成行动。

这里的“持续”很重要。

Agent 的价值不只是偶尔做对一个决定,而是把一连串决定和行动真正推进到任务结束。

Runtime 负责让这条链不断掉。

14.3 稳定的部分结构化,不确定的部分交给模型

Jianmu 选择 Behavior Tree,并不是因为相信所有任务都应该提前写死。

恰恰相反。

真正适合 Agent 的任务,本来就包含大量不确定性。

但“不确定”也不意味着所有东西都应该每次由模型重新决定。

例如:

退款金额超过阈值必须审批
主接口失败以后允许重试
重试仍失败要走备用方案
结果必须经过验证以后才能结束

这些已经稳定的控制关系,没有必要每一轮都提醒模型:

“记住哦,失败三次以后要换方案。”

它们更适合直接进入执行结构。

因此 Jianmu 的一个核心原则是:

稳定的部分结构化,不确定的部分继续交给模型。

可以简单理解成:

Agent Loop      → Behavior Tree Tick
动态语义判断    → Model
原子外部动作    → Tool
稳定企业能力    → Tree Skill

Behavior Tree 在这里不是“替代 Agentic behavior”,而是在承载 Agentic behavior 的运行循环。

一个叶子节点完全可以还是 ReAct、LLM、RAG、Tool 或另一个 Agent。

树负责的是:

谁先执行
谁失败以后走谁
什么时候 Retry
什么时候 Wait
什么时候并行
哪个稳定做法可以沉淀成 Tree Skill

所以 Jianmu 追求的不是把所有行为都变成确定流程,也不是让模型拥有没有边界的自由。

它更关心的是:

哪些东西值得确定,哪些东西必须保持开放。

这也是 Behavior Tree 作为 Loop 内核真正有意义的地方。

14.4 等待、失败、人介入和恢复都应该是正常运行状态

很多 Demo 默认任务世界是同步的:

调用 Tool
 ↓
马上得到结果
 ↓
继续

真实世界不是这样。

一个 Agent 很可能大部分时间都在等:

等 API
等用户
等审批
等 callback
等另一个 Agent
等某个业务状态变化

如果系统把“等待”当异常,长时 Agent 很快就会变得非常别扭。

所以 Jianmu 的另一个设计判断是:

等待不是异常,而是 Agent 生命周期中的正常状态。

同样,Human-in-the-Loop 也不应该被理解成:

“Agent 不够聪明,所以失败了,需要人救场。”

很多业务动作本来就必须有人负责最终决策。

例如:

高额退款
删除生产数据
真实资金操作
危险代码执行
关键业务授权

这时人介入不是 Agent 能力不足,而是系统治理的一部分。

所以 Jianmu 把 Suspend / Resume、Approval、Guard 和 Sandbox 都放进 Runtime,而不是当作外围补丁。

失败也一样。

真正可靠的系统不是假设永远不失败,而是清楚定义:

失败以后 Retry 吗?
Fallback 吗?
暂停吗?
重启吗?
需要恢复哪些状态?
哪些副作用不能再做一遍?

因此 Jianmu 所谓 Durable,不只是“把 State 保存到磁盘”。

更重要的是:

任务经历等待、中断和故障以后,执行语义还能保持一致。

这也是为什么 Checkpoint、Tree State、Suspension Record、Mailbox Cursor 和幂等语义都值得存在。

14.5 Tree Skill 让能力积累,Swarm 让多个执行体持续协作

前面的几个设计主要解决:

一个 Agent 怎么把事情做完。

但 Jianmu 后来又自然出现了两个更大的时间尺度。

第一个是:

同一个 Agent 做过很多任务以后,能不能留下能力?

这对应 Skill。

第二个是:

一个 Agent 做不完的事情,多个 Agent 能不能长期协作?

这对应 Swarm。

所以可以把 Jianmu 看成四个尺度:

一次任务内部
Behavior Tree Tick 管 Agent Loop
        ↓
一段时间上的任务
Runtime 管生命周期、事件和恢复
        ↓
很多次任务之间
Tree Skill 管稳定能力的积累和复用
        ↓
多个执行体之间
Swarm 管通信、生命周期和动态协作

Skill 让成功经验不必永远停留在某一次 Trace 里。

一段已经验证稳定的做法,可以被整理成 Prompt Skill,也可以进一步变成 Tree Skill。企业化真正需要的确定性,主要就在 Tree Skill 里形成。

以后其他 Agent 再遇到相似问题,就不一定需要从头探索。它调用的是一套已经被运行、调试、审计和版本化过的树。

Swarm 则把同样的 Runtime 思想扩展到多个 Agent。

Jianmu 的多智能体不是:

几个模型轮流说话

而是:

多个有独立身份、State、Mailbox 和 Lifecycle 的 Agent
在共同 Runtime 中持续协作

其中通信本身属于 Runtime。

消息可以成为事件,事件可以唤醒另一个 Agent;Agent 可以创建新的 Agent,加入 Group、订阅 Topic,整个协作网络可以在任务过程中发生变化。

因此 Swarm 并不是和单 Agent Runtime 完全不同的一套思想。

它更像把同样的事件驱动机制放大了:

单 Agent:
外部变化 → Event → Agent 被唤醒

Swarm:
Agent A 行动 → Message → Agent B 被唤醒

而 Skill 又让这些 Agent 使用的能力本身可以继续沉淀。

所以 Jianmu 后面真正有意思的方向,是这几件事开始连接起来:

长期运行
   ↓
产生真实执行数据
   ↓
稳定做法沉淀成 Tree Skill
   ↓
Tree Skill 被更多 Agent 使用
   ↓
Swarm 产生更多协作经验
   ↓
继续验证和改进能力

这也是为什么持续学习和 RSI 会自然出现在 Jianmu 的长期演进里。