news 2026/11/4 2:14:30

pi-purge源码剖析:before_agent_start钩子如何精准切除宿主身份段还不切坏提示词

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
pi-purge源码剖析:before_agent_start钩子如何精准切除宿主身份段还不切坏提示词

【免费下载链接】pi-purge

pi extension: /purge swaps pi's built-in assistant persona for your own prompt file

项目地址:https://gitcode.com/gh_mirrors/pi/pi-purge
点击查看免费下载

pi-purge 是一个 pi 扩展:在会话里输入/purge,就能把 pi 内置的助手身份段从系统提示词中精准切除,换成你自己的人设提示词。它专为提示词工程而生——对比同一请求在「宿主提示词完整 / 精简 / 缺失」三种条件下的行为差异。本文带你从源码层面拆解它的核心:before_agent_start钩子是如何做到"只切该切的,绝不误伤"的。

这个扩展做了什么:一句话讲清 pi-purge

一句话:/purge是一个会话级开关,开启后每轮对话都把系统提示词"动一次手术"——把 pi 默认的"你是运行在 pi 中的专家编程助手"这段宿主身份清掉,把你要的提示词挂到最前面。🔧

它遵守三个设计约束(写在 extensions/pi-purge.ts 的头部注释里):

  1. 默认不启用——不输入/purge,pi 与未安装本扩展时完全一致,不改提示词、不读盘;
  2. 会话级独立——状态只活在内存里,每次session_start归零,退出即失,绝不落盘;
  3. 自带人设——默认用内嵌的示例正文,/purge source <路径>可换成你自己的文件。

架构总览:一个文件、两个钩子、一个命令

整个扩展只有一个实现文件 extensions/pi-purge.ts,注册内容极其克制:

注册项作用
session_start钩子每个新会话从"关闭"状态开始,重新加载人设正文
before_agent_start钩子在每轮请求发出前改写系统提示词(核心)
/purge命令on/off/status/mode/source五个子命令

没有后台任务,没有文件写入。测试套件最后甚至断言临时 agent 目录是空的(见 test/pi-purge.test.mjs),用证据证明它不留任何状态痕迹。

before_agent_start 钩子:在"模型开口前"动刀

before_agent_start是 pi 提供给扩展的拦截点:每轮对话在发给模型之前,钩子能拿到 pi 组装好的完整系统提示词,并有权替换它。这就是"手术刀"落下的时机。🔍

钩子的骨架(extensions/pi-purge.ts):

