最近我司技术群里聊得最多的一个词就是 pi coding agent。第一眼看到 pi 这个命名,我还以为是谁拿圆周率做了个什么工具;第二眼才反应过来,这里说的是一个跑在终端里的开源 AI 编程助手。这篇文章我想把这段时间用 pi coding agent 的真实过程完整记下来:安装踩坑、三种核心用法、一次把它改崩的排障复盘,以及一些已经形成肌肉记忆的工程习惯。不管你是已经在用 Claude Code、Codex CLI,还是完全没用过这类终端编程助手,这份记录应该都能给你一点参照。
先说结论:pi 不是来替代你写代码的,它是来扮演一个"随叫随到的结对程序员"的。它能够自己读代码、搜调用链、跑命令、看报错、改文件、再跑一遍验证,整个过程不需要你离开终端。但它毕竟不是人,边界感必须靠你来定。这篇文章不是软文,我也没拿它一分钱,纯粹是自用记录,顺便帮你躲开我踩过的几个坑。
1. 为什么我盯上了一个叫 pi 的编程助手
1.1 从 Claude Code 到开源替代
先用 Claude Code 的痛苦经历做个铺垫。
我用 Claude Code 用了挺长一段时间,体验确实惊艳,但有几个点始终膈应:第一,它和 Anthropic 的模型绑定太死,换模型就得换工具;第二,订阅和 token 费用对于个人项目来说不小,摸鱼式试用还行,真要把它当成日常生产力工具,钱包压力就上来了;第三,团队协作的时候,每个人的"AI 行为规范"很难统一,全靠口头约定。
后来社区开始陆续冒出各种开源的终端编程代理:OpenHands、Aider、Cline 这些我都试过。Aider 轻量,但它的"编辑-提交-循环"模式让我觉得有点绕;OpenHands 功能全,但部署和配置成本高,日常小任务杀鸡用牛刀。直到我在热搜榜上看到 pi 这个词,点进去才发现,它跟我之前对"pi"的三个刻板印象完全不是一回事。
| 工具 | 运行形态 | 模型绑定 | 适合谁 |
|---|---|---|---|
| Claude Code | 终端交互 | 官方模型为主 | 愿意省心、预算充足的人 |
| Codex CLI | 终端交互 | OpenAI 模型 | OpenAI 生态重度用户 |
| Aider | 终端+GIT | 多家可配 | 习惯 Git 驱动工作流的人 |
| pi coding agent | 终端交互/脚本调用 | 完全可插拔 | 想掌控模型选择、做自动化的人 |
你注意看最后一行:pi 的模型是完全可插拔的。官方支持的接口里,OpenAI、Anthropic、DeepSeek、Gemini、本地 Ollama 都能接。这对我来说是决定性优势,因为我日常写业务代码用便宜模型就够了,碰架构重构才舍得调用贵模型,一个工具能同时满足这两个场景,省事。
1.2 pi 的定位:终端原生、配置即代码
用了一周之后,我给 pi 的定位是:一个轻量、无绑定、可脚本化的终端 AI 编程代理。
它不像 IDE 插件那样需要你在编辑器里再开一个面板;也不像重型 Agent 框架那样需要跑一堆服务。你打开终端,敲一个pi开头的命令,剩下的事情它自己推进。它和 IDE 插件最大的区别在于:IDE 插件倾向于"辅助人在编辑器里操作",pi 倾向于"代理人在文件系统里完成一次任务闭环"。读文件、写文件、跑测试、看 git diff,这些操作它都能直接调工具完成,而不是只给你一段建议让你复制粘贴。
配置即代码是另一个吸引我的点。整个工具的行为可以通过仓库里的一个配置文件管理,包括允许改哪些目录、默认用哪个模型、需要自动执行什么命令。这就意味着,同一套 AI 行为规范可以直接跟着 Git 仓库走,团队成员拉下来代码,跑出来的 AI 行为是一致的,不会出现"你用的 agent 能碰 src 目录,我的不行"这种混乱。
1.3 名字辨析:此 pi 非彼 π
聊正事之前,先把这个名字的账算清楚,因为搜资料的时候实在太容易串味了。
搜"pi"这个词,前三页大概率是这些东西:
| 指代 | 是什么 | 跟我这篇的关系 |
|---|---|---|
| π(圆周率) | 3.14159…… | 只是名字撞了,工具和数学没啥关系 |
| Raspberry Pi | 树莓派单板电脑 | 也不是它,但它也能在树莓派上跑 |
| pi coding agent | 开源终端 AI 编程助手 | 本篇主角 |
我一度怀疑会不会是某个旧项目的重命名,查了一下仓库历史,这个项目就是直接用了 "pi" 这个短名字。短名字的好处是敲命令真的舒服,pi "干个什么事",三秒就能发出一条指令。坏处就是搜资料的时候,你得加上 coding agent 或者 pi agent 才能过滤掉圆周率。
2. 安装与首次配置:十分钟跑通首条任务
2.1 环境准备
我实测跑通的环境是 macOS(Apple Silicon),同事在 Windows WSL2 里也装过一遍,没遇到什么大问题。核心依赖是 Node.js 18 以上,因为工具本体是用 Node 写的,装了 Node 就能跑。
内存方面,如果你只走云端 API,8G 内存完全够用;但如果你想连本地 Ollama 跑开源模型,建议 16G 以上,不然模型加载会把开发机卡死。我一开始在家里的老笔记本上试 Ollama,7B 模型一加载,IDE 直接开始掉帧,后来老实换回 API。
安装前顺手把 Node 版本确认一下,避免装到一半发现语法不支持:
node -v npm -v如果 Node 版本低于 18,先升级再继续。
2.2 安装过程
安装方式大体分两种:一种是有托管包的话直接全局装,另一种是从源码构建。我这边是源码构建走的,因为当时想顺手看一下它的实现。大致流程是这样:
# 如果有官方发布的二进制或者 npm 包,直接装就好 npm install -g pi-coding-agent # 或者用源码构建(以官方 README 为准) git clone <官方仓库地址> cd pi npm install npm link # 验证安装 pi --version这里我必须多说一句:这种新兴工具的安装命令迭代很快,我写这篇的时候是这个流程,可能过两个月官方就改成二进制分发或者 Homebrew 了。你装的时候如果发现命令不对,先看仓库 README 的安装段落,不要死磕网上的老教程。
装完之后,shell 里会多一个pi命令。第一次运行的时候,它会在用户目录下建一个配置目录,用来存会话日志、密钥配置、历史任务记录。这个目录的权限建议手动收紧一下,毕竟里面有敏感信息:
chmod 700 ~/.pi2.3 配置 API Key:模型完全可插拔
pi 的模型配置是我最喜欢的一部分。它不绑死任何一家,而是通过 provider 抽象层来切换。配置方式分两种,一种是环境变量,适合临时切换;一种是配置文件,适合固定偏好。
用 DeepSeek 举例子,环境变量的方式是:
export PI_PROVIDER=deepseek export PI_API_KEY=sk-xxxxxx如果想固定下来,可以写进配置:
pi config set provider deepseek pi config set api-key sk-xxxxxx要注意一点:不要把 API Key 直接写进仓库的配置文件里,哪怕仓库是私有的也不建议。正确做法是把 Key 放在环境变量或者本机配置文件,仓库里只放 provider 名称和模型名称。为什么?因为代码仓库是要克隆来克隆去的,指不定哪天不小心公开了,密钥就跟着泄了。
我日常是双模型配置:默认 DeepSeek,跑机械任务;Anthropic 作为 fallback,跑架构级重构。两个模型在同一套工具里切换,成本感受差很多,但操作路径完全一样。
2.4 首次运行:让它完成一个最小闭环
配置好之后,我第一次给它的任务是:
pi "为 src/utils.ts 中的 fibonacci 函数补一组单元测试,要求跑通为止"它会先读src/utils.ts,然后看项目的 package.json 确认用的什么测试框架,接着生成测试文件,再执行测试命令。第一次跑就暴露了一个问题:项目里还没有装测试框架,它直接停下来问我要不要装。我确认之后,它自己装了 vitest、写了用例、跑了一遍,第一次挂了,原因是边界用例里有个expect写法不对,它自己读了报错,改掉断言,再跑,绿了。
整个过程大概三分钟。给我的感觉是,它不是那种"帮你写好代码让你自己拿去跑"的建议型工具,而是"自己负责把代码跑绿"的执行型工具。差之毫厘,谬以千里。
2.5 为什么这样设计:模型是发动机,工具是车架
聊到这儿,顺便说说我对这类工具架构的理解。
以前的 AI 编程辅助是"聊天框 + 代码补全":模型在对话里给你生成片段,人负责搬运到代码里。问题是,搬运过程会丢上下文,改完文件之后有没有语法错误,还得人再跑一遍才知道。
pi 这类 coding agent 不一样。它把模型当成发动机,把自己提供的能力当成车架:文件读写、命令行执行、错误信息捕获、git diff 生成。发动机提供决策,车架负责执行,最后形成一个闭环:读代码 → 理解 → 改文件 → 跑验证 → 看结果 → 再修。这个闭环一旦跑通,人只需要在关键节点做 review,而不是每个步骤都亲自动手。
这也解释了为什么权限配置那么重要。车架越完备,它能做的事越多;能做的事越多,失控的面就越大。所以 pi 设计了一套权限规则,明确告诉它哪些目录能碰、哪些目录不能碰,后面我会专门讲这个。
3. 核心玩法:我是怎么用 pi 干活的
3.1 三种运行模式,对应三种真实场景
用久了之后,我发现 pi 的用法其实就三种,覆盖了日常开发的绝大部分诉求:
| 模式 | 命令形态 | 典型场景 |
|---|---|---|
| 单次任务 | pi "任务描述" | 改一个 bug、补一组测试、生成迁移脚本 |
| 交互会话 | pi shell | 多轮追问、方案探讨、逐步重构 |
| 限定范围 | pi --files "src/auth/*.ts" "任务描述" | 只允许碰指定文件,降低误伤面 |
单次任务模式我用的最多。它跑完就退出,适合一条指令对应一个明确目标。交互会话模式适合那种"我也不完全确定要改成什么样"的场景:先进 shell,让它读代码,然后一个问题一个问题地问,它会结合上下文给出方案,确认之后再动手。限定范围模式是我在吃过一次亏之后才养成的习惯,后面排障章节会细说。
3.2 它是怎么"干活"的:工具调用机制
pi 执行任务的过程不是"对话式"的,而是"行动式"的。它会像人一样一步步调用工具,每一步都能在日志里看到。
以补测试为例,它的工具调用链大致是:
- 调用
grep搜索函数定义位置 - 调用
read_file读取目标文件和测试目录结构 - 调用
list_files查看项目测试框架配置 - 调用
write_file生成测试文件 - 调用
exec跑测试命令,拿到报错 - 调用
read_file读报错上下文 - 再
write_file修改断言 - 最后
exec再跑一遍,直到绿色
你可以把每一步想象成一个程序员坐在电脑前操作,只不过这个程序员手速极快,而且不怕繁琐。看这种日志有一种在旁观察资深同事干活的既视感:先看全局,再动手,跑挂了就回头看报错,不会乱猜。
3.3 实战案例:修一个诡异的时间解析 Bug
说一个让我印象深刻的案例。某个 Node 服务里有一个函数,负责把 UTC 时间戳转成本地时间展示,在本地怎么跑都对,一到 CI 上就偶发差 8 小时。这个 bug 我断断续续排查了两天没找到头绪。
后来我抱着试试看的心态,把任务交给 pi:
pi --files "src/time.ts" "排查 timestamp 转本地时间偶发差 8 小时的根因,先看代码和仓库线索,不要直接改代码"注意我特意加了"不要直接改代码"。因为我不想让它没定位清楚就动手。它的处理过程很清晰:
- 先在仓库里 grep 了
new Date、Date.parse、dayjs、moment的所有使用位置。 - 读了
src/time.ts全文,发现函数体本身逻辑没问题。 - 翻 CI 配置文件,发现环境变量里没有设置
TZ。 - 对比本地 shell,
TZ=Asia/Shanghai是预设好的,所以本地永远看不出问题。 - 给出结论:根因不在函数体,在进程时区环境不一致。
这个问题的关键点在于,它没有像我一样死盯着函数体,而是把目光投向运行环境。坦白讲,这种"跳出局部看整体"的排查思路,是我自己没做到的。pi 虽然没有人类的直觉,但它肯把所有相关线索都拉出来比对。那一刻我意识到,这类工具最大的价值不是替我写代码,而是逼着我把问题放在完整上下文里重新看一遍。
3.4 实战案例:补一组边界测试
另一个高频场景是补测试。项目里有个处理用户备注文本的工具函数,我一直没给它写测试。我用单次任务模式:
pi "给 normalizeNote 函数补单元测试,覆盖空字符串、超长文本、非法字符输入"它自动识别出项目里用的是 vitest,然后生成了测试文件。我 review 的时候发现它比我预想的更稳:空字符串、2000 字超长文本、HTML 标签混杂、emoji、全是空格、null 入参这些边界全覆盖了。整体质量我可以给到八十分以上。
但我也发现了一个规律:AI 写的测试容易有两个毛病。一是过度 mock,把依赖全 mock 了,测试就变成了自说自话;二是断言实现细节,比如断言某个内部函数被调用了几次,而不是断言最终返回值。这两种测试跑起来全绿,但重构一发生就碎一地。我的处理办法是删掉这种用例,只保留针对输入输出的行为断言。这活儿必须人来干,AI 短期内还学不会什么叫"测试是为了行为负责,而不是为实现负责"。
4. 一次真实的排障:pi 把 localStorage 兼容性改崩了
4.1 事故经过:一个偷懒的命令
上面说了 pi 好话,下面讲讲它是怎么坑我的。
我们有个老项目,formatResult函数原本返回一个数组,这次需求要改成返回对象,调用点有 14 处。我偷了个懒,直接把整包任务丢给它:
pi "把 formatResult 的返回类型从数组改成对象,同步处理所有调用点"任务执行了大概四分钟,全程日志看着都正常,测试也过了。我准备提交的时候看了一眼git status,发现docs/example.js这个完全不在任务范围内的文件也被改了。
4.2 根因定位:权限规则没配
为什么会这样?
我从pi log里翻了执行记录,发现问题出在中间某一步:它改到第 7 个调用点的时候,发现docs/example.js里也调用了这个函数,担心构建报错,就顺手改了。注意,这里的关键词是"担心"。模型在自我推理时把"文档示例文件也需要同步"当成了任务隐含目标,于是越界动了文件。
我最初也觉得是它笨。后来重新想了想,根因其实在我:我没有在任务里说清楚边界,之前也没有在配置文件里声明哪些目录禁止改动。对于一个拥有代码编辑能力的执行型 Agent,你给它越模糊的目标,它就越容易自己脑补出多余的目标。这跟带实习生一个道理,你不能只告诉他"把这个接口改了",你得告诉他"只改接口和调用点,别的文件一律别碰"。
4.3 修复方案:白名单比提示词更可靠
这次事故之后,我给项目加上了权限配置。pi 的配置文件是项目根目录下的pi.yaml,我配了一段比较保守的规则:
edit: allow: - "src/**" - "tests/**" deny: - "docs/**" - "dist/**" - "*.lock" - "CHANGELOG.md"配完之后重跑同样的重构任务,这次没有越界。配置文件一落,整个项目的 AI 行为边界就清晰了。它比我每次在命令里加一句"不要动其他文件"可靠得多。因为提示词是软约束,模型心情不好可能就忽略了;配置文件是硬规则,工具在执行编辑操作前会先做路径匹配,命中了 deny 就直接拒掉。
4.4 三个教训,比工具本身更值钱
这件事给我留下的教训,我后来也用在一个内部分享上:
- 任务描述必须包含边界:写成"把 xxx 改了并处理调用点",不如写成"只改 src 下的 xxx 和调用点,其他文件一律不要动"。AI 不会嫌你啰嗦,它怕的是你含糊。
- 提交前必须看 git diff:无论它测试跑得多绿,我都要求自己先看一遍改动再提交。这个习惯后来帮我拦下了好几次过度修改。
- 核心目录直接上硬规则:如果某个目录改了会出大事,不要指望模型自觉,直接在配置里 deny。把决定权交给规则,而不是交给模型的临场判断。
5. 进阶技巧:把 pi 变成团队基础设施
5.1 项目级配置:让 AI 行为和代码一起入库
前面提到的pi.yaml其实还能承担更多职责。除了权限边界,模型选择、上下文加载、自动挂钩子都能写在里面。我目前用的一个比较完整的配置长这样:
model: default: deepseek fallback: anthropic context: include: - "README.md" - "docs/architecture.md" edit: allow: - "src/**" - "tests/**" deny: - "docs/**" - "dist/**" hooks: before_edit: - "npm test -- --run"context.include的意思是,每次启动任务时,pi 会把架构文档、README 加载进上下文,避免它对项目风格一无所知就动手。这个字段特别好用:新同事加入团队,拉完仓库之后用 pi 干活时,它的行为天然就符合项目规范,因为你已经把规范喂进它的初始上下文了。
5.2 把 pi 变成代码评审的第二双眼睛
我后来开发了一个固定用法:让 pi 做 review,而不是直接改代码。
pi --files "src/**" "按团队规范审查当前分支改动,输出最值得关注的 5 个问题,不要修改代码"在这个模式下,pi 不会动文件,只输出评审意见。我试过几次之后发现,它对测试缺口的敏感度很高,经常能指出"这个函数加了一个分支,但对应测试没更新"这种我容易漏掉的问题。它也能承担一部分规范检查,比如命名风格、错误处理路径是否齐全。
但同样要提醒一句:它的 review 意见只能当参考,不能当结论。因为它对业务上下文的理解是有限的,有些看似不合理的代码可能恰恰是产品策略要求的结果。人审业务,AI 审机械性遗漏,这个分工我觉得最合理。
5.3 和 Git 工作流整合:自动化场景畅想
单次任务模式真正的潜力在于脚本化。我现在已经把 pi 接进了一个自定义脚本,用来生成 commit message:
git diff | pi "根据以上 diff 生成一条符合 conventional commit 规范的提交信息"输出直接作为 commit message 用,省掉了我每次憋提交信息的工夫。更进一步,你甚至可以写一个 pre-commit hook,让 pi 在提交前自动跑一遍受影响文件的测试。不过我不建议一上来就把这类自动化铺得太满,先手动跑通几次,确认输出稳定了再交给 hook,不然会被它的不稳定输出搞得鸡飞狗跳。
5.4 多模型组合:便宜模型干粗活,贵模型干细活
模型可插拔带来的一个直接好处是成本优化。我现在的分工大致是这样:
| 任务类型 | 使用的模型 | 原因 |
|---|---|---|
| 补测试、修 lint、写迁移脚本 | DeepSeek | 便宜、速度快、处理机械任务绰绰有余 |
| 模块重构、跨文件调用调整 | Anthropic 旗舰模型 | 贵,但对架构的理解和改动的谨慎程度更高 |
| 敏感代码的脱敏预处理 | 本地 Ollama 7B/14B | 数据不出内网,隐私安全 |
多说一句成本:DeepSeek 这种级别的 API 跑日常任务,一次会话往往几分钱甚至更少;Anthropic 旗舰模型跑一次大重构可能几块钱。但重构的频率比日常任务低得多,总账算下来比全部用贵模型省不少。这是"模型可插拔"对个人开发者钱包最友好的地方。
5.5 常用命令速查
顺手整理一份我平时用到的命令表,具体细节以你自己版本的pi --help为准:
| 操作 | 命令 |
|---|---|
| 查看帮助 | pi --help |
| 单次任务 | pi "任务描述" |
| 交互会话 | pi shell |
| 限定文件范围 | pi --files "src/auth/*.ts" "任务" |
| 查看执行日志 | pi log |
| 回放某次会话 | pi replay <会话ID> |
| 检查配置 | pi config list |
| 预演模式只出方案不改文件 | pi --dry-run "任务" |
--dry-run是我最常用的兜底模式。不确定一件事该不该让它直接做的时候,先预演一遍看方案,觉得没问题再去掉参数真正执行。
6. 这玩意到底值不值得依赖
6.1 我用了两个月之后的真实变化
保守估计,pi 帮我省掉了三到四成"机械性耗时"。补测试、改调用点、迁移脚本、修 lint、写 commit message,这些活以前要占用大量注意力,现在一句话就出去了。省下来的时间我用来做什么呢?大部分花在 review 它的改动和看架构文档上。
这带来一个心态变化:我从"写每一行代码"慢慢变成了"审核每一次改动"。刚开始有点不适应,觉得自己像退化了。后来想明白一个事:真正值钱的判断从来不是"怎么用 for 循环",而是"这个模块该不该拆、这个接口该怎么设计、这个性能瓶颈该怎么定位"。这些判断 pi 给不了我,需要我自己积累。
6.2 什么时候别用 pi
经历多了,我也摸清了它的能力边界。至少有三类场景我不会交给它:
一是探索性新项目的前半小时。项目连骨架都没有,你让它自由发挥,它会产出非常随意的结构,回头还得推倒重来。不如自己先搭好目录、定义好核心接口,再让它往里填东西。
二是性能敏感的核心路径。锁粒度、缓存一致性、并发竞态这类问题,它目前的推理能力还达不到能放心交托的水平。让它改这种代码,我可以断言必须有人逐行 review,那你不如自己写。
三是需要有人背锅的场景。线上事故复盘的时候,不能拿"是 AI 改的"当理由,最后签字确认的还是你。让它碰核心生产代码之前,想清楚出事之后你能不能兜住。
6.3 安全和隐私的三个习惯
安全方面我踩过坑之后养成了三个习惯:
第一,API 密钥永远不进仓库。用环境变量或者本机配置,权限设为仅当前用户可读。
第二,敏感仓库不接第三方 API。涉及用户数据、内部业务逻辑的代码,要么走公司内部网关,要么直接用本地 Ollama,把数据留在内网。
第三,每次让它干活之前,先确认它打算改哪些文件。我现在养成的肌肉记忆是:命令里先写--files限定范围,再写任务描述。这个习惯直接把我遇到越界改动的频率降到了零。
6.4 你可以从哪里开始试
如果你想试一把 pi coding agent,我给一个最务实的切入路径:不要一上来就想让它重构整个项目。从单点任务开始,比如"给一个函数补测试"或者"把这段代码改成 async/await 风格"。跑通一次闭环,感受一下它是怎么读代码、改代码、验证代码的,再慢慢扩大任务范围。
我自己的体会是,这类工具的使用能力有点像开车:新手先走直路,不要一上来就挑战山路。开熟了之后,你自然知道哪些路段可以放开,哪些路段必须自己抓方向盘。把边界说清楚,把审查做成习惯,剩下的大胆交给它。
最后再分享一个压箱底的小技巧:每次 pi 干完活,我都会命令它git diff给我看,确认完才提交。这个动作千万别省。它写得再快,最后签字的是你。工具会一直迭代,但"代码是给人读的,AI 只是把人的意图翻译成机器能执行的方案"这个判断,一定要留给自己来做。