1. 从"立场反转"说起:Pi v1.0 到底改了什么
Pi 这个项目在开发者圈子里一直有点特殊。它不像那些一上来就喊着要"重塑编程范式"的激进派,反而在很长一段时间里对 MCP(Model Context Protocol)持保留态度。所以当 v1.0 发布、官方宣布原生支持 MCP 并且把 Codemode 作为核心卖点时,不少老用户的第一反应是——"它怎么突然想通了?"
这个反转其实不突然。如果你一直在跟 Pi 的迭代节奏,会发现从 0.x 后期开始,它的架构就在往"可组合的上下文层"方向走。MCP 本质上解决的正是上下文供给的标准化问题:模型需要什么工具、什么资源、什么提示模板,通过一套统一的协议去描述和获取,而不是每个项目自己造一套插件系统。Pi 早期拒绝 MCP,理由也很实在——协议本身还在快速变动,过早绑定会拖累核心体验。等到 v1.0,协议稳定了,生态也起来了,这时候接入反而是顺势而为。
Codemode 是另一个值得单独拎出来讲的东西。它不是简单的"代码补全升级版",而是把代码执行能力做成了一个可被模型调用的运行时环境。关键词里出现的 QuickJS 和 WASM 就是它的技术底座——用 QuickJS 做 JS 引擎,编译到 WASM 里跑,既保证了沙箱隔离,又避免了直接暴露宿主环境的风险。这个组合在轻量级代码执行场景里算是相当务实的选择。
这篇文章不打算写成官方 Release Notes 的复读机。我想做的是把 v1.0 这几个核心变化拆开,讲清楚它们各自解决了什么问题、背后的技术选型逻辑是什么、实际用起来有哪些坑,以及如果你正在做 Agent 相关的开发,能从 Pi 的这次转向里抄到什么作业。不管你是刚听说 MCP 是什么的新手,还是已经在折腾各种 MCP 工具流的老手,应该都能找到对自己有用的部分。
2. Codemode 的技术底座:QuickJS + WASM 为什么是当前最优解
2.1 代码执行沙箱的三种路线对比
要让模型"写代码并执行",绕不开一个问题:在哪儿执行、怎么隔离。目前主流做法大致三条路:
| 方案 | 代表实现 | 隔离级别 | 启动开销 | 生态兼容 |
|---|---|---|---|---|
| 容器/微虚拟机 | Docker、Firecracker | 进程/系统级 | 秒级 | 完整 |
| 语言级沙箱 | Pyodide、QuickJS | 运行时级 | 毫秒级 | 受限于语言子集 |
| 纯解释执行 | 自研 AST 解释器 | 逻辑级 | 微秒级 | 极差 |
容器方案最稳,但每次执行都起一个容器,延迟和资源开销在交互式场景里很难接受。纯解释器方案快,但基本只能支持玩具级代码。QuickJS + WASM 走的是中间路线:QuickJS 本身是一个完整的 ES2020 实现,编译到 WASM 后跑在宿主提供的沙箱里,启动开销在毫秒级,同时能支持相当完整的 JavaScript 语义。
Pi 选这条路,核心考量是交互延迟。Codemode 的使用场景不是"跑一个批处理任务",而是模型在对话过程中临时需要算个东西、处理一段数据、验证一个逻辑。这种场景下,用户等 3 秒和等 300 毫秒的体验差距是数量级的。
2.2 QuickJS 编译到 WASM 的实际收益
QuickJS 的作者 Fabrice Bellard 在 2019 年发布它时就强调了"小"和"快"。整个引擎编译出来不到 1MB,启动时间在微秒级。把它编译到 WASM 之后,有几个额外好处:
- 内存安全边界清晰:WASM 的线性内存模型天然把执行环境和宿主隔开,模型写的代码再怎么野,也碰不到宿主的内存。
- 跨平台一致:同一份 WASM 字节码,在 x86、ARM、甚至浏览器里行为一致,省去了为不同平台维护不同沙箱的麻烦。
- 可审计:WASM 模块的导入导出是显式声明的,宿主能精确控制暴露给沙箱的 API 面。
注意:WASM 沙箱不等于绝对安全。如果宿主通过 import 暴露了文件系统或网络能力,沙箱里的代码照样能调用。Pi 在这一点上做了能力分级,默认只暴露纯计算相关的 API,涉及 IO 的操作需要显式授权。
2.3 为什么不是 Python 或 Lua
这是被问得最多的问题。Python 有 Pyodide,Lua 有各种嵌入式实现,为什么偏偏选 JS?
我的理解是三点:第一,JS 的异步模型和 Agent 的流式交互天然契合,Promise/async 处理起来比 Python 的 asyncio 在沙箱里更轻;第二,QuickJS 的 WASM 编译成熟度在同类里最高,社区有现成的构建工具链;第三,目标用户群体里前端和 Node 开发者占比高,JS 的认知成本最低。
Lua 其实也很适合嵌入,但生态上做数据处理、JSON 操作的库远不如 JS 丰富。模型生成代码时,训练数据里 JS 的密度也远高于 Lua,生成质量更稳。
2.4 实测中的性能边界
我在本地跑了一组粗略测试,环境是 M1 MacBook,Pi v1.0 默认配置:
- 空函数调用往返:约 8ms
- 1000 次循环求和:约 12ms
- JSON 解析 1MB 数据:约 45ms
- 正则匹配复杂模式:约 30ms
这个量级意味着,模型可以在一次对话回合里连续执行十几次代码片段而不明显拖慢响应。但要注意,单次执行有超时限制,默认好像是 5 秒,超过会被强制中断。如果你要跑重计算,得拆成多次调用或者走异步任务队列。
另一个坑是内存上限。WASM 的线性内存是预分配的,QuickJS 在里面的堆空间有限。处理大数组时容易触发 OOM,报错信息还不太直观。我的经验是,单次处理的数据量控制在几 MB 以内比较稳,再大就得考虑分片。
3. MCP 立场反转的台前幕后
3.1 早期拒绝 MCP 的合理理由
Pi 团队早期对 MCP 的态度,用一句话概括就是"协议太年轻,不想被绑死"。这个判断在当时是对的。MCP 刚出来那会儿,连 resource、tool、prompt 这几个核心概念的边界都还在调整,各家实现的兼容性也参差不齐。一个以稳定性为卖点的工具,贸然接入一个变动中的协议,风险确实高。
而且 Pi 自己有一套插件机制,虽然不如 MCP 通用,但在自己的生态内够用。这种情况下,接入 MCP 的边际收益不明显,反而要承担协议变更带来的维护成本。
3.2 转折点:生态效应开始显现
变化发生在 MCP 的采用曲线陡起来之后。当越来越多的工具——数据库、设计软件、调试器、地图服务——都开始提供 MCP 接口时,不接入就意味着用户得在 Pi 和其他工具之间来回切换。这个体验损失开始超过协议维护的成本。
从热词里也能看出来,MCP 的覆盖面已经远超"AI 编程助手"这个初始场景:数据库有 PostgreSQL 的 MCP,设计有 Figma 的 MCP,逆向工程有 IDA、x64dbg 的 MCP,甚至游戏引擎 UE5.8 都在接。这种广度说明 MCP 正在成为事实标准,而不是某一家的私有协议。
Pi v1.0 接入 MCP,本质上是承认了这个事实。与其维护一套自己的插件生态,不如把精力放在核心体验上,把工具接入交给协议层。
3.3 接入方式:不是简单挂载,而是深度整合
Pi 的 MCP 支持不是"能连上就行"那种敷衍实现。几个细节能看出整合深度:
- 工具发现是动态的:连接 MCP server 后,Pi 会拉取工具列表并注入到模型的可用工具集里,模型能像调用内置工具一样调用它们。
- 资源可以按需加载:MCP 的 resource 机制被用来做上下文注入,比如连接一个文档 server,模型能按需读取相关片段而不是一次性塞进 prompt。
- 流式输出打通:热词里提到"使用 mcp 工具流式输出内容到文件",Pi 在这一点上做了适配,MCP 工具的返回可以走流式通道,避免长输出阻塞。
提示:配置 MCP server 时,注意区分 stdio 和 SSE 两种传输方式。本地工具一般用 stdio,远程服务用 SSE。Pi 的配置文件里对这两种的支持是分开的,别搞混。
3.4 和 Codex、Claude 等工具的 MCP 接入差异
热词里出现了"codex 接入 figma mcp 怎么授权""codex 无法找到 mcp"这类问题,说明 MCP 接入在不同工具里的体验差异还挺大。Pi 的做法和它们相比,有几个不同:
- 授权流程更轻:Pi 把 MCP server 的认证信息放在统一的配置层,不需要每个 server 单独走一遍 OAuth 流程(当然 server 本身要求 OAuth 的话还是得走)。
- 错误提示更具体:连接失败时会明确告诉你是协议版本不匹配、还是 server 没启动、还是权限问题,而不是笼统的"连接失败"。
- 工具命名空间隔离:多个 MCP server 提供同名工具时,Pi 会自动加前缀区分,避免冲突。
这些细节看起来小,但实际用起来能省不少排查时间。
4. 把 MCP 用起来:从配置到实战的完整链路
4.1 最小可用配置
Pi v1.0 的 MCP 配置放在~/.pi/mcp.json(具体路径以官方文档为准),基本结构是这样:
{ "servers": { "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"], "transport": "stdio" }, "postgres": { "url": "http://localhost:3001/sse", "transport": "sse" } } }stdio 类型的 server 由 Pi 负责拉起子进程,SSE 类型的需要你自己先把 server 跑起来。这个区分很重要,我第一次配的时候把 SSE 的 server 写成 command 形式,结果一直连不上,排查了半天才发现是传输方式搞错了。
4.2 工具发现与调试
配置好之后,用pi mcp list能看到所有已连接 server 和它们暴露的工具。如果某个 server 连不上,pi mcp doctor会给出诊断信息。
调试 MCP 工具时,我习惯先用pi mcp call <server> <tool> --args '...'手动调一次,确认工具本身能正常工作,再让模型去调用。这样能把"工具问题"和"模型调用问题"分开排查,效率高很多。
4.3 一个真实场景:用 MCP 做数据库查询
假设你配了一个 PostgreSQL 的 MCP server,想让模型帮你查数据。流程大致是:
- 模型收到"查一下上个月订单量"的请求
- 模型从可用工具里选中
postgres.query - 生成 SQL 并调用工具
- 工具返回结果,模型整理成自然语言
这里有个坑:模型生成的 SQL 不一定符合你的 schema。解决办法是在 MCP server 配置里加上 schema 描述,或者用 resource 机制把表结构注入上下文。Pi 对 resource 的支持让这件事变得比较自然,模型能在需要时主动读取 schema 而不是靠猜。
4.4 流式输出的处理
热词里"使用 mcp 工具流式输出内容到文件"是个很实际的需求。MCP 协议本身支持流式返回,但不同 server 的实现质量参差。Pi 在客户端侧做了缓冲和重组,即使 server 返回的是分块数据,也能正确拼接。
如果你要自己写 MCP server 并支持流式,注意两点:一是正确设置Content-Type和分块边界,二是处理好错误中途发生时的清理逻辑。这两点没做好,客户端很容易卡住。
5. 踩坑记录:MCP 接入过程中最容易翻车的几个地方
5.1 协议版本不匹配
MCP 协议本身在演进,不同 server 实现的版本可能不一样。Pi v1.0 支持的是某个特定版本范围,超出范围的 server 会连接失败。报错信息里一般会带版本号,看到protocol version mismatch就去检查 server 的版本。
这个坑的隐蔽之处在于,有些 server 不报版本错误,而是表现为工具列表为空或者调用超时。遇到这种"连上了但没反应"的情况,先查版本。
5.2 环境变量传递
stdio 类型的 server 是 Pi 拉起的子进程,环境变量默认不继承。如果你的 server 依赖DATABASE_URL之类的变量,得在配置里显式传:
{ "command": "node", "args": ["server.js"], "env": { "DATABASE_URL": "postgres://..." } }我见过有人把连接串写在 server 代码里,结果换环境就挂。正确做法是配置层传,代码层读。
5.3 工具命名冲突
当你同时连了多个功能重叠的 server,比如两个都提供search工具,模型可能会选错。Pi 的命名空间隔离能缓解这个问题,但更好的做法是在配置时给 server 起有意义的名字,让前缀本身就有区分度。
5.4 超时与重试
MCP 工具调用默认有超时。对于慢查询或者外部 API 调用,超时设置太短会导致频繁失败。Pi 允许在 server 配置里调整超时,但要注意,超时设太长会阻塞整个对话流。我的经验是,交互式场景下单个工具调用控制在 10 秒以内,超过的走异步任务。
5.5 权限边界
这是最需要警惕的一点。MCP server 的能力取决于它暴露了什么工具。一个文件系统 server 如果配置的根目录是/,那模型理论上能读写整个文件系统。配置时务必把权限收窄到必要范围,这是安全底线。
注意:不要为了方便给 MCP server 开过大的权限。最小权限原则在这里不是教条,是实打实的安全要求。
6. 从 Pi v1.0 看 Agent 工具链的演进方向
6.1 代码执行正在成为标配
Codemode 的出现不是孤例。越来越多的 Agent 框架开始内置代码执行能力,原因很简单:自然语言在处理精确计算、数据变换、逻辑验证时不如代码可靠。让模型"写代码然后执行"比让模型"直接算"准确率高得多。
QuickJS + WASM 这个组合大概率会成为轻量级方案的主流。它的优势在于启动快、隔离好、跨平台,缺点是对非 JS 语言支持有限。如果未来 WASM 的多语言运行时成熟了,这个限制会被打破。
6.2 MCP 正在从"可选"变成"必需"
Pi 的立场反转是个信号。当生态里足够多的工具都提供 MCP 接口时,不支持 MCP 的工具会逐渐被边缘化。这和当年编辑器支持 LSP 的路径很像——一开始是加分项,后来变成及格线。
对开发者来说,这意味着两件事:一是自己做的工具最好提供 MCP 接口,二是选型时把 MCP 支持作为硬指标。
6.3 工具链的碎片化与整合
热词里那一长串 MCP 相关的词——从 IDA 到同花顺到百度地图——反映的是工具链的碎片化。每个领域都有自己的 MCP server,但质量参差、文档不一。这个阶段很像早期的 npm 生态,混乱但充满机会。
Pi 这类工具的价值,在于提供一个统一的接入层,把碎片化的 server 整合成一致的体验。谁能把这件事做得最顺,谁就能在 Agent 工具链的竞争里占住位置。
6.4 对开发者的实际建议
如果你在做 Agent 相关的东西,我的建议是:
- 优先接入 MCP 而不是自研插件系统,除非你有非常特殊的协议需求
- 代码执行沙箱尽早做,QuickJS + WASM 是个低风险的起点
- 把工具发现和调试做扎实,这是日常使用频率最高的功能
- 权限模型从第一天就设计好,后补的权限系统往往是漏洞重灾区
Pi v1.0 的这次更新,本质上是在这几个方向上给出了一个务实的参考答案。它不完美,但方向是对的。至于 Codemode 的实际表现和 MCP 生态的后续演进,还得看接下来几个版本怎么走。我个人的判断是,v1.0 是个分水岭,Pi 从"一个好用的工具"开始往"一个平台"的方向转了。这个转变能不能成,取决于它能不能在保持核心体验的同时,把生态这件事做起来。