pi.on("before_agent_start", async (event) => { if (!enabled || body.length === 0) return; // 未开启?直接放行,一字不改 // ... 按 strict / replace / append 三种模式处理宿主提示词 ... return { systemPrompt: host.length > 0 ? `${body}\n\n${host}` : body }; });

两个细节值得新手注意:

  • 第一行就是安全阀:未开启或人设为空时返回undefined,pi 使用原始提示词。这就是"默认零副作用"的实现方式。
  • 人设永远挂头部:返回的提示词是你的正文 + 换行 + 宿主剩余部分。提示词里靠前的内容权重更高,挂头部才能让你的指令"压住"宿主框架措辞。

三种组合模式:strict / replace / append 怎么选

钩子中间的处理按模式分叉(extensions/pi-purge.ts),对照表来自 README.zh-CN.md:

模式实际发给模型的系统提示词适用场景
append你的提示词 + pi 原提示词(一字不改)对照组:基线行为,加一层自己的指令
replace你的提示词 + 去掉「助手身份句」和「内置文档段」的 pi 提示词想测量宿主框架措辞的影响,又不想丢工具上下文
strict你的提示词 + 仅Current working directory: …把人设当成唯一变量隔离出来(默认模式)

strict之所以"跨版本行为一致",是因为它根本不做任何文本匹配——宿主提示词整段丢弃,只留工作目录(extensions/pi-purge.ts)。而工具能力不受影响:工具的 schema 走 API 的tools参数,不依赖系统提示词里的文字。

精准切除的秘密:stripHostPersona 的固定文案定位

replace模式才是真正考验刀工的地方。切除逻辑全部在 stripHostPersona 函数 里,它的思路是:用固定文案定位,而不是猜边界。

pi 默认提示词的结构是稳定的,函数锁定了三段"锚点"(extensions/pi-purge.ts):

const HOST_IDENTITY = "You are an expert coding assistant operating inside pi, a coding agent harness."; const HOST_DOCS_START = "Pi documentation (read only when the user asks about pi itself"; const HOST_DOCS_END = "(e.g., tui.md for TUI API details)";

切除分两步,每步都有明确的边界处理:

第一步:切身份句。先indexOf(HOST_IDENTITY)找到这句话,再找到它所在行的行尾\n,把[起点, 行尾]整行切掉——连身份句带换行符干净移除,前后文本拼接不留空行碎屑。

第二步:切 pi 文档段。这一段较长,需要首尾双锚点:先找HOST_DOCS_START,再从起点之后找HOST_DOCS_END。找到后还会向前跳过若干换行符(extensions/pi-purge.ts),把段落前面的空行一起清掉,避免切完留下一坨空白。

关键在第三步——失败策略:任一处匹配不到,就整段跳过、原样返回。注释写得很直白:"pi 升级改文案时退化为 append,而不是把整段提示词切坏。"

为什么"切不中"反而更安全:失败即原样返回

很多提示词改写类工具的死穴是:靠正则或行号猜测位置,宿主文案一升级就切错地方,提示词被搅成乱码。pi-purge 用两条规则堵死这个风险:

  • 只信固定文案,不信位置。不用行号、不用正则范围,indexOf找不到锚点就当作"这段不存在",直接放弃切除;
  • 文档段必须双锚点同时命中(extensions/pi-purge.ts)。只有起点没有终点?不切。宁可整段保留,也不做半截切除。

而且每次切除的结果都被如实记账:lastCut变量记录上一轮到底切掉了什么(extensions/pi-purge.ts)。运行/purge status就能看到身份段 已切除 / pi 文档段 未匹配这样的实况汇报——生效了还是退化成 append,一查便知,绝不"静默失败"。

测试如何保证不切坏:9 组断言

光有信心不够,test/pi-purge.test.mjs 用真实形态的 pi 提示词(REAL_PI_PROMPT)把刀口逐行验证了一遍:

  • replace 模式:断言身份句、文档段被切除,同时Available tools:、Guidelines、<project_context>原封不动(test/pi-purge.test.mjs);
  • 防误伤用例:注入一份没有身份句和文档段的自定义提示词,断言它原样保留(test/pi-purge.test.mjs)——这正是"切不中就别动刀"的直接证据;
  • 会话隔离:新会话、resume都不继承上一会话的开启状态;
  • 换源回滚:指向不存在的文件时报错并回滚到内嵌人设;
  • 零落盘:跑完整个套件,临时 agent 目录依然为空。

另有 test/pi-purge-env-source.test.mjs 验证PI_PURGE_SOURCE环境变量的初始源行为。npm test即可全部跑通。

新手上手:三步开启 pi-purge

🚀 上手非常简单:

pi install npm:pi-purge

进入 pi 会话后:

/purge source C:/prompts/my-instructions.md /purge mode replace /purge on

包内自带一段简短示例人设,所以装完直接/purge也能跑。用/purge status可随时查看当前模式、人设来源和上一轮的切除实况;想回到原样,/purge off一条命令即可。

💡 实验提示:strict会连AGENTS.md、项目上下文、其他扩展注入的段落一起丢掉,这是它能做单变量隔离的原因,也意味着strict下的结论不能直接和普通会话对比;扩展加载顺序也会影响钩子看到的内容,建议把/purge status的输出连同实验结果一起记录。

关键文件速查

文件内容
extensions/pi-purge.ts全部实现:钩子、命令、切除函数
test/pi-purge.test.mjs主测试套件(9 组断言)
test/pi-purge-env-source.test.mjsPI_PURGE_SOURCE环境变量测试
README.zh-CN.md / README.md中文 / 英文完整文档

总结:pi-purge 的"精准"不来自复杂的解析,而来自克制的策略——固定文案锚点、双锚点校验、匹配不到就原样返回、结果如实汇报。这四个原则叠加,让before_agent_start钩子既能把宿主身份段切得干干净净,又永远不会把提示词切坏。对新手而言,这也是学习 pi 扩展开发的好范本:整个文件不到 250 行,钩子、状态管理、失败回滚一个不少。

【免费下载链接】pi-purge

pi extension: /purge swaps pi's built-in assistant persona for your own prompt file

项目地址:https://gitcode.com/gh_mirrors/pi/pi-purge
点击查看免费下载

相关推荐

上一篇:OpenDroid 提示注入防御指南:如何防止恶意通知劫持你的 AI 助理
下一篇:Drama 3 混合注意力机制揭秘:Full Attention 与 Linear Attention 如何分工

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/4 2:14:20

3 步装好 GitHub 汉化插件,代码区一字不动

3 步装好 GitHub 汉化插件&#xff0c;代码区一字不动 【免费下载链接】github-chinese GitHub 汉化插件&#xff0c;GitHub 中文化界面。 (GitHub Translation To Chinese) 项目地址: https://gitcode.com/gh_mirrors/gi/github-chinese 点了三回 Fork&#xff0c;才意…

作者头像 李华
网站建设 2026/11/4 2:13:33

经典蓝牙扫描设备名称为空的机制分析与解决方法

一句话先答&#xff1a;不是名字"丢了"——名字的获取有一条两级降级机制兜底&#xff0c;最终的空名字是小概率的漏网之鱼&#xff08;实测 5% 左右&#xff09;&#xff0c;而漏网的根源&#xff0c;是补查"失败一次就永久放弃"。做蓝牙的兄弟大概都见过…

作者头像 李华
网站建设 2026/11/4 2:13:01

C# 系列教程_6 运算符 系统精讲(新手友好・详尽版)

运算符&#xff08;Operator&#xff09;就是用来对数据执行运算、比较、判断的符号。参与运算的数据叫做操作数。例&#xff1a;int a 1 2;&#xff1a;运算符1 和 2&#xff1a;操作数1 2&#xff1a;表达式&#xff08;Expression&#xff09;&#xff0c;表达式运算后会…

作者头像 李华
网站建设 2026/11/4 2:10:28

告别 Node 环境难题!Codex 一键安装包完整实操教程

前言 相比手动安装 Node.js、再逐条敲命令&#xff0c;一键安装包已经把环境配置、依赖安装和客户端部署全部打包好&#xff0c;省去了繁琐的搭建步骤&#xff0c;特别适合不想折腾、希望快速上手的用户。整个过程中只需按提示操作&#xff0c;几分钟就能开始使用。 一、下载…

作者头像 李华