核心架构:一个循环解决所有问题
Pi的开发者Armin Ronacher和Mario Zechner做了一个关键判断——现代顶尖大语言模型(如Claude Sonnet)已经具备足够的推理和工具使用能力,框架层面不需要再做复杂的编排。基于这个判断,Pi的核心代码就是一个while循环,位于 packages/agent/src/agent-loop.ts:
循环逻辑可以拆解为四步:
- 把用户消息发给LLM
- LLM返回"我要用工具" → 执行工具 → 把结果返回给LLM
- LLM继续思考,可能还要调用工具 → 重复步骤2
- LLM返回"我完成了" → 检查有没有新的用户消息 → 有就继续,没有就结束
没有状态机,没有DAG,没有递归调用。整个Agent的行为完全由LLM自身的推理能力驱动,框架只负责"对话-执行-反馈"这个最小闭环。
四个工具,覆盖全部操作
在 packages/coding-agent/src/core/tools/index.ts 中,Pi只定义了四个核心工具:
| 工具 | 功能 | 用途 |
|---|---|---|
| read | 读取文件内容 | AI需要了解代码现状 |
| bash | 执行shell命令 | 运行git、npm、测试、grep、find等 |
| edit | 精确修改文件(查找替换) | 修改现有代码 |
| write | 写入新文件 | 创建新文件 |
这里最值得注意的是bash工具的设计思路。Pi的哲学是"Bash就是你所需要的一切"——通过bash,AI可以调用grep、find、ls、git、npm,整个Unix工具链都成为Agent的能力延伸。不需要为每个功能单独封装一个工具,让LLM自己组合系统已有的命令行工具。
这个设计遵循的是经典的Unix哲学:每个工具做一件事,通过组合完成复杂任务。对独立开发者来说,这意味着你不需要花大量时间开发自定义工具——先看看系统里已经有什么。
技能系统:文档即能力
Pi大约25%的系统提示词用于"元文档"——教AI如何扩展自己的能力。这通过Skill系统实现,代码在 packages/coding-agent/src/core/skills.ts。
工作流程是这样的:
- 启动时:Pi扫描指定目录下的所有SKILL.md文件
- 系统提示词中:只告诉AI有哪些技能可用(名称+描述),不包含详细内容
- 按需加载:当任务匹配某个技能描述时,AI主动用read工具读取完整的SKILL.md
- SKILL.md内容:包含具体操作步骤、脚本命令、示例
一个典型的SKILL.md可能长这样:
Usage
./extract-text.js <input.pdf> # Extract text
./extract-tables.js <input.pdf> # Extract tables
这个设计有两个精妙之处。第一,"渐进式披露"——系统提示词里只放索引信息,详细内容按需加载,避免token浪费。第二,热重载——Skill就是Markdown文件,修改后AI下次读取时立即生效,没有注册流程,不需要重启。编写即用,修改即生效。
转向队列:实时干预正在执行的Agent
这是Pi最有特色的交互设计,位于 packages/agent/src/agent.ts。
设想一个场景:AI正在按计划执行一系列操作(工具A → 工具B → 工具C),你发现它走错方向了,发送一条消息"等等,不要用那个方法"。Pi设计了两种队列来处理这种情况:
- 转向队列(steer):当前工具执行完后,立即处理你的消息,跳过剩余计划中的工具调用
- 后续队列(followUp):等AI这一轮完全结束后再处理
这就像开车时"立刻转向"和"下一个路口再转"的区别。对于任何需要人机协作的Agent场景,这种分级干预机制都值得借鉴——既给用户实时纠正的能力,又不会因为强制终止导致状态不一致。
上下文管理:拒绝向量数据库
Pi明确拒绝了向量数据库、记忆银行等外部记忆系统。它的"记忆"策略在 compaction/compaction.ts 中实现,逻辑很直接:
- 优先用真实代码:AI直接用read/grep读取项目文件,而不是依赖可能过时的摘要或嵌入
- 对话历史管理:当上下文接近窗口上限时,把较早的对话压缩成结构化摘要
- 摘要格式:保留目标、约束、进度、关键决策、下一步——是人类可读的结构化信息,不是不可解释的向量嵌入
这个选择背后有一个务实的判断:对于编码场景,源码本身就是最权威的"记忆",任何中间层的缓存和索引都可能过期。与其维护一套复杂的记忆系统,不如让AI每次都直接读取最新的源文件。
对独立开发者的实践意义
Pi的设计可以提炼出几条可直接应用的原则:
- 工具设计做减法:不要为每个功能写一个自定义工具,先评估bash + 系统命令能否覆盖需求
- 文档驱动能力扩展:用Markdown文件定义Agent的技能,比硬编码更灵活,迭代成本接近零
- 渐进式加载提示词:系统提示词只放索引,详细指令按需读取,在有限的上下文窗口里最大化信息密度
- 结构化摘要优于向量检索:用LLM生成人类可读的摘要来管理长对话,比嵌入方案更可控、更可调试
- 设计干预机制:任何面向用户的Agent都应该允许实时纠正,而不是只能等它跑完
Pi的整体代码量和架构复杂度,完全在一个人可以掌控的范围内。它证明了一件事:当底层LLM足够强时,框架层的核心竞争力不是功能的丰富度,而是约束的精准度。在AI Agent领域,知道什么不做,可能比知道做什么更重要。