OpenClaw 背后的极简革命:Pi Agent 这个只带 4 个工具

OpenClaw 爆火背后,藏着什么秘密?

过去几周,OpenClaw 在各个技术社区疯狂刷屏。这个被描述为”科幻带点疯狂”的 AI 编程助手,以其惊人的自主能力和病毒式传播速度,成为 2025-2026 年最受瞩目的 AI 项目之一。

但你可能不知道的是:OpenClaw 的核心不是魔法,而是一个叫做 Pi 的极简框架。

Pi 由 Mario Zechner 开发,它拒绝功能膨胀,坚持只用 4 个基础工具:Read(读取)、Write(写入)、Edit(编辑)和 Bash(命令行)。它的系统提示词是同类工具中最短的。然而,正是这种极致的简约,让它成为 Armin Ronacher 等资深开发者几乎唯一使用的编程助手,也成为 OpenClaw 选择它作为底层技术的原因。

本文将揭开 OpenClaw 背后的技术秘密,深入解析 Pi 的极简哲学。你会看到:

  • 为什么 OpenClaw 选择 Pi 而不是功能更丰富的框架
  • 为什么 4 个工具足以完成所有编程任务
  • Pi 为什么明确拒绝行业标准协议(MCP)
  • 树状会话结构如何让调试效率提升 10 倍
  • 如何让 AI 自己编写、热重载、扩展自己的功能

极简核心:一个 while 循环 + 4 个工具

Pi 的核心设计哲学可以用一句话概括:一个调用 LLM 的 while 循环,加上四个基础工具。

让我们看看这个极简架构是如何工作的。

双循环架构:对话与执行的无限循环

Pi 的核心确实就是一个 while 循环。在 packages/agent/src/agent-loop.ts 中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 外层循环:处理后续消息队列
while (true) {
let hasMoreToolCalls = true;
let steeringAfterTools: AgentMessage[] | null = null;

// 内层循环:处理工具调用和转向消息
while (hasMoreToolCalls || pendingMessages.length > 0) {
// 1. 处理待处理消息(用户新输入或转向消息)
if (pendingMessages.length > 0) {
for (const message of pendingMessages) {
currentContext.messages.push(message);
}
pendingMessages = [];
}

// 2. 调用 LLM 获取响应
const message = await streamAssistantResponse(currentContext, config, signal, stream);

// 3. 检查是否有工具调用
const toolCalls = message.content.filter((c) => c.type === "toolCall");
hasMoreToolCalls = toolCalls.length > 0;

// 4. 执行工具调用
if (hasMoreToolCalls) {
const toolExecution = await executeToolCalls(
currentContext.tools, message, signal, stream, config.getSteeringMessages
);
// 工具结果会作为新消息加入上下文
for (const result of toolExecution.toolResults) {
currentContext.messages.push(result);
}
}

// 5. 检查转向消息(实时干预)
pendingMessages = (await config.getSteeringMessages?.()) || [];
}

// 6. 检查后续消息队列
const followUpMessages = (await config.getFollowUpMessages?.()) || [];
if (followUpMessages.length > 0) {
pendingMessages = followUpMessages;
continue; // 继续外层循环
}
break; // 没有更多消息,结束
}

这个循环逻辑极其简单:

  1. 把用户消息发给 AI
  2. AI 说”我要用工具” → 执行工具 → 把结果告诉 AI
  3. AI 继续思考,可能还要用工具 → 重复步骤 2
  4. AI 说”我完成了” → 检查有没有新用户消息 → 有就继续,没有就结束

这就是全部。没有复杂的状态机,没有工作流引擎,没有递归调用——就是一个简单的”对话-执行-反馈”循环。

四件套:Unix 哲学在 AI 领域的应用

packages/coding-agent/src/core/tools/index.ts 中,Pi 只定义了四个核心工具:

1
2
3
4
5
// 默认工具集:只有 4 个
export const codingTools: Tool[] = [readTool, bashTool, editTool, writeTool];

// 只读工具集(用于探索阶段)
export const readOnlyTools: Tool[] = [readTool, grepTool, findTool, lsTool];
工具 功能 为什么足够
Read 读取文件内容 AI 需要知道代码长什么样
Bash 执行 shell 命令 运行 git、npm、测试、grep、find 等
Edit 精确修改文件(查找替换) 修改现有代码
Write 写入新文件 创建新文件

