Pi Agent 101|10|Mode Adapters

Interactive、Print、RPC 和 SDK 不是四套 agent,而是同一个 AgentSessionRuntime 的四种外壳。

Pi Agent 101|10|Mode Adapters

先说人话:同一个厨师,可以在餐厅出菜,也可以做外卖,也可以给后厨系统供餐。菜谱和厨房不应该重写三遍。

Pi 的 interactive、print、RPC、SDK 也是这样。它们只是不同入口,底下共享同一个 AgentSessionRuntime。

一个 agent 系统如果同时支持 TUI、脚本调用、RPC 和 SDK,很容易复制多套逻辑。Pi 没走这条路:mode adapter 只处理输入输出,核心 agent 生命周期由同一个 AgentSessionRuntime 推进。

Mode Adapters

这张图的重点是:入口不同,不代表 runtime 不同。Interactive、Print、RPC、SDK 面向的用户和输出形式都不一样,但它们应该尽量共享同一套 session、tool runtime、provider adapter 和 compaction 逻辑。

否则产品会出现很难解释的分叉:TUI 支持恢复,RPC 不支持;CLI 会压缩上下文,SDK 不会;print mode 的工具结果和 interactive mode 的工具结果长得不一样。

给基础读者的慢速版地图

同一个 Agent 核心可以有不同外壳:终端交互、一次性命令、JSON 输出、RPC 嵌入。Mode Adapter 的作用就是把不同入口接到同一套运行时上。这样产品形态可以变化,但任务逻辑、会话状态和工具机制保持一致。

Mode Adapters|一核多壳

读图说明:这张图把“一核多壳”拆成五个连续位置。先不要记术语,先看每一格负责什么,以及上一格的结果怎样交给下一格。

Mode Adapters|模式选择

读图说明:这张图把“模式选择”拆成五个连续位置。先不要记术语,先看每一格负责什么,以及上一格的结果怎样交给下一格。

Mode Adapters|共享能力

读图说明:这张图把“共享能力”拆成五个连续位置。先不要记术语,先看每一格负责什么,以及上一格的结果怎样交给下一格。

Mode Adapters|差异能力

读图说明:这张图把“差异能力”拆成五个连续位置。先不要记术语,先看每一格负责什么,以及上一格的结果怎样交给下一格。

Mode Adapters|会话替换

读图说明:这张图把“会话替换”拆成五个连续位置。先不要记术语,先看每一格负责什么,以及上一格的结果怎样交给下一格。

这组图的目的不是替代正文,而是给读者一个低门槛入口:先形成整体画面,再回到正文理解为什么这些边界必须存在。

读完这一篇,你应该能看懂什么

  • 理解 interactive / print / RPC / SDK 如何共享 runtime
  • 看清 mode adapter 为什么应该是薄层
  • 学会把 agent event 作为跨模式协议

和主流产品怎么对应

Claude Code 和 Codex CLI 主要给你终端入口,但它们也需要脚本化输出、JSON 事件或被外部流程调用。Cursor 把入口做进 IDE,OpenClaw 则可能同时有 channel、gateway、CLI、后台任务和调试界面。

这些入口如果各写一套 agent,行为迟早分叉:TUI 能恢复,RPC 不能恢复;CLI 会压缩上下文,SDK 忘了压缩。Mode adapter 的意义,就是让入口变化停在外壳层,底下仍然共用一套 runtime。

四种入口

  • Mode:Interactive
    • 使用场景:终端交互式 coding agent
    • 核心输出:TUI 组件和实时状态
  • Mode:Print
    • 使用场景:脚本、CI、一次性 prompt
    • 核心输出:text 或 JSON event lines
  • Mode:RPC
    • 使用场景:进程集成、外部客户端
    • 核心输出:command/response/event protocol
  • Mode:SDK
    • 使用场景:嵌入其他应用
    • 核心输出:程序化 session API

这些入口不应该各自实现工具执行、上下文压缩、provider 调用或 session persistence。它们应该订阅同一套 session events。

Interactive mode

Interactive mode 消费 message_start/update/end、tool_execution_*、queue_update、session 切换等事件,把它们变成 TUI components。用户按 Enter 时,如果 agent 正在运行,消息可能成为 steering;Alt+Enter 则可能成为 follow-up。

Interactive 的复杂度主要在产品体验,不在 agent loop 本身。

Print mode 适合脚本和 CI。它仍然创建 session runtime,只是输出方式不同:text mode 关注最终 assistant 文本,JSON mode 可以逐行输出 session events。

这说明“非交互模式”不应该意味着“简化版 agent”。它应该是同一个 runtime 的不同呈现。

RPC mode

RPC mode 把 Pi 变成 headless agent process:stdin 接收 command,stdout 输出 response/event。它支持 prompt、steer、follow_up、abort、state 和 session 操作。外部应用可以把 Pi 当作一个本地 agent server。

  • prompt:用户在输入框里按 Enter 启动一次任务
  • steer:agent 运行中补一句,当前 turn/工具结束后进入
  • follow_up:当前任务收束后再追加下一件事
  • abort:用户按 Escape 取消当前 run
  • state:读取当前 session、model、queue、运行状态
  • session commands:/new、/fork、/switch、/resume 这类会话操作

这组命令的重点是:RPC 不是另一个简化版 agent,而是把 TUI 的关键操作变成进程协议。

放到修测试这个例子里

同样是“修复失败测试”,四种入口的体验很不一样。

Interactive mode 会把模型输出、工具调用、测试日志和编辑结果实时展示给用户。用户可以中途 steering,也可以取消当前任务。

Print mode 更适合脚本。它可能只关心最终文本,或者把每个 event 按 JSON 行吐出去,方便 CI 或其他程序消费。

