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 被截断而完全无效。合理做法是:
- 按任务类型记录实际输出 token;
- 观察 P95 和被截断样本;
- 结合供应商最大输出限制设置 reserve;
- 对结构化输出设置 schema 和停止条件;
- 模型或 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. 失败注入与验收
做下面四次修改,并记录预算报告:
- 把
window_limit改为 100,观察动态预算; - 把 tool schema 增长三倍,确认它挤压的是 dynamic budget;
- 让
output_reserve + safety_margin超过窗口,确认构造阶段抛错; - 为“只读事故查询”和“创建工单”设计两套预算,解释写操作为什么可能需要更少工具、更严格输出和额外运行限制。
完成标准:你能够为请求预算、运行预算、租户预算和评估预算分别说出负责人、测量单位和超限动作,并能从报告解释某条证据为什么没有进入模型。