做 CreatorWeave 的时候,有个问题困扰了我很久: Agent 的核心循环到底是自己写,还是用现成的?
自己写吧,容易写出 bug,而且 LLM 的各种边界情况(流式中断、工具调用嵌套、跨 Provider 差异)比你想象的多得多。用现成的吧,LangChain JS 太重,Vercel AI SDK 不够灵活,其他框架要么不支持浏览器,要么 API 设计让你觉得自己在写 Java。
最后我选了 @earendil-works/pi-agent-core 。
这篇聊聊为什么选它,以及在浏览器端踩了多少坑。
pi-agent-core 是什么?
先介绍一下这位选手。
我最初注意到 pi-agent-core,是因为 OpenClaw ------就是那个全网都在"养"的"小龙虾"。2026 年开年爆火,几个月 GitHub 星标突破 25 万,登顶历史增长最快开源项目。我去看了它的源码,发现核心循环干净得不像话------于是顺藤摸瓜找到了 pi。
pi 的哲学就一句话: 我不需要的,就不做。
它的工具只有 4 个:read、write、edit、bash。系统提示词不到 1000 token。没有 Plan 模式,没有 MCP 支持,没有子 Agent,没有待办清单。运行模式?YOLO------给你全部权限,你自己负责。
听起来很疯对吧?但就是这么一套极简架构,撑起了全网最火的编程 Agent。
pi 的架构分三层:
| 层 | 包名 | 干什么的 |
|---|---|---|
| LLM 统一 API | pi-ai |
多 Provider 适配、流式、工具调用、跨 Provider 上下文切换 |
| Agent 循环 | pi-agent-core |
工具执行、事件流、消息队列 |
| 终端产品 | pi-coding-agent |
CLI 界面、会话管理、主题 |
我只需要中间两层。
但这张表只讲了 pi 本身,没讲 CreatorWeave 在上面造了什么。补一张全景图:
lua
┌─────────────────────────────────────────────────┐
│ CreatorWeave 扩展层 │
│ ┌──────────┐ ┌───────────┐ ┌───────────────┐ │
│ │ToolRegistry│ │ SubAgent │ │Context Manager│ │
│ │ 30+ 工具 │ │ 独立Agent │ │ 压缩+智能截断 │ │
│ └──────────┘ └───────────┘ └───────────────┘ │
│ ┌──────────┐ ┌───────────┐ ┌───────────────┐ │
│ │VFS 抽象 │ │ ToolPolicy│ │Prompt 增强 │ │
│ │3套存储统一│ │ 安全钩子 │ │STABLE+DYNAMIC │ │
│ └──────────┘ └───────────┘ └───────────────┘ │
├─────────────────────────────────────────────────┤
│ pi-agent-core 层 │
│ Agent 循环 · 事件流 · 消息队列 │
├─────────────────────────────────────────────────┤
│ pi-ai 层 │
│ 多 Provider 适配 · 流式 · 工具调用 │
└─────────────────────────────────────────────────┘
底下两层是 pi 的,上面六块是 CreatorWeave 造的轮子。下面展开讲。
为什么选它?
选型的时候我认真对比了几个方案:
LangChain JS --- 功能全,但太重了。光 @langchain/core 就拽进来一堆依赖,浏览器打包后体积感人。而且它的 Agent 抽象层太多了,你写个工具得继承这个类、实现那个接口、注册到那个 registry......写完感觉自己不是在写 Agent,是在写 Java。
Vercel AI SDK --- 轻量,React 集成好,但它是为"对话式 UI"设计的,不是为"Agent 工具循环"设计的。你想精细控制工具执行、上下文压缩、事件流?抱歉,这些得自己加。
完全自研 --- 我不是没想过。但 LLM 的边界情况太多了:OpenAI 的 reasoning_content 和 Anthropic 的 thinking 是两个字段;Cerebras 不认 store 参数;Mistral 要用 max_tokens 而不是 max_completion_tokens......这些坑,pi-ai 已经全踩过了。
最后选 pi-agent-core,理由很实在:
- 体积小 --- 没有黑魔法,没有隐式注入,代码读得懂
- 浏览器友好 --- pi-ai 本身就支持浏览器运行,CORS 都处理好了
- 事件流设计 --- 每一步都有事件(message_start、tool_execution_start、tool_execution_end),完美适合做 UI
- TypeBox schema --- 工具参数类型安全,前端工程师狂喜
- 跨 Provider --- 切模型像切电台一样丝滑,上下文自动适配
说白了就是: 它够用,又不挡路。
浏览器端:五个要命的挑战
选完框架只是开始。真正让我头秃的是: pi-agent-core 是给终端设计的,我在浏览器里跑。
这俩环境的差距,大概就像:一个是在自家厨房做菜,锅碗瓢盆随你用;另一个是在野外露营,只有一个便携炉和两根柴火。
挑战一:没有文件系统
终端里的 Agent 想读文件?cat package.json。想写文件?echo "hello" > file.txt。想找文件?find . -name "*.ts"。简单粗暴,万物皆可 bash。
浏览器呢?没有文件系统。你有的是 File System Access API ------用户手动授权一个文件夹,你才能读写里面的文件。没授权的?对不起,碰都不能碰。
而且浏览器的文件操作全是异步的,不像 Node.js 的 fs.readFileSync 能一把梭。Agent 说"帮我读一下 package.json",你不能让它等 500ms 的异步回调吧?
我们的方案: 做了一个 VFS(Virtual File System)后端抽象,统一了三套存储:
| 后端 | 用途 | 底层 |
|---|---|---|
| workspace | 用户授权的本地文件 | File System Access API |
| agent | Agent 工作缓存 | OPFS |
| assets | 用户上传的临时文件 | OPFS |
对 Agent 来说,read("src/main.ts") 跟在终端里一样自然------它不知道底层是本地文件还是 OPFS 缓存,也不需要知道。
挑战二:没有 bash
这是最痛的。
pi-coding-agent 的哲学是"bash 解决一切"------装依赖?npm install。看日志?tail -f。跑测试?pytest。一个工具打天下。
浏览器里没有 bash。没有 shell。没有 npm。没有终端。你说 exec("ls -la"),浏览器只会看着你说:你好,我是谁,我在哪?
我们的方案: 把 bash 的功能拆成 30+ 个专用工具。听起来很多,但每个工具只做一件事,比 bash 更精确:
less
bash: "cat src/main.ts | head -20" → read(path, limit: 20)
bash: "grep -r 'TODO' src/" → search(query: "TODO", path: "src/")
bash: "ls src/components/" → ls(path: "src/components/")
bash: "sed -i 's/old/new/g' file.ts" → edit(path, old_text, new_text)
bash: "python3 analyze.py" → python(code: "...")
有些事情确实没法替代------比如网页搜索,我们通过浏览器扩展桥接。但大部分常见操作,专用工具比 bash 更安全、更可控、也更省 token。
用 30 个精确工具替代 1 个万能 bash,本质是用约束换安全。 浏览器不允许你有一把万能钥匙,那就给每扇门配一把专用钥匙------虽然多了点,但每把钥匙开不了错的门。
挑战三:工具从 4 个膨胀到 30+
pi-coding-agent 只有 4 个工具,系统提示词不到 1000 token。
CreatorWeave 呢?30+ 内置工具 + MCP 工具 + WebMCP 工具 + WASM 插件 + Skills 工具。工具描述加起来要吃掉好几千 token。
问题来了: 工具越多,LLM 越容易选错。
你问它"帮我搜一下这个项目里的 TODO",它可能调 search(对),也可能调 read(不对),甚至可能调 python 然后写一段 grep 代码(离谱但真的发生过)。
我们的方案:
- 工具分组 --- 按功能分类(文件操作、执行、Git、SubAgent...),让 LLM 知道"这类需求找这类工具"
- 模式过滤 --- Plan 模式只暴露只读工具,Act 模式才放开写操作。这样 Agent 在"看"的时候不会手欠改你的代码
- 工具推荐 --- 系统提示词里加了工具使用规则,直接告诉 LLM:"搜索文件用 search,别用 python 写 grep"
但这只是治标。LLM 接口能接受的工具数量是有限的,一旦 WebMCP 正式发布,工具列表可能极速膨胀------几十个变成几百个。到那时候,光靠分组和过滤就不够了。我们后续要研究 tool search :让 LLM 先搜一下有哪些工具可用,再决定调哪个,而不是把全部工具描述一股脑塞进上下文。
挑战四:上下文窗口更紧张
终端里通常一个会话解决一个问题。浏览器端呢?用户可能同时开了 3 个工作区,每个工作区有自己的对话历史。
而且浏览器端的工具返回结果可能很大------你 search 一个大项目,返回 200 条匹配,每条 3 行上下文,那就是 600 行。塞进上下文?窗口直接爆炸。
我们的方案:三层防御
- 分层 Prompt 缓存 --- 系统提示词分 STABLE 层(人格 + 模式,缓存友好)和 DYNAMIC 层(Skills + 日期,每轮变化),最大化利用 LLM 的 Prompt Cache
- 上下文压缩 --- 上下文用量超过 85% 自动触发压缩,用 LLM 生成摘要替换旧消息。还搞了个 Baseline 机制:记录压缩的截止时间戳,下次只加载
[摘要] + [新消息] - 工具结果智能截断 --- search 结果太大?用 二分查找 找到最多能塞多少条结果。不是粗暴地砍掉后半截,而是保证返回的永远是有效 JSON
对,你没看错,我们在 Agent 系统里写了二分查找------二分查找插入点,保证返回的永远是合法 JSON,而不是截断到一半的乱码。生活就是这么魔幻。
挑战五:安全模型完全不同
pi-coding-agent 的态度是:YOLO。全部权限,你自己负责。这很 Unix 哲学,也很省事。
浏览器的态度恰恰相反: 默认沙盒隔离,按需授权。
用户授权了 A 文件夹,你读 B 文件夹就是越权。Agent 想删 .env 文件?不行。Agent 想执行 rm -rf /?想都别想。
但这不是限制, 这是优势。 浏览器的沙盒机制天然更安全,也更符合普通用户的需求------大多数人不想给一个 AI 全部权限,他们只想让 AI 在自己划定的范围内干活。工作区隔离让多个工作区可以同时做不同的事,互不干扰。
我们的方案:双重防护 + 变更审批
- Plan/Act 双模式 --- Plan 模式下只暴露只读工具(read、search、ls),Agent 只能看不能动。用户确认了再切 Act 模式。就像 Git 的 dry-run,先看看要改什么,再动手
- ToolPolicy --- 在工具执行前插了个钩子,检查路径是否在保护列表里(
.env、.git、.ssh),检查命令是否匹配危险模式(rm -rf /、curl | sh)。命中就拦下来 - 变更审批 --- 基于 OPFS 做了一套类似 Git 的版本管理,所有文件修改先进入待审批状态,用户确认后才真正生效。每个工作区独立隔离,多工作区并行互不影响
我们造了什么轮子
总结一下,在 pi-agent-core 之上,CreatorWeave 新增的层:
ToolRegistry --- 工具注册中心
单例模式,运行时动态注册/注销。内置工具是基础,MCP / WebMCP / WASM Plugin / Skills 按需注入。所有工具输出统一成 ToolEnvelopeV2 信封格式------{ ok: true, data } 或 { ok: false, error }。前端解析工具结果再也不用猜格式了。
SubAgent 系统
每个子 Agent 都是一个完整的 AgentLoop 实例------不是执行预定义脚本的傀儡,是有独立上下文、能自主调用工具的"分身"。状态转换用 CAS(Compare-And-Swap)做乐观并发控制,用 SQLite 做持久化。页面刷新了?没关系,活跃任务会被标记为 SESSION_INTERRUPTED,下次打开可以 resume。
还搞了个健康检测:如果子 Agent 状态是"完成"但输出内容极短、同时有大量工具调用,大概率是 API 中断了------自动检测出来,提示用户 resume。
Context Manager
上下文压缩、Baseline 机制、工具结果智能截断------前面挑战四里讲过的三层防御,都由它统一调度。
Prompt 增强
IntelligenceCoordinator 负责注入人格、记忆、项目上下文。Prompt 分 STABLE(缓存友好)和 DYNAMIC(每轮变化)两层,最大化利用 LLM 的 Prompt Cache,省钱省时间。
学到了什么
- 终端极简是对的,但浏览器不能极简 --- pi-coding-agent 用 4 个工具就撑起了全网最火的编程 Agent,少即是多;但浏览器场景太复杂,4 个工具真不够用,你总不能让用户在浏览器里开 bash。这矛盾吗?不矛盾------终端和浏览器是两个世界,各有各的"刚好够用"
- 工具多了有多的代价 --- 30 个工具的描述就占好几千 token,LLM 越容易选错。选对工具比多加工具重要,后续可能要引入 tool search 来解决膨胀问题
- 上下文是最稀缺的资源 --- 每一次工具调用都在消耗窗口,必须精打细算。二分查找截断、上下文压缩、分层缓存,本质都是在抢窗口空间
- 浏览器沙盒是优势不是限制 --- 默认隔离、按需授权、变更审批、工作区隔离,这些不是"不如终端",而是比 YOLO 更适合"给普通人用"的产品
pi-agent-core 是一个很好的起点------小、干净、不挡路。但它不是为浏览器设计的。CreatorWeave 在它之上造了一层"浏览器端 Agent 基础设施",处理文件系统、工具编排、上下文管理、安全管控这些浏览器端特有的问题。
这套东西还在持续迭代。如果你对浏览器端 AI Agent 感兴趣,欢迎来看源码、提 PR、或者直接拍砖。
🔗 链接:
- pi-agent-core:[github.com/earendil-wo...](https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fearendil-works%2Fpi "https://github.com/earendil-works/pi")(github.com/earendil-wo...)
- CreatorWeave:[github.com/nutstore/cr...](https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fnutstore%2Fcreatorweave "https://github.com/nutstore/creatorweave")(github.com/nutstore/cr...)
- 在线体验:[creatorweave.eo2suite.cn](https://link.juejin.cn?target=https%3A%2F%2Fcreatorweave.eo2suite.cn%2F "https://creatorweave.eo2suite.cn/")(creatorweave.eo2suite.cn/)
如果觉得有意思,点个赞让更多人看到。如果想参与贡献,欢迎提 PR!