pi 是个啥-能被你自己改造的终端编程助手以及它和 opencode 的区别

我平时用 opencode 挺多的,用得也算顺手。前一阵子崔总跟我说,建议也试试 pi 吧。我一开始还纳闷,pi 是个啥东西,没听说过。装上一看才明白,它跟 opencode 是同一类东西,都是跑在终端里的 AI 编程助手,但这两个家伙的脾气完全不一样。

这篇文章就说说 pi 是啥、怎么用,以及它和 opencode 到底差在哪。我尽量按自己用下来的实际感受写,不吹也不黑,讲错了的地方欢迎指出来。


pi 是个啥

pi 的全名是 @earendil-works/pi-coding-agent,作者是 Mario Zechner,也就是当年写 libGDX 的那个 badlogic。官网是 pi.dev,MIT 协议,用 TypeScript 写的,跑在 Node 上,要求 Node 22.19 以上。我装的时候是 0.85.1。

它给自己的定位是 minimal terminal coding harness,直译就是"极简的终端编程外壳"。注意它说的是 harness,外壳,不是 framework,也不是 platform。意思很清楚:它只管最核心的那点事,剩下的都留着让你自己加。

默认情况下,pi 只给模型四个工具,read、write、edit、bash,另外还有 grep、find、ls 这些查东西用的。就这些。你让它干活,它就靠这么几个工具去干。

最有个性的地方,是它故意不做很多东西。官方文档里说得很直白:

No MCP. No sub-agents. No permission popups. No plan mode. No built-in to-dos. No background bash.

翻译过来就是:没有 MCP、没有子智能体、没有权限弹窗、没有计划模式、没有内置待办、没有后台 bash。

这几样东西,在 opencode 里基本都有。pi 的态度是,你要你就自己搭,或者装别人写好的包,别指望我塞给你。

我刚看到这段的时候,第一反应是,这不等于啥都没有吗。后来用了一阵子才转过弯来,它不是没有,是把这些都做成了"可选",而不是"必须"。内核小,改起来就方便,这跟 opencode 那种"开箱即用"是两个路子。

怎么装、怎么跑起来

安装有两种方式,一种是 npm,一种是官方脚本。npm 这种:

npm install -g --ignore-scripts @earendil-works/pi-coding-agent

那个 --ignore-scripts 是官方特意让加的,因为 pi 正常安装不需要跑依赖的安装脚本,加上这个更安稳。

如果你更喜欢脚本,也可以:

curl -fsSL https://pi.dev/install.sh | sh

装完要配一个模型。最省事的是设个环境变量:

export ANTHROPIC_API_KEY=sk-ant-...
pi

或者不设环境变量,直接敲 pi 进去,再用 /login 选提供商:

/login

然后就能用了。在终端里敲 pi,进去就是交互界面,直接跟它说话就行,跟 opencode 一样,没什么学习成本。

日常怎么用

进到界面里,编辑框有几个用法挺顺手。输入 @ 可以模糊搜项目里的文件,Tab 补全路径,Shift+Enter 换行。想用外部编辑器按 Ctrl+G。要贴图直接 Ctrl+V,或者把图片拖进终端。还有个我觉得挺方便的,输入 !command 能把命令跑掉、把结果发给模型,!!command 则是跑掉但不发给模型。

输入 / 会弹出命令。常用的有这些:

命令 干嘛的
/login /logout 管提供商的登录
/model 换模型,选的时候按 Ctrl+S 存成默认
/thinking 换思考档位,同样能 Ctrl+S 存默认
/settings 主题、消息投递、传输方式这些设置
/resume 从之前的会话里挑一个继续
/new 开新会话
/tree 跳到会话的任意一点,从那儿接着往下
/fork /clone 从某条消息分叉、或者复制当前分支
/compact 手动压缩上下文
/export /import 导出、导入会话
/share 传成私有 gist,给一个能看的网页链接
/hotkeys 看所有快捷键

快捷键里,Ctrl+L 换模型,Shift+Tab 切思考档位,连按两下 Escape 打开 /tree,Ctrl+O 折叠工具输出,Ctrl+T 折叠思考块,连按两下 Ctrl+C 退出。

还有个小细节,pi 支持消息排队。它正在干活的时候,你按 Enter 发的是"引导消息",等它这一轮工具调用跑完就插进去;按 Alt+Enter 发的是"后续消息",得等它彻底干完才发。这个在多轮任务里挺有用,不用干等着。

