芥末
发布于 2026-06-17 / 2 阅读
0
0

AI 编程工具的 Token 成本机制:缓存、配置与对话策略

使用 AI 编程工具时,很多人会有一个疑问:明明只输入了一句话,为什么额度消耗这么快?

原因很简单:模型收到的内容远不止那一句话。一次完整调用通常会包含系统指令、工具定义、项目规则、对话历史、工具调用结果,以及本轮新增输入。用户刚输入的那一小段文本,经常只占总输入的很小一部分。

要控制 AI 编程成本,不能只盯着“我说了多少字”,而要理解三件事:

  1. Token 是怎么计算的;
  2. 每次 API 调用实际发送了什么;
  3. 哪些内容可以被缓存,哪些内容每次都要重新付费。

Token 不是字数

Token 是大语言模型处理文本时的基本单位,它不是严格意义上的“字”或“词”。不同模型使用的 tokenizer 不完全一样,但可以用下面的经验值估算。

内容类型 粗略换算 说明
英文 1 token ≈ 4 个字符,约等于 0.75 个单词 hello 通常是 1 个 token,长单词可能被拆分
中文 1 个汉字 ≈ 1~2 个 token 常见汉字通常较省,生僻字或复杂组合可能更贵
代码 波动较大 关键字、变量名、符号、缩进都会消耗 token

一些常见规模可以这样估算:

内容 大致 Token 数
1000 字中文说明 1200~1800 tokens
200 行 Python 代码 2000~4000 tokens
一份中等规模项目规则文档 2000~5000 tokens
一个复杂工具返回结果 3000~10000 tokens

代码的 token 消耗经常比直觉更高,因为模型不只看自然语言,还要处理标点、括号、缩进、路径、变量名和字符串。

一次 API 调用包含哪些内容

在 AI 编程工具里,每发出一次请求,模型接收到的通常不是单条消息,而是一整包上下文。

flowchart TD
    A[用户输入一句话] --> B[组装完整上下文]

    B --> C[System Prompt<br/>系统指令、工具定义、项目规则、Memory]
    B --> D[对话历史<br/>用户消息、AI 回复、工具调用入参和结果]
    B --> E[本轮新增输入<br/>当前需求、附加文件、选中文本]

    C --> F[发送给模型]
    D --> F
    E --> F

    F --> G[模型输出<br/>文字回复或工具调用指令]
    G --> H[输出进入下一轮历史]

一次调用可以拆成四部分:

部分 是否经常出现 典型规模 成本特点
System Prompt 每轮都有 8k~25k tokens 固定成本,缓存后便宜很多
对话历史 逐轮增长 5k~100k+ tokens 会越来越大,但可缓存
本轮输入 每轮新增 0.5k~3k tokens 通常全价
模型输出 每轮产生 1k~8k tokens 按输出价格计费,通常比输入贵

真正的大头通常是前两项。用户输入可能只有几十个 token,但系统指令和历史上下文可能已经有几万 token。

Prompt Cache:为什么旧会话可能比新会话便宜

如果每次调用都从头计算完整上下文,长对话的成本会增长得非常快。

假设:

  • System Prompt:15k tokens;
  • 每轮新增历史:2k tokens;
  • 连续对话 10 轮。

没有缓存时,每一轮都要重新计算全部内容。

Turn 1: 15k + 2k  = 17k
Turn 2: 15k + 4k  = 19k
Turn 3: 15k + 6k  = 21k
...
Turn 10: 15k + 20k = 35k

10 轮输入合计 ≈ 260k tokens

因为每一轮都会带上之前所有历史,总成本接近二次增长。对话越长,重复计算越多。

KV Cache 的核心原理

大语言模型常用 Transformer 架构。模型处理前文时,会为每个 token 计算注意力机制需要的 Key 和 Value 张量。只要前缀内容不变,这些 Key 和 Value 也不会变。

KV Cache 的做法就是:把已经算过的前缀结果缓存起来。下一次请求如果前缀完全匹配,就直接读取缓存,不再按全价重新计算。

flowchart LR
    A[稳定前缀<br/>System Prompt + 历史消息] --> B[计算 Key / Value]
    B --> C[(KV Cache)]

    D[下一轮请求] --> E{前缀是否匹配}
    E -- 匹配 --> F[读取缓存]
    E -- 不匹配 --> G[重新计算]
    F --> H[只计算新增内容]
    G --> H

这类缓存也常被称为 Prompt Cache。它不是把模型回复缓存起来,而是把“已经处理过的输入前缀”缓存起来。

写入、命中、全价三种输入价格

