OpenClaw Agent 01:为什么要自己写 Agent——告别框架黑盒与生产级方案对比

在 AI 应用开发的探索过程中,很多开发者都经历过类似的心路历程:使用 LangChain、Dify 或 Coze 搭建原型时,只需要几行 Python 代码或在画布上拖拽几个节点,一个看起来无所不能的智能体就跑通了。

然而,一旦团队试图将这样的 Agent 推向严肃的工业级生产环境(例如构建一个能够自主编写、调试代码并提交 PR 的 Coding Agent,或者一个 7×24 小时长期驻留的个人研发助理),工程上的“暗礁”就会接踵而至:

  • 行为偶发失控,但排查异常时深陷 30 层框架内部堆栈;
  • 想对工具执行的入参做一点微观截断或权限校验,发现要重写好几个抽象基类;
  • 第三方框架版本迭代极快,每个月都有破坏性变更(Breaking Changes),依赖树膨胀导致容器体积动辄几个 G。

这不是开发者的技术水平问题,而是由重型第三方框架的设计哲学决定的。


真正跑在生产上的 Coding Agent 都在用什么?

回顾当前业界最成功的几款生产级 Coding Agent 产品——无论是商业闭源的 Claude Code、Cursor,还是高质量开源的 Pi,它们有一个共同的特征:核心运行时均未依赖任何重型第三方编排框架,而是采用了极致克制、透明的自研轻量架构。

对比两者的工程取舍矩阵:

架构维度 传统第三方框架方案 生产级 Coding Agent 方案 工程收益与考量
执行模型 线性链(Chain)/ 复杂静态 DAG EventStream + Agent Loop 实时输出生命周期事件,解耦 UI 渲染与排错跟踪
上下文管理 简单的消息截断或整段向量检索 可插拔 Context Engine 在有限 Token 预算内分级调度系统指令、记忆与近期消息
工具调用 串行同步执行 并行异步执行(Promise.all) 并发读文件与网络 I/O,将延迟从 $O(n)$ 降为 $O(1)$
长期记忆 向量数据库粗暴存储对话历史 文件级持久化(MEMORY.md) 人类可读、Git 可版本控制、零额外中间件运维成本
工程语言 绝大多数为 Python TypeScript / Go 强静态类型约束、高并发事件循环、无 GIL 瓶颈

项目辨析:Pi、pi-mono 与 OpenClaw 的技术定位

在深入架构前,我们需要准确理解几个名词在技术脉络中的定位:

1. Pi 与 pi-mono

Pi 是由开源极客 Mario Zechner 发起的 TypeScript Agent Harness 项目,狭义上也指用户在终端直接运行的 pi 命令行交互产品。pi-mono 是该项目早期的 Monorepo 仓库名称(上游现已迁移更名为 earendil-works/pi)。

Pi 内部清晰地划分为了多层包结构:

  • @earendil-works/pi-ai:多大模型 Provider 统一抽象,抹平 OpenAI、Anthropic、Gemini 之间的 API 差异;
  • @earendil-works/pi-agent-core:通用的 Agent 运行引擎,实现核心循环、状态流转与工具派发;
  • @earendil-works/pi-coding-agent:基于核心引擎组装的终端 Coding Agent,提供用户可执行的 pi 命令;
  • @earendil-works/pi-tui:终端字符界面渲染组件。

2. OpenClaw 的产品演进

OpenClaw 的早期实现借鉴并改编了 Pi 的 Agent Loop 架构,但它不是 Pi 的简单套壳。两者的目标场景完全不同:

  • Pi 面向终端极客编程:轻量、无状态偏向、单次任务完成后退出;
  • OpenClaw 面向长期驻留的个人助理:建设了完整的 WebSocket 控制网关、多渠道(Telegram、Slack、飞书、Discord)统一路由、复杂的多用户隔离与安全沙箱、以及三层记忆系统。

根据官方架构演进,OpenClaw 的内置运行时已完全内化至其自身代码库(packages/agent-core 和 src/agents),保留了从 Pi 继承的优秀设计,同时针对个人助理的长期运行进行了深度强化。


Agent 的底层本质:一个极其质朴的循环

拨开所有框架花哨的概念包装,任何智能体在底层的数学与控制流本质完全是同一个东西:

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
// 简化自 Pi / OpenClaw 的核心执行逻辑
async function* agentLoop(messages: Message[]): AsyncGenerator<AgentEvent> {
while (true) {
// 1. 调用大模型获取响应
const response = await llm.chat(messages);
yield { type: 'message_end', content: response };

// 2. 如果模型没有请求任何工具,说明生成完毕,跳出循环
if (!response.toolCalls?.length) {
break;
}

// 3. 并发执行模型请求的所有本地或远程工具
const results = await Promise.all(
response.toolCalls.map(async (call) => {
yield { type: 'tool_execution_start', toolCall: call };
const res = await executeTool(call);
yield { type: 'tool_execution_end', result: res };
return res;
})
);

// 4. 将工具的执行结果转换成消息,追加到会话上下文,进入下一轮判定
messages.push(...results.map(formatToolMessage));
}
}

智能体与普通聊天机器人(Chatbot)的本质区别仅在这一行逻辑:当大模型返回包含 tool_calls 时,程序拦截执行本地代码,并将观察到的客观事实送回上下文继续让模型决策,直到模型认为任务完成为止。

一旦你看透了这几十行代码,就会明白为什么重型框架的深层继承往往是过度设计:一个 while 循环加上合理的事件发射机制,就能承载 95% 以上的单智能体任务。


技术选型考量:谁适合自研轻量 Agent?

自研 Agent 运行时并不是盲目造轮子,而是一次清晰的工程权衡:

强烈推荐自研轻量架构的场景

  1. 构建深度代码助手或桌面级 Agent:对执行延迟要求极高、要求首字流式输出、工具并发执行不可阻塞;
  2. 生产环境对安全与合规零容忍:必须精准拦截每一条 Shell 命令、防止越权访问本地敏感文件、严禁不可控的黑盒依赖;
  3. 技术面试与深度架构突破:需要向技术团队证明自己对智能体底层原理(调度、上下文修剪、事件流)拥有源码级的掌握,而非仅仅是个 API 调包工程师。

适合继续使用开源重型框架的场景

  1. 快速原型演示(PoC):给业务部门做概念展示,重点在于 2 天内上线,对后续维护成本不敏感;
  2. 图形化低代码平台:非技术人员需要通过拖拉拽节点搭建问答知识库。

关联导航