优化前如何检查 Prompt 中最耗 Token 的部分

优化前如何检查 Prompt 中最耗 Token 的部分
当 LLM 请求成本上升,或者快要触及上下文窗口时,很多人会先删掉“看起来最长”的那段文字。但字符数、单词数和 Token 数并不是固定换算关系。这样做可能只省下少量 Token,却误删了保障质量、格式或安全的关键指令。
更稳妥的方法是:先检查 Prompt 中最耗 Token 的部分,再开始优化。把完整请求拆成可测量的组件,记录基线,每次只删除或替换一个组件,然后比较 input token 的变化。得到数据之后,再决定哪些内容应该压缩、按需检索、摘要或删除。
本文提供一套可复用的 Prompt Token 拆分流程、可以直接测试的示例,以及适合放进 Pull Request 或 Prompt 评审文档的审计表。
什么是 Prompt 的“组件”?
在这套方法中,只要某部分能够单独移除,并且其他测试条件保持不变,就可以把它视为一个组件。常见组件包括:
- System Prompt;
- Developer 指令或框架自动添加的包装消息;
- 工具定义与 JSON Schema;
- Few-shot 示例;
- RAG 检索内容;
- 对话历史;
- 用户输入;
- 结构化输出 Schema;
- 重复的元数据、政策或模板。
不要只检查 Prompt 编辑器中能看到的文字。模型最终收到的序列化请求,可能还包含工具 Schema、框架消息、历史记录和动态检索内容。基线必须尽量还原真实请求。
为什么不能只看文字长度
Token 切分会受到 tokenizer、模型系列、标点、空格、代码、JSON、URL、标识符和语言影响。一段不长但字段很多的工具 Schema,可能比一段更长的普通英文占用更多 Token。
如果模型提供商支持请求前计数,应优先使用官方计数方式。OpenAI 为 Responses 请求提供 input token 计数接口,Anthropic 提供 Message token counting 接口,Gemini 提供 countTokens。tiktoken 等离线 tokenizer 适合其明确支持的编码,但不能把某个 tokenizer 的结果当成所有模型的通用答案。
最实用的规则是:固定同一个目标模型、同一种计数方式和同一份序列化请求,每次只改变一个组件。
分七步检查 Prompt 中最耗 Token 的部分
第一步:保存一份接近生产环境的完整请求
选择真实工作流中具有代表性的请求。包含 System 和 Developer 层、实际启用的工具、响应 Schema、常见检索量、典型对话历史和正常用户消息。
删除密钥和个人信息,但保留整体结构。如果生产环境会路由到不同工具集或不同检索规模,应分别建立基线。
第二步:加入稳定的组件边界
把各部分复制到测试夹具中,并加入明确标记。标记可以提高可读性,也能减少测试时误改其他组件的风险。
<<<SYSTEM>>>
你是客服助手。请遵守退款政策,并返回 JSON。
<<<END_SYSTEM>>>
<<<TOOLS>>>
[在这里粘贴序列化后的工具定义或 Schema。]
<<<END_TOOLS>>>
<<<EXAMPLES>>>
[在这里粘贴 Few-shot 示例。]
<<<END_EXAMPLES>>>
<<<RETRIEVAL>>>
[在这里粘贴检索片段。]
<<<END_RETRIEVAL>>>
<<<HISTORY>>>
[在这里粘贴有代表性的对话历史。]
<<<END_HISTORY>>>
<<<USER>>>
商品拆封 21 天后还能退货吗?
<<<END_USER>>>
这些标签会增加少量仅用于测试的 Token。所有变体都保留相同标签,差值才具有可比性。
第三步:测量完整基线
用与目标模型匹配的方法统计完整请求:
- 如果提供商提供请求前 Token 计数接口,优先使用该接口;
- 否则使用该模型明确指定的 tokenizer;
- 完成真实请求后,保存接口返回的 input 和 output usage。
同时记录模型 ID、tokenizer 或计数方式、请求路径、日期和基线 input token。脱离模型与计数方法的单个数字,很难在之后复用。
第四步:进行单变量删减测试
复制基线,每个版本只删除一个组件。不要一次同时精简多个部分。
| 变体 | 唯一变化 | 差值代表什么 |
|---|---|---|
| 完整基线 | 无 | 接近生产请求的总输入 |
| 无工具 | 删除工具定义 | 工具与 Schema 开销 |
| 无示例 | 删除 Few-shot 示例 | 示例开销 |
| 无检索 | 删除检索片段 | RAG 内容开销 |
| 无历史 | 删除历史消息 | 对话历史开销 |
| 最小 System | 只保留关键约束 | 可能可压缩的指令开销 |
每个组件的估算方式为:
组件估算 Token = 基线 input token - 变体 input token
这个差值不是对模型内部机制的数学分解,但因为序列化输入受控、变动组件明确,所以非常适合工程决策。
第五步:同时按单次占用和重复次数排序
单次很大的组件,不一定是工作流总成本最高的组件。还要记录它会被发送多少次。
重复 Token 暴露量 = 组件估算 Token × 适用调用次数 × 最大重试次数
例如,一个 900 Token 的工具 Schema 如果被发送 20 次,累计输入暴露量会超过一个只使用一次的 6,000 Token 参考文档。多智能体工作流尤其要检查完整调用图,而不只是第一次请求。
建议做两种排序:
- 单次请求占比:定位上下文窗口压力;
- 重复暴露量:定位成本和延迟压力。
第六步:用 TokenTest 验证结果
TokenTest.io 可以在你找出重组件之后提供两类验证。
第一,用相关端点运行 TokenTest 评测,并查看 Token integrity 结果。当前 D4 检查包括 usage 是否存在、总量是否一致、输入是否随 Prompt 增长、输出计量是否合理、Token 上限与停止信号是否关联、流式 usage 是否一致,以及缓存 Token 证据。这些检查用于判断真实端点在请求改变后是否合理报告 Token 行为。
第二,打开 高级 → 协议与离线分析,粘贴原始响应 JSON。无需提交 API Key,也可以检查响应中是否存在模型和 usage 证据。
先粘贴这份基线示例:
{
"id": "prompt_audit_before",
"model": "your-model-id",
"content": [
{"type": "text", "text": "AUDIT_OK 7e42b9"}
],
"usage": {
"input_tokens": 8420,
"output_tokens": 34
}
}
然后粘贴一个只删除检索内容的变体响应:
{
"id": "prompt_audit_no_retrieval",
"model": "your-model-id",
"content": [
{"type": "text", "text": "AUDIT_OK 7e42b9"}
],
"usage": {
"input_tokens": 5160,
"output_tokens": 33
}
}
在这个受控示例中,input token 相差 3,260,说明被删除的检索组件占比最高。生产决策必须使用真实响应和实际模型 ID。这里的数字只用于演示对比方法,不是基准测试或价格声明。
如果需要更完整的上线前端点排查流程,可继续阅读《TokenTest.io 如何在上线前调试高成本 Prompt》。
第七步:优先优化“高收益、低风险”组件
最大的组件不一定应该直接删除。可以按以下四项评估:估算 Token、重复次数、行为风险和可选动作。
| 组件 | 估算占用 | 重复情况 | 修改风险 | 建议的第一步 |
|---|---|---|---|---|
| 重复指令 | 高 | 每次调用 | 低至中 | 去重 |
| 工具 Schema | 中至高 | 工具调用 | 中 | 路由后再加载工具 |
| 检索内容 | 高且波动 | 检索调用 | 中 | 限制数量、重排或按需检索 |
| Few-shot 示例 | 中 | 相关调用 | 中至高 | 删除重复示例 |
| 对话历史 | 持续增长 | 后续轮次 | 中至高 | 达到阈值后摘要 |
| 核心安全或格式规则 | 通常较小 | 每次调用 | 高 | 保留并做回归测试 |
优先选择“测得差值大、修改风险低”的组件。每次优化后,都要重新测试任务完成度、安全性、格式、工具选择和答案质量。
可复用的 Prompt 组件审计表
可以把下表复制到 Pull Request、Prompt Registry 或实验记录中。
| 组件 | 基线是否包含 | 变体计数 | 估算 Token | 每轮调用 | 重试上限 | 重复暴露量 | 拟议修改 | 质量检查 |
|---|---|---|---|---|---|---|---|---|
| System | 是 | |||||||
| Developer/框架 | 是 | |||||||
| 工具/Schema | 是 | |||||||
| Few-shot 示例 | 是 | |||||||
| 检索内容 | 是 | |||||||
| 对话历史 | 是 | |||||||
| 用户输入 | 是 | |||||||
| 响应 Schema | 是 |
把完整夹具和结果一起保存。之后再修改 Prompt 时,就能与相同基线比较,而不是依赖记忆。
分析 Prompt Token 用量时的常见错误
只统计源文件,不统计序列化请求
框架可能在运行时加入包装消息、选定工具、Schema 描述或历史记录。要检查真正发送的内容,而不只是手写的 Prompt 文件。
一次修改多个组件
如果同一个变体同时缩短 System Prompt、删除示例并限制检索,你无法判断哪项修改带来节省,也无法定位哪项修改破坏了行为。
使用不同模型或 tokenizer 做横向差值
组件审计期间应固定目标模型和计数方式。迁移模型后,应重新运行完整审计。
只追求更少 Token,不测试结果
更短不等于更好。至少保留一组回归用例,用于检查关键约束、工具调用、输出结构和典型边界条件。可参考《如何建立一套 Token 感知的 Prompt 审查流程》,把这些检查做成发布门槛。
忽略多语言版本
不要假设英文 Prompt 与中文翻译的 Token 数成固定比例。每个本地化请求都应使用实际目标模型重新统计。可阅读《为什么中文 Prompt 的 Token 预算可能和英文不同》了解专门的对比方法。
常见问题
能否精确计算每个 Prompt 组件的 Token?
如果组件可以独立序列化,并且你使用兼容 tokenizer,就能得到组件自身的精确计数。但完整聊天请求可能带有提供商特定的格式或包装,因此基于完整请求的单变量删减通常更适合工程决策。
应该先优化 System Prompt 吗?
只有在测量显示它占比明显,而且行为测试证明可以安全修改时才应该优先优化。工具 Schema、检索、历史或重复示例可能更重。
TokenTest 能替代提供商的 Token Counter 吗?
不能。输入规划应使用官方请求前计数或正确 tokenizer。TokenTest 适合在修改后检查真实端点行为、usage 完整性和原始响应证据。
应该多久重新审计一次?
当模型、tokenizer、工具集、检索策略、响应 Schema、Prompt 模板或历史策略发生变化时,应重新审计。较大的 Prompt 修改也适合在合并前运行一次。
先检查,再优化
可靠的方法不是先删掉看起来最长的段落,而是先保存完整基线,每次只移除一个组件,按差值、重复次数和风险排序,再用真实端点的 usage 证据验证最终结果。
当你要检查 Prompt 中最耗 Token 的部分时,应优先处理“可以测量、反复发送、且修改风险可控”的组件。打开 TokenTest.io,测试你的端点或粘贴原始响应,把结果保存为下一次 Prompt 优化前的明确预算。