会话能长成一棵树

这块是 pi 我觉得最好玩的地方。

它的会话存成 JSONL 文件,而且里面的结构是树,每条记录有 id 和 parentId。好处是,你可以在同一个文件里原地分支,不用另开文件。

比如你聊着聊着发现前面某步走歪了,按 /tree 就能把整个会话树调出来,跳到那个点,从那儿重新走下去,两条分支的历史都留着。/fork 是从某条消息分出一个新会话文件,/clone 是把当前分支整个复制一份。

命令行里也能干这些事:

pi -c                  # 继续最近一次会话
pi -r                  # 浏览挑一个历史会话
pi --no-session        # 临时模式,不保存
pi --name "my task"    # 起个名字
pi --fork <path|id>    # 从某个会话分叉出来

上下文快满了怎么办?pi 有压缩,叫 compaction。手动是 /compact,自动默认也开着,快满了会自己总结前面的内容。要说明的是这个压缩是有损的,前面的细节会被总结掉,但完整历史还在 JSONL 里,想翻旧账用 /tree 回去看就行。

模型和提供商

pi 支持的提供商不少。订阅类的可以接 Claude Pro/Max、ChatGPT Plus/Pro 的 Codex、还有 GitHub Copilot。API key 类的就更多了,Anthropic、OpenAI、Google、DeepSeek、Mistral、Groq、xAI、OpenRouter、Kimi、MiniMax 一大堆。

换模型就 /model,选中了按 Ctrl+S 能存成默认。命令行里可以用 --list-models 列出来,用 --models 指定一批给 Ctrl+P 循环切换,像我这样经常换模型的人挺方便。

它还内置了 llama.cpp 的路由服务,/login llama.cpp 配上,再用 /llama 下模型、加载模型,本地跑也行。

有意思的是,pi 的提供商列表里居然还有 OpenCode Zen 和 OpenCode Go。也就是说,你可以用 pi 这个客户端,去连 opencode 家的模型服务。

如果你要接的是那种 OpenAI、Anthropic、Google 格式的自定义服务,可以在 ~/.pi/agent/models.json 里加。要是碰到非标准 API 或者要 OAuth,那就得写扩展了。

四件套和包

pi 的定制,主要靠四样东西,官方叫 prompt templates、skills、extensions、themes。

prompt templates 就是把常用提示词存成 Markdown,放到 ~/.pi/agent/prompts/,用的时候输入 /名字 就展开了。

skills 是技能,跟 opencode 用的是同一套 Agent Skills 标准,放在 ~/.pi/agent/skills/ 或者 ~/.agents/skills/。用的话输入 /skill:名字,或者让模型自己按需加载。这点挺省事的——我把同一套技能,同时装给了 opencode 和 pi,两边都能用,不用维护两份。(顺带说一句,pi 也能直接加载 ~/.claude/skills~/.codex/skills 这些别的工具的技能目录,在 settings 里配上就行。)

extensions 是扩展,用 TypeScript 写。这个是 pi 的重头戏。它能加自定义工具、加命令、加键盘快捷键、拦事件,还能改 UI,甚至连内置工具都能整个换掉。官方示例里连 Doom 都给塞进去了,等模型干活的时候打游戏。前面说的那些"pi 故意不做"的功能——子智能体、计划模式、权限闸门、MCP 支持——理论上都能用扩展自己搭出来。

themes 是主题,改完直接热加载,不用重启。prompt template、skill、extension、theme 这四样,加上包管理,合起来就是 pi packages。可以打包成 npm 包或者 git 仓库分享给别人:

pi install npm:@foo/pi-tools
pi install git:github.com/user/repo
pi list
pi update --all
pi config        # 在 TUI 里开关各个包资源

除了交互模式,还能当积木用

pi 不只是个给人用的 TUI,它还有几种程序化的用法。

比如打印模式,跑完就退,适合写脚本:

pi -p "总结一下这个代码库"
cat README.md | pi -p "把这段文字总结一下"

再比如 JSON 模式,所有事件按 JSON 行输出,方便别的程序解析;还有 RPC 模式,走 stdin/stdout,给非 Node 的进程集成用。最后它本身就是个 SDK,可以在自己的 TypeScript 程序里直接把它嵌进去:

import { createAgentSession, ModelRuntime, SessionManager } from "@earendil-works/pi-coding-agent";