以 Claude API 的计费思路为例,输入 token 可以分成三类。

Token 类型 价格倍率 触发条件
缓存写入 基础输入价 × 1.25 某段前缀第一次出现,需要写入缓存
缓存命中 基础输入价 × 0.1 后续请求命中相同前缀,直接读取缓存
全价输入 基础输入价 × 1.0 本轮新增内容,或无法命中的内容

不同模型的具体单价会变化,但“缓存命中显著便宜”这个规律很重要。缓存读取通常只需要基础输入价的十分之一。

模型 基础输入 缓存写入 缓存读取 输出
Claude Opus 4 $5 / M $6.25 / M $0.50 / M $25 / M
Claude Sonnet 4 $3 / M $3.75 / M $0.30 / M $15 / M
Claude Haiku 4.5 $1 / M $1.25 / M $0.10 / M $5 / M

M 表示一百万 tokens。对于 Opus 这类模型,命中缓存后的输入价格甚至可能低于更小模型的基础输入价格。

有缓存后的 10 轮成本

继续使用前面的假设:

  • System Prompt:15k tokens;
  • 每轮新增:2k tokens;
  • 缓存命中价格按 0.1 倍计算;
  • 首次写入按 1.25 倍计算。
Turn 1:
System 15k × 1.25 + 新增 2k × 1.0
= 20.75k 等价 tokens

Turn 2:
System 15k × 0.1 + 历史 2k × 0.1 + 新增 2k × 1.0
= 3.7k 等价 tokens

Turn 3:
System 15k × 0.1 + 历史 4k × 0.1 + 新增 2k × 1.0
= 3.9k 等价 tokens

Turn 10:
System 15k × 0.1 + 历史 18k × 0.1 + 新增 2k × 1.0
= 5.3k 等价 tokens

对比结果更直观:

场景 10 轮输入规模 等价成本 增长特征
无缓存 约 260k 全价 tokens 约 260k 接近 O(N²)
有缓存 仍发送约 260k tokens 约 62k 更接近 O(N)

缓存不会让上下文消失,但会让稳定前缀变得便宜。长会话的优势就在这里:只要前缀稳定,后续每轮主要支付新增部分。

缓存只能从头匹配

Prompt Cache 的关键限制是“前缀匹配”。它不是在任意位置找相同片段,而是从输入开头开始逐段匹配。

一个典型上下文可以看成一条链:

flowchart LR
    A[核心系统指令] --> B[工具定义]
    B --> C[Rules]
    C --> D[Memory]
    D --> E[项目文档]
    E --> F[历史消息 1]
    F --> G[历史消息 2]
    G --> H[本轮新增]

如果只是在末尾追加新消息,前面的内容都能命中缓存。

[命中 System] -> [命中 Tools] -> [命中 Rules] -> [命中 Memory] -> [命中历史] -> [新增消息全价]

如果中间某一段变了,变化点之后的内容都不能继续复用。

变化位置 命中情况 成本影响
只追加新消息 前缀基本全命中 最省,只为新增内容付全价
修改 Rules Rules 之前命中,Rules 之后失效 后续历史需要重新计算
修改 Memory Memory 之前命中,Memory 之后失效 项目文档和历史可能重新计算
切换模型 基本无法复用 不同模型的 KV 张量不能互通
新开会话 重新冷启动 System Prompt 和历史都要重新建立

因此,频繁修改配置、切换模型、新开窗口,都会破坏缓存收益。

缓存有效期与保活

缓存通常有有效期。以 Anthropic API 的常见机制为例,默认缓存有效期是 5 分钟,也可以通过付费选项延长。部分产品层可能会为订阅用户做额外优化,例如把有效期扩展到 1 小时。

每次命中缓存时,过期计时通常会被刷新。也就是说,只要在过期前继续发送匹配前缀的请求,缓存就能持续存在。

实践中要注意两点:

行为 结果
连续工作,中间间隔很短 大概率持续命中缓存
长时间离开后再回来 可能缓存过期,下一轮变成冷启动
用简单消息维持会话活跃 可以减少长任务中缓存失效的概率

如果正在处理一个持续数小时的大任务,长时间暂停前要意识到:回来后的第一轮可能会比之前更贵、更慢。

配置项如何影响 Token 成本

AI 编程工具通常有多层配置:Memory、Rules、Skills、MCP 工具、项目说明文档等。它们看起来都是“给 AI 的规则”,但加载方式完全不同。

不同加载方式决定了它们的成本差异。