RPC mode 更像把 Pi 变成一个 headless agent process。外部应用通过 stdin 发 command,通过 stdout 收 response/event。它适合被 OpenClaw 这类更大的系统接进去:上层不需要嵌入整个 TUI,只需要控制 agent、订阅事件、在必要时 abort 或 follow_up。

SDK mode 则更适合直接嵌入应用代码。你不是启动一个进程,而是在自己的程序里创建 runtime。

四种入口的差异

  • 场景:上下文处理
    • Interactive:共享同一套 AgentSession
    • Print:共享同一套 AgentSession
    • RPC:共享同一套 AgentSession
    • SDK:共享同一套 AgentSession
  • 场景:错误展示
    • Interactive:TUI 里实时显示
    • Print:stdout/stderr 或 JSON event
    • RPC:response/event 返回给宿主进程
    • SDK:抛错或事件交给调用方
  • 场景:用户中断
    • Interactive:键盘操作,例如 Escape
    • Print:进程信号或命令结束
    • RPC:abort command
    • SDK:调用 runtime API
  • 场景:运行中追加输入
    • Interactive:steering / follow-up
    • Print:通常不强调
    • RPC:steer / follow_up command
    • SDK:API 调用

这组对照的重点是:入口可以不同,但上下文、工具、session、compaction 不能各写一套。否则同一个任务在 TUI 里能恢复,在 RPC 里不能恢复,系统会很快变得不可预测。

可迁移的边界

如果自己做 harness,mode adapter 只应该处理“怎么输入、怎么输出、怎么展示事件”。interactive、print、RPC、SDK 可以有完全不同的体验,但底层 session、tool runtime、provider adapter 和 compaction 应该尽量共用。

Mode Adapter 是产品外壳,不是第二套 agent

Interactive mode 的重点是实时反馈和用户介入;print mode 的重点是脚本化输出;RPC 的重点是进程协议;SDK 的重点是嵌入应用。它们确实都需要自己的输入输出逻辑,但不应该各自处理模型调用、工具执行和 session 写入。

判断一个 agent 产品是否走向复杂化,可以看它有没有把 mode 和 runtime 混在一起。如果混在一起,新增一个入口就等于重写一遍 agent。

多入口系统最怕行为不一致

同一个“修复失败测试”的任务,在 TUI 里、RPC 里和 SDK 里,底层应该经过同样的消息流、工具结果和 session 记录。区别只应该是展示方式和控制方式。

这也是 OpenClaw 这类多 channel 系统必须关心 Mode Adapter 的原因。channel 可以很多,但 agent runtime 最好只有一套。

这里的取舍

  • 取舍:多入口
    • Pi 的倾向:共用 AgentSessionRuntime
    • 可迁移原则:不要复制 agent lifecycle
  • 取舍:跨模式协议
    • Pi 的倾向:Session events
    • 可迁移原则:UI/RPC/SDK 应消费同一种事件
  • 取舍:Interactive
    • Pi 的倾向:复杂 UI,薄 agent 逻辑
    • 可迁移原则:产品体验不要污染 core loop
  • 取舍:RPC
    • Pi 的倾向:headless process
    • 可迁移原则agent runtime 可服务外部客户端

如果你在读 OpenClaw

如果你在读 OpenClaw,这一篇对应 gateway、headless run、CLI/TUI 和外部进程集成。上层入口可以很多,但底层 agent runtime 最好只有一套。否则同一个任务在不同入口下会表现不一致。

源码里真正能看到的多入口设计

Pi 的 mode 不是四套 agent。Interactive、print、JSON、RPC 最终都围绕同一套 AgentSession 和 Session Runtime 工作。差别在于输入从哪里来、事件怎么输出、UI 请求如何呈现、进程生命周期怎么管理。

Interactive 模式提供完整终端 UI;print 模式适合脚本和 CI,关注最终文本或事件流;JSON 输出适合机器记录;RPC 模式则把 Pi 变成一个长期运行的 headless agent process,由外部宿主通过协议控制。

会话替换也是共享的。new、resume、fork、switch 都会走同一条 runtime 替换路径:通知扩展、关闭旧 session、重建当前目录相关服务、创建新 session、让当前 mode 重新绑定。这避免了不同入口各自实现一套恢复逻辑。

为什么 Mode Adapter 是产品化关键

很多 agent 产品一开始只有 CLI,后来想接 IDE、Web、Slack、后台任务,就会发现底层逻辑散在界面代码里。Pi 的设计提醒我们:入口可以多,底座最好只有一套。

同一个“修复失败测试”任务,在 TUI 里应该能实时显示,在 print 模式里应该能脚本化拿到结果,在 RPC 里应该能被外部应用控制。但三者底层的 session、工具、压缩和模型事件应该一致。

Mode Adapter 讲的就是这条产品边界:外壳可以不同,agent runtime 不应该分叉。

阅读时可以用的三问

第一,这个入口是不是复用了同一套 runtime。只要换入口就换行为,后续维护一定会出问题。

第二,这个入口给用户什么控制能力。TUI 有快捷键,RPC 有 command,SDK 有 API;能力可以不同,但语义应该一致。

第三,这个入口如何暴露事件。长任务不能只等最终答案,至少要能观察运行状态、工具执行、错误和结束原因。

如果只记住一句话

入口可以很多,agent runtime 最好只有一套。

小结

入口可以很多,但不要让每个入口都长出一套 agent。先把 runtime 做成可订阅、可控制、可恢复的内核,再让 TUI、脚本、RPC 和 SDK 去包装它。这样同一个任务换个入口,行为才不会变味。