要让它遵守项目里的规矩,就在项目根目录放个 AGENTS.md(或者 CLAUDE.md),pi 启动会自动读。想整个换掉系统提示词,用 .pi/SYSTEM.md

pi 和 opencode 有啥不一样

说到这儿,可能有人会问,那它跟 opencode 到底选哪个。我先把两边的主要区别摆出来,都是我自己用下来加上看文档整理的。

方面 pi opencode
定位 极简内核,自己拼 功能齐全,开箱即用
出身 Mario Zechner(badlogic) SST 团队
子智能体 没有,自己搭 有,主/子 agent
MCP 没有,写扩展加
计划模式 没有
权限弹窗 没有 有权限配置
扩展方式 TypeScript 扩展 插件 + 配置 + 命令 Markdown
会话 JSONL 树,原地分支 会话 + 分享 + 回退
形态 终端 TUI + 库 TUI + 服务端 + 网页 + 桌面端
集成 SDK / RPC / JSON ACP / MCP / GitHub / serve / attach
技能 Agent Skills 标准 Agent Skills 标准

差别最大的,我认为是思路。opencode 是"我都给你配好,你直接用",它有子智能体、有 MCP、有权限控制、能起服务端、有网页和桌面端、还跟 GitHub 打通,能 opencode githubopencode pr 直接拉 PR。功能面铺得很宽。你可以把它当成一个完整的开发平台来用。

pi 反过来,它相信"你不想要我强塞的东西"。核心就四个工具,剩下的全靠扩展和包。你不动手,它就是个很小的终端助手;你愿意折腾,它能被改成任何样子,而且不用去 fork 它的源码。

会话这块是 pi 的强项。它的树状会话和原地分支,用起来比一般工具的"线性历史"灵活,尤其是那种试错很多的任务。

隐私和安全上,得说两句实在话。pi 明确没有权限弹窗,官方建议是要么在容器里跑,要么自己用扩展写确认流程。扩展和技能又是能执行任意代码的,第三方包一定要先看看源码再装。opencode 这边至少有权限配置这一层,你可以把危险的 bash 命令设成要确认或者直接拒绝。这两点在取舍上得想清楚。

做了个对照实验,看看谁快

前面说 pi 手感快,这只是感觉,不算数。所以我认真做了一组对照实验,想看看差距到底从哪来。

条件尽量卡平:同一个模型(DeepSeek 的 deepseek-chat,两边都直连官方接口),同一个任务——目录里放一个算平均值的 buggy.py,让它读文件、找 bug、修好、跑一遍,把结果告诉我;每次都在全新的空目录里跑。为了排除干扰,我把 pi 的技能、扩展、上下文文件全关掉,opencode 那边用一个只留 provider 的最小配置,两边各跑 4 次取平均。

这里说的"快",用的是墙钟时间,也就是从敲下回车到它彻底干完,现实中真实等了多久。这个数里包含启动、把提示词发给模型、模型生成,还有它读文件、改文件、跑命令的全过程,跟咱们的体感一致。

结果是这样:

指标 pi opencode
总耗时 4.40 秒 7.32 秒
第一轮模型响应 0.60 秒 4.33 秒
输入 token 809 6310
缓存读 token 6016 23936
输出 token 289 231
总 token 7114 30477
工具调用 / 模型回合 3 / 4 3 / 4
正确率 4/4 4/4

两边干的活一模一样,都修对了,工具调用和回合数也一样。但你看输出 token,289 对 231,基本是一个量级——说明模型"想"和"说"的量差不多。差的全在输入这一侧:opencode 每一轮背的上下文,差不多是 pi 的 4 倍。

这 4 倍是哪来的?我单独测了一句废话"只回复 ok",不触发任何工具:pi 是 1515 个 token,opencode 是 7333 个。一上来 opencode 就多背了将近 6000 token。原因也不神秘,它的内置工具多(read、edit、write、bash、glob、grep、list、patch、task、todowrite、webfetch 一大堆),每个工具的定义都要发给模型,再加上它内置了好几套 agent 的系统提示词。pi 默认就四个工具,提示词也短。

输出差不多、输入差很多,意味着时间差主要花在"把上下文喂给模型"这一步,也就是预填充和网络传输,而不是模型在思考。

技能装得越多,差距会怎么变

这才是有意思的地方。pi 和 opencode 都遵循同一套 Agent Skills 标准,技能的名字和描述都是常驻在系统提示词里的(正文要按需才读)。那技能一多,两边的差距会不会被拉大?

