上下文构建与 Token 成本控制:企业级策略
这一篇聚焦一个在企业里必定会被问到的问题:上下文怎么构造、Token 怎么控?既要让模型“看得够多”,又不能让每次调用都烧钱烧到无法落地。
为什么要把“Token 成本”当成一等公民?
在个人项目里,很容易忽略一个事实:
大模型调用的成本是和 Token 成线性关系的,而 IDE 又是一个高频交互场景:
- 每一次补全、Inline Chat、多文件重构,背后都是一次或多次模型调用;
- 如果不控制上下文长度和调用频率,团队级使用时成本会迅速失控;
- 对延迟也有直接影响:prompt 越长,端到端等待时间越高。
从企业视角看,“如何做 Token 成本控制?”不只是账务问题,也是:
- 架构设计问题:上下文如何分层、索引如何设计;
- 产品策略问题:哪些交互应该“实时”,哪些可以“按需触发”;
- 观测问题:如何知道是哪类功能在吃掉绝大部分 Token。
上下文的三层结构:核心 / 相关 / 附加信息
一个不错的实践是把上下文拆成三层,每层都有明确优先级:
核心上下文(必须塞进去)
- 当前文件中光标所在函数/类的完整实现;
- 用户选中的代码块;
- 与任务强绑定的信息(例如编译错误、测试失败堆栈)。
相关上下文(预算足够时尽量塞)
- 同一文件中和当前函数紧耦合的辅助函数;
- 同一模块/包下被当前文件调用的关键接口实现;
- 最近编辑过的文件里与本次改动高相关的片段。
附加信息(只在需要时塞)
- 相关文档/注释摘要;
- 历史对话中和当前任务强相关的几轮对话;
- 配置信息、环境说明等。
构建上下文时,可以先按优先级填核心,再用剩余 Token 预算去填相关和附加部分。
动态裁剪:按任务类型分配 Token 预算
不同任务的“信息胃口”不一样,没必要一刀切:
代码补全(特别是单行补全):
- 主要依赖光标附近代码 + 当前函数/类;
- 项目级上下文可以非常克制,甚至可以只用 LSP 补全作为约束。
局部重写 / Inline Chat:
- 需要整个函数和文件头部 imports;
- 对跨文件信息依赖相对有限。
多文件重构 / 项目级问答(RAG):
- 需要从索引里调大量相关片段;
- 这类调用本身可以标记成“重型请求”,通过频控和显式 UI 触发。
可以为每类任务设一个大致的 Token 上限,比如:
- 补全:prompt ≤ 1k token;
- Inline 重写:prompt ≤ 2–3k;
- 项目级 RAG 问答:prompt ≤ 4–8k。
在构造上下文时,先估算各段文本长度,再按优先级填充,超出的直接截断或省略。
优先级拼接:谁先占坑,谁后被裁
当 Token 预算不够时,需要有一套“谁先被踢”的规则。一个常见策略:
- 当前文件的目标函数/类 永远保留完整;
- 当前文件其他函数按“调用关系距离 + 代码行数短长”排序,靠前的优先;
- 索引召回的其他文件按相关度排序,取 Top-K,再按 Token 预算裁;
- 文档/注释类上下文最后塞,如果不够就先丢弃这部分。
对于项目级 RAG,可以再细化一层:
- 按类型优先级:
- 优先代码,其次设计文档,再其次是其它文本;
- 对于“修 bug”类任务,优先错误堆栈和相关代码。
这样可以保证:
- 就算预算很紧,模型至少能看到“正在改的那块代码”和直接相关的实现;
- 不会出现“远方的注释/文档”把近处的关键逻辑挤掉的情况。
上下文缓存:不要为同一块信息重复买单
在 IDE 里,很多操作是围绕同一段代码、多次迭代进行的,例如:
- 连续几次对同一个函数做重写/优化;
- 在同一组文件里多次进行测试生成/bug 修复。
这时可以利用几种缓存方式减少 Token 消耗:
会话级缓存
- 把本轮会话中已经发送过的“项目级背景”缓存成一个短摘要,在后续请求里复用;
- 对某个函数/模块的长注释/设计文档只摘要一次。
项目级缓存
- 对整个项目的“全局说明”(例如架构概览、主要模块划分)提前做一次摘要,存在本地或服务端;
- 后续所有请求都引用同一份短摘要,而不是每次重新压缩。
模板缓存
- 系统提示 + 通用指令部分保持固定,通过“prefix caching”减少实际发送长度(取决于模型/提供方是否支持)。
这些手段不会改变单次请求在语义上的效果,但可以显著降低平均 Token 成本。
观测与策略迭代:先量出来,再优化
企业级环境里,想认真回答“Token 成本怎么控”,需要先把数据打通:
每次调用要打点:
- 功能来源(补全 / Inline Chat / 多文件重构 / RAG 问答等);
- 实际 prompt 长度 / 输出长度;
- 使用结果(用户是否接受、是否撤销)。
定期汇总:
- 按功能、按团队、按仓库统计 Token 消耗;
- 找出“高成本低收益”的场景优先优化。
有了这些数据之后,可以做一些策略调整,例如:
- 对成本极高但接受率不高的功能:调低默认开启频率,改成“显式触发”;
- 对成本不高但帮助很大的功能:可以适度放宽上下文预算或增加调用频率。
和上下文构建结合起来看那几个问题
回到前面的问题:
4️⃣ 如何做 Token 成本控制?
- 通过三层上下文结构 + 动态裁剪 + 优先级拼接 + 缓存 + 观测闭环,一层层收紧;
- 不指望一次性找到完美策略,而是靠监控数据持续调节。
5️⃣ RAG 如何避免错误召回?
- 控制召回数量和类别,只把“真的相关”的片段塞进 prompt;
- 在上下文不足以支持高质量回答时,宁可让模型说“不确定”,也不要硬编。
对一个 IDE 工程师来说,把“上下文构建”看作一个独立子系统,并且:
- 在接口里显式传递任务类型和 Token 预算;
- 在实现里显式维护不同优先级的上下文队列;
会比在各个 feature 里“看心情拼 prompt”稳得多,也更容易在企业规模下迭代。