Ohhnews

分类导航

$ cd ..
foojay原文

上下文即预算:八个杠杆与三种工作流模式

#上下文管理#token预算#提示缓存#mcp#工作流模式

目录
令牌实际上去了哪里 八大杠杆

一周内就能收回成本的八种杠杆和三种工作流模式。

一个五十人的开发团队每个月可能在AI编码助手上默默烧掉三万美元,根本没人注意到。高级请求配额到第三周就告警了。账单来了,没人说得清钱花在了哪里。

成本是显而易见的痛点。另外两个则更隐蔽:

  • 延迟。 更大的上下文需要更长时间。模型思考更多,你的等待也更久。
  • 上下文腐化。 这是最出人意料的一点。Anthropic 和 Chroma 都曾表明,随着上下文窗口被填满,模型的回忆和推理能力会退化——即使远未达到标称的窗口上限。200K 令牌的模型在 150K 标记时的表现确实不如在 20K 标记时。更多的上下文并非免费;超过某个点后,它反而会带来损害。
    能同时解决这三个问题的思维模型是:停止将上下文当作免费自助餐。把它看作每次对话中需要花费的预算。

本文是一份实用指南,教你如何精打细算:令牌实际流向了哪里,八种可以改变局面的杠杆,以及在此基础上叠加增效的三种工作流模式。

[LOADING...]

令牌实际上去了哪里

每次向编码助手发出的请求都是一叠桶。不同工具和会话的形状各不相同,但大致如下:

典型份额说明
系统提示 / 指令5–15%已复制粘贴数月的模板化内容
工具 / 函数模式10–40%每次对话都要重新发送
检索到的文件与代码块20–60%最大的杠杆,几乎总是如此
对话历史10–30%线性增长,直到你将其压缩
模型输出5–20%冗长的描述不仅生成昂贵,阅读也贵

值得注意的几点:

  • 工具模式的占比远超预期。 五个连接的 MCP 服务器很容易在每请求产生 5,000–10,000 令牌,你还没输入一个字呢。模型不一定使用该工具——模式无论如何都会发送。
  • 对话历史无界增长。 一个 30 轮次的聊天,每提一个新问题都要为前 29 轮付费,再加上你新提交的。
  • 输出量虽小,但每令牌成本高。 在大多数直接 API 中,输出令牌的成本是输入令牌的三到五倍。一条回复写着“当然!让我先解释一下我打算做什么……”然后再做正事——这纯粹是开销。

经验法则: 在优化之前,先分析你自己的流量。主导会话的那个桶很少是你直觉以为的那个。

在 Copilot 上下文中,你不能直接看到令牌计数——但你能看到症状。打开 Output → “GitHub Copilot Chat”,观察 ccreq 行:每一行显示模型、延迟和每次对话的请求类型。当同一个问题在第二段聊天里耗时是第一次的三倍时,你就亲眼看到了令牌计量表在运行。

[LOADING...]

八大杠杆

这些不是按优先级排列的——而是按你在一次会话中自然遇到的顺序。前三个(上下文、缓存、工具)关乎请求的形状。接下来三个(指令、模型、输出)关乎你如何与助手对话。最后两个(仓库、可观测性)是让其他所有杠杆生效的基础。

[LOADING...]


A. 上下文工程——限定你的请求

大多数AI工作流中最大的浪费是:在 agent 模式的聊天中,带着完整代码库的访问权限提出模糊问题。agent 尽职尽责地探索,读取十个文件,找到它需要的两个,全部总结一遍,然后回答。每一步你都要付费。

比较一下:

糟糕: “重构订单确认邮件,使用新的模板引擎。”

agent 打开 src/main/java/com/example/demo/email/ 下的四个文件,读取 WelcomeEmailService.java 获取它不需要的上下文,考虑是否应该存在 templates/ 资源目录,然后提出一个庞大的 diff,顺便还把某个方法重命名了。

良好: “重构 #file:src/main/java/com/example/demo/email/OrderConfirmationService.java,使其调用 #file:src/main/java/com/example/demo/email/TemplateEngine.javarender 方法,而不是 renderLegacy。保持行为一致。”

agent 打开两个文件。diff 只有三个有意义的代码行。整个轮次的成本大约是十分之一。

明确是免费的。你提供的每一个 #file:(Copilot)或显式路径(Claude Code),都是 agent 不用去寻找的块。每一句“保持行为一致”都是一道护栏,防止出现200行的旁支任务。

周一做这件事:#file: 作为默认习惯。只有在你确实不知道你不知道什么的时候,才使用带有广泛检索的 agent 模式。


B. 提示缓存——顺序很重要