为什么不需要更多?看 Bash 工具的定义:

1
2
3
4
const bashSchema = Type.Object({
command: Type.String({ description: "Bash command to execute" }),
timeout: Type.Optional(Type.Number({ description: "Timeout in seconds" })),
});

Bash 可以调用 grep、find、ls、git、npm……整个 Unix 工具链都是 AI 的延伸。Pi 的哲学是:不要为每个功能写新工具,让 AI 用 Bash 调用现有工具。

Armin Ronacher 这样评价:”Pi… 拥有我所知的最短的系统提示词。”这不仅仅是风格上的选择;这是对逻辑引擎的”疏通”。通过保持核心小巧、指令稀疏,Pi 减轻了底层大语言模型(LLM)的认知负担。这让模型的原始推理能力得以主导,从而减少了幻觉,显著提高了可靠性。

为什么 Pi 明确拒绝行业标准协议(MCP)

Pi 最具争议的技术决策或许是它对 Model Context Protocol(MCP,模型上下文协议) 的明确拒绝。当整个行业都在争先恐后地将 MCP 作为连接智能体与工具的标准时,Pi 却有意将其排除在外。

这不是”懒惰的遗漏”,而是一个经过深思熟虑的架构必要选择。

MCP 的局限性:缓存陷阱

像 MCP 这样的标准协议要求工具在会话开始时加载。这使得在不清空整个缓存或让 AI 困惑的情况下,几乎不可能完全重新加载或更新工具的功能。

试想一下这个场景:你正在用 AI 助手调试一个工具,但工具本身出了问题。如果使用 MCP 协议,你需要:

  1. 停止当前会话
  2. 修复工具代码
  3. 重新启动整个会话
  4. 重新加载所有上下文
  5. AI 可能会困惑:”我之前是怎么调用这个工具的?”

所有上下文都丢失了。

Pi 的解决方案:软件构建软件

相反,Pi 践行着”软件构建软件”的理念。如果智能体需要新能力,它不会下载插件。它会进入一个**”编写-重载-测试”循环**:编写扩展代码、热重载环境、迭代直到新功能稳定。

这让智能体成为一个自我进化的实体,能够实时维护和增强自己的功能。

Pi 的底层 AI SDK 设计为模型无关的。因为会话文件使用自定义消息来存储扩展状态,而非依赖供应商特定功能,你可以将复杂的会话在 Anthropic、OpenAI 或 Google 的模型之间迁移,而不会丢失进度。

实时热重载:修改即生效

Pi 的扩展系统支持内置热重载。当智能体编写新代码后,可以立即重载环境进行测试,无需重启会话。这种设计让 AI 能够快速迭代,构建出符合特定需求的个性化工具。

例如,Armin Ronacher 没有使用外部 CLI 或 MCP 服务器进行浏览器自动化,而是让智能体构建了一个直接利用 Chrome DevTools Protocol(CDP,Chrome 开发者工具协议) 的技能。任务完成后,这个技能可以被直接丢弃。智能体维护着自己的功能,不被那些它不需要的”社区技能”所累。

树状会话:让调试不再是一场噩梦

大多数 AI 界面都受困于”线性陷阱”,将对话视为简单的时间线消息序列。这是人类记忆和 LLM 上下文的局限,而 Pi 的树状会话架构优雅地绕过了这一点。

分支工作流:保持”上下文尊严”

在 Pi 中,会话是分支的。这支持一种保持上下文完整性的工作流:

场景 传统线性会话 Pi 的树状会话
工具损坏需要修复 在当前会话中混杂调试日志,污染主任务上下文 分支到一个全新的上下文去修复,主会话保持干净
修复完成后 继续在当前混乱的上下文中工作 “回退”到主分支,智能体会总结支线任务并带回结果
模型切换 上下文丢失或格式不兼容 通过 pi-ai SDK 实现上下文可移植性,可在 Anthropic、OpenAI、Google 模型间迁移

这种设计在代码审查场景中特别有用。/review 扩展会将会话分支到一个全新的上下文中审查代码,生成 diff,并在合并前特别标注新添加的依赖项。

