本文是「Pi-Agent 项目原理详解」的开篇。不涉及源码细节,而是回答一个更根本的问题:Pi 是什么?它为什么值得你花时间?读完这篇,你会对 Pi 的三个身份——编码工具、学习教材、开发 SDK——有一个清晰的全局认知。
一、开场:三个问题,一个答案
你可能因为三种不同的原因点开了这个系列:
- “我想找个好用的编码 Agent” — 你受够了臃肿的工具,想要一个极简、透明、快的东西
- “我想知道 Agent 到底怎么做的” — 你翻过一些 Agent 框架的源码,要么太复杂(几万行起跳),要么太简陋(一个 while 循环就敢叫 Agent)
- “我要做自己的 Agent” — 你有垂直场景的需求,需要基于 SDK 做二次开发,不想从零造轮子
这三个问题,恰好对应 Pi 的三个身份。而这三个身份指向同一个项目,这本身就值得好奇。
在深入源码之前,我们先站远一点,看看 Pi 的全貌。
二、Pi 是什么:一张图看懂
一句话定义
Pi 是一款极简、可扩展的终端编码 Agent 外壳(coding agent harness),由 libGDX 作者 Mario Zechner 创建,全部用 TypeScript 编写,MIT 协议开源。
拆开来看:
- “编码 Agent” — 它能读懂你的代码库,写代码、改代码、跑命令,像一个坐在你旁边的结对编程伙伴
- “终端外壳” — 它住在终端里,没有 GUI,没有 IDE 插件,输出写进终端回滚缓冲区。这决定了它的一切后续设计选择
- “极简” — 核心四个内置工具(read / write / edit / bash)、约 90 词(英文 word,非 token)的静态系统提示词模板(运行时拼接 tools/skills/contextFiles 后通常 200-400 词)、约 12000 行 TUI 代码(核心
tui.ts单文件约 1700 行)。它刻意不构建 MCP、子 Agent、计划模式、权限弹窗、后台 bash - “可扩展” — 极简核心之上的缺失功能,通过 TypeScript 扩展、技能、Pi Package 来补充
关键数字
| 指标 | 数值 | 含义 |
|---|---|---|
| GitHub Stars | 64,000+ | 十个月的增长,社区验证了需求 |
| 内置工具数 | 4 核心 + 3 辅助 | 核心:read / write / edit / bash;辅助:grep / find / ls |
| 系统提示词 | 静态模板 ~90 词(英文 word,运行时 200-400 词) | 对比 Claude Code 的数万字 |
| TUI 代码量 | ~12000 行 | 核心 tui.ts 单文件约 1700 行;Mario 的游戏引擎背景带来的”克制” |
| 支持供应商 | 30+ 家 | 源码 KnownProvider 枚举实际 35 个(含区域变体),独立品牌约 27 个;Anthropic、OpenAI、Google、Groq、Ollama 等 |
| 核心包数量 | 4 个 | pi-ai / pi-agent-core / pi-tui / pi-coding-agent |
| 运行模式 | 4 种 | 交互 / print-JSON / RPC / SDK |
关于数字的说明:Pi 官网早期营销材料常说”4 个内置工具”、“15+ 家供应商”、“约 600 行 TUI”——前两者分别指核心 4 个工具(不含 grep/find/ls 辅助工具)和早期版本列举的知名厂商;“600 行 TUI”是早期版本的数字,v0.80.2 实际已增长到约 12000 行。本表按 v0.80.2 源码实际数字呈现,避免读者对照源码时困惑。
四个核心包,各司其职
┌──────────────────────────────────────────┐
│ pi-coding-agent │ ← 完整 CLI 产品 + SDK
│ 系统提示词 · 内置工具 · 会话管理 · 扩展 │
├──────────────────────────────────────────┤
│ pi-tui │ pi-agent-core │ ← 终端 UI + Agent 引擎
│ 差分渲染 · 组件系统 │ AgentLoop · 工具 │
│ │ 系统 · 事件流 │
├──────────────────────┴───────────────────┤
│ pi-ai │ ← 多供应商 LLM 抽象
│ 统一 API · 上下文交接 · 流式 · Token 追踪│
└──────────────────────────────────────────┘
这四层里,pi-ai / pi-agent-core / pi-coding-agent 构成一条三层堆栈(每层可独立使用),pi-tui 是一个正交的 UI 库,与 Agent 体系完全解耦——你可以只用 pi-ai 调模型,也可以用 pi-agent-core 在你自己的应用里跑 Agent Loop,完全不需要碰 CLI。这是 Pi 作为 SDK 的核心价值,我们在第五节细讲。
配图说明:四个核心包的分层依赖图。coding-agent 在顶层(产品+SDK),agent-core 在中层(引擎),pi-ai 在底层(模型抽象),pi-tui 是平行的 UI 层不依赖任何 AI 包。底部展示四种运行模式。
外围还有一个实验性的
pi-orchestrator(v0.80.x 新增),负责多 Agent 编排,不在核心学习主线内。
三、视角一:作为编码 Agent —— 一个好用的日常工具
3.1 Pi 是什么:积木,而非整车
先用一句话把 Pi 的位置说清楚:Pi 不是又一个 Cursor 或 Claude Code——它是一盒让你按自己心意拼出自己 CodingAgent 的积木。
打个比方。Cursor 像一辆造好的整车——座椅、空调、导航都装好了,你坐进去就能开。Claude Code 也是一辆整车,只是配了赛车引擎和强化悬挂。Pi 不一样——它给你的是发动机、底盘、转向柱、电路系统,外加一份”我们已经帮你验证过这套组合能跑”的保证。它自带一个能直接开的默认配置(你 pi 一回车就启动了),但它的核心价值在于:你可以把这套零件拆开、重组、加料、换皮,造一辆完全按你工作流定制的车。
这个定位是 Pi 一切设计决策的源头。理解了它,下面几件事就都说得通了:
- 为什么系统提示词只有约 1,000 个 token?因为”该说什么”应该由你决定,不该被框架预判
- 为什么只内置 4 个工具(read / write / edit / bash)?因为更多内置工具 = 更多不可改变的约束
- 为什么没有 MCP / 计划模式 / 子 Agent / 待办?因为这些都是”整车上的功能”,Pi 把它们留给你——你想用什么模式,就用扩展去搭
社区观察者 Pasquale 把这个分野说得最锋利:
“像 Claude Code 和 Codex CLI 这类工具,优化的是’在精心打磨的环境里尽快拿到第一次成功’…… Pi 把优先级挪到了’对工具的所有权’上。它不给你计划模式,它给你构造一个完全按你心意行事的计划模式所需的构建块。”
这不是说 Pi “不能开箱即用”——它完全能。pi 一回车,你就在和一个能干的编码 Agent 对话了。但 Pi 的”好用”,本质上不是它做加法做出来的,而是它做减法之后把所有加法的权力留给你。一位社区观察者把它叫作”世上最可驾驭(steerable)的外壳”——可驾驭,不是因为它响应快、而是因为你对它每一个动作都有否决权和改造权。
适用人群判断:如果你生活在终端里、熟悉 tmux 和容器、对每一个关不掉的功能都烦躁——Pi 是你的工具。如果你要的是零配置开箱即用、最小配置跑起来——选 Cursor 或 Claude Code。这不是优劣问题,是工作方式契合度的问题。
3.2 五根定制杠杆:Pi 没有的功能,全都可以自己造
§3.1 说过 Pi 没有 MCP、没有计划模式、没有子 Agent、没有 loop 模式、没有待办——你可能要问:那这些”商业 Agent 标配功能”我想要怎么办?
答案就在 §3.1 那句”它不给你计划模式,它给你构造计划模式所需的构建块”。Pi 给你五根杠杆来把它塑形成你想要的形状——前四根用于自己用,第五根用于把成果分享出去。这五根杠杆本身才是 Pi 真正的能力所在:极简的核心 + 强大的杠杆,让你拿到的是”一个能长成任何形状的 Agent”,而不是”一个被作者决定了长成什么形状的 Agent”。
扩展(Extensions)——最被低估、也是最强的一根杠杆
扩展是 TypeScript 文件,会被 Pi 自动加载、还支持热重载。改一个扩展文件,正在跑的会话立即生效,不用重启。这点看似小事,其实是个杀手锏——它催生了一种独特的玩法:让编码 Agent 自己改自己的能力。Mario 在演讲里特别强调这一点。
扩展能碰的东西很深:工具、斜杠命令、键盘快捷键、事件钩子、整套 TUI 组件树——换句话说,Pi 不藏私,把内脏都暴露给你了。
关键是:§3.1 列出的那些”Pi 没有的功能”,全部都能用扩展实现。Pi 仓库附了 50 多个官方扩展示例,社区观察者 Rushi 拆解过:
“那些你大概以为是默认行为的内置能力——子 Agent、计划模式、权限门禁、沙箱、MCP 集成、自定义编辑器——全都可以作为扩展实现,并在仓库里以示例形式提供。”
把这句话翻成大白话:商业 Agent 把这些功能焊死在产品里,Pi 把它们拆下来变成可选模块。你想要 MCP?装一个 MCP 扩展就行。你想要子 Agent?派生一个新的 Pi 实例的扩展就有现成的。你想要 loop 模式(让 Agent 自己迭代到任务完成)?写一个扩展拦截 turn_end 事件再触发下一轮就行——本教程第 11 章会带你从零写一个。
更狠的是——如果官方扩展没满足你,你可以自己写一个完全按你需求的。Mario 描述过一个例子:有人五分钟写了一套 read、write、edit、bash,通过 SSH 操作远程机器——彻底替换掉了内置工具。如果你想给 Pi 加一个权限审批弹窗(毕竟默认 YOLO),约 50 行扩展代码就够了。如果你想 fork 出一套完全不同的 UI(比如把 Agent 跑在浏览器里、用 React 重画界面),也办得到。Pi 的能力,随你愿意定制它的意愿而线性增长。
技能(Skills)——按需加载的能力包
技能是”指令 + 工具”打包的能力包,采用渐进式披露——只在被调用时才进上下文,平时不占一个 token。它解决一个核心矛盾:你既想要丰富的能力库、又不想每个会话都为用不上的能力付上下文税。
技能和扩展的关系可以这样理解:扩展是给 Agent 加新能力(加新工具、加新命令、加新模式),技能是给 Agent 加新知识(“遇到 X 任务该怎么做”)。两者可以叠加——一个扩展可以注册若干技能,一个技能也可以调用扩展提供的工具。
提示词模板(Prompt Templates)——可复用的工作流
针对重复性任务的可复用 markdown 模板,支持参数。比如你天天做 code review,可以写一个模板把”读 diff、检查风格、给反馈”的指令固化下来。需要时通过斜杠命令一键加载。
主题(Themes)——可实时重载的 TUI 皮肤
TUI 的图形主题。在会话进行中切换,立即生效。这是杠杆里最轻的一根,但对长期使用者来说很重要——你要看一个工具一整天,它得让你眼睛舒服。
Pi 包(Pi Packages)——把上面四样打包分发
扩展、技能、模板、主题都可以打包成一个 Pi 包,从 npm 或 git 安装:
pi install npm:@foo/pi-tools
# 或者直接从 git 仓库
pi install git:github.com/user/repo
这套模型和开发者每天都在用的包管理器高度相似——这种熟悉感是它被快速采纳的原因之一。你写好一个扩展,发到 npm 上,全世界任何 Pi 用户一行命令就能装上。这把”自己造”的范围从”自己用”扩展到了”社区共享”。
注:扩展、技能、模板、主题、Pi 包的具体写法,本教程后续章节会专门展开。本节只是让你先建立”Pi 是可塑的、且缺什么都能自己补”这个心智。
3.3 它带来的日常红利:默认配置就很好用
讲完了”Pi 是积木”,回到最实际的问题:那 Pi 这盒积木按默认配置拼出来之后,作为一个日常编码工具,体验怎么样?答案:好得令人吃惊。
Pi 在 TerminalBench 基准测试(约 82 项计算机使用与编程任务的 Agent 评估)中排名第二,使用 Claude Opus 4.5 时仅次于 Terminus——尽管它没有 MCP 支持、没有子 Agent、没有计划模式、没有后台 bash、没有内置待办。这一结果表明一件事:极简的取向没牺牲能力,那些”整车上的功能”对一个能干的 Agent 来说并不是必需品。
下面是默认配置下你立刻能享受到的几个红利:
上下文干净得令人羡慕。这是 Pi 最硬核的差异化。系统提示词 + 工具定义加起来不到 1,000 个 token,对比 Claude Code 的数万 token。上下文窗口是 Agent 最稀缺的资源——固定指令占得越少,留给你的代码、项目上下文的空间就越多。Pi 不会在背后偷偷注入任何东西,所有 prompt 源码公开可见,你甚至可以用 SYSTEM.md 文件把整个系统提示词替换掉。
透明到骨头里。你能看到模型收到的每一条消息、每一次工具调用的完整输入输出、跨会话的完整成本追踪、会话的 HTML/JSON 导出。用过其他编码 Agent 的人大概都经历过:Agent 做了个奇怪决定,你想知道它为什么这样做,但你看不到它”看到”了什么。在 Pi 里没有这种黑箱。
模型自由(30+ 供应商)。Pi 支持 35 个 KnownProvider(Anthropic、OpenAI、Google、Azure、Bedrock、Mistral、Groq、Cerebras、xAI、Hugging Face、Kimi、MiniMax、OpenRouter、Ollama、DeepSeek、智谱、小米、Together、Fireworks 等等,去重后约 27 个独立品牌)。更重要的是会话中途切换模型——用 /model 或 Ctrl+L。比如用 Claude 做复杂推理、切到 MiniMax 做简单文本处理省钱。pi-ai 在底层处理了跨供应商的上下文交接(思考轨迹转换、签名 blob 回放等),虽然本质有损、但比”切换等于重新开始”强多了。
树状会话:走错路就分叉。Pi 把会话存成树结构(DAG,有向无环图),而不是线性日志。/tree 跳到任意历史消息、从那里分叉出新分支继续探索。所有分支活在同一个文件里。调试时尤其有用——你可以在同一个起点尝试三种不同的修复方案,不必担心”回不去了”。
YOLO 模式与安全哲学。Pi 默认 YOLO——Agent 不经审批弹窗直接执行动作。Mario 的论点是:基于审批的安全措施会让用户疲劳(“弹窗疲劳”),最终要么被整体禁用、要么沦为看都不看就机械点同意的”安全表演(security theater)“。他建议把容器化作为安全边界。如果你确实需要审批流程,约 50 行扩展代码可以自己实现——框架提供了所有钩子。
3.4 上手一分钟
curl -fsSL https://pi.dev/install.sh | sh
# 或者
npm install -g --ignore-scripts @earendil-works/pi-coding-agent
然后在任意项目目录里运行 pi。设一个 ANTHROPIC_API_KEY 环境变量,或者用 /login 完成认证,就可以开始了。
3.5 不靠环境变量:用 models.json 定义第三方模型
官方教程里默认让你设 ANTHROPIC_API_KEY,但实际项目里你大概率想用的是国内的智谱、DeepSeek、Kimi、Qwen 之类。这些不可能靠一个环境变量搞定——你需要告诉 Pi:base URL 在哪、用哪种 API 协议、模型 ID 叫什么、上下文窗口多大。
Pi 的解法是一个本地 JSON 配置文件:~/.pi/agent/models.json(Windows 下是 C:\Users\<你>\.pi\agent\models.json)。文件由 ModelRegistry.create() 在启动时自动读取,不需要任何命令行参数。
一个真实例子:
{
"providers": {
"zhipu": {
"baseUrl": "https://open.bigmodel.cn/api/paas/v4",
"api": "openai-completions",
"apiKey": "<your-zhipu-key>",
"models": [
{ "id": "glm-4.5-air", "name": "GLM-4.5-Air" },
{ "id": "glm-4-flash", "name": "GLM-4-Flash" }
]
},
"deepseek": {
"baseUrl": "https://api.deepseek.com",
"api": "openai-completions",
"apiKey": "<your-deepseek-key>",
"models": [
{ "id": "deepseek-v4-flash", "name": "DeepSeek V4 Flash" },
{
"id": "deepseek-v4-pro",
"name": "DeepSeek V4 Pro",
"contextWindow": 1000000,
"maxTokens": 384000
}
]
}
}
}
拆开看几个关键字段:
providers— 顶层是 provider 字典,键名(zhipu/deepseek)是你自己起的名字,会作为模型的provider字段显示api— 选协议。最常见的是openai-completions(OpenAI 兼容接口,国内厂商几乎都支持)、anthropic-messages、openai-responses。这个字段决定了 Pi 用哪种请求格式去调baseUrl— provider 的接口地址apiKey— 明文存放。务必把.pi/加进.gitignore,否则一个git add .就会泄露models— 该 provider 下的模型列表。id是调 API 时传的真实模型名,name是 TUI 里显示的友好名contextWindow/maxTokens— 可选,告诉 Pi 这个模型的窗口和最大输出长度,影响上下文压缩策略
配置完之后怎么用? 三种方式:
- 临时切换:会话中按
/model或Ctrl+L,列出所有已加载模型(包括你刚配的)fuzzy 搜索选一个 - 设为默认:编辑
~/.pi/agent/settings.json,加上"defaultProvider": "deepseek"和"defaultModel": "deepseek-v4-pro",启动 Pi 就直接用它 - 命令行查列表:
pi models(或pi models deepseek做 fuzzy 过滤)—— 出错时会在终端顶部打印models.json的解析错误,方便排查
models.json 还支持两种进阶用法(本教程不展开):用 modelOverrides 给内置 provider 的某个具体模型打补丁(比如改 baseUrl 指向自部署网关);用 compat 字段处理非标准接口的兼容性问题(比如某些网关需要特殊的 max_tokens 字段名)。schema 的完整定义在 model-registry.ts:158-218。
四、视角二:作为学习素材 —— Agent 设计的教科书
第二个身份:Pi 是学习”怎么构建一个生产级 Agent”的绝佳教材。
4.1 为什么是 Pi?——因为它足够小
很多 Agent 框架动辄几万行代码,光是搞清楚启动流程就要读几十个文件。Pi 的核心循环只有几百行,但它的设计质量一点都不”简陋”——它在 TerminalBench 基准测试中排名第二(使用 Claude Opus 4.5),仅次于 Terminus,尽管它缺少 MCP、子 Agent、计划模式等功能。
这意味着你可以在有限的时间内真正”读完”一个高质量 Agent 的全部核心代码。 这种事对 Claude Code 来说是不可能的,对 LangChain 也是不可能的。
4.2 本教程会讲什么
本教程(插图版)目前已发布 10 章,前 6 章建立核心理解,后 4 章进入进阶工程议题:
| 章节 | 主题 | 核心问题 | 难度 |
|---|---|---|---|
| 第 1 章 | 开篇总览 | Pi 是什么?为什么值得学? | 入门 |
| 第 2 章 | 项目结构与分层架构 | 四个包怎么分工?为什么这样分层? | 入门 |
| 第 3 章 | Agent Loop | 怎么让 LLM 反复思考和行动? | ★ 核心 |
| 第 4 章 | 模型调用 | 怎么用一套代码调 30+ 家模型? | ★ 核心 |
| 第 5 章 | 工具系统 | 工具怎么定义、验证、执行? | ★ 核心 |
| 第 6 章 | 消息系统 | 对话历史怎么表示和传递? | ★ 核心 |
| 第 7 章 | 事件驱动架构 | 为什么需要事件? | 进阶 |
| 第 8 章 | 上下文工程 | 怎么让有限窗口装下无限对话? | 进阶 |
| 第 9 章 | 上下文压缩 | 对话太长怎么办? | 进阶 |
| 第 10 章 | 会话管理 | 会话怎么存、怎么恢复、怎么分叉? | 进阶 |
后续规划:第 11 章 扩展系统、第 12 章 测试模式、第 13 章 设计精华总结 等高阶主题暂未在本教程覆盖,感兴趣的读者可以查阅 pi 官方仓库 的源码与文档。
阅读建议:前 6 章建议按顺序通读,它们是理解 Pi-Agent 运行机制的基础。第 7 章起可按需跳读,每章相对独立。
每一个章节都会回答三个层次的问题:是什么(概念)、怎么做(源码分析)、为什么这样做(设计取舍)。
4.3 Pi 的”减法哲学”:真正的教育在取舍里
看一个”什么都做了”的框架,你只能学到”他们做了什么”。看一个刻意什么都不做的框架,你才能学到”做 Agent 到底需要什么”。
Pi 官网的 “What we didn’t build” 章节是一份倒过来的宣言。竞争对手在罗列功能,Pi 在罗列舍弃。每一次舍弃背后,都有清晰的工程理由:
| Pi 不做的 | 为什么不做 | 替代方案 |
|---|---|---|
| MCP 支持 | MCP 服务器(如 Playwright MCP)会在会话开始灌入 13,700+ token 的工具描述 | 带 README 的 CLI 工具,Agent 按需读取 |
| 子 Agent | 增加复杂度,降低可观察性 | tmux 多实例,或专用扩展 |
| 权限弹窗 | 导致”弹窗疲劳”,沦为安全表演 | 容器化隔离,或用扩展搭审批流程 |
| 计划模式 | 计划写到 markdown 文件里更持久、可复用 | 写 plan.md 文件 |
| 后台 bash | tmux 已经解决了这个问题 | 用 tmux |
| 内置待办 | TODO.md 文件更灵活 | 用 markdown 文件或自建扩展 |
这些取舍是理解 Pi 设计哲学的关键,也是学习 Agent 设计时最有价值的思考素材。
五、视角三:作为 SDK —— 构建你自己的 Agent
第三个身份:Pi 是一套可以独立复用的 SDK,让你在它的基础上构建自己的 Agent 应用。
5.1 SDK 堆栈:三层架构 + 一个正交的 UI 库
回看第二节那张四层架构图,你会发现 pi-tui 是和 pi-agent-core 并排画的——它不在堆栈链上,而是 coding-agent 在交互模式下才用到的”侧依赖”。所以从 SDK 复用角度,Pi 实际是一条三层堆栈(pi-ai → pi-agent-core → pi-coding-agent),加上一个正交的终端 UI 库(pi-tui)。堆栈三层每层都可独立使用,UI 库也可独立使用——但它解决的是与 Agent 无关的另一类问题。
Layer 1: pi-ai — 只管调模型
// 入口在 compat 子模块(不在主入口)
import { getModel, stream } from '@earendil-works/pi-ai/compat';
import type { Context } from '@earendil-works/pi-ai';
const model = getModel('anthropic', 'claude-sonnet-4-5');
// Context 是 interface(不是 class),用对象字面量构造
const context: Context = {
systemPrompt: 'You are helpful.',
messages: [{ role: 'user', content: 'Hello!' }],
};
// stream() 返回事件流;complete() 则直接 await 拿到最终 AssistantMessage
const eventStream = stream(model, context);
for await (const event of eventStream) {
if (event.type === 'text_delta') process.stdout.write(event.delta);
}
pi-ai 不依赖任何 Agent 概念。你可以在任何需要调 LLM 的项目里用它——聊天机器人、文档分析、代码审查工具、甚至和 Agent 完全无关的应用。它支持 30+ 供应商、流式输出、跨供应商上下文交接、token 成本追踪、以及浏览器端运行。
Layer 2: pi-agent-core — 只管跑循环
// 教学示意(简化);真实 API 见 agent.ts:166 的 Agent 类
// Agent 类构造函数只接受 AgentOptions(convertToLlm/streamFn/beforeToolCall 等)
// model/tools/systemPrompt 是在调用 prompt() 时通过 AgentSessionConfig 传入
import { Agent } from '@earendil-works/pi-agent-core';
// 注意:defineTool 在 coding-agent 包,不在 agent-core
// import { defineTool } from '@earendil-works/pi-coding-agent';
const agent = new Agent({
/* AgentOptions:钩子、streamFn、convertToLlm 等 */
});
// 真实运行入口:agent.prompt() 内部调用 private 的 runWithLifecycle()
// 返回事件流需通过 subscribe(listener) 订阅,事件类型见 types.ts 的 AgentEvent 联合类型
pi-agent-core 依赖 pi-ai,但不依赖 pi-coding-agent 或 pi-tui。你可以用它构建任意类型的 Agent——不限于编码场景。数据分析 Agent、客服 Agent、自动化测试 Agent——只要是需要”模型思考 → 调工具 → 看结果 → 再思考”循环的场景,都可以用。
Layer 3: pi-coding-agent — 完整的 CLI + SDK
这是堆栈的最顶层,把下面两层组装成一个完整的编码 Agent 产品。同时也暴露出 SDK 接口,让你以”无头”(headless)模式在自己的应用中嵌入 Agent:
import { createAgentSession } from '@earendil-works/pi-coding-agent';
import { getModel } from '@earendil-works/pi-ai/compat';
const session = await createAgentSession({
cwd: '/path/to/project',
model: getModel('anthropic', 'claude-sonnet-4-5'), // Model 对象,不是 {id, api}
});
// subscribe 接收一个监听器函数,事件类型是 AgentSessionEvent 联合类型
session.subscribe((event) => {
if (event.type === 'turn_end') {
console.log('Agent 完成了一轮思考');
}
});
await session.prompt('Read the codebase and explain the architecture.');
侧库: pi-tui — 一个与 Agent 无关的终端 UI 库
把 pi-tui 单独拿出来说,是因为它有个特别的属性:完全独立于 Pi 的 Agent 体系。它的 package.json 只依赖 get-east-asian-width和 marked(markdown 解析)两个包,源码里零处 import 来自 @earendil-works/pi-* 的兄弟包。反倒是 coding-agent 单向依赖它(比如 list-models.ts:6 从 pi-tui 引入 fuzzyFilter)。
pi-tui 是 Mario 的老本行(libGDX 游戏引擎作者)的作品,约 12000 行代码实现了:
- 差分渲染 —— 每帧只重绘变化的单元格,基本无闪烁
- 保留模式 UI —— 类似 React 的声明式组件系统,而非 ncurses 那种命令式
- 内置组件 —— 带自动补全的输入框、markdown 渲染器、语法高亮、模糊搜索
它有什么用? 跟 Agent 没关系——任何需要终端交互界面的 Node.js 程序都能用:CLI 工具、交互式 dashboard、TUI 游戏、自定义 REPL。如果你曾经觉得 blessed/ink 要么太重要么太抽象,pi-tui 是一个值得读源码的极简替代品。
为什么会出现在 Pi 里? 因为 Pi 选择”终端外壳”形态(见第二节),就必须自己解决终端渲染问题。Mario 没用任何现成 TUI 库,而是按游戏引擎的思路重写了一个。这个”副产物”反而成了 Pi 最容易脱离 Pi 单独复用的部分——它根本不在乎你是在调 LLM 还是在做别的事。
5.2 扩展系统:让 Agent 修改自己的能力
Pi 的扩展系统具备热重载能力——当 Agent 修改了一个扩展文件,改动立即生效,无需重启会话。这催生了一种强大的模式:可以让编码 Agent 来修改和增强自己的能力。
扩展可以实现:
- 自定义工具 — 定义新的 tool,带 TypeBox schema 参数校验
- UI 组件 — 在终端里嵌入自定义界面
- 斜杠命令 — 注册新的
/命令 - 事件监听 — 在工具调用、turn 结束等时机插入逻辑
- 主题 — 定制 TUI 外观
- 提示词模板 — 可复用的 prompt 片段
这五种定制杠杆(扩展、技能、提示词模板、主题、Pi Package),本质上提供了从”用 Pi”到”改造 Pi”的平滑升级路径。
5.3 四种运行模式
| 模式 | 用途 | 示例 |
|---|---|---|
| 交互模式 | 日常编程的经典 TUI | pi |
| print/JSON 模式 | 脚本和 CI/CD 流水线 | pi -p "explain this code" |
| RPC 模式 | 通过 stdin/stdout 交换 JSON | 集成进非 Node.js 程序 |
| SDK 模式 | 嵌入自己的应用 | createAgentSession() |
这种多模式设计意味着 Pi 可以从”开发者手边的工具”无缝演进为”生产系统中 Agent 能力的提供者”——你不需要在项目成长后换一套框架。
5.4 开源项目已经在用
OpenClaw 等项目已经在生产环境中使用 Pi 的 SDK,把每一个 Agent 实例跑在 Pi 上。Pi Package 可以通过 npm 或 git 分发,生态正在形成。
六、Pi 的对立面:两种相反的哲学
理解 Pi 最好的方式,是看它的对立面。
Claude Code 代表”全包”路线:内置计划模式、子 Agent、MCP、权限弹窗、待办追踪——一艘功能齐全的”飞船”。系统提示词数万字,功能持续膨胀,用户被推送着适应工具。
Everything Claude Code(214K+ Stars)则把这种哲学推向极致:数百条现成命令和 Agent 打包在一起,用户从”满”开始,慢慢删。
Pi 代表相反的轨迹:从”空”开始,让你来填。 核心极简,扩展随心。工具适应你的工作流,而不是强迫你适应工具的设计。
这两种哲学没有绝对的对错。但如果你是一个”想知道 Agent 到底在干什么”的人,Pi 大概率更适合你。
七、总结
Pi 是一个”三位一体”的项目:
- 作为工具:一个极简、透明、可驾驭的终端编码 Agent。上下文干净、模型自由、树状会话、YOLO 默认——适合想要完全掌控自己工具的开发者
- 作为教材:一个高质量、可读完的 Agent 设计参考。10 章内容覆盖 Agent 架构的核心决策点(从 Agent Loop 到会话管理),每一行代码都有”为什么这样做”的答案
- 作为 SDK:一套层次分明、可独立复用的开发套件。三层堆栈(
pi-ai → pi-agent-core → pi-coding-agent)每层都能单独使用,外加一个与 Agent 解耦的pi-tui终端 UI 库;四种运行模式覆盖从本地到生产的所有场景
但最重要的是,Pi 证明了做减法是一种有竞争力的产品立场。在一个正朝着”全包”狂奔的赛道里,“我不需要的,就不会被构建”这句话本身,就是一项真正的功能。
版本说明
本文档系列基于 Pi v0.80.2 编写。代码分析以 earendil-works/pi 仓库的实际源码为准(教程链接指向 main 分支,可能与 v0.80.2 有微小差异)。