现在所有主流提供商都支持提示缓存。Anthropic 和 OpenAI 对缓存命中收取约 基本输入成本的10%。Google 的 Gemini 则明确实现。机制相同:提示开头的一个稳定前缀在首次请求后被缓存,后续请求可以廉价读取。

因此,成本规范的关键在于顺序

[ 工具定义 ]           ← 很少变化           ┐
[ 系统提示 ]           ← 很少变化           │ 缓存这些
[ 技能 / 规则 ]        ← 每个仓库稳定         ┘
[ 检索到的文件 ]        ← 按任务变化
[ 对话 ]               ← 每轮变化

静态在上,动态在下。你能构造的最长稳定前缀就是最可缓存的前缀。

典型的反模式看起来无害却代价惨重:

$ java
// 不要这样做
String system = "Today is " + Instant.now() + "\n\n" + ACTUAL_SYSTEM_PROMPT;

将时间戳放在系统提示的开头会在每次请求时破坏缓存。你将整天为相同的10KB前导内容支付全价。解决办法是将动态内容推送到用户消息或提示的尾部。

周一做这件事: 审计系统提示的200个令牌。任何每请求变化的内容都应该放在更靠后的位置。


C. 工具与 MCP 卫生——每个模式都是一笔开销

每个连接的工具都会将其完整的 JSON 模式随每次请求发送。一个典型的 MCP 服务器有 8–15 个工具,每轮对话成本 400–2,500 令牌。连接了五个服务器?你每轮对话可能要为模型从未调用的工具定义支付 5,000–10,000 令牌。

把 MCP 服务器当作浏览器扩展:有用,但只保留你今天真正需要的。

// .vscode/mcp.json --- 保持简短
{
  "servers": {
    "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem"] }
    // 不需要时禁用 github、playwright、brave-search 等
  }
}

同样的规范也适用于你自己构建的工具。一个返回 { id, summary } 的工具是廉价的。一个返回 50 字段 JSON 对象的工具是昂贵的——模型每轮引用它时都要重新处理所有 50 个字段。默认使用紧凑的响应,并附带可选的 ?expand=... 参数供少数需要完整数据的调用者使用。

周一做这件事: 打开 MCP 服务器列表,禁用所有你本周没有主动用过的东西。按需重新启用。


D. 自定义指令与技能——一次固化

任何你在聊天中反复输入的内容都应该放在一个指令文件中。具体文件名可能不同——.github/copilot-instructions.mdCLAUDE.mdAGENTS.md、Cursor Rules——但原则相同:将你的团队约定写一次,提交,让仓库中的每次聊天都继承它们。

一个小例子胜过千言万语:

[LOADING...]

一共六行。从此,这个仓库里的任何聊天都不会再提议使用 Jest,不会在 diff 就能解决问题时抛出一个全文件重写,也不会用“当然!让我先解释一下我打算做什么……”作为开场白。

对于特定技术栈的规则,使用路径作用域指令。在 Copilot 中:

$ config
---
applyTo: "src/main/java/**/*.java"
---
# src/ 的测试约定
- 使用 JUnit 5,通过 `mvn test` 运行。
- 测试镜像源树,位于 `src/test/java/...` 下,命名为 `<Name>Test.java`。

只有当匹配的文件在作用域内时才会加载此文件。仓库级规则放在全局指令中;特定技术栈的规则放在作用域指令中。两者都提交,都版本化,都是团队资产——而不是埋在某人 IDE 设置中的个人偏好。

周一做这件事: 检查你上周在聊天窗口中输入的内容。任何出现超过两次的东西都适合放入一个指令文件。


E. 模型路由——从便宜的起步,卡住时升级

日常任务默认使用最贵的模型,如果你不加干预的话。你可能刚刚为了同一个答案支付了 10 倍的代价。

一个可靠的默认路由表:

任务模型倍数(Copilot)
内联补全、简单聊天最便宜的可用(如 GPT-4.1)
实际编码工作中档(GPT-5 / Claude Sonnet)
长上下文重构 / agent 模式中档加长上下文
真正困难的推理顶级(Claude Opus)10×

规则是:从便宜的起步,只在卡住时升级。 “卡住”意味着你已经在良好上下文下尝试了中档模型,但它显然没抓住要点——而不是“我想要更确信”,也不是“我有时间浪费”。

数学效果会叠加。一个 50 人团队,每天每人运行 20 次 agent,使用 10× 模型比使用 2× 模型成本高五倍——在大多数日子里,生成的 diff 却是一样的。

周一做这件事: 将默认模型固定为中档。让 Opus 成为一个带有明确理由的刻意选择。


F. 输出规范——diff 而非长篇大论

每个模型都有“让我先解释一下我打算做什么”的本能。这很礼貌,但也纯粹是成本。

同样的修复,两种问法:

