1. 从 1.4 万 Token 到 200 Token:这次迁移到底在省什么
第一次看到"系统提示词从 1.4W 砍到 200"这个数字对比时,我的反应和大多数人一样——要么是标题党,要么是砍掉了核心能力。毕竟在 AI 编程助手这个领域,系统提示词基本等同于这个工具的"人格"和"能力边界",1.4 万 Token 的系统提示词意味着什么?意味着每次对话还没开始,你就已经为大约一万四千个 Token 买了单。按主流大模型的输入计价方式粗算,如果一天跑 200 次对话,光是系统提示词这一项,一天就是 280 万 Token 的输入消耗。这个数字放在个人开发者身上可能还能忍,但放在团队日常使用场景里,月底账单出来的时候是真的会让人倒吸一口凉气。
我这次迁移的核心动机非常直接:降低单位对话的固定开销。所谓固定开销,就是不管你问的是"帮我写个快排"还是"解释一下这段报错",每次请求都要重复携带的那部分上下文。Claude Code 的系统提示词之所以庞大,是因为它内置了大量工具定义、行为规范、安全约束、输出格式要求、多轮对话管理逻辑等等。这些东西确实有用,但它们不应该以"每次全量重发"的方式存在。Pi 这个工具的思路完全不同——它把系统提示词压缩到了 200 Token 左右,把绝大部分能力通过外部工具调用和按需加载的方式来实现。
这里要先说清楚一个概念,避免新手误解:系统提示词短,不等于能力弱。这是两套完全不同的架构哲学。Claude Code 走的是"重提示词、轻编排"的路线,把所有规则塞进上下文让模型自己判断;Pi 走的是"轻提示词、重编排"的路线,系统提示词只负责告诉模型"你是一个编程助手,你可以调用以下工具",具体怎么用、什么时候用,交给外层的编排逻辑和工具本身的设计来约束。打个比方,前者像是给员工发了一本 500 页的员工手册,每次干活前都要先读一遍;后者像是给员工一张工牌和一把钥匙,告诉他"需要什么自己去拿"。
这次实战我完整走了一遍迁移流程,包括环境准备、配置改写、工具映射、行为对齐、实测验证五个阶段。整个过程踩了不少坑,也总结出了一些常规文档里不会写的经验。下面我会把每个环节拆开讲,重点放在"为什么这样设计"和"实际跑起来会遇到什么"这两件事上。适合正在被 Token 账单困扰、或者对 AI 编程助手底层机制感兴趣的开发者参考。如果你只是偶尔用用、对成本不敏感,那这篇文章的价值可能有限;但如果你每天要跑几百次对话,或者在做团队级的工具选型,那接下来的内容应该能帮你省下真金白银。
2. 两套架构的底层差异:为什么提示词能差出 70 倍
2.1 系统提示词到底装了什么
要理解 1.4 万和 200 的差距,得先搞清楚那 1.4 万 Token 里到底装了什么。我实际拆解过一份典型的重型编程助手系统提示词,大致可以分成这么几块:
- 工具定义:每个可调用工具的名称、描述、参数 schema、使用示例。一个功能完整的编程助手通常有 15 到 25 个工具,每个工具的完整定义平均 300 到 500 Token,光这一项就是 5000 到 10000 Token。
- 行为规范:什么时候该问用户、什么时候该直接动手、代码风格要求、注释规范、错误处理约定、安全边界等等。这部分通常 2000 到 4000 Token。
- 输出格式约束:Markdown 格式要求、代码块标注、文件路径引用方式、diff 展示规范等。这部分 1000 到 2000 Token。
- 上下文管理规则:多轮对话怎么压缩、历史信息怎么取舍、长文件怎么分片处理。这部分 1000 到 2000 Token。
- 安全与合规约束:哪些操作要二次确认、哪些文件不能碰、哪些命令禁止执行。这部分 500 到 1500 Token。
加起来,1.4 万 Token 其实一点都不夸张,甚至算是克制的结果。问题在于,这些内容里有大量是静态的、可复用的、不需要每次重发的。工具定义尤其典型——工具列表在会话期间基本不变,但每次请求都要完整携带一遍,这就是纯粹的浪费。
2.2 Pi 的"薄提示词 + 厚编排"是怎么运作的
Pi 的做法是把上面这些内容做了一次彻底的分层。系统提示词里只保留最核心的身份声明和工具调用协议,大概 200 Token 左右,内容大致是"你是一个编程助手,可以通过以下方式调用工具,请根据任务需要选择合适的工具"。剩下的全部下沉到两个地方:
第一层是工具注册表。工具的定义不再塞进系统提示词,而是由外层编排程序维护。当模型决定要调用某个工具时,编排程序根据工具名去注册表里查完整的参数 schema,然后执行。模型本身不需要"记住"所有工具的完整定义,它只需要知道"有这么个工具存在"以及"大概能干什么"。这就像你不需要背下整个通讯录,只需要知道手机里有通讯录这个功能,需要的时候去查就行。
第二层是按需注入的上下文。行为规范、输出格式这些内容,Pi 把它们拆成了独立的"指令片段",只在特定场景下注入。比如当模型要执行文件写入操作时,才注入"文件写入规范"这一段;当模型要处理报错时,才注入"错误处理约定"这一段。这种按需注入的方式,让每次请求实际携带的上下文量大幅下降。
我用一个具体的数字对比来说明差距。假设一次典型的"帮我修复这个 bug"的对话:
| 项目 | Claude Code 方案 | Pi 方案 |
|---|---|---|
| 系统提示词 | 约 14000 Token | 约 200 Token |
| 工具定义 | 包含在系统提示词内 | 按需查询,不占上下文 |
| 行为规范 | 包含在系统提示词内 | 按需注入,平均 300 Token |
| 单次对话固定开销 | 约 14000 Token | 约 500 Token |
| 200 次对话日开销 | 约 280 万 Token | 约 10 万 Token |
这个对比就是"账单暴降 85%"这个说法的来源。注意,这里说的是固定开销的下降,不是总开销的下降。实际总开销还要算上对话内容本身、工具调用返回结果、多轮历史等,但固定开销的下降是实打实的,而且随着对话次数增加,节省的绝对值会越来越大。
2.3 这种架构转变的代价是什么
天下没有免费的午餐。Pi 这种薄提示词架构省了 Token,但代价也很明显:
第一,编排层复杂度上升。原来模型自己就能判断的事情,现在需要外层程序来辅助判断。比如"什么时候该问用户确认",Claude Code 靠系统提示词里的规则让模型自己决定,Pi 则需要编排程序根据操作类型来判断——写文件要确认、删文件要确认、执行命令要确认。这意味着你需要维护一套更复杂的编排逻辑。
第二,行为一致性需要额外保障。重型提示词的一个好处是行为稳定,因为规则都写在明面上。薄提示词架构下,模型的行为更多依赖工具设计和编排逻辑,如果工具设计得不好,模型可能会做出意料之外的选择。我实测下来,Pi 在简单任务上表现很稳,但在复杂多步任务上,偶尔会出现"工具选择犹豫"的情况,需要编排层做兜底。
第三,迁移成本真实存在。如果你已经有一套基于 Claude Code 的工作流,迁移到 Pi 不是改个配置就完事,需要重新映射工具、重写部分编排逻辑、重新验证行为。这部分工作量我后面会详细讲。
理解了这些底层差异,接下来的实操部分就好懂了。你做的每一步配置,本质上都是在"把原来塞在提示词里的东西,搬到编排层去"。
3. 迁移前的环境盘点与工具映射
3.1 先搞清楚你现在的依赖面
动手之前,我建议先做一次彻底的依赖盘点。很多人迁移到一半发现跑不通,就是因为没搞清楚自己到底依赖了原工具的哪些能力。我的做法是列一张清单,把日常使用中实际触发过的功能全部记下来,然后逐个确认 Pi 这边有没有对应方案。
盘点维度建议按这个顺序来:
- 文件操作类:读文件、写文件、改文件、列目录、搜索文件内容。这是最基础的一类,几乎所有编程助手都支持。
- 命令执行类:跑测试、跑构建、跑 lint、跑 git 操作。这类操作的风险等级最高,需要重点确认权限控制。
- 代码理解类:符号查找、引用查找、类型推断、依赖分析。这类能力在不同工具间差异最大。
- 外部集成类:访问文档、查询 API、调用外部服务。这类通常需要额外的配置。
- 交互类:多轮对话、中断恢复、任务分解、结果确认。这类影响使用体验。
我当时的清单大概有 30 多项,逐项对照下来,发现 Pi 原生支持了其中 80% 左右,剩下的 20% 需要通过自定义工具或者编排逻辑来补。这个比例算是比较健康的,如果原生支持率低于 60%,迁移的性价比就要重新评估了。
3.2 工具映射表:哪些能直接对应,哪些要自己补
下面是我实际整理的工具映射表,把 Claude Code 的常见能力和 Pi 的对应方案列出来。这张表是迁移的核心参考,建议你根据自己的实际使用情况做增删。
| 原能力 | Pi 对应方案 | 迁移难度 | 备注 |
|---|---|---|---|
| 读取文件 | 原生 read 工具 | 低 | 参数基本一致 |
| 写入文件 | 原生 write 工具 | 低 | 注意路径规范差异 |
| 编辑文件 | 原生 edit 工具 | 中 | 匹配逻辑略有不同 |
| 执行命令 | 原生 bash 工具 | 中 | 权限模型需要重新配置 |
| 搜索内容 | 原生 grep 工具 | 低 | 正则语法基本兼容 |
| 查找文件 | 原生 glob 工具 | 低 | 通配符规则一致 |
| 符号查找 | 需自定义或依赖 LSP | 高 | 这是最大的能力缺口 |
| 引用查找 | 需自定义或依赖 LSP | 高 | 同上 |
| 任务分解 | 编排层实现 | 中 | 需要自己写逻辑 |
| 结果确认 | 编排层实现 | 中 | 需要自己写逻辑 |
| 多轮压缩 | 编排层实现 | 高 | 需要设计压缩策略 |
从这张表能看出来,基础文件操作和命令执行的迁移难度最低,基本上改改配置就能跑。代码理解类能力是最大的缺口,因为这类能力在原工具里往往依赖内置的索引和语言服务,Pi 这边需要你自己接 LSP 或者用外部工具补。交互类能力需要自己在编排层实现,这是迁移工作量的大头。
我的建议是分阶段迁移:第一阶段先把文件操作和命令执行跑通,保证基本可用;第二阶段补代码理解能力;第三阶段优化交互体验。不要想着一次性全迁完,那样很容易中途卡死。
3.3 环境准备中最容易忽略的三个细节
环境准备这块,官方文档通常会告诉你装什么依赖、配什么变量,但有几个细节是我踩过坑之后才意识到的:
第一个是工作目录的边界。Pi 默认的工作目录范围可能和你预期的不一样。我一开始没注意,结果模型试图读取工作目录之外的文件时被拦了,排查了半天才发现是配置问题。建议在配置里明确指定允许访问的目录范围,并且用绝对路径,避免相对路径带来的歧义。
第二个是命令执行的超时设置。默认超时时间通常比较短,跑个完整的测试套件可能就超时了。我建议根据你的实际场景调整,跑单元测试设 60 秒,跑集成测试设 300 秒,跑构建设 600 秒。超时设置太短会导致任务频繁中断,太长又会在卡死时浪费资源。
第三个是输出长度的限制。命令执行的输出如果太长,会被截断,模型只能看到前面一部分。这在跑测试的时候特别坑——错误信息往往在输出末尾,结果被截掉了。解决办法是在编排层做输出处理,比如只保留最后 N 行,或者用 grep 过滤出关键信息再返回给模型。
提示:环境准备阶段建议先用一个最小化的测试项目验证,不要直接上生产项目。我见过有人直接在主仓库上试,结果模型误操作改了一堆文件,回滚都费劲。
4. 配置改写:把 1.4 万 Token 的规则拆解重组
4.1 系统提示词的"减法"怎么做
配置改写的核心思路是做减法。原来系统提示词里的每一条规则,你都要问自己三个问题:这条规则是必须的吗?这条规则能移到编排层吗?这条规则能按需注入吗?
我实际拆解的时候,把原系统提示词的内容分成了四类:
第一类:身份声明。比如"你是一个专业的编程助手"。这类必须保留,但可以极度精简,一句话就够。
第二类:工具调用协议。比如"你可以通过特定格式调用工具"。这类必须保留,因为模型需要知道怎么触发工具调用。但具体的工具定义可以移走,只保留调用格式说明。
第三类:行为规范。比如"修改文件前要确认""不要执行危险命令"。这类可以大部分移到编排层,由程序来强制约束,而不是靠模型自觉。
第四类:输出格式。比如"代码块要标注语言""文件路径要用特定格式"。这类可以按需注入,或者干脆在编排层做后处理。
按这个分类处理下来,原本 1.4 万 Token 的内容,真正必须留在系统提示词里的只有 200 Token 左右。剩下的要么移到了编排层,要么变成了按需注入的片段。
4.2 按需注入的触发条件设计
按需注入是 Pi 架构的精髓,但触发条件的设计很讲究。设计得太粗,起不到节省效果;设计得太细,编排逻辑会变得极其复杂。我实测下来,比较合理的粒度是按操作类型来触发。
具体来说,我设计了这么几组注入规则:
- 当模型要执行文件写入时,注入"文件写入规范"片段,包含路径规范、编码要求、换行符处理等。
- 当模型要执行命令时,注入"命令执行规范"片段,包含超时设置、输出处理、错误码解读等。
- 当模型要处理报错时,注入"错误处理约定"片段,包含常见错误类型、排查思路、修复优先级等。
- 当模型要多步操作时,注入"任务分解规范"片段,包含步骤拆分原则、依赖处理、中断恢复等。
每组片段大概 200 到 500 Token,只在对应场景下注入。这样算下来,一次典型的文件修改操作,实际携带的上下文是 200(系统提示词)+ 300(文件写入规范)+ 对话内容,比原来动辄 1.4 万 Token 起步要轻得多。
这里有个经验:注入片段的内容要"够用就好",不要追求大而全。我一开始把文件写入规范写得很详细,结果发现大部分内容在实际操作中根本用不到,反而增加了 Token 消耗。后来精简到只保留最关键的几条,效果反而更好。
4.3 编排层的兜底逻辑怎么写
薄提示词架构下,编排层要承担起原来系统提示词的部分职责。我实际写的兜底逻辑主要覆盖三个方面:
权限控制。这是最重要的。所有文件写入、命令执行操作,都要经过权限检查。我的做法是维护一个白名单,明确哪些目录可写、哪些命令可执行。白名单之外的操作,一律拦截并提示用户确认。这个逻辑不能靠模型自觉,必须由程序强制。
输出后处理。模型返回的内容需要做格式化和校验。比如检查代码块是否正确闭合、文件路径是否存在、diff 格式是否合法。发现问题就自动修正或者重新请求。这层处理能显著提升输出的稳定性。
异常恢复。工具调用失败时,编排层要决定是重试、降级还是报错。我的策略是:网络类错误自动重试三次,参数类错误直接报错并提示模型修正,权限类错误拦截并提示用户。这套逻辑写下来大概 200 行代码,但能省掉大量手动排查的时间。
注意:编排层的兜底逻辑不要写得太"聪明"。我一开始试图让编排层自动修正模型的所有小错误,结果发现有些"错误"其实是模型的合理选择,自动修正反而帮了倒忙。后来改成只处理明确的、无歧义的错误,效果就好多了。
5. 实测验证:账单降了,但体验有没有降
5.1 我设计的四组对照测试
迁移完成后,我做了一组对照测试,目的是验证"账单降了,体验有没有降"。测试设计如下:
第一组:简单文件操作。任务是"读取某个配置文件,修改其中一个参数,保存"。这组测试的是基础能力,看迁移后是否还能稳定完成。
第二组:多步任务。任务是"找到项目里所有使用了某个废弃 API 的地方,逐个替换成新 API,然后跑测试验证"。这组测试的是任务分解和连续操作能力。
第三组:错误排查。任务是"跑测试,根据报错信息定位问题,修复后重新验证"。这组测试的是错误理解和迭代修复能力。
第四组:长对话。任务是连续进行 20 轮对话,每轮都是独立的代码问题。这组测试的是长对话下的上下文管理和成本控制。
每组测试我都跑了 10 次,记录成功率、平均耗时、Token 消耗三个指标。
5.2 实测数据与意外发现
测试结果如下表:
| 测试组 | 成功率 | 平均耗时 | 平均 Token 消耗 | 对比原方案 |
|---|---|---|---|---|
| 简单文件操作 | 10/10 | 8 秒 | 约 1200 | 节省约 70% |
| 多步任务 | 8/10 | 45 秒 | 约 8500 | 节省约 65% |
| 错误排查 | 7/10 | 60 秒 | 约 12000 | 节省约 60% |
| 长对话(20 轮) | 10/10 | 累计 180 秒 | 约 15000 | 节省约 85% |
几个意外发现值得说说:
第一,简单任务的节省比例反而不如长对话。这符合预期,因为简单任务的固定开销占比高,但对话内容本身也有消耗,所以总节省比例被拉低了。长对话的节省比例最高,因为固定开销被摊薄了,而且按需注入的机制在长对话中优势更明显。
第二,多步任务和错误排查的成功率有下降。多步任务从原来的 9/10 降到了 8/10,错误排查从 8/10 降到了 7/10。分析原因,主要是编排层的任务分解逻辑还不够完善,在复杂场景下偶尔会"迷路"。这是薄提示词架构的固有代价,需要通过优化编排逻辑来弥补。
第三,耗时普遍增加了 10% 到 20%。因为多了编排层的处理,以及按需注入带来的额外请求。这个代价我认为可以接受,毕竟省下来的钱是实打实的。
第四,长对话的上下文管理是个关键点。20 轮对话下来,如果不做压缩,上下文会膨胀得很快。我用的策略是每 5 轮做一次摘要压缩,把历史对话压缩成关键信息。这个策略实测下来效果不错,既控制了 Token 消耗,又保留了必要的上下文。
5.3 哪些场景不适合迁移
实测下来,有几类场景我建议不要迁移,或者至少不要急着迁移:
第一类是重度依赖代码理解能力的场景。如果你的日常工作大量涉及符号查找、引用分析、类型推断,Pi 这边需要额外接 LSP,配置复杂度高,收益不明显。
第二类是对响应速度极度敏感的场景。编排层的额外处理会带来延迟,如果你需要毫秒级的响应,这个延迟可能无法接受。
第三类是任务极其复杂的场景。多步任务和错误排查的成功率下降说明,Pi 在复杂任务上的稳定性还不如重型提示词方案。如果你的任务经常涉及十几步的连续操作,建议再观望一段时间。
第四类是小规模使用场景。如果你一天就跑几十次对话,省下来的钱可能还不够覆盖迁移成本。这种情况下,继续用原方案更划算。
6. 踩坑记录:那些文档里不会写的细节
6.1 工具参数不兼容导致的静默失败
迁移过程中最坑的一个问题,是工具参数不兼容导致的静默失败。具体表现是:模型调用了工具,工具也返回了结果,但结果不对,而且没有任何报错。我排查了很久才发现,是某个参数的类型不匹配——原工具接受字符串,Pi 这边要求数组,模型按原习惯传了字符串,Pi 这边做了隐式转换,转换结果不符合预期,但没报错。
这类问题的隐蔽性极强,因为表面上一切正常。我的解决办法是在编排层加一层参数校验,对每个工具的关键参数做类型和范围检查,不匹配就明确报错,而不是静默转换。这层校验加上之后,类似问题基本绝迹了。
提示:迁移后一定要做一轮完整的回归测试,重点检查那些"看起来正常但结果不对"的情况。静默失败比显式报错危险得多。
6.2 上下文压缩策略的反复调整
长对话场景下的上下文压缩,我前后调整了四五次才找到比较合适的策略。一开始我用的是"固定轮数压缩",每 5 轮压缩一次,结果发现有些关键信息在压缩中丢失了,导致后续对话出现上下文断裂。后来改成"按 Token 量压缩",超过阈值才压缩,效果好一些,但压缩时机不好控制。
最终的方案是混合策略:既看轮数也看 Token 量,两个条件满足其一就触发压缩;压缩时保留最近 3 轮的完整内容,更早的内容做摘要;摘要时优先保留文件路径、函数名、错误信息这类结构化信息,对话性的内容可以大幅精简。这套策略实测下来,20 轮对话的上下文能控制在合理范围内,同时关键信息不丢失。
6.3 权限配置过严导致的效率下降
权限配置这块我一开始走的是"最严"路线,所有写操作都要确认。结果实际用起来极其痛苦,改个配置文件都要点确认,效率比原来还低。后来我调整了策略,按操作类型分级:
- 读操作:全部放行,不确认。
- 写操作:工作目录内的放行,工作目录外的确认。
- 命令执行:白名单内的放行,白名单外的确认。
- 删除操作:一律确认。
这个分级策略在安全和效率之间找到了比较好的平衡点。实测下来,日常操作中需要确认的比例从原来的 100% 降到了 15% 左右,体验好了很多。
6.4 模型"偷懒"行为的识别与纠正
薄提示词架构下,模型偶尔会出现"偷懒"行为——比如该分步执行的任务,它试图一步到位;该验证的结果,它跳过验证直接汇报完成。这类行为在重型提示词方案下较少见,因为系统提示词里有明确的"必须分步""必须验证"的约束。
我的纠正办法是在编排层加行为检测:检测到模型试图跳过验证步骤时,强制插入验证环节;检测到模型试图一步完成多步任务时,强制拆解。这套检测逻辑写起来不复杂,但效果很明显,能把"偷懒"行为的比例降到很低。
7. 迁移后的日常维护与持续优化
7.1 建立 Token 消耗的监控习惯
迁移完成后,我养成了一个习惯:每周看一次 Token 消耗报表。不是为了省钱而省钱,而是通过消耗数据来发现异常。比如某周消耗突然暴涨,通常意味着有任务陷入了循环,或者某个工具的返回结果异常膨胀。早发现早处理,能避免账单失控。
监控的粒度建议按"任务类型"来分,而不是只看总量。我分了文件操作、命令执行、代码理解、对话问答四类,分别记录消耗。这样能清楚看到哪类任务的成本最高,有针对性地优化。
7.2 按需注入片段的迭代
按需注入的片段不是一次写完就完事的,需要根据实际使用情况持续迭代。我的做法是每月回顾一次,看看哪些片段被频繁触发但效果一般,哪些场景缺少对应的片段。频繁触发但效果一般的片段,考虑精简或合并;缺少片段的场景,补充新的片段。
迭代的时候要注意版本管理。每次修改片段都记录一下改动内容和原因,方便回溯。我有一次改了一个片段,结果导致某类任务的成功率下降,靠版本记录才快速定位到问题。
7.3 编排层逻辑的模块化
编排层的逻辑会随着使用不断增长,如果不做模块化,很快就会变成一团乱麻。我的做法是按职责拆成独立模块:权限模块、注入模块、校验模块、压缩模块、监控模块。每个模块有清晰的输入输出接口,模块之间通过标准化的数据结构通信。
这样拆的好处是,修改某个模块不会影响其他模块,测试也方便。比如我想调整压缩策略,只需要改压缩模块,跑一下压缩模块的单元测试就行,不用整个流程重跑。
7.4 什么时候该考虑回迁
最后说一个现实问题:什么时候该考虑回迁。迁移不是单向的,如果 Pi 方案在你的场景下确实不合适,回迁也是合理选择。我总结了几条回迁信号:
- 复杂任务成功率持续低于 70%,且优化编排逻辑后没有明显改善。
- 维护编排层的成本超过了节省的 Token 成本。
- 出现了 Pi 架构无法解决的能力缺口,且没有可行的补充方案。
- 团队其他成员的学习成本过高,影响了整体效率。
出现这些信号时,不要硬撑。工具是为人服务的,不是人为工具服务。我见过有人为了"坚持用新方案"而忍受各种不便,这就本末倒置了。
我个人在实际操作中的体会是,Pi 这套方案最适合高频、中低复杂度、对成本敏感的使用场景。如果你的场景符合这个画像,迁移的收益会很明显;如果不符合,建议先小范围试点,验证效果后再决定是否全面迁移。迁移过程中最重要的不是照搬配置,而是理解"为什么要这样设计",只有这样,遇到问题时才能自己找到解法,而不是到处找现成答案。