flowchart TB
    A[Memory<br/>全量常驻] --> B[Rules<br/>常驻或触发]
    B --> C[Skills<br/>加载前轻量,加载后进入历史]
    C --> D[MCP 工具<br/>Schema 常驻,结果进入历史]

    A1[适合一句话偏好] -.-> A
    B1[适合编码规范和场景模板] -.-> B
    C1[适合完整工作流] -.-> C
    D1[适合浏览器、数据库、部署等外部能力] -.-> D

Memory:简单但全量常驻

Memory 通常用于记录用户偏好或项目约定。它的特点是:所有记忆条目会被拼接后注入 System Prompt,不会根据当前任务自动筛选。

例如:

- Python 缩进使用 4 个空格
- SQL 不等于使用 <>
- 文档统一使用 Markdown
- 部署脚本放在 scripts/ 目录

这些内容单条很短,总量也许只有几百 tokens,但它们每轮都会进入系统上下文。

Memory 的问题不只在 token 数量,还在两个隐性影响:

影响 说明
缓存链影响 修改任意一条 Memory,都可能让它后面的前缀失效
注意力噪声 与当前任务无关的偏好也会被模型看到,可能干扰判断

Memory 适合放一句话能说清的稳定偏好,不适合放复杂规范、长模板或完整流程。

Rules:高频常驻,低频触发

Rules 比 Memory 更适合承载结构化规范。它通常支持不同加载模式。

模式 加载时机 Token 影响 适合内容
常驻 每轮都进入 System Prompt 增加固定系统成本,缓存后变便宜 高频编码规范
触发式 根据关键词或语义加载 不触发时几乎零成本 特定场景模板
手动 用户显式指定时加载 完全按需 低频流程或特殊约束

一个合理的规则配置可能是:

code-style-guide.mdc      -> 常驻      -> 每个编码任务都要遵守
api-generation.mdc        -> 触发式    -> 只有生成 API 时加载
migration-checklist.mdc   -> 触发式    -> 只有数据库迁移时加载
release-process.mdc       -> 手动      -> 只有发版任务时加载

常驻 Rules 的数量越多,System Prompt 越重。低频规则如果也常驻,就会变成每轮都要支付的固定税。

Skills:加载前很轻,加载后留在历史里

Skills 通常用于描述一个完整能力包。它可能包含:

  • SKILL.md:技能说明和执行流程;
  • references/:参考资料;
  • scripts/:可执行脚本。

它的成本模式和 Rules 不一样。

阶段 上下文状态 Token 成本
未加载 只有简短 description 出现在可用列表中 很低,常见几十 tokens
被触发加载 SKILL.md 全文注入对话 一次性 5k~15k tokens
加载之后 内容留在对话历史中 后续可缓存,但无法从历史中移除

Skills 适合完整工作流,而不是单条规范。比如“数仓开发流程”“代码审查流程”“接口压测流程”这类任务,往往需要指令、参考文档和脚本配合,放在 Skills 里更合适。

但不要随意预加载 Skills。一个 10k tokens 的技能文件,一旦进入历史,后续每轮都会带着它,只是缓存命中后成本降低而已。

MCP 工具:定义常驻,结果累积

MCP(Model Context Protocol,模型上下文协议)用于把外部工具接入模型,例如浏览器自动化、数据库查询、文件系统操作、部署平台调用等。

MCP 的成本分成两部分。

成本来源 说明
工具定义 每个工具的 JSON Schema 常驻在 System Prompt 中,常见 200~500 tokens
调用结果 工具返回内容会进入对话历史,后续每轮继续携带

工具定义看起来不大,但如果全局启用很多闲置工具,固定成本会明显增加。

工具行为 典型返回规模 后续缓存命中后的等价成本
读取 200 行文件 3k~5k tokens 300~500 tokens / 轮
搜索代码并返回 10 条结果 2k~4k tokens 200~400 tokens / 轮
执行长输出命令 1k~10k tokens 100~1000 tokens / 轮

复杂任务中,工具调用结果经常比用户输入大得多。一个会话如果调用了 20 次工具,对话历史里可能已经积累了 40k~100k tokens 的结果。

内容应该放在哪一层

配置分层的原则是:越高频、越短、越稳定的内容,越适合常驻;越低频、越长、越场景化的内容,越应该按需加载。

内容类型 推荐位置 原因
“变量命名用 snake_case” Memory 一句话偏好,全量常驻也不贵
代码风格规范 常驻 Rules 高频使用,结构化表达更清楚
API 生成模板 触发式 Rules 只有生成接口时才需要
数据迁移检查清单 触发式 Rules 低频但需要明确步骤
完整开发流程 Skills 需要指令、参考资料和脚本
浏览器操作、数据库查询 MCP 工具 需要外部系统能力
大型项目背景说明 项目文档 + 引用 核心内容常驻,细节用路径引用