“在 templateEngine.js 中,welcome 模板缺少一个感叹号。给我看更新后的文件。

→ 返回 30 行。(如果是 600 行文件,则返回 600 行。)

“在 templateEngine.js 中,welcome 模板缺少一个感叹号。只回复一个统一 diff,不要任何评论。

→ 返回 5 行。

在直接 API 上,输出令牌的价格通常是输入令牌的三到五倍。在像 Copilot 这样的按请求付费模型下,冗长输出同样有害:它增加延迟,为后续对话填充上下文,并更快地将较早的有用内容逐出。

杠杆在系统提示中。copilot-instructions.md 里的两行代码能让仓库中的每次聊天从此表现更好:

  • 简洁,不要开场白。
  • 优先使用 diff 而非完整文件。

周一做这件事: 添加这两行。


G. 仓库卫生——索引器看到什么

驱动检索的索引器遵循 .gitignore。收紧它。

$ diff
+target/
+*.class
+*.jar
+.idea/
+*.iml
 *.log

重要陷阱: 如果一个文件已经被 git 跟踪,将其路径添加到 .gitignore 并不会解除跟踪——索引器仍然能看到它。你还需要:

$ bash
git rm --cached target/demo-0.0.1-SNAPSHOT.jar

对于密钥、测试夹具和供应商依赖,请使用组织/仓库级别的内容排除(大多数编码助手提供商都暴露此功能)。

仓库卫生的另一半是在每个模块的顶部添加摘要注释

$ java
// TemplateEngine —— 核心渲染器。新邮件使用 render(id, data)。
// renderLegacy(id, data) 已弃用,仅由 OrderConfirmationService 使用。
// 已注册模板:welcome、order_confirmation_v2。

三行,约 50 令牌。现在“模板引擎做什么?”这个问题无需读取文件其余部分就能回答。每个模块顶部的 200 令牌摘要胜过每次重新读取 5,000 令牌的代码。

周一做这件事: 对不应被索引的内容执行 git rm --cached;为你最关心的模块添加三行摘要。


H. 可观测性——延迟就是你的令牌计量表

你看不到 Copilot 的令牌数量。你也不需要。使用你已有的代理:

回复延迟≈ 输入令牌
< 5 秒20 秒接近上限——开始新聊天

当你第四个聊天的同一个问题比在全新聊天中耗时三倍时,你已经实时看到了上下文的膨胀。解决办法是“带摘要的新聊天”,而不是“等它完成”。

你还可以像 lint 包体积一样 lint 上下文膨胀。CI 中一个 30 行的脚本足以捕获最常见的退化:

$ node
// 如果任何 .github/instructions/*.md 超过 150 行,则失败
import { readdir, readFile } from "node:fs/promises";
const files = (await readdir(".github/instructions")).filter(f => f.endsWith(".md"));
let failed = false;
for (const f of files) {
  const lines = (await readFile(`.github/instructions/${f}`, "utf8")).split("\n").length;
  console.log(`${lines > 150 ? "❌" : "✅"} ${f}: ${lines}`);
  if (lines > 150) failed = true;
}
if (failed) process.exit(1);

将其接入 CI,上下文膨胀就不会在 PR 之间悄悄累积。

[LOADING...]

周一做这件事: 在你的编辑器旁放一个秒表,用一天时间数“一、二、三”(而不是千字文)。你会知道哪些聊天需要轮换。## 三种能产生协同效应的工作流模式

以上八个杠杆降低了单次交互的成本。而以下三种模式则能减少昂贵交互的次数。将它们叠加运用。

[LOADING...]


1. 拉尔夫·威格姆循环

以《辛普森一家》中那位以不懈愚蠢为超能力的角色命名。这个配方刻意显得朴实无华:

  1. 创建一个包含复选框任务的 TODO.md 文件。
  2. 廉价模型开启代理模式对话。
  3. 告诉它:“读取 TODO.md。选中第一个未勾选的项目。仅实现该任务。运行 npm test。如果通过,勾选该框并提交。选中下一个。重复。”

就这样。代理逐个任务地遍历整个列表。

为何有效:

  • 每次迭代从一个小而新的上下文开始。 聊天历史不会像在自由对话中那样不断膨胀。
  • 状态存储在磁盘上TODO.md 和 git 提交),而非对话令牌中。
  • 廉价模型就足够了,因为每个任务都很小且独立。
  • 可随时重启。 中途关闭聊天,开启新对话,再次运行提示——它会从上次中断处继续。

运行之后,git log --oneline 读起来就像一份变更日志:每个任务一个提交,提交信息以任务标题开头,可以轻松回退任何一步。与那种典型的“修复一切”的巨型提交相比,你再也回不去了。

[LOADING...]


