上个月对账的时候,我盯着账单里那一串输入 token 的数字看了三遍,才确认自己没看错:某个商业编码代理一个月吃掉了我接近六位数的 token 费用。翻明细时发现,最离谱的不是我写的需求,而是它自带的那份系统提示词——每次请求都要完整读一遍,一万四千多 token,月账单里四分之一左右的消耗都花在这份“出厂说明书”上。后来我把日常编码工作迁到一个叫 Pi 的轻量级开源编码代理上,系统提示词从 14180 token 被我一路砍到 203 token,再配合上下文压缩和工具按需加载,单月输入 token 的量直接降了 85%。这篇就是这次迁移的完整复盘,含配置、实测数据和踩坑记录。
如果你也在用那种“开箱即用”的重型编码代理做日常开发,每月 token 费用水涨船高,或者只是想知道系统提示词到底是怎么把钱花掉的,这篇应该对胃口。我会先讲清楚 1.4W token 是从哪来的,再解释 Pi 为什么能把它压到 200 token,然后是完整迁移步骤和一份可复制的账单优化方案。
1. 先搞清楚钱花哪了:1.4W Token 的系统提示词到底塞了什么
1.1 每一轮请求都在为同一份提示词买单
很多人以为 AI 编程工具的 token 消耗主要来自我们输入的描述和 AI 生成的代码,这个印象对聊天机器人是对的,但对编码代理来说是错的。
编码代理的运行方式和聊天机器人有本质区别:它每处理一轮请求,都要把“系统提示词 + 历史对话 + 最新指令 + 相关文件内容”打包发给模型。这意味着系统提示词不是一次性成本,而是每一轮请求都重复计算的固定成本。你只输入“看看这个函数哪里有问题”,也要为那 1.4W token 的提示词付钱,因为模型必须把它当作上下文的第一段来读。
更麻烦的是编码代理的工作方式是长会话。它模仿一个“一直坐在终端里的工程师”,不会像普通聊天那样每次开新对话,而是几十轮、上百轮地保持同一个会话。一轮省 1.4W token 看着没什么,乘以 80 轮就是一个很大的数:每完成一个稍复杂点的任务,光系统提示词的固定开销就超过 100 万 token。一个月积累下来,这笔钱很快就变成账单上用黑体标出来的大数字。
所以想优化 AI 编程成本,第一刀就应该砍在系统提示词上。它是最稳定的、最可预测的、和最容易被忽视的重复支出。
1.2 1.4W Token 的构成拆解
我在迁移前把原工具的系统提示词导出,逐段拆开统计了一下,大致是这样一个构成:
| 组成部分 | 估计 Token 数 | 作用 |
|---|---|---|
| 内置工具定义 | 约 6500 | 几十个函数的 JSON Schema,每个 100~300 token |
| 工具使用规则 | 约 2200 | 什么情况调什么工具、工具调用的顺序和约束 |
| 编码行为准则 | 约 1800 | 代码风格、语言偏好、安全边界 |
| 少样本示例 | 约 1500 | 为了引导输出格式放入的演示对话 |
| 动态项目上下文 | 约 1400 | Git 状态、目录结构、语言统计等即时注入 |
| 输出格式与语气设置 | 约 800 | 对回答格式、详细程度的硬性要求 |
| 其他零散条目 | 约 600 | 版本信息、时间戳、环境描述 |
合在一起就是 14180 token 左右。注意一个关键事实:这 1.4W 里,真正和“当前任务”强相关的只有那一千多 token 的动态项目上下文,剩下的全是通用能力描述。也就是说,无论用户给什么任务,都要为这套庞大的“通用能力列表”付钱。
还有一个容易被忽略的问题:工具定义用的 JSON Schema 占大头。模型只有看到工具定义才知道能调哪些函数,所以早期编码代理倾向于把所有工具一次全塞进去,不考虑你是不是真的用到。这就相当于进餐厅先把整本菜单念一遍,哪怕你只想点一杯水。
2. Pi 凭什么能把系统提示词压到 200 Token
2.1 极简系统提示词:只保留身份与铁律
Pi 给我最大的启发是它的设计哲学:系统提示词只保留两类东西,一是“你是谁”,二是“死线”。其他全部走按需加载。
“你是谁”就是一两句话,说明这是一个跑在终端里的编码助手,工作目录是当前项目。“死线”则是无论如何都不许违反的规则,比如不执行破坏性命令、不改 .gitignore 之外的文件、复杂操作先列计划。这两样加起来很容易控制在 200 token 以内。
这里有一个很多人会踩的思维误区:总以为上下文里放的东西越多,模型表现就越好。实际并不是。对一个已经训练过海量代码数据的模型来说,它根本不缺“如何写代码”的知识,缺的是“当前这个项目里该怎么用这些知识”的现场信息。把一堆通用准则塞进系统提示词,只是在给账单充值,并不会显著提升回答质量。
我自己实践后的体会是:系统提示词更像劳动合同而不是技术手册。技术细节应该放项目规则文件里,需要时再读;劳动合同只需要规定身份、边界、和出了问题怎么办。Pi 正是这样设计的,它把“详细的工具说明”全部拆出去,让系统提示词瘦身成一张便签。
2.2 工具与技能从“全量注入”改成“按需发现”
传统编码代理把所有工具的定义都放在系统提示词里,让模型从第一步就知道所有可用函数。Pi 的做法完全相反:它默认只注入少数基础能力,其余工具通过 MCP(Model Context Protocol,模型上下文协议)按需发现。
用生活化的类比解释 MCP:它相当于给 AI 提供了一个通用 USB-C 接口,需要连打印机就插打印机的驱动,需要连摄像头就插摄像头的驱动。传统方案是出厂时把所有驱动都焊在主板上,结果就是哪怕你只用一句命令,也得加载完整驱动库,白白占用上下文。
在 Pi 里,一个工具只有在模型决定调用它的时候才被注入定义。比如你让它读文件,它先把 read 工具的 Schema 拿进上下文,调用完就释放;不调用 shell 就算从头到尾不加载 shell 相关的定义。这样既保住了能力,又不会长期占用上下文窗口。
按需加载的代价是工具调用链路上多了一次发现请求,但这个代价是值得的,因为省下的 token 是每轮都在省的,而发现请求只是偶尔发生一次。我从实际用量统计来看,这个取舍几乎不需要犹豫。
2.3 上下文管理:真正的省钱大头
系统提示词从 1.4W 降到 200,确实减少了固定开销,但如果你以为 85% 的降幅全靠这一点,那就错了。真正的大头是 Pi 对历史对话的上下文压缩策略。
传统编码代理在长会话里会把所有历史消息原封不动地放进下一轮请求,导致越用到后面成本越高。Pi 默认采用一种“分层摘要”策略:对话超过一定轮数后,会把前面的历史压缩成结构化摘要,而不是把原始消息全部回传。这就像每次开会之前,先看上一轮的会议纪要,而不是把当时的录音逐字重放一遍。
举个例子:一个 60 轮的任务会话,传统工具最后一轮可能要把前面 59 轮的全部内容都带上,每轮约 800 token 的话就是 4.7 万 token 的历史开销。Pi 会把前 40 轮压成一条 200~400 token 的摘要,最后一轮请求的输入量直接少一个数量级。
还有一层是缓存策略。模型服务商通常对重复的上下文前缀给缓存价格,系统提示词固定且命中的话,输入成本还能再降。Pi 的系统提示词只有 200 token,几乎每次都能命中缓存,这点是我原来没想到的额外收益。
3. 迁移到 Pi 的完整实操记录
3.1 迁移前先做三件事
我建议任何团队在迁移前都不要急着删掉旧工具,先花一个小时做完这三件事:
把日常任务清单列出来。我列出的场景大概是六类:读代码定位问题、跨文件重构、写单元测试、执行 Git 操作、写一次性脚本、处理构建报错。每一项对应一个“原来怎么用、现在怎么用”的清单,后面配置时就知道哪些能力必须保留,哪些只是理论上好看。
把系统提示词里真正有用的部分挑出来。注意不是让你照抄,而是提炼出“规则性内容”。我原来那套工具里的行为准则,真正管用的也就四条:先计划再动手、修改代码要给出 diff、不碰无关文件、遵守版本管理规范。这四条后来全部进了 Pi 的系统提示词。
设计好验证方式。我留了一周的“双轨期”,同一个任务先在原工具跑一遍,再用 Pi 跑一遍,记录成功率、完成时间、以及 token 消耗。没有验证就切换,后面出了问题你都不知道该找谁。
3.2 200 Token 系统提示词长什么样
这是我最终采用的系统提示词模板,按 tokenizer 统计约 203 token,标题里的“从 1.4W 砍到 200”说的就是它:
你是运行在终端里的编程助手 Pi,工作目录是当前项目。 规则: 1. 先理解任务,再给出计划;复杂任务必须向用户确认。 2. 不知道的信息先查,不许凭空猜测。 3. 只修改必要的文件,遵守 .gitignore。 4. 输出保持简洁;涉及代码改动时用 diff 展示。 5. 不执行明确有破坏性的命令,危险操作先提示。就这么短。你可能会怀疑:这么点提示词能干活吗?我的回答是能,因为编码能力本来就在模型自己脑子里,不需要写在系统提示词里。系统提示词只是“唤醒”模型的工作状态,而不是“教育”模型怎么写代码。
这里有一个实操细节:中文字符按 token 计算通常比英文贵,如果你用的是中文系统提示词,注意控制字数。上面这段有 130 多个汉字,在部分 tokenizer 下已经接近 200 token,如果想再压缩,可以把规则减到三条核心,把语气类描述删掉。
3.3 核心能力迁移:Shell、文件、Git、MCP
系统提示词只是第一步,真正的迁移是把原来依赖的内置能力在 Pi 里重新架起来。我的配置长这样:
{ "model": "fast-coding-model", "system_prompt_file": ".pi/system.txt", "tools": { "shell": true, "read": true, "write": true, "diff": true, "git": true }, "mcp_servers": { "project_index": { "command": "my-local-index-server", "args": ["--project-root", "${PROJECT_DIR}"] } }, "context": { "mode": "compact", "max_history_messages": 40, "compress_threshold": 6000, "cache_prompt_prefix": true } }几项关键配置的作用:shell打开终端命令执行能力,这是编码代理的根基,没有它就无法跑测试、查日志、装依赖。read和write是文件读写,注意这里只给了路径级权限,没有把所有文件都浸入上下文,文件内容是按需读的。git用来做状态查询和提交。project_index是在 MCP 里注册的一个本地项目索引服务,它只在需要全局搜索符号引用时才启动,日常对话完全不参与计费。
不建议一上来就把所有 MCP 服务全接上,每多一个服务,模型就多一层工具选择成本。迁移阶段只留最核心的三个:shell、文件、git,跑顺之后再逐渐加。
3.4 项目约定怎么带过去
这是迁移中最容易被轻视、也最容易失败的一步。原工具有一套很复杂的规则系统,能把项目里的代码风格、目录结构、命名规范都注入上下文。Pi 不这么做,它把项目约定放在项目根目录的一个规则文件里,测试后我发现这种方式性价比高得多。
规则文件内容示例:
# 项目约定 - 后端使用 Python 3.9+,前端使用 Vue,禁止引入重型 UI 框架。 - 新增功能必须配套单测,单测放在 tests/ 目录,文件按模块组织。 - 变量命名用 snake_case,常量用大写。 - 改动前先读 README.md 和 docs/ 下相关文档。 - 所有数据库查询必须走服务层,禁止在组件里直接写 SQL。关键点在于:这个文件不会被系统提示词全文加载,Pi 在需要时主动读取,或者在任务涉及对应文件时读取。效果是既保留了项目规范,又不会让规范成为每轮请求的固定开销。你可以把这个文件纳入版本管理,团队所有人共用,新成员上手时它还能当一份活文档。
4. 实测数据:Token 账单到底降了多少
4.1 测试方法和采集口径
我先说清楚我采集了多少数据,免得你以为我拍脑袋算的。我跑了 20 个工作日,每周都做同样一组 12 个任务,记录两套工具的输入 token、输出 token、请求轮数、以及任务成功率。采集口径是模型服务端返回的实际计费 token 数,不是我猜的估算值。
这里一个容易搞错的点是“计费 token 和上下文 token 不是一回事”。模型服务的计费规则通常是对输入消息重新切一次 token,系统提示词、历史消息、工具定义都会算,有时候还按消息条数和缓存命中情况打折。所以直接对比客户端显示的 token 数不可靠,我会以服务端为准。
采集期间保持任务列表完全一致,包括代码仓和分支,避免任务复杂度差异造成数据失真。下一节就是我最核心的一组对比数据。
4.2 分场景数据对比
| 任务类型 | 迁移前输入Token/任务 | 迁移后输入Token/任务 | 降幅 | 备注 |
|---|---|---|---|---|
| 定位单个 bug | 约 85000 | 约 12000 | 86% | 原工具把全套工具定义都带上了 |
| 跨文件小重构 | 约 240000 | 约 32000 | 87% | 上下文压缩效果最明显 |
| 写单元测试 | 约 180000 | 约 26000 | 86% | 输出 token 反而略增,因为测试更完整 |
| 查日志 / 跑命令 | 约 43000 | 约 7000 | 84% | 输出 token 差异不大 |
| 一次性脚本生成 | 约 65000 | 约 11000 | 83% | 任务成功率基本相同 |
| 大型全局重构 | 约 600000 | 约 90000 | 85% | 成功率下降约 8%,后面会细说 |
可以看到每类任务的降幅都在 83%~87% 之间,平均为 85.4%。这和我账单上的实际数字吻合:迁移前一个月输入 token 约 1.25 亿,迁移后约 1800 万,节省了约 1.07 亿 token 的输入量。
比较诚实地说,输出 token 并没有等比例下降,某些任务还略有上升。但因为输入 token 按单价算通常比输出便宜三四倍,所以总成本的变化主要由输入侧主导。账单降幅比我预期的还要好一点,因为缓存命中又省了一笔。
4.3 85% 的降幅是从哪几项挤出来的
很多人会想当然地认为,85% 全靠“系统提示词从 1.4W 砍到 200”。如果只做这一项,理论降幅其实只有 12% 左右。实际 85% 是多管齐下的结果,我把贡献拆分了一下:
| 优化项 | 对降幅的大致贡献 | 原因 |
|---|---|---|
| 系统提示词瘦身 | 约 10%~15% | 每轮固定开销直接从 1.4W 降到 200 |
| 工具定义按需加载 | 约 25%~30% | 不再每轮注入几十个工具 Schema |
| 历史上下文压缩 | 约 30%~35% | 长会话不再回传全部原始消息 |
| 缓存与输入前缀复用 | 约 10%~15% | 固定前缀往往命中更便宜的缓存档位 |
| 输出约束与对话轮数减少 | 约 5%~10% | 更少废话后,总轮数进一步下降 |
合起来就是 85% 上下。最重要的启发是:系统提示词瘦身是“敲门砖”,但它解决的只是固定成本;如果不对历史上下文下狠手,省下的那 12% 很快会随着对话变长而反弹。所以后续维护时,我把优化重心放在上下文压缩参数上,而不是继续抠那几句系统提示词。
5. 迁移后踩坑实录与排查清单
5.1 坑一:Pi 不认项目里的老规矩
迁移第一天就翻车了。我让 Pi 修一个后端接口的小 bug,它按照通用编码风格把函数名改成了驼峰命名,直接和项目里既有的 snake_case 风格冲突,CI 直接红。原因很简单:Pi 没有加载项目规则文件时,就会按模型自己习惯的方式输出。
解决方案就是把规则文件纳入项目根目录并显式告诉 Pi 存在这样一个文件。我后来在系统提示词里补了一句“任务开始前先查看项目规则文件”,效果立竿见影。这也是为什么我不建议把系统提示词压到只剩一句“你是助手”,至少要留一个触发规则文件的钩子。
5.2 坑二:MCP 工具频繁掉线
第二个坑出在 MCP 服务稳定性上。我接入本地索引服务后,发现 Pi 偶尔会返回“工具不可用”,导致任务中断。排查后发现是 MCP 服务进程在空闲时被系统回收,Pi 又没做自动重启。
我的解法是写了一个守护脚本,定期探测 MCP 服务端口,不可用就拉起。更省心的方案是减少 MCP 服务数量,只保留真正高频使用的服务,把低频工具都通过 shell 命令代替。迁移初期最忌讳的就是为了“能力完整”把服务挂一堆,每多一个服务就是一个新的故障点。
5.3 坑三:长上下文被压缩后丢了细节
上下文压缩省 token,但确实有代价。大型全局重构任务中,Pi 把早期历史压缩后,会在后续步骤里忘掉某一处已经改动过文件的确切位置,偶尔出现重复修改同一个函数的情况。我在“大型全局重构”任务上统计到成功率约比原工具低 8%,主要就是这个原因。
应对方案有两个:一是把大任务拆成多个小阶段,每个阶段结束让 Pi 输出一份变更摘要;二是对关键文件使用引用模式,让 Pi 在需要时重新读取文件最新内容,而不是依赖早期历史。第二个方案最管用,因为重复读文件虽然多花一点 token,但错误率下降远比 token 成本重要。
5.4 坑四:团队环境行为不一致
迁移完成后,我发现同样一个任务,在我机器上 Pi 表现正常,在同事机器上却频繁改错文件。排查到最后是每个人的项目规则文件版本不一致,有人没有拉最新代码,有人还带着旧的规则样例。
解决方法是把规则文件路径固定,并把它和系统提示词文件一起放进仓库的公共配置目录,通过版本管理统一。顺便建议在团队内做一个迁移约定:谁的本地配置和主分支不一致,谁负责处理后续的回归问题。工具再便宜,也换不来团队协作里反复出现的认知差。
5.5 常见问题速查表
| 现象 | 出现频率 | 排查方向 | 解决建议 |
|---|---|---|---|
| 生成代码风格与项目不一致 | 高 | 是否加载了规则文件 | 检查 AGENTS 规则文件存在性与路径 |
| 工具调用返回失败 | 中 | MCP 服务状态、端口、进程 | 用守护脚本拉活,或减少服务数量 |
| 大型任务出现重复修改 | 中 | 历史压缩导致上下文丢失 | 拆阶段、关键文件改用引用模式 |
| 团队间回答差异大 | 中 | 配置版本不一致 | 配置入库,强制统一 |
| 垂直大文件处理卡顿 | 低 | 单文件内容超过上下文窗口 | 用 grep/搜索代替全文读取 |
这个表相当于我后来排障的 checklist。遇到问题先按表排查,再去看日志,比每次都从头分析要快得多。
6. 哪些场景先别跟着我迁
6.1 不适合迁移的几种情况
迁移不是无脑省钱,有几类场景我是坚决不建议照搬的。
依赖重度多模态的任务不建议迁。Pi 是纯文本为主的编码代理,原工具有不少视觉理解能力,比如根据截图识别页面布局错误、从设计稿里提取样式参数。这种任务一来 Pi 做不了,二来为了模拟类似效果又要把工具和模型能力堆回去,成本反而上去了。
企业合规和完整审计场景不建议迁。原工具带有一套成熟的权限管控、操作日志、审批流程,Pi 的开源方案相对轻,虽然可以通过外部脚本补齐一部分,但真到审计要求时,逐条弥补的成本会超过你省下的 token 钱。
对代码仓库无差别的全局搜索重建类任务,也要谨慎。Pi 的上下文压缩是按“会话”做的,不是按“代码库”做的。在几十个模块的大仓库里做需要同时感知十几个文件的架构重构,它那套摘要很容易把文件间关联关系抹平。这种情况下,它省下的 token 会比额外花掉的还多,你得反复让它重新读文件,任务完成时间会明显拉长。
6.2 我的最终判断
我不主张所有人都把系统提示词砍到 200 token。我的判断标准是:系统提示词等于固定租金,历史上下文等于滚动成本,工具定义等于按人头收费的订阅。你先分清这三笔钱,再决定砍哪一笔。
就我个人而言,日常 80% 的编码任务其实用不到那套重型工具的大部分能力,剩下 20% 的复杂任务我再临时切回原工具,用“双轨制”跑了一个月之后,整体账单降幅依旧稳定在 80% 以上,同事那边也没有再抱怨过工具不好使。
最后再分享一个从这次迁移里学到的通用思路:任何 AI 服务的成本优化,都先从“测量计费口径”开始。你先搞清楚哪一部分 token 在重复消耗、哪一部分永远不会命中缓存,再去改配置。别看别人说系统提示词长就盲目砍,也别听人夸某个工具省钱就直接迁。把账单打开,逐项对一遍,你自然会知道该动哪一刀。