用着 agent,你迟早会冒出个念头——"它 rm -rf 之前能不能先问我一句?""能不能让它说话正经点?"传统答案是改源码。但 pi 给了你另一条路:它在自己运转的每个关节都留了一个钩子,你在旁边挂一个小文件接住,就能插手——不碰一行源码。这条路,它叫 extension。
你已经学完《亲手写一个 Agent》,手里有一个看得懂的 agent 了。用着用着,你迟早冒出这类念头:
- “它
rm -rf之前,能不能先问我一句?” - “我想让它某些时候说话像海盗,玩一下。”
- “这个项目我想给它加条规矩,但不想写进主系统提示。”
传统的答案只有一个:改源码。 翻进 pi 的代码,找到执行工具那一段,插进去几行——然后每次 pi 升级,你的补丁就得重打一遍。又累,又脆。
pi 不让你这么干。它给了你另一条路。

pi 在每个关节都留了一个钩子
回想主课那六件:Session 存、Loop 转、Context 装、ToolUse 动手、Provider 接模型、人设。pi 运转时,会一件一件地走过这些关节。
关键在于:每走到一个关节,pi 都会”喊一嗓子”。
- 准备调一个工具了 → 喊一声
tool_call - 要开始一轮了、系统提示刚拼好 → 喊一声
before_agent_start - 要压缩上下文了 → 喊一声
session_before_compact - 一个新会话起来了 → 喊一声
session_start
平时没人接这些嗓子,pi 自顾自往下走。但只要你写个小函数接住某一嗓子,就能在那个关节插手——拦下它、改一改、加点东西。
这个”挂在旁边、接住某个关节”的小文件,就是 extension。
出门的叫法。 别的产品——比如 Claude Code——管这类”给主程序外挂能力”的东西叫 plugin(插件)。pi 不用这个词,它叫 extension(扩展)。意思是一码事:不改主程序,往上加能力。本课统一用 pi 的原生词 extension,你跟别人对话时知道它约等于”插件”就行。
它到底长什么样:十几行
先给你看一眼,破除”扩展一定很复杂”的错觉。下面这个 extension 让 agent 能切换到”海盗模式”(源码 examples/extensions/pirate.ts),去掉注释就十几行:
export default function (pi) {
let pirateMode = false;
// 加一个 /pirate 命令,用来开关
pi.registerCommand("pirate", {
handler: async (_args, ctx) => {
pirateMode = !pirateMode;
ctx.ui.notify(pirateMode ? "海盗模式开!" : "海盗模式关");
},
});
// 接住"系统提示刚拼好"这一嗓子——开着就往后面加一段
pi.on("before_agent_start", async (event) => {
if (pirateMode) {
return { systemPrompt: event.systemPrompt + "\n\n从现在起,像海盗一样说话。" };
}
});
}
你不用全看懂。只要抓住这个形状:
pi.on("某个关节", 函数)—— 接住 pi 喊的那一嗓子。- 想改,就在函数里
return一个改动(这里是”给系统提示加一段”)。 pi.registerCommand—— 顺手加一个/命令。
就这么点东西,你改动了 agent 的人设——而 pi 的源码,一行没动。
你能改的,是你已经认识的那六件
extension 最妙的地方:它开的口子,正好挂在你主课学过的每个大件上。所以这门番外不是新知识,是回到那六件,看它们各自留的门:
| 你想改的 | 挂在哪个大件 | pi 喊的那一嗓子 |
|---|---|---|
| 危险命令先问一句 | ToolUse 的准备关 | tool_call |
| 换个系统提示 / 加条规矩 | 人设 | before_agent_start |
| 自己决定怎么压缩 | Context | session_before_compact |
| 会话一起来就做点事 | Session | session_start |
看懂这张表,你就懂了这门课的走法:每一节,回到一个大件,学它那道门怎么开。
带走这一句
pi 不用改源码就能改行为——因为它在运转的每个关节都”喊一嗓子”(触发一个事件),你写个小文件(extension,别人叫 plugin)接住那一嗓子,
return一个改动就行。而这些关节,正是你主课学过的那六件:改工具、改人设、改压缩、改会话,都是回到老地方开一道门。十几行,一行源码不碰。
下一课
这一节你看到了形状。下一课把形状拆开:一个 extension 其实只有三样东西——接事件(pi.on)、加命令(registerCommand)、跟界面说话(ctx.ui)。三样认全,你就能读懂任何一个 extension,也能开始写自己的。