乐于分享
好东西不私藏

想学 Agent 又不知道看什么源码,我决定拆 Pi

想学 Agent 又不知道看什么源码,我决定拆 Pi

上一篇把 Codex 修 Bug 的过程拆开以后,Agent Loop 这件事,我算是有了一点具体的感觉。

模型先看任务,再决定要不要读文件、跑命令;工具执行完,结果重新交给模型;模型拿着新的信息,继续判断下一步。这个过程说清楚以后并不复杂。

问题是,真让我自己从一个空目录开始写,我还是不知道该从哪里下手。

模型怎么接?工具放在哪里?消息来回传的时候,状态又是谁管的?

这些问题靠画图还能继续讲,但再往下讲,估计连我自己都会觉得有点虚。我需要找一个已经跑起来的项目,看看别人到底是怎么把这些东西接到一起的。

我前后翻了几个 Agent 项目,最后留下的是 Pi,github地址在这:https://github.com/earendil-works/pi

我写这篇时,它大约有 7.9 万个 Star。这个数字当然很显眼,也会让人下意识觉得:这么多人关注,拿来学应该不会错。

但我没有马上决定用它。

因为项目很火和适合初学者拆是两回事。有些 Agent 项目首页看着很完整,点进源码却会发现里面同时放着工作流、知识库、多 Agent、监控、评测和各种模型适配。功能确实多,可我现在连最基本的循环都刚弄明白,进去以后大概率只是在目录之间来回跳。

我想找的项目不用什么都有,但最好能让我看到一条完整的线:底下怎么调用模型,中间怎么让 Agent 跑起来,最外面又是怎么变成一个真正能用的程序。

Pi 的仓库刚好能顺着这条线往下看。

我原本以为 Pi 就是另一个 Codex

刚知道 Pi 的时候,我把它理解成一个终端里的 Coding Agent。安装以后输入 pi,然后就可以让它读代码、改文件、运行命令。

这个理解也没错,只是说的是最外面那一层。

翻仓库时,我看到它把几个核心包分开了:

pi-ai
pi-agent-core
pi-coding-agent
pi-tui

名字看着有点多,不过顺着一次实际使用过程想,就没那么绕了。

我们在终端里直接使用的是 pi-coding-agent。对话、会话、文件操作,还有执行命令这些功能,最后都在这里组成了一个可以运行的 Coding Agent。

继续往里看,会碰到 pi-agent-core。它负责 Agent 运行时、工具调用和状态。上一篇反复提到的那个循环,主要就在这一层发生。

再下面的 pi-ai 用来处理不同模型的调用。OpenAI、Anthropic、Google 的接口各有差异,上层如果每接一个模型都自己适配一遍,很快就会变得很乱,所以 Pi 单独做了一层。

pi-tui 比较好理解,它管的是终端界面。

我现在脑子里的关系大概是:

pi-coding-agent     最后拿来使用的 Coding Agent
        ↓
pi-agent-core       让 Agent 和工具循环起来
        ↓
pi-ai               和不同模型打交道

pi-tui              把交互显示在终端里

这也是我最后选 Pi 的主要原因。它有成品,可以先跑起来看看;里面的关键部分又没有全搅在一起。以后写到模型调用,就去对照 pi-ai;自己开始写 Agent Loop,再去看 pi-agent-core

不需要现在就把整个仓库读一遍。

还有一个细节我挺喜欢。Pi 默认给 Coding Agent 的工具只有四个:readwriteedit 和 bash

读文件、写文件、修改文件、执行命令。

数量不多,但已经足够完成不少编程任务。正因为工具少,第一次观察它时,反而容易看清模型为什么选这个工具、工具结果回来后又做了什么。要是一上来就有几十个工具,我估计又会把注意力放到功能列表上。

先别读源码,我决定把它跑起来

仓库结构大致看完后,我本来想直接打开 pi-agent-core

后来还是忍住了。

一个程序连实际界面都没见过,就开始追它的状态和事件,很容易把自己追晕。先用一次,至少以后在源码里看到某个工具调用时,知道它最后会出现在什么地方。

Pi 可以直接通过 npm 安装:

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

装好以后,可以先确认一下版本:

pi --version

注意最好node版本要 >= 22.19.0才能安装最新的pi版本

接着进入准备好的实验目录,输入 pi,按照界面提示输入apikey,就可以接入AI模型了,我这次选择的是接入deepseek的api。

更具体的环境配置可以直接参考 Pi 的官方文档:(https://github.com/earendil-works/pi/blob/main/packages/coding-agent/README.md),这里不展开。

第一次就让它做件很小的事

环境准备好以后,我单独建了一个实验目录,没有直接拿现有项目来试。

这么做还有一个原因。Pi 在仓库说明里专门提醒过,它默认没有一套内置的权限系统去限制文件、进程、网络或者凭据访问。它能做什么,很大程度上取决于启动它的用户本来就有什么权限。如果需要更严格的边界,要另外使用容器或者沙箱。

这一点和我平时使用 Codex 时看到的权限确认不太一样。

第一次尝试没必要上来就挑战真实项目。目录里放一个测试文件,跑错了也没什么损失。

我准备的 input.txt 内容如下:

这是我第一次运行 Pi。

这次实验只验证三件事:
1. Pi 能读取当前目录里的文件;
2. Pi 能根据文件内容完成一个简单任务;
3. Pi 能在当前目录创建一个新文件。

DeepSeek 接好以后,接下来要发给 Pi 的任务是:

读取当前目录里的 input.txt,把内容整理成 summary.md。summary.md 需要包含一个标题和三条要点,不要修改 input.txt。完成后告诉我你使用了哪些工具。

这次不考验模型能不能写出多好的总结。我只想看它会不会先调用 read,拿到文件内容后再调用 write,最后把文件留在当前目录。

整个过程非常顺利,也符合我们的预期,我发现pi的速度非常快,几乎我刚发送他就秒回我并且完成任务了,没有过多的思考。

接下来才轮到源码

选定 Pi,并不等于下一篇就要冲进 pi-agent-core 逐行读代码。

我现在只知道它大致分成哪几层,也把程序装了起来。真要看懂 Agent Loop,还得先把最底下那件事补上:一次普通的模型调用,究竟传了哪些消息,又拿回了什么。

所以下一篇我准备先不碰工具,只写一个最小的模型调用。

等我自己把 System Prompt、用户消息和模型输出接起来,再回头看 pi-ai,里面很多代码应该才会从“项目作者的写法”,变成我能对照着理解的东西。