你正在 OpenClaw 之上搭多 agent 平台。那么有件事必须先讲清楚:OpenClaw 自己不是一个 agent 运行时,它只是 pi 的一层封装。真正跑 agent 循环、管会话、调模型的,是 pi。看懂 pi,等于看懂了你脚下那层地基的脾气。
内容截止:2026 年 5 月。agent 工具领域是目前变化最快的技术赛道之一,下面这些是本轮调研期内真实发生的变动,用来说明"为什么时效性重要",而不是抽象地警告你:
badlogic/pi-mono 迁移到组织名 earendil-works/pi,star 数已突破 56k(OpenClaw 单周冲到 14.5 万 star 直接把 pi 带火)。@mariozechner/pi-* 发布,但已出现 Rust 重写版(pi_agent_rust)和多个第三方扩展生态(子 agent、浏览器技能等)。| 层级 | 内容类型 | 半衰期 | 建议复查 |
|---|---|---|---|
| 快变 | 具体模型名 / 价格 / star 排名 / 包版本号 / 第三方扩展清单 | 1–3 个月 | 每月扫一次 |
| 中变 | 四层包的 API 细节(事件名、方法签名、扩展 hook 点) | 3–6 个月 | 每季度核对 |
| 慢变 | 分层架构 / 会话 JSONL 模型 / SDK 嵌入方式 / 工作流 | 6–12 个月 | 半年回看 |
| 稳定 | 极简主义设计哲学 / "trust through execution" / 判断框架 | 结构性稳定 | 基本不变 |
pi 是一个用 TypeScript 写的编码 agent 工具包(agent harness)。它的作者是 Mario Zechner(网名 badlogic)——就是写了 libGDX 那套游戏框架的人。
故事的起点很"工程师式怨气":他用 Claude Code 用得越来越烦,觉得这类工具像"一艘 80% 功能根本用不上的宇宙飞船"。于是他反向而行,做了一个只有 4 个工具、系统提示词不到 1000 token 的 agent。这个 agent 叫 pi。
然后剧情反转:pi 成了 OpenClaw 的底层发动机,而 OpenClaw 在一周内冲到 14 万+ star,把 pi 一起带上了热搜。所以你现在选 OpenClaw 当运行时,本质上就是在用 pi。
定位上,pi 同时是三样东西:一个能直接用的 CLI 编码助手、一套能嵌进自己产品的 SDK、以及一个可被 agent 自我改写的开放系统(你可以让 pi 自己给自己写扩展)。
理解 pi,先理解它的"反框架"立场。文中那句被反复引用的话最能概括:
其他每个框架都是在"加法"——在已有 agent 上叠流程、记忆、协调层。pi 正相反,它是一次刻意的"减法"。 —— 对 pi 设计原则的概括(Interesting Engineering 技术评述)
Mario 的逻辑链是这样的:所有前沿模型都被 RL 训练得"懂什么是编码 agent"了。模型天然知道 bash 是什么、文件怎么读写。所以——
search_in_codebase 工具,让模型用 bash 跑 rg(ripgrep)。gh。mcporter 把 MCP 调用暴露成 CLI,再用 bash 调。每烤进一个专用工具,就等于替模型预先决定了"该怎么做这件事",反而限制了它。所以 pi 只给模型四样东西:
读文件内容和图片(jpg/png/gif/webp)。文本截断到 2000 行或 50KB,支持 offset/limit 翻页。
写文件,不存在则创建,存在则覆盖,自动建父目录。
精确替换文件里的文本,oldText 必须逐字(含空白)匹配。做外科手术式的小改。
在工作目录执行 shell 命令,返回 stdout/stderr。这是"无限能力"的入口——其余一切靠它。
另外有一个常被低估的工程亮点:pi 的 TUI 用了类似 React diff 算法的差分渲染(differential rendering),所以终端里 Markdown 和语法高亮完全不闪烁,而且"回到之前任意一轮"的能力是同类里最强的。
pi 是一个 npm workspaces 的 monorepo(锁步版本),核心是四个层层叠加的包。每一层只加一点能力,你用多少拿多少。
一个统一接口调所有 LLM:Anthropic、OpenAI、Google、Bedrock、Mistral、Groq、xAI、OpenRouter、Ollama……每家流式格式都不同,pi-ai 把它们归一化成同一套事件(text_delta、thinking_delta、toolcall_*、done、error)。你只写一次流处理逻辑,换 provider 只改一行 getModel(...)。
底层用各家官方 SDK,靠 api 字段决定走哪个 SDK——这就是为什么任何 OpenAI 兼容端点(Ollama、vLLM、DeepSeek)都能直接接进来。还内置 2000+ 模型目录和成本追踪。
models.json 里加一个 provider 指向 DeepSeek 的兼容端点即可,连官方 Claude Agent SDK 都不一定需要。pi-ai 本身就是那个"多 provider 路由层"。
把 pi-ai 包成一个 Agent 类,跑标准 agent loop:发消息给模型 → 执行模型要调的工具 → 把结果喂回去 → 重复,直到模型停。你不用自己写循环。工具用 TypeBox schema 定义(执行前用 AJV 校验),每个工具有 name / label / description / parameters / execute。
它向外发一整套事件:agent_start / turn_start / message_update / tool_execution_start / tool_execution_end / agent_end 等——这套事件流是你后面做"LiveStream 执行可视化"的现成数据源。
在 core 之上加了:7 个内置工具(默认 4 个 + grep/find/ls 三个可选)、JSONL 会话持久化、自动上下文压缩(compaction)、技能(skills)、扩展系统,以及 AuthStorage(多 provider 凭证 + OAuth)和 ModelRegistry(自定义 provider/模型)。一句 createAgentSession() 把这些全接好。
差分渲染的 TUI:语法高亮的 Markdown、带 slash 命令和文件路径自动补全的多行编辑器、loading 动画、零闪烁。如果你做的是 Web 而非终端界面,这一层你会换成 pi-web-ui(见 §5)。
这一节是真正决定"你能在上面盖什么楼"的几个机制。每一个都直接对应你平台里的某个需求。
会话存成 JSONL 文件,每条记录有 id 和 parentId——这是一棵树,不是线性历史。于是你能:导航回任意历史点继续(branch(entryId) 实现"从这里重试"),整棵树都能 getTree() 出来渲染分支选择器。
因为 JSONL 是 append-only,崩溃最多丢一行。OpenClaw 就是每个频道线程一个会话文件(~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl),各会话独立、崩溃安全。
steer() 打断:当前工具跑完后立刻插入你的消息,剩余待执行的工具被跳过。用于"用户在 agent 干活时实时打字纠偏"。followUp() 排队:不打断,排到 agent 自然结束之后。用于程序化链式调用。OpenClaw 用 steering 处理实时用户消息,用 follow-up 做程序化串联。对你的"群聊里 @某个 agent 改需求",这俩就是核心原语。
工具让模型"做事";扩展让你改"agent 怎么运转",而 LLM 完全不知道扩展存在。扩展挂在生命周期事件上:
context:每次调 LLM 前重写消息数组(OpenClaw 用它静默裁剪超大工具结果、省 token)。session_before_compact:用你自己的摘要逻辑替换默认压缩(OpenClaw 换成多阶段管线,专门保住文件操作历史和工具失败数据)。tool_call:拦截/闸门化工具调用(做权限控制)。before_agent_start:注入额外上下文或改提示词。session_start / session_switch:会话切换时反应。扩展还能 registerCommand(注册面向用户的命令,不是 LLM 工具)、registerShortcut 等。
默认工具操作的是 process.cwd()。多用户产品里这不行——每个 agent 必须锁死在自己的工作区。createReadTool(workspace) 这类工厂能把所有路径限定到某个目录。更狠的是每个工厂可传一个 operations 对象,覆写底层 I/O:
readFile 换成"从远程服务器拉文件"。exec 换成"在 Docker 容器里跑"。OpenClaw 正是用工厂给每个 agent 造工作区限定的工具,再裹一层中间件:权限检查、图片归一化,以及 Claude Code 参数兼容别名(file_path→path、old_string→oldText)——所以 Claude Code 的 skills 能直接在 pi 上跑。
session.agent.streamFn 是 agent 每次要调 LLM 时实际调用的函数。默认是 streamSimple,但你能包一层来注入 header、调参数、按 provider 加逻辑。OpenClaw 用它加 OpenRouter 归因 header、给 Anthropic 开 prompt caching(cacheRetention: "long")。
长对话超出上下文窗口时,pi 把旧消息摘要、保留近期消息。createAgentSession 默认开自动压缩,接近窗口上限时触发。完整历史永远留在 JSONL 文件里,只有内存里的上下文被压。你也能手动 session.compact("保住所有文件路径和代码改动") 给摘要导向。
交互式 CLI,配 pi-tui。日常人机协作。
一次性输出,适合脚本和管道。
进程间集成,把 pi 当子进程驱动。
嵌进你自己的应用——OpenClaw 走的就是这条。你的平台也应该走这条。
四个核心包之外,monorepo 还有几个把系统往不同方向延伸的包,对你都直接有用:
Lit 写的浏览器聊天组件。开箱 ChatPanel:流式、文件附件、在沙箱 iframe 里渲染 HTML/SVG/Markdown 工件。你做群聊 Web 界面的起点。
把消息委派给 pi-coding-agent 的 Slack bot。每频道 agent 隔离、Docker 沙箱、定时事件、自管理的工具安装。多渠道 + 隔离的参考实现。
用 vLLM 在 GPU pod 上部署开源模型的 CLI(DataCrunch / RunPod / Vast.ai / 裸机)。每个模型暴露 OpenAI 兼容端点给 pi-ai 消费。
pi 的技能库,兼容 Claude Code 和 Codex CLI 的 skills。意味着现有 skill 生态你能直接复用。
第三方生态也在长:pi-subagents(给 pi 加 Claude Code 风格的并行子 agent、可中途 steering)、oh-my-pi(coding-first 的分支,能继承 .claude/.cursor/.codex 等已有配置)、以及 mitsuhiko 等人维护的扩展集(/review、/todos、CDP 浏览器技能)。
分两类:作为成品工具直接用,和作为 SDK 搭东西。
npm i -g @mariozechner/pi-coding-agent 然后 pi。/reload 接着用。deploy、调 API、查数据库等。这是对你最有价值的一节。你的"群聊式 + 数字员工自主认领任务 + 真实交付物"平台,几乎每个设计点都能在 pi 的原语上找到落点。下面把你的架构决策逐条映射。
createAgentSession + 独立 JSONL。群聊本质是"多个 session 共享一个消息总线"。你只需要在上面做一层"消息路由 + UI 聚合"。steer() 直接把 @某 agent 的消息插进它的 session;第二级你自己写一个调度器扩展决定派给谁,用 followUp() 派活;第三级用 before_agent_start 给候选 agent 注入"你是否该接这个任务"的自评提示。session.subscribe() 把每个 tool_execution_start/end、message_update 都吐给你,你只要把这些事件渲染到群聊 UI 即可。pi-web-ui 的 ChatPanel 已经做了一半。session_before_compact 把要长期保留的东西摘要进一个"记忆条目");长期 = 你自己的存储,用 context 扩展在每次调用前把相关长期记忆注入消息数组。JSONL 树还顺手给你"可回溯的情景记忆"。models.json 加一个指向 DeepSeek 兼容端点的 provider,getModel 选它即可。甚至可以做到"同一个群里不同 agent 用不同模型/不同价位"。createReadTool(workspace) 等工厂锁死目录,operations 把 bash 丢进 Docker。这正是 OpenClaw 多用户安全的做法,照抄即可。createAgentSession + 扩展 API + 事件流这三样。建议你早点写一个最小 demo:两个 pi session 共享一个消息总线,用 steer 互相喊话——这能在一两天内验证你整个平台的核心假设。
pi-subagents 第三方扩展可参考或直接用。tool_call 扩展加审批闸门。