实时干预:转向队列(Steering Queue)

这是 Pi 最独特的功能之一。想象你在和 AI 对话,AI 正在执行一系列操作:

正常情况:AI 调用工具 A → 调用工具 B → 调用工具 C → 完成任务

发现问题:你看到 AI 走错方向了,发送消息:”等等,不要用那个方法”

Pi 的处理机制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
export class Agent {
private steeringQueue: AgentMessage[] = []; // 转向队列
private followUpQueue: AgentMessage[] = []; // 后续队列

/**
* 发送转向消息:中断当前执行
* 在当前工具执行完成后立即处理,跳过剩余工具
*/
steer(m: AgentMessage) {
this.steeringQueue.push(m);
}

/**
* 发送后续消息:在当前轮次完全结束后处理
*/
followUp(m: AgentMessage) {
this.followUpQueue.push(m);
}
}
  • 转向队列(steer):如果消息进入转向队列,当前工具执行完后立即处理你的消息,跳过剩余工具
  • 后续队列(followUp):如果消息进入后续队列,等 AI 这一轮完全结束后再处理

这就像开车时的”紧急转向”和”下一站停靠”的区别——给用户细粒度的干预权。

技能系统:让 AI 自己教自己

Pi 的”元文档”约占总提示词的 25%,教 AI 如何扩展自己。这是通过技能系统(Skill System) 实现的。

渐进式披露:按需加载

packages/coding-agent/src/core/skills.ts 中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
export interface Skill {
name: string; // 技能名称
description: string; // 技能描述(AI 根据这个决定何时加载)
filePath: string; // 技能文件路径
baseDir: string; // 技能根目录
source: string; // 来源(user/project/path)
disableModelInvocation: boolean; // 是否禁用自动调用
}

// 加载技能
export function loadSkills(options: LoadSkillsOptions = {}): LoadSkillsResult {
// 从多个位置加载:
// - ~/.pi/agent/skills/ (全局)
// - .pi/skills/ (项目本地)
// - CLI --skill 参数指定的路径
}

// 将技能格式化为系统提示词
export function formatSkillsForPrompt(skills: Skill[]): string {
const lines = [
"The following skills provide specialized instructions for specific tasks.",
"Use the read tool to load a skill's file when the task matches its description.",
...
"",
];
for (const skill of visibleSkills) {
lines.push(`### ${skill.name}`);
lines.push(`${skill.description}`);
lines.push(`File: ${skill.filePath}`);
lines.push("");
}
return lines.join("\n");
}

技能系统的工作流程:

  1. 启动时:Pi 扫描指定目录下的所有 SKILL.md 文件
  2. 系统提示词中:只告诉 AI 有哪些技能(名称+描述),不包含详细内容
  3. AI 按需加载:当任务匹配技能描述时,AI 用 read 工具读取完整的 SKILL.md
  4. SKILL.md 内容:包含具体操作步骤、脚本命令、示例等

文档即代码:用 Markdown 写能力

一个典型的 SKILL.md

1
2
3
4
5
6
7
8
9
10
11
12
---
name: pdf-processing
description: Extracts text and tables from PDF files. Use when working with PDF documents.
---

# PDF Processing

## Setup

Run once before first use:
```bash
cd /path/to/pdf-processing && npm install

Usage

1
2
./extract-text.js    # Extract text
./extract-tables.js # Extract tables
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

**热重载原理**:Skill 就是 Markdown 文件。当 AI 读取它时,内容立即进入上下文。**没有注册过程,没有重启需求**——这就是"编写即用,修改即生效"。

### 实战案例:Clanker 扩展

在 Pi 生态系统中,智能体常被称为"**Clanker**"——这是对"智能体即构建者"的昵称。以下是一些由智能体创建的斜杠命令:

- **`/answer`**:从智能体的文本中提取问题,并将其重新格式化为干净的输入框,防止混乱的内联对话
- **`/review`**:将会话分支到一个全新的上下文中审查代码,生成 diff,并在合并前特别标注新添加的依赖项
- **`/todos`**:管理 `.pi/todos` 目录中基于 Markdown 的任务列表,让人类和智能体都能跟踪进度

这些扩展不是从通用市场拉取的;它们是由 Clanker 根据你的具体需求手工打造的。

## 代码即真理:没有外部记忆系统

Pi 明确拒绝向量数据库、记忆银行等外部记忆系统。它的"记忆"策略很简单:

```typescript
export interface CompactionSettings {
enabled: boolean;
reserveTokens: number; // 预留 token 数(默认 16384)
keepRecentTokens: number; // 保留最近对话 token 数(默认 20000)
}