一个常见错误是把所有东西都塞进 System Prompt。这样做最直接的问题是固定成本变大,而且任何配置变动都会破坏缓存链。

更合理的做法是:

短偏好          -> Memory
高频规范        -> 常驻 Rules
低频模板        -> 触发式 Rules
完整流程        -> Skills
外部能力        -> MCP
大型参考资料    -> 文件引用,不要全文内联

Sub-Agent 不一定省钱,但能隔离上下文

很多 AI 编程工具支持 Sub-Agent。主 Agent 可以派出独立子 Agent 去做代码搜索、审查、分析等任务。

Sub-Agent 的价值不是天然省 token,而是隔离上下文,防止主会话被大量工具结果撑大。

Sub-Agent 为什么不能直接复用主会话缓存

主 Agent 和 Sub-Agent 往往有不同的上下文。

差异 对缓存的影响
工具集不同 工具 Schema 不同,前缀不匹配
消息历史不同 子 Agent 是独立任务上下文
模型可能不同 不同模型的 KV Cache 不能互通
系统指令不同 缓存前缀从开头就可能不一致

一个对比可以说明问题。

主 Agent 第 8 轮:
System 15k × 0.1 + 历史 23k × 0.1 + 新增 2k
= 5.8k 等价 tokens

Sub-Agent 第 1 轮:
System 10k × 1.25 + 传入任务 3k
= 15.5k 等价 tokens

子 Agent 经常是冷启动,因此单次调用可能更贵。

什么时候适合用 Sub-Agent

场景 推荐方式 原因
读取少量文件 主 Agent 直接处理 主会话已有缓存,边际成本低
大范围代码探索 Sub-Agent 避免几十个文件结果进入主历史
独立代码审查 Sub-Agent 审查上下文可以隔离,结论再回传
可用便宜模型完成的子任务 Sub-Agent 子任务用更低成本模型处理
需要长期共享上下文的任务 主 Agent 避免子 Agent 反复冷启动

Sub-Agent 更像“上下文防火墙”。它把脏活、重活、探索性工作放到独立上下文里,主会话只接收整理后的结论。

成本优化策略

Token 成本优化可以分成两类:配置侧和对话侧。

配置侧决定固定系统成本有多大,对话侧决定缓存是否稳定、历史是否膨胀。

配置侧:会话开始前一次性配好

配置类内容位于上下文前缀中,修改它们很容易打断缓存链。因此,最好在会话开始前整理好 Rules、Memory、MCP 工具和项目文档,任务进行中尽量不要频繁改。

Rules 优化

策略 做法 效果
减少常驻规则 只把高频规则设为常驻 降低每轮系统税
低频规则触发式加载 通过关键词或语义触发 不用时不进上下文
合并同类规则 多个碎规则合成一个结构化规则 减少元信息开销
精简规则内容 删除重复示例,保留约束和必要例子 降低规则体积

错误配置和合理配置的差异很明显:

不合理:
5 条规则全部常驻
=> System Prompt 增加 5k~15k tokens

更合理:
1 条高频规则常驻 + 4 条低频规则触发式加载
=> 常驻部分降到 1k~3k tokens

Skills 优化

策略 做法 效果
不预加载 让工具按任务判断是否加载 避免无效注入 5k~15k tokens
精简 SKILL.md 只放核心流程,长资料放 references/ 降低首次加载成本
写清 description 明确触发场景和关键词 减少误加载

Memory 优化

策略 做法 效果
定期清理 删除过时偏好和重复约定 减少噪声
合并相似条目 把多条同类规则合成一条 降低条目数量
控制长度 每条 1~2 句话 保持 Memory 轻量

MCP 工具优化

策略 做法 效果
禁用闲置工具 不把所有工具全局打开 减少 Schema 固定成本
按项目启用工具 每个项目只启用需要的 MCP 降低 System Prompt 体积
控制返回内容 搜索、日志、命令输出尽量限制范围 减少历史膨胀

项目文档优化

项目说明文档可以帮助模型理解代码库,但不要把所有细节都内联进去。

更好的写法是保留核心信息,并用路径指向细节:

# 项目约定

- 后端入口在 `src/server/`
- 数据库迁移脚本在 `migrations/`
- API 规范参考 `docs/api-style.md`
- 发版流程参考 `.ai/skills/release/SKILL.md`

这样模型能知道去哪找信息,而不是每一轮都携带所有文档全文。

配置优化的量化效果

