Pi Agent 101|10|Mode Adapters
Interactive、Print、RPC 和 SDK 不是四套 agent,而是同一个 AgentSessionRuntime 的四种外壳。
先说人话:同一个厨师,可以在餐厅出菜,也可以做外卖,也可以给后厨系统供餐。菜谱和厨房不应该重写三遍。
Pi 的 interactive、print、RPC、SDK 也是这样。它们只是不同入口,底下共享同一个 AgentSessionRuntime。
一个 agent 系统如果同时支持 TUI、脚本调用、RPC 和 SDK,很容易复制多套逻辑。Pi 没走这条路:mode adapter 只处理输入输出,核心 agent 生命周期由同一个 AgentSessionRuntime 推进。

这张图的重点是:入口不同,不代表 runtime 不同。Interactive、Print、RPC、SDK 面向的用户和输出形式都不一样,但它们应该尽量共享同一套 session、tool runtime、provider adapter 和 compaction 逻辑。
否则产品会出现很难解释的分叉:TUI 支持恢复,RPC 不支持;CLI 会压缩上下文,SDK 不会;print mode 的工具结果和 interactive mode 的工具结果长得不一样。
给基础读者的慢速版地图
同一个 Agent 核心可以有不同外壳:终端交互、一次性命令、JSON 输出、RPC 嵌入。Mode Adapter 的作用就是把不同入口接到同一套运行时上。这样产品形态可以变化,但任务逻辑、会话状态和工具机制保持一致。
读图说明:这张图把“一核多壳”拆成五个连续位置。先不要记术语,先看每一格负责什么,以及上一格的结果怎样交给下一格。
读图说明:这张图把“模式选择”拆成五个连续位置。先不要记术语,先看每一格负责什么,以及上一格的结果怎样交给下一格。
读图说明:这张图把“共享能力”拆成五个连续位置。先不要记术语,先看每一格负责什么,以及上一格的结果怎样交给下一格。
读图说明:这张图把“差异能力”拆成五个连续位置。先不要记术语,先看每一格负责什么,以及上一格的结果怎样交给下一格。
读图说明:这张图把“会话替换”拆成五个连续位置。先不要记术语,先看每一格负责什么,以及上一格的结果怎样交给下一格。
这组图的目的不是替代正文,而是给读者一个低门槛入口:先形成整体画面,再回到正文理解为什么这些边界必须存在。
读完这一篇,你应该能看懂什么
- 理解 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
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 去包装它。这样同一个任务换个入口,行为才不会变味。