KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA

03. Token 预算应该分给谁? — keel 龙骨

现在我们知道动态空间还有 127 个教学 token。接下来的争议通常比计算更困难:安全团队说系统规则不能删,工具团队说 schema 必须完整,产品要求带最近二十轮对话,检索系统返回十段历史事故,模型还需要生成结构化结论。

现在我们知道动态空间还有 127 个教学 token。接下来的争议通常比计算更困难:安全团队说系统规则不能删,工具团队说 schema 必须完整,产品要求带最近二十轮对话,检索系统返回十段历史事故,模型还需要生成结构化结论。

如果每个模块都把自己的内容声明为“最高优先级”,最终策略就是把请求推到窗口边缘,然后等待随机失败。Token Budget 的价值不是做一张漂亮配额表,而是把资源竞争变成可以审查、执行和复盘的契约。

1. 从支付事故拆出四层工作集

层 当前案例里的内容 默认策略
固定规则 身份、安全约束、证据引用格式 版本化并保护关键部分
能力描述 本轮可用工具及 schema 只发送当前任务真正可用的工具
当前任务 用户目标、当前步骤、审批结果 高优先级,保证运行可继续
动态证据 监控、工具结果、历史消息、记忆候选 选择、分组、压缩或按 ID 回查

随后从总窗口扣除 output reserve、fixed reserve 和 safety margin。注意“固定规则”不等于整份产品手册永久原样发送,“工具 schema 不能截断”也不等于每轮发送注册表里的全部工具。

真正影响授权、身份和输出结构的规则应保护;背景说明可以移到版本化资源。工具集合应根据当前状态裁剪,这会同时减少 token、模型选错工具的概率和提示注入面。

2. 预算不是一个 max_tokens

至少要区分四种预算:

请求预算:一次模型调用能装多少,超限时选择/压缩/拒绝
运行预算:整个 Agent 最多调用多少步、多少 token、多少费用
租户预算:一个用户可占用多少 worker、队列和供应商额度
评估预算:比较策略时允许使用多少调用和 token

它们的失败动作完全不同。请求预算不足时可能压缩;运行预算耗尽时应停止;租户预算不足时可能排队或限流;评估预算超出时必须把样本记为失败,不能偷偷增加额度让某个策略看起来更好。

3. 看懂 BudgetPlan 的责任边界

项目代码只负责确定性算术:

@property
def input_budget(self) -> int:
    return self.window_limit - self.output_reserve - self.fixed_reserve - self.safety_margin

@property
def dynamic_budget(self) -> int:
    return self.input_budget - self.system_budget - self.tool_schema_budget

它没有替你决定哪条历史重要,也没有调用模型摘要。这种分离是有意的:预算计划负责给出合法容量,第四章的 selector 才负责在动态预算内选材料。

运行:

python courses/foundation/context-engineering/course/project/examples/01_measure_and_budget.py

得到:

window: 220
input budget: 158
dynamic budget: 127
system/tool schema: 16 15

这个报告能解释三个问题:本轮总边界是多少;固定部分用了多少;真正可竞争的空间还剩多少。

4. 输出预留要来自任务,而不是百分比口诀

“固定预留 20%”可以作为实验起点,不能作为所有场景的行业定律。

只返回 {"ok": true} 的分类请求和生成带证据、风险、下一步的事故报告,需要的输出长度不同。工具调用还可能因为参数 JSON 被截断而完全无效。合理做法是:

  1. 按任务类型记录实际输出 token;
  2. 观察 P95 和被截断样本;
  3. 结合供应商最大输出限制设置 reserve;
  4. 对结构化输出设置 schema 和停止条件;
  5. 模型或 prompt 升级后重新校准。

预留过小会截断,预留过大则会提前挤压输入并频繁触发 compaction。这是质量、延迟和容量的权衡,不存在一个脱离任务分布的最佳比例。

5. 静态预算和动态预算分别解决什么

静态预算为关键类别设硬边界,例如系统规则最多 600、工具 schema 最多 1000。它简单、可预测,适合安全边界和容量保护,但容易浪费暂时空闲的配额。

动态预算允许证据、历史和记忆候选共享剩余空间,根据任务状态重新分配。它利用率更高,但必须保留保护项、每类最大值、稳定选择顺序、丢弃原因和策略版本。

生产系统通常组合两者:先保护硬边界,再让动态材料竞争剩余容量。不是“动态”就让模型自由决定重要性。

6. 一个可以复盘的预算报告

{
  "run_id": "run-42",
  "model": "provider/model@version",
  "window_limit": 8192,
  "output_reserve": 800,
  "fixed_reserve": 128,
  "safety_margin": 256,
  "input_budget": 7008,
  "system_tokens": 420,
  "tool_schema_tokens": 760,
  "dynamic_budget": 5828,
  "used_dynamic": 5400,
  "dropped": ["memory:old-17", "log:chunk-03"]
}

这不是给最终用户看的 UI,而是故障复盘和离线评估证据。没有它,模型漏掉历史事故时,你无法判断是 selector 主动丢弃、计数误差、压缩遗漏,还是模型利用失败。

7. 三种典型失败

固定部分已经超预算

系统规则与工具 schema 相加后,dynamic_budget < 0。正确动作是减少本轮工具集合、缩短非关键规则、降低输出目标或拒绝请求;不能让 selector 从当前用户目标里“省一点”。

大工具结果垄断动态空间

一个日志工具返回 5000 行,挤掉当前监控和审批状态。工具结果应先分块、结构化、去重并保存 evidence ID,不能把原始响应天然视为高优先级。

运行预算被请求预算掩盖

每轮都合法,但 Agent 连续执行 200 次工具调用。窗口没有溢出,费用和时延却失控。Harness 仍要维护最大步骤、deadline 和总 token/费用停止条件。

8. 失败注入与验收

做下面四次修改,并记录预算报告:

  1. 把 window_limit 改为 100,观察动态预算;
  2. 把 tool schema 增长三倍,确认它挤压的是 dynamic budget;
  3. 让 output_reserve + safety_margin 超过窗口,确认构造阶段抛错;
  4. 为“只读事故查询”和“创建工单”设计两套预算,解释写操作为什么可能需要更少工具、更严格输出和额外运行限制。

完成标准:你能够为请求预算、运行预算、租户预算和评估预算分别说出负责人、测量单位和超限动作,并能从报告解释某条证据为什么没有进入模型。

下一章:预算不足时先保留什么?

进入 keel 阅读