ARTICLE · 1176817
11 万 Star 的 Pi:把 AI 编程助手拆到源码层,终端 Agent 原来是这样工作的
适合读者:AI 编程工具使用者、终端重度用户、Agent 应用开发者、想了解“AI 编程助手内部如何运转”的工程师。
阅读时长:约 18 分钟。
项目地址:https://github.com/earendil-works/pi
如果你最近关注 AI 编程工具,大概率已经见过类似产品:你在编辑器里提需求,它读代码、改文件、跑测试,最后给你一份修改结果。
但大多数工具把内部过程藏得很深。你知道它“能干活”,却不一定知道它为什么能干活:消息怎么组织?工具怎么调用?上下文怎么压缩?会话为什么能分叉?扩展为什么能改行为?
Pi 有意思的地方就在这里。
它不只是一个终端里的 AI 编程助手,也是一套拆得比较清楚的 Agent 运行框架。你可以把它当成日常写代码的工具,也可以顺着源码看到:一个现代 Coding Agent,究竟是怎么把 LLM、工具调用、会话状态、终端 UI 和扩展系统组装起来的。
截至 2026 年 10 月 13 日写稿核验时,这个项目在 GitHub 上已经有 114,798 个 Star、14,624 个 Fork,使用 MIT License,主要语言是 TypeScript。它热度很高,但更值得关注的是:它的代码结构足够清晰,适合拿来做 Agent 工程化学习样本。
这篇文章会按四个层次展开:
Pi 到底能做什么; 如何安装、配置和日常使用; 源码架构和 Agent Loop 的实现原理; 它的优势、短板,以及适合什么人。
一、先说清楚:Pi 不是 Raspberry Pi
这里的 Pi,全称可以理解为 Pi Coding Agent。它跟树莓派没有关系。
一句话概括:
Pi 是一个运行在终端里的 AI 编程 Agent,也是一套可嵌入、可扩展的 Agent Harness。
“Agent Harness”这个词很重要。它不是在说“我接了一个大模型 API”,而是在说:工具提供了模型调用之外的一整套承载机制,包括:
读写项目文件; 执行 shell 命令; 维护多轮对话状态; 把工具结果重新送回模型; 支持会话恢复、分叉和压缩; 支持扩展、技能、MCP、SDK、RPC; 用 TUI 把过程展示给用户。
所以,Pi 既可以直接使用,也可以被拆开研究。
普通用户看到的是:
cd /path/to/project
pi开发者看到的是:
CLI 参数
→ 会话管理器
→ 模型与工具解析
→ AgentSession
→ Agent Loop
→ LLM Streaming
→ Tool Calling
→ Tool Result
→ 下一轮这就是 Pi 的价值:把“AI 帮我写代码”这件事,从黑盒产品变成了可以阅读、可以改造、可以嵌入自己系统的工程结构。
二、它到底能做什么?
先看一个真实使用画面。
这张图里,Pi 正在终端中搭建一个 FastAPI 项目。它已经不是简单地补全几行代码,而是在连续执行“项目级动作”:
创建 bbs_project/src/api/main.py;创建 bbs_project/src/api/agents.py;引入 FastAPI、CORS、数据库会话和多个 Agent 类; 生成用户、帖子、线程、Agent 等 API 路由; 把当前执行过程实时显示在终端里。
这类行为背后不是“单次问答”,而是一个典型 Agent Loop:
理解任务
→ 查看项目结构
→ 生成或修改文件
→ 执行命令验证
→ 根据结果继续修改
→ 直到任务完成或被用户中断Pi 默认提供的编码工具很克制,主要有:
read | |
bash | |
edit | |
write | |
grep | |
find | |
ls |
默认启用的是 read、bash、edit、write。grep、find、ls 属于可用的只读工具,可以通过参数显式启用。
这个设计很像一把“瑞士军刀”:工具数量不多,但刚好覆盖 Coding Agent 最核心的动作——看、改、跑、再看结果。
三、安装和第一次运行
1. 环境要求
当前源码要求:
Node.js >= 22.19.0可以先检查:
node-v如果你的 Node 版本较低,建议先升级,否则可能连安装或启动都会失败。
2. 官方脚本安装
macOS / Linux:
curl-fsSL https://pi.dev/install.sh |shWindows PowerShell:
powershell -c "irm https://pi.dev/install.ps1 | iex"3. npm 安装
也可以通过 npm 安装 CLI 包:
npm install -g--ignore-scripts @earendil-works/pi-coding-agent这里的 --ignore-scripts 很值得注意。它体现了项目的一种供应链安全倾向:尽量减少安装脚本带来的额外执行面。项目 README 也提到了精确锁定直接依赖、以 package-lock.json 作为依赖事实来源、在 CI 中做 npm audit 和签名检查等实践。
4. 进入项目并启动
cd /path/to/project
pi第一次使用时,通常需要先配置模型供应商。交互界面中输入:
/login然后根据提示完成登录或 API Key 配置。
之后就可以输入自然语言任务,例如:
先阅读这个项目的目录结构,告诉我入口文件在哪里,不要修改任何文件。或者:
帮我找出最近的登录相关改动,并解释可能引入的回归风险。四、日常使用:把它当成“终端里的编程搭子”
Pi 的使用方式主要有四类。
1. 交互式 TUI
最典型方式:
cd your-project
pi进入交互界面后,可以使用一些高频操作:
@路径 | |
!git status | |
!!命令 | |
/model | |
/thinking | |
/settings | |
/export | |
/share | |
Ctrl+O | |
Ctrl+T |
这套交互很符合终端用户习惯:你不用离开项目目录,也不用把代码反复复制到聊天窗口里。
2. Print 模式:问完就走
pi-p"List all .ts files in src/"适合脚本化、一次性问答,或者你只想让 Pi 快速给出结论。
3. JSON 模式:给其他程序消费
pi--mode json -p"Summarize this repository"JSON 模式会把 Agent 运行过程输出为结构化事件流,适合接入日志系统、可视化面板或自动化平台。
事件类型包括:
agent_start
turn_start
message_start
message_update
message_end
tool_execution_start
tool_execution_update
tool_execution_end
turn_end
agent_end换句话说,Pi 不只告诉你“最后答案是什么”,还会把“它经历了哪些步骤”暴露出来。
4. RPC 模式:把它变成长期运行的服务
pi--mode rpcRPC 模式通过 JSONL 的 stdin/stdout 通信。对平台型团队来说,这比“开一个终端给人用”更重要:你可以把 Pi 接到内部研发平台、代码审查机器人或任务调度系统里。
五、只读审查:一个更安全的入门姿势
第一次接触这类工具,不建议上来就让它自由改项目。
更稳妥的方式是只启用只读工具:
pi--tools read,grep,find,ls -p"Review this project"这个命令只允许 Pi 读取、搜索和列目录,不启用 edit、write、bash。
你可以先让它做这些事:
阅读项目结构,输出模块关系图。找出所有数据库查询入口,并检查是否有明显 N+1 问题。分析最近的 git diff,列出潜在风险,但不要修改文件。确认它理解项目之后,再逐步开放编辑和命令执行能力。
六、源码架构:Pi 不是一个单文件 CLI
从根目录 package.json 看,Pi 是一个 TypeScript monorepo,工作区包括:
{
"workspaces":["packages/*","apps/*"]
}当前源码包版本为 1.2.0,核心包可以按职责这样理解:
packages/coding-agent | @earendil-works/pi-coding-agent |
packages/agent | @earendil-works/pi-agent-core |
packages/ai | @earendil-works/pi-ai |
packages/tui | |
packages/chord | |
packages/durable | |
packages/telemetry | |
packages/codemode | |
packages/mcp | |
packages/env | |
packages/evals |
这个拆法说明 Pi 的目标不只是“做一个 CLI”。它把几件事分开了:
- 模型接入层
:屏蔽不同 LLM 供应商差异; - Agent 核心层
:处理消息、状态、工具调用和事件流; - 编码产品层
:提供面向开发者的 CLI、TUI、会话和工具; - 扩展层
:允许第三方注册工具、命令、快捷键、Provider、MCP Server; - 持久化层
:让会话不是一次性的聊天记录,而是可恢复、可分叉、可压缩的数据结构。
如果你想学习 Agent 工程化,最值得看的不是某个单点算法,而是这些边界是怎么划出来的。
七、核心实现原理:Agent Loop 是怎么转起来的?
Pi 的核心循环可以用一条流水线理解:
AgentMessage[]
→ transformContext()
→ AgentMessage[]
→ convertToLlm()
→ Message[]
→ LLM Streaming
→ Tool Calls
→ Tool Results
→ 是否继续下一轮这里有两个概念要分清。
1. AgentMessage 是 Pi 自己的内部消息模型
内部消息不直接等于某个供应商的 API 消息格式。
这样做的好处是:Agent 状态、工具调用结果、图片、thinking、使用统计等信息,可以先按 Pi 自己的模型保存;只有当真正要调用某个 LLM 时,才通过 convertToLlm() 转成对应供应商需要的格式。
这就是所谓的边界转换:
let messages = context.messages;
if (config.transformContext) {
messages =await config.transformContext(messages, signal);
}
const llmMessages =await config.convertToLlm(messages);这套设计避免了内部状态被某个供应商 API 绑死。
2. 工具调用不是“模型说了算”
模型返回工具调用请求之后,Pi 还会做工程校验:
收到 tool call
→ 校验参数是否符合 schema
→ 触发 beforeToolCall
→ 按配置顺序或并行执行
→ 触发 afterToolCall
→ 把 toolResult 写回消息历史这很重要。因为模型输出本质上是文本和结构化片段,可能不完整、不合法,甚至危险。成熟的 Agent Runtime 必须在模型和真实系统之间加一层“执行闸门”。
agent-loop.ts 中还有一个细节:如果模型因为长度限制停止,某些工具调用可能被截断。Pi 会拒绝执行这种“可能不完整”的工具调用。这个判断看似小,却是很多玩具 Agent 和工程化 Agent 的差别。
3. 一轮结束后,不一定真的结束
如果工具执行产生了结果,或者用户插入了 steering / follow-up 消息,Agent 会进入下一轮:
第 1 轮:模型决定读取文件
第 2 轮:根据文件内容决定修改方案
第 3 轮:执行测试
第 4 轮:根据测试失败结果修复
第 5 轮:输出总结这就是为什么它会给人一种“持续干活”的感觉。
本质不是魔法,而是:
模型输出动作 → 系统执行动作 → 动作结果重新成为模型上下文 → 模型继续决策。
八、CLI 启动时发生了什么?
packages/coding-agent/src/main.ts 的注释说得很直白:这个文件负责解析 CLI 参数,并把参数翻译成 createAgentSession() 的选项,真正重的活由 SDK 完成。
启动链路大致是:
解析 CLI 参数
→ 处理 auth / package / config / MCP 等子命令
→ 创建 SettingsManager
→ 创建、打开或 fork SessionManager
→ 解析项目信任状态
→ 创建 AgentSessionServices
→ 解析模型与工具
→ 创建 AgentSession
→ 进入 interactive / print / json / rpc 模式运行模式由参数和终端环境共同决定:
functionresolveAppMode(parsed: Args, stdinIsTTY:boolean, stdoutIsTTY:boolean): AppMode {
if (parsed.mode==="rpc") return"rpc";
if (parsed.mode==="json") return"json";
if (parsed.print||!stdinIsTTY ||!stdoutIsTTY) return"print";
return"interactive";
}这段逻辑很能体现产品设计:
人在终端里操作,就进入 TUI; 输出被管道接走,就自动进入 print; 明确指定 JSON/RPC,就进入程序化模式; 同一个 Agent 核心,被不同前端复用。
九、会话不是聊天记录,而是一棵树
很多聊天工具的会话是线性的:一条消息接一条消息。
Pi 的会话更接近 Git 分支。官方文档把它描述为一棵树,每条记录有:
interface SessionEntryBase {
type:string;
id:string;
parentId:string|null;
timestamp:string;
}一个会话文件是 JSONL,开头类似:
{"type":"session","version":3,"id":"uuid","timestamp":"2024-12-03T14:00:00.000Z","cwd":"/path/to/project"}后续消息通过 id 和 parentId 组成树。当前激活分支决定模型看到哪些上下文。
因此它可以支持:
/tree | |
/fork | |
/clone | |
/compact | |
pi --continue | |
pi --resume |
这个设计对真实开发很有意义。
比如你可以在一个节点分叉:
分支 A:让 Agent 用方案一重构
分支 B:让 Agent 用方案二重构然后对比结果,而不是让两条思路互相污染。
十、上下文工程:Pi 不只是“把全部历史塞给模型”
长任务最大的敌人是上下文窗口。
Pi 的解决思路包括几层。
1. 结构化 System Prompt
system-prompt.ts 会把系统提示拆成多个部分:
preamble; tools; rules; docs; addendum; project_context; skills; cwd; 自定义 section。
这比把所有提示词拼成一大段字符串更清晰,也方便扩展系统按需插入内容。
2. 项目文档发现
Pi 会发现 AGENTS.md、CLAUDE.md 等项目文档,把它们作为项目上下文的一部分。
这意味着团队可以把编码规范、目录约定、测试命令、禁止事项写进仓库,让 Agent 在进入项目时自动吸收。
3. Skills 按需加载
Skill 是一个包含 SKILL.md 的目录:
---
name: pdf-tools
description: Extract text and tables from PDF files. Use when reading, converting, or inspecting PDFs.
---Pi 不会把所有技能全文都塞进启动上下文,而是根据任务按需加载。这很像人类工程师:不是把所有手册背下来,而是知道什么时候去查哪本手册。
4. Prompt Templates 变成斜杠命令
一个 Markdown 模板可以变成可复用命令:
---
description: Review staged git changes
argument-hint: "[focus]"
---
Review the staged changes. Focus on ${1:-correctness, security, and error handling}.团队可以把常见审查流程沉淀成模板,减少每个人重复写提示词。
5. Compaction 不删除历史
当上下文接近窗口上限时,Pi 会追加压缩摘要。判断逻辑可以概括为:
contextTokens > contextWindow - reserveTokens默认值中:
reserveTokens = 16384
keepRecentTokens = 20000重点是:压缩不会删掉原始记录,而是追加一条摘要,并改变后续模型看到的上下文。原始会话仍然可追踪。
十一、扩展系统:Pi 真正的想象力所在
Pi 的扩展是 TypeScript 模块,在进程内加载。一个最小扩展可以这样写:
importtype { ExtensionAPI } from"@earendil-works/pi-coding-agent";
exportdefaultfunction (pi: ExtensionAPI) {
pi.registerCommand("hello", {
description:"Show a greeting",
handler:async (name, ctx) => {
ctx.ui.notify(`Hello, ${name ||"world"}!`,"info");
},
});
}扩展能注册的不只是命令,还包括:
自定义工具; 斜杠命令; 快捷键; CLI flag; 模型 Provider; MCP Server; 虚拟模型; 事件处理器; 终端 UI 渲染器。
这意味着 Pi 可以从“一个工具”长成“一个平台”。
比如团队可以写内部扩展:
接入公司私有模型网关; 注册代码规范检查工具; 把测试平台、需求平台接进来; 在 Agent 修改文件前后自动做安全扫描; 把会话事件同步到内部观测系统。
当然,能力越大,风险也越大。扩展在进程内运行,这意味着你必须像对待依赖包一样审查扩展来源。
十二、SDK:把 Agent 嵌进你自己的应用
如果你不想用 CLI,也可以用 SDK。
最小示例:
import { createAgentSession } from"@earendil-works/pi-coding-agent";
const { session } =awaitcreateAgentSession();
try {
await session.prompt("What files are in the current directory?");
console.log(session.getLastAssistantText());
} finally {
session.dispose();
}更底层一点,可以直接使用 pi-agent-core:
import { Agent } from"@earendil-works/pi-agent-core";
import { createModels } from"@earendil-works/pi-ai";
import { anthropicProvider } from"@earendil-works/pi-ai/providers/anthropic";
const models =createModels();
models.setProvider(anthropicProvider());
const model = models.getModel("anthropic","claude-sonnet-4-6");
const agent =newAgent({
initialState: {
systemPrompt:"You are a helpful assistant.",
model,
},
streamFn: models.streamSimple.bind(models),
});
await agent.prompt("Hello!");这时候,Pi 不再是一个终端命令,而是你应用里的 Agent Runtime。
十三、优点:为什么它值得关注?
1. 架构边界清楚
模型、Agent 核心、CLI、TUI、会话、扩展、遥测都拆开了。阅读源码时,你能清楚看到每一层的职责。
2. 工程细节比普通 Demo 完整
比如:
工具参数 schema 校验; 截断工具调用保护; 事件流; steering / follow-up; 会话树; compaction; SDK / JSON / RPC 多入口; 供应链安装加固。
这些内容决定了一个 Agent 能不能从 Demo 走向真实使用。
3. 终端体验足够自然
对习惯命令行的人来说,pi、!git status、@文件、/model、/tree 比不断切换网页或 IDE 面板更顺滑。
4. 可扩展性强
工具、Provider、MCP、Skills、Prompt Templates、Extensions 都给了入口。它既可以个人使用,也可以被团队改造成内部平台组件。
5. MIT License
对学习和二次开发都比较友好。
十四、缺点和风险:这部分一定要认真看
1. 它不是沙箱
官方安全文档说得很明确:Pi 没有内置一套用于限制文件系统、进程、网络或凭证访问的权限系统。默认情况下,它以启动用户和启动进程的权限运行。
这句话翻译成人话就是:
你能删什么、改什么、访问什么,它理论上也可能删什么、改什么、访问什么。
项目信任机制可以阻止不受信项目自动加载资源,但它不是沙箱。
2. 不要无人值守地跑在敏感目录
不建议直接在以下环境开放完整工具能力:
生产服务器; 含私钥、凭证、客户数据的目录; 未审查的第三方仓库; 无人值守的自动化任务。
如果一定要做,优先使用容器、虚拟机或操作系统级隔离。
官方给出的 Docker 思路大致是:
FROM node:24-bookworm-slim
RUNapt-get update \
&&apt-get install -y--no-install-recommends bash ca-certificates git ripgrep \
&&rm-rf /var/lib/apt/lists/*
RUNnpm install -g--ignore-scripts @earendil-works/pi-coding-agent
WORKDIR /workspace
ENTRYPOINT ["pi"]运行时只挂载必要目录:
docker run --rm-it\
-e ANTHROPIC_API_KEY \
-v"$PWD:/workspace"\
-v pi-agent-home:/root/.pi/agent \
pi-sandbox3. 成本与效果取决于模型
Pi 的框架再好,也不能让弱模型凭空变强。复杂任务的效果仍然取决于:
模型能力; 上下文质量; 工具设计; 项目文档; 用户拆解任务的方式。
长任务还可能产生不低 token 成本。
4. 项目迭代很快
高活跃度是优点,也意味着 CLI 参数、SDK API、扩展接口和文档可能持续变化。用于生产系统时,建议锁定版本并保留回归测试。
5. 学习曲线存在
如果只是想“问一句、改一行”,Pi 可能显得比普通聊天机器人复杂。它更适合真正需要项目级操作、自动化和扩展的人。
十五、推荐的上手路线
我建议按四步走。
第一步:只读模式
pi--tools read,grep,find,ls -p"Review this project"先让它读项目、讲架构、找风险,不给写权限。
第二步:小范围修改
在一个干净 Git 分支上运行:
git checkout -b pi-test
pi然后给它一个小任务:
把 src/utils 下重复的时间格式化逻辑抽成公共函数,并补充测试。要求它先给计划,再修改。
第三步:引入项目规范
在仓库里写 AGENTS.md,例如:
# Project Rules
- 修改代码前先阅读相关模块。
- 不修改 generated/ 目录。
- 完成后运行 `npm test`。
- API 变更必须同步更新 docs。让项目规范进入上下文,而不是每次口头重复。
第四步:需要自动化时再接 SDK / RPC
当你确认它在自己的工作流里稳定后,再考虑:
用 SDK 嵌入内部工具; 用 JSON 模式做日志和审计; 用 RPC 模式接入平台; 用扩展系统接入私有模型和内部工具。
十六、它适合谁?
适合:
经常在终端里工作的开发者; 想研究 Coding Agent 内部实现的人; 想把 Agent 嵌入自己产品的人; 需要会话分叉、恢复、导出和审计的人; 想基于 MCP / Skills / Extensions 做内部平台的人。
不太适合:
完全不想接触命令行的人; 只需要简单代码补全的人; 无法承担模型 API 成本的人; 希望在生产环境“不设防”运行 Agent 的人。
结语:Pi 最值得学的,不是“它会写代码”
AI 编程工具越来越多,单看“能不能生成代码”,差异正在缩小。
真正拉开差距的是:
上下文怎么组织; 工具调用怎么校验; 会话状态怎么持久化; 长任务怎么压缩; 人机介入怎么设计; 扩展系统怎么控制边界; 安全风险怎么被诚实说明。
Pi 的价值就在于,它把这些关键部分都摆在了源码里。
你可以只把它当成一个终端 AI 编程助手;也可以更进一步,把它当成一份正在快速演进的 Agent 工程教材。
如果你最近想认真理解“AI 编程工具到底怎么做出来的”,这个项目值得 clone 下来,从 coding-agent、agent、ai 三个包开始读。
参考资料
Pi GitHub 仓库:https://github.com/earendil-works/pi 项目 README:https://github.com/earendil-works/pi/blob/main/README.md CLI 文档:https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/cli.md 使用文档:https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/usage.md 会话格式:https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/session-format.md Compaction 文档:https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/compaction.md 扩展系统:https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/extensions.md Skills 文档:https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/skills.md 安全说明:https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/security.md 容器化运行:https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/containerization.md SDK 文档:https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/sdk.md
写在最后:如果这篇文章对你有帮助,欢迎转发给正在研究 AI 编程、Agent 架构或终端工作流的朋友。工具会不断更新,但这些 Agent 工程化的底层问题,值得我们反复拆开看。















































