2. 自动压缩

大多数助手不会主动进行激进压缩。你需要主动推动。

当对话达到上下文窗口的 60%–80% 时(你会知道的——回复开始变得缓慢),停下来并提问:

总结我们讨论过的内容:目标、我们接触过的文件、做出的决策、未解决的问题以及下一步行动。控制在 300 字以内,使用项目符号。

将输出保存到 plan.md。开启一个全新的对话。附上该文件:

#file:plan.md 继续。下一步是……

新对话的第一个请求远比旧对话的最后一个请求要小得多。模型能够毫无障碍地接过主线。大致而言:一份 4KB 的摘要保留了 95% 的信号,却只花费了 3% 的成本。

额外的模式:这份摘要文件成为了一个稳定、可缓存的前缀。任何引用它的未来对话都能在压缩之上享受提示缓存的好处。一次总结带来两个叠加的胜利。

如果你对压缩的实现感兴趣,可以查看这个技能,它被一些自定义代理所使用。

经验法则: 每个任务一个对话。新任务 → 新对话,附上摘要。


3. 规划者 → 实现者 → 审查者(代理交接)

这是改变功能构建方式的一种模式。三个简短、聚焦的对话,三种不同的模型选择,以及一个共享的产物:

[LOADING...]

  • 规划者 —— 昂贵模型,仅一次调用。读取功能需求,生成 plan.md,包含目标、验收标准、任务、预计会修改的文件、范围外项目以及风险。尚未编写代码。
  • 实现者 —— 廉价模型,代理模式,全新对话。只看到 plan.md。在其上运行一个拉尔夫循环:选中第一个未勾选任务,实现,测试,勾选框,提交,重复。
  • 审查者 —— 昂贵模型,全新对话。只看到 plan.md 和差异。标记每个验收标准为通过或失败,列出错误、代码异味、范围外的修改。最后给出判定:通过判定:需要修改

三个对话,一个端到端功能大约需要 5–8 次优质请求。相比之下,一个全程使用最昂贵模型的巨型对话:轻松超过 30 次请求,且乘数高达 10 倍。

关键纪律:交接产物plan.md、差异、审查笔记)是唯一跨越边界的东西。绝不传递聊天历史。这样你才能保持每个代理的上下文小巧、集中且廉价。

周一清单

将此固定到你的团队维基上。取有用的部分,忽略其余部分。

仓库设置

  • 添加一个顶层指令文件(copilot-instructions.mdAGENTS.mdCLAUDE.md 或你工具对应的等效文件),包含构建、测试、代码检查、约定和输出风格规则。
  • 为栈特定规则添加路径限定的指令文件(例如 src/ 下的测试约定)。
  • .gitignore 忽略构建输出、快照和大型固件。对已跟踪的内容执行 git rm --cached
  • 为你的前 10 个模块添加三行的“此模块做什么”的摘要注释。
  • 添加一个持续集成代码检查,如果指令文件超过约 150 行或提示文件超过约 250 行则失败。

每次会话的习惯

  • 关闭本次会话中不需要的 MCP 服务器。按需重新启用。
  • 默认使用中档模型。仅在遇到困难时升级到顶级模型——并且要有理由。
  • 对于范围明确的任务,使用 #file:(或你工具的等效方式)代替广泛检索/代理模式。
  • 要求差异,而非完整文件。
  • 每个新任务都在全新对话中开始。
  • 当回复开始变慢时(约 60% 上下文),总结到 plan.md 并在新对话中继续。

本周尝试的工作流模式

  • 对一个包含杂务小任务的 TODO.md 运行拉尔夫循环。
  • 对一个真正的功能使用规划者/实现者/审查者拆分。留意请求数量。
  • 将延迟视为你的令牌计。在一天中数一数阿姆斯特丹。

结语

思维转变很小,但收获不容小觑。

提示工程曾经是关于巧妙的措辞。上下文工程——本文真正讨论的内容——是关于窗口里有什么、没有什么。更小的提示、更少的工具、限定的检索、摘要而非历史、廉价模型做廉价工作、昂贵模型处理罕见的困难部分。

这些都不是新奇的。这些都不难。大多数团队实际上没有令牌问题,他们有的是纪律问题。这些杠杆很无聊。但协同效应是真实的:一个采用上述做法哪怕一半的团队,都会看到延迟下降、优质请求消耗显著降低,而且反直觉的是,回答质量会提高,因为模型不再被无关上下文淹没。

请记住这一句话:

最糟糕的令牌是你正在付费却没有注意到的那些。

留意你的 ccreq 行。数一数阿姆斯特丹。像花自己的钱一样使用预算。

本文《上下文即预算——八个杠杆与三种工作流模式》首发于 foojay