// 当上下文窗口快满时,压缩历史
export function shouldCompact(
contextTokens: number,
contextWindow: number,
settings: CompactionSettings
): boolean {
return contextTokens > contextWindow - settings.reserveTokens;
}

// 压缩策略:保留最近 N 个 token 的对话,更早的用 LLM 总结
export function findCutPoint(
entries: SessionEntry[],
startIndex: number,
endIndex: number,
keepRecentTokens: number,
): CutPointResult {
// 从最新消息开始,向前累积 token
// 当超过 keepRecentTokens 时,在那个点"切断"
// 更早的内容会被 LLM 总结成摘要
}

三层记忆策略

  1. 优先用真实代码:AI 直接用 read/grep 读取项目文件,而不是依赖可能过时的摘要
  2. 对话历史管理:当上下文快满时,把太旧的对话压缩成摘要
  3. 结构化摘要:保留目标、约束、进度、关键决策、下一步——结构化信息,而不是向量嵌入

Pi 的设计告诉我们:在 AI 时代,减法比加法更难,但也更有价值。

高性能 TUI:终端也能跑 Doom

当许多智能体优先考虑脆弱、臃肿的网页 GUI 时,Pi 采用了基于 @mariozechner/pi-tui 库构建的高性能终端用户界面(TUI,Terminal User Interface)

这里的技术秘密是差分渲染(differential rendering)。这确保了界面极其稳定和高性能。在这个闪烁、内存饥渴的 Web 应用时代,Pi 代表了工程尊严。

Armin Ronacher 评价:”它不闪烁,不消耗大量内存,不会莫名其妙崩溃。”

这个 TUI 不仅仅是基础 shell;它支持复杂的组件,如 spinner(加载动画)交互式文件选择器数据表格。为了证明其灵活性,开发者甚至在终端界面中实现了一个可直接运行的 Doom 游戏版本。如果 TUI 能够处理 Doom 的渲染需求,它就能处理开发者可能需要的任何调试仪表板或数据可视化。

总结:极简主义的胜利

Pi 及其更广泛的生态系统(包括 OpenClaw 等项目)代表了向”作为极简基础而非功能丰富产品”的智能体的根本性转变。

核心要点

  1. 极简核心:一个 while 循环 + 4 个基础工具(Read、Write、Edit、Bash)足以完成所有编程任务
  2. 拒绝 MCP:热重载和自我扩展能力比遵循行业标准协议更重要
  3. 树状会话:分支工作流保持上下文完整性,让调试不再混乱
  4. 技能系统:渐进式披露,让 AI 按需加载能力,实现自我进化
  5. 代码即真理:结构化摘要优于向量检索,直接读取源码而非依赖过期记忆

可迁移经验

无论你是否使用 Pi,这些设计原则都值得借鉴:

  • 工具设计遵循 Unix 哲学:每个工具做一件事,但可以组合
  • 优先使用系统已有能力,而非重新发明
  • 渐进式披露:只把必要信息放系统提示词,详细内容按需加载
  • 文档即代码:用 Markdown 写”能力”,而不是写代码
  • 给用户干预权:允许在 AI 执行中实时纠正
  • 结构化摘要优于向量检索:用 LLM 生成”人类可读”的摘要

思考题

  1. 你当前使用的 AI 编程助手有哪些功能是”功能膨胀”?哪些是真正的核心能力?
  2. 如果你的 AI 助手只能使用 4 个工具,你会选择哪 4 个?为什么?
  3. 在”预置功能的幻觉”和”无限自我构建的力量”之间,你会如何选择?

进一步学习

在 Pi 的世界里,答案就是唯一的出路。

OpenClaw 背后的极简革命:Pi Agent 这个只带 4 个工具

https://beixiu.net/openclaw-pi-agent/

作者

北嗅

发布于

2026-02-13

更新于

2026-02-26

许可协议

评论