OpenClaw 的框架内核:Pi
在 AI Agent 领域,大家很容易陷入一种“堆料”思路:工具越来越多,配置越来越复杂,系统越来越像一台难以维护的巨型机器。 Pi 反其道而行。它选择做减法,把框架压缩到最小,只保留真正必要的部分。 它的核心设计理念,可以概括成一句话: 一个调用 LLM 的 while 循环,加上四个基础工具。 Pi 是一个极简、可扩展的 AI 编码智能体框架(harness)。它并不试图替模型“想太多”,而是默认一个前提:像 Claude Sonnet 这样的模型,本身已经具备足够强的推理与规划能力。框架真正要做的,不是替它设计复杂工作流,而是给它一个稳定、清晰、低摩擦的执行环境。 这也是 OpenClaw 建立在 Pi 之上后依然能保持高效的原因。它强大,不是因为设计复杂,而是因为设计克制。 一句话理解 Pi 如果要用最通俗的话解释 Pi,可以把它理解为: 用户提出任务。 LLM 决定下一步要做什么。 框架执行工具调用,并把结果返回给 LLM。 重复这个过程,直到任务完成。 也就是说,Pi 的本质并不是一套庞大的 Agent 基础设施,而是一个非常稳定的“对话 - 执行 - 反馈”循环。 核心循环:Pi 如何驱动一个 Agent 下面这段代码,基本就是 Pi 的核心运行方式: // 外层循环:处理后续消息队列 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; // 没有更多消息,结束 } 这个循环看上去朴素,但正是 Pi 的关键。 ...