假设优化前后如下:

优化前:
- 多条 Rules 全部常驻
- 10 个 MCP 工具全局启用
- 30 条 Memory
- 大型项目文档全文内联

System Prompt ≈ 25k tokens
缓存命中后每轮等价成本 ≈ 25k × 0.1 = 2.5k

优化后:
- 1 条高频 Rule 常驻
- 低频 Rules 触发式加载
- MCP 按项目启用
- Memory 控制在 500 tokens 以内
- 项目文档用引用代替全文

System Prompt ≈ 12k tokens
缓存命中后每轮等价成本 ≈ 12k × 0.1 = 1.2k

每轮节省约 1.3k 等价 tokens。长任务如果进行 100 轮,就能少消耗约 130k 等价 tokens。

对话侧:保护缓存,减少无效轮次

会话进行中,最重要的是保护缓存前缀。很多看似普通的操作,其实会让下一轮变成冷启动。

保护缓存

原则 做法 原因
一个任务尽量用同一个会话完成 不频繁开新窗口 新会话需要重新建立 System Prompt 和历史
不频繁切换模型 选定模型后持续使用 不同模型的缓存不能互通
不在任务中途改配置 Rules、Memory、MCP 尽量提前配好 配置变化会打断前缀匹配
长时间任务保持活跃 避免缓存过期 过期后需要重新计算前缀

减少无效 Token

原则 低效方式 更高效方式
一次说清需求 分三轮补充字段、约束、输出格式 一次给出目标、输入、限制和验收标准
少贴无关代码 直接贴 500 行文件 指出文件路径、函数名、错误行和现象
限制工具输出范围 让工具返回完整日志 只返回最近 100 行或匹配关键字
避免重复确认 每一步都问“继续吗” 让 AI 在可控范围内连续完成
跨会话保存计划 只靠聊天历史承接 把方案写进 plan.md 或任务文件

复杂任务尤其适合把计划沉淀到文件里。这样即使换会话,也不用把完整历史重新解释一遍,只需要让模型读取关键文件。

示例:

# task-plan.md

## 目标
把用户订单导出接口改为异步任务模式。

## 已确认约束
- 保持原接口兼容
- 新增任务状态查询接口
- 导出文件保留 7 天

## 待完成
- 调整数据库表结构
- 增加异步任务 worker
- 补充接口测试

这种文件化上下文比长聊天历史更稳定,也更容易被复用。

常见误区

误区 实际情况
“我只输入一行字,不应该很贵” 用户输入通常只是零头,系统指令和历史上下文才是大头
“长对话越来越贵,所以要经常新开窗口” 稳定长会话能命中缓存,新窗口反而会冷启动
“Sub-Agent 一定省 token” 子 Agent 常常冷启动,它的优势是隔离上下文
“Memory 很耗 token” Memory 通常不大,但过多无关条目会增加噪声并影响缓存链
“压缩历史一定省钱” 压缩可能改变前缀,导致缓存失效;接近上下文上限时再考虑
“Rules 越多越好” 常驻 Rules 会增加固定系统成本,低频规则应按需加载
“Skills 加载了不用也没关系” SKILL.md 一旦进入历史,后续会话轮次都会携带
“配置可以边做边改” 修改 Rules、Memory、项目文档或 MCP 工具可能打断缓存

一套实用判断框架

控制 AI 编程工具的 Token 消耗,可以用下面这套流程判断。

flowchart TD
    A[准备一个任务] --> B{内容是否每轮都需要?}

    B -- 是 --> C{是否很短且稳定?}
    C -- 是 --> D[放入 Memory]
    C -- 否 --> E[放入常驻 Rules]

    B -- 否 --> F{是否是低频规范或模板?}
    F -- 是 --> G[放入触发式 Rules]
    F -- 否 --> H{是否是完整工作流?}

    H -- 是 --> I[做成 Skills]
    H -- 否 --> J{是否需要外部能力?}

    J -- 是 --> K[启用对应 MCP 工具]
    J -- 否 --> L[放在项目文档中按需引用]

再配合四条会话习惯:

  1. 同一个任务尽量在同一个会话里完成;
  2. 会话中途不要频繁改配置;
  3. 不要随意加载大型 Skills;
  4. 工具调用要控制范围,避免把无关结果塞进历史。

AI 编程的成本不只取决于输入了多少字,更取决于上下文如何组织、缓存是否命中、配置是否轻量、工具结果是否膨胀。把常驻内容压小,把低频内容改成按需加载,把长任务稳定放在同一个会话里,通常就能用同样额度完成更多工作。


评论