我用统一规格的技能做了个扫描,还是测一句"ok"的输入 token:

技能数 pi opencode
0 1515 7333
10 3659 9443
43 10490 16406
100 22289 28433
200 42989 49533

把它拟合成一条直线,能看出:

  • pi:成本 ≈ 1561 + 207 × 技能数
  • opencode:成本 ≈ 7333 + 211 × 技能数

关键结论是:每装一个技能,两边增加的开销几乎一样(207 对 211),差距全在起跑线上那个固定的 5800。 技能本身不是差距来源,基线才是。所以技能越多,opencode 的相对劣势反而越小,但绝对差距基本卡在 5800 上下不动。

拿我自己那套 43 个技能来说:pi 一个请求 15051 token,opencode 20256。跑一个 4 轮的编码任务,总 token 是这样:

技能数 pi 总 token opencode 总 token
0 7171 30541
43(真实) 61284 82175
200 168290 194595

这里得划个重点:技能数会把每个任务的 token 成倍放大,因为每一轮都要把完整上下文重发一遍。 43 个技能就把一个 4 轮任务从 7 千 token 顶到了 6 万(pi)。公式大概就是:任务总 token ≈ 回合数 × (基线 + 210 × 技能数)。所以真要省钱,最有效的不是换工具,而是把技能精简掉——这一条对 pi 和 opencode 都成立。

换个模型会变吗

我又用 deepseek-reasoner(带思考的那个)测了一遍。结论是:换模型不改变两边的固定差距。opencode 不管用 chat 还是 reasoner,每个任务都稳定地比 pi 多背两万多 token,正好是 4 轮乘以那个 5800 的基线差。差距是壳带来的常数,不是模型带来的。

启动速度也顺带量了:pi 冷启动约 0.44 秒,opencode 约 0.75 秒。不过真正让 opencode 显慢的,是第一轮那个大上下文,不是这零点几秒。

所以"pi 快一些"这事,拆开看其实很朴素:它省的是那个固定的上下文基线,不是它有什么更快的引擎。 输出和回合数两边一样,说明模型那一侧是同一个东西;差的只是每一轮要背多少包袱。

当然,这个实验也有局限,我得说清楚:样本不大(各 4 次),而且我把两边都调成了最小配置。你真实用起来,opencode 还会加载 agent、规则这些,盘子只会更大;pi 的技能是描述常驻、正文按需,涨得慢一些。数值会变,但"pi 省在固定基线、技能对两边等价"这个结论不会变。

我的一些看法

要我说,这俩不是非要二选一。

如果你想要一个东西,装上就能干活,功能越全越好,团队里还要统一管控权限,那 opencode 更合适。它有子智能体、有 MCP、有权限这一套,拿来就能用。

如果你跟我一样,喜欢把工具拆开看、按自己习惯组装,还经常写点小脚本小扩展,那 pi 会让你觉得很舒服。它内核小,改起来不费劲,出了什么问题也容易看明白。而且它是认真在做"可扩展",不是嘴上说说。

我用下来的感觉是,平时常规的写代码、改代码、跑命令,两个都能干,差别不大。真到了要分支探索、要接一堆自定义流程的时候,pi 的树状会话和扩展能力就显出好处了。反过来,要做那种需要子智能体分工、需要连 MCP 服务、需要团队权限管控的活,opencode 更省心。

还有个我挺喜欢的地方,是这两个工具并不互斥。技能是同一套标准,模型服务也能互相用(pi 能连 opencode 的 Zen/Go),会话也各管各的。完全可以两个都装着,看当天想干什么就用哪个。

最后

说句实在的,pi 这种"故意少做"的工具,一开始会让人有点不习惯,觉得啥都得自己来。但用久了会发现,正是因为它肯把决定权留给你,才没那么多"它以为你需要"的东西。

当然,天下没有免费的午餐。东西越少,你要自己补的就越多;权限没有弹窗,出了事也得自己担着。所以装第三方扩展之前,多看一眼代码,这个习惯一定要有。

想试试的话,官网是 pi.dev,源码在 GitHub 上(earendil-works/pi),npm 包名是 @earendil-works/pi-coding-agent。我这边是 0.85.1,opencode 是 1.18.31,上面说的都是这个版本的实际用法,后面版本要是有变化,以官方文档为准。