返回 AICAP-180
B5 · Day 44tool/context engineering + 指标树

context-budget 表

Day 41 立了「context 是有限 token 预算」的命题,Day 43 把 context-token 列成指标树输入层的一个叶子。

阶段: B5 · tool/context engineering + 指标树(Day 41-50) 标签: #context-budget #compaction #offload #token-quota

今日导引(由浅入深)

Day 41 立了「context 是有限 token 预算」的命题,Day 43 把 context-token 列成指标树输入层的一个叶子。

今天把这个叶子做实——context-budget 表:把窗口拆成 system / tools / 检索 / 历史四类配额,任一超额就触发裁剪策略。这是 B1→B18 曲线里第一次把「预算」从口号变成一张带配额列、实测列、超额标红的可提交表。

它紧接 Day 43,因为没有指标树先把 token 列为可测叶子,预算表就无处挂载;它通向 Day 45,因为 tools 这一类配额的超额,正是 Day 45 重设计(合并 + 收窄 schema)要削减的。

今天的「最小可判定产出」:对 AML Copilot 一次 SAR 流程,用已绿 tokenizer 实测四类 token,填出 3 行(或四类)budget 表,超额行标红——离线可出。

1. 机理精读

定义。 context budget 把模型上下文窗口拆成四类配额system(系统提示)、tools(工具 schema/描述)、检索(retrieved evidence)、历史(对话/步骤历史)。

每类预先分一个 token 上限;任一类超额即触发裁剪策略。预算法的本质是逼迫显式取舍,而非默认把窗口塞满到模型自己开始丢信息。参考 Anthropic《Effective context engineering》(2025-09)的 budget / compaction 段落。

三类裁剪策略。 超额时有三种处理:

  1. 压缩(summarize / compaction):把长历史摘要成短摘要,保语义丢冗余——主流 agent 框架(Claude Agent SDK)已内建。
  2. 外置(offload):把大块内容写到文件/外部存储,context 里只留指针,用到再取。
  3. 丢弃(prune):直接删掉低信号片段(如过期的中间步骤)。

三者权衡是「信息保真 vs token 节省」:

  • compaction 保真度高但有摘要损失(可能丢细节);
  • prune 最省但可能误删(删错了无法恢复);
  • offload 最保真但加一次取回延迟(多一跳 IO)。

选哪个取决于「被裁内容的可恢复性与信号密度」:高信号难摘要的(如关键证据)宜 offload,低信号冗余的(如过期中间步骤)可 prune,长但语义可压的(如多轮历史)宜 compaction。

为什么按这四类分。 因为四类的可压缩性增长性不同:

  • system 通常固定、最不该动;
  • tools 随工具数线性增长,是 Day 45 重设计的削减对象;
  • 检索按 query 波动,可用 top-k 截断;
  • 历史随轮次单调增长,是 compaction/prune 的首要目标。

按类切开,才能对不同类用不同策略,而不是一刀切截断尾部。

关键权衡。 配额总和应留出余量给输出(completion)与「中段不被忽略」的安全垫(呼应 Day 41 的 lost-in-the-middle)。

配额过紧会频繁触发裁剪、丢约束;过松等于没预算、回到塞满模式。所以预算不是静态死数,而是「按这次任务的信噪比动态分配」。

与相邻概念的边界。 预算表是 Day 43 指标树「输入层 token 叶子」的执行细化:指标树告诉你「要测 token」,预算表告诉你「测完按四类配额判超额并裁剪」。

它也不同于单纯统计 token——预算表的价值在「配额 vs 实测」的差,以及超额触发的动作(裁哪一类、用哪种策略)。

2. 推导 / 手算 / 代码走读

代码日:走读 src/agent/eval/tokenizer.ts(实测 token)与 src/agent/mcp/contextAudit.ts(预算表实现)。

  • src/agent/eval/tokenizer.tstokenReport(texts, model)
    • 对一组文本逐条 encode().length 计 token,给 totalTokens / meanCharsPerToken
    • 今天把四类组件文本(system / tools / 检索 / 历史)各作为一条喂进去,即得各类实测 token;
    • tokenizer 已绿(vocab=456、2.01 c/t)。
  • src/agent/mcp/contextAudit.tscontextBudget(components, merges=200)——这就是 Day44 的预算表实现:
    • 入参是 Array<{label, text, quota}>,先 trainBpe 出模型;
    • 再对每个组件 encode().lengthtokens,算 overBy = max(0, tokens - quota)
    • 汇总 totalTokens / totalQuota / overBudget = rows.some(overBy>0)
    • overBy>0 的行即「超额标红」的判据。
  • 同文件 auditToolContext(tools, merges=200)
    • 单独算 tools 这一类配额的逐工具细分(descTokens + sigTokens);
    • 是预算表里 tools 行的下钻来源——也直接喂 Day 43 指标树的「context tokens / tool」叶子。
  • 诚实 CAVEAT(代码注释明写)
    • BPE 每次调用按传入 corpus 现拟合,所以逐组件计数是该次调用内的相对值,跨调用不可比,也不等于生产分词器(tiktoken/cl100k);
    • 要稳定跨调用数字,需 trainBpe() 一次固定参考语料再复用;
    • 今天的预算表因此是相对配额审计,不是绝对计费——这条限制必须写进产出表的脚注。

预算表骨架(今天要填的产出形状,配额为示意):

| 类别     | 配额 quota | 实测 tokens | overBy | 超额? | 裁剪策略 |
|----------|-----------|-------------|--------|------|----------|
| system   | 400       | 380         | 0      |      | —        |
| tools    | 600       | 720         | 120    | 🔴   | →D45 收窄 |
| 检索     | 1200      | 1100        | 0      |      | top-k 截断 |
| 历史     | 800       | 950         | 150    | 🔴   | compaction |

手算示例:设 tools 配额 600、实测 720,则 overBy = max(0, 720-600) = 120,该行 overBudget=true,标红(🔴),提示去 Day 45 削 tools;历史 超额则触发 compaction。注意上表 token 数为示意——真实实测来自对 AML SAR 流程跑 contextBudget(),且受「相对配额、非生产分词器」CAVEAT 约束。

3. 今日实战

  1. 取 AML Copilot 一次 SAR 流程作为被测样本(system prompt + 来自 toolRegistry 的 tools schema + 检索到的证据 + 对话历史)。
  2. src/agent/eval/tokenizer.tstokenReport()(或 contextAudit.tscontextBudget())对四类分别实测 token。
  3. 填一张 budget 表:每行 配额 quota | 实测 tokens | overByoverBy>0 的行标红。
  4. commit 产出的 context-budget 表,脚注注明「相对配额、非生产分词器」的 CAVEAT。

4. 今日实测 / 产出

  • tokenizer 已绿,可离线测真实 token。
  • 3 行 budget 表为「待跑(离线可出)」——产出 committed context-budget 表,含配额列、实测列、超额标红
  • tokenizer 真实基线已有:1760 tokens over 29 prompts

(诚实状态:tokenizer 与 contextBudget() 已绿,预算表无 key 阻塞、纯待执行;真实基线 1760 tokens / 29 prompts 为已测数字,逐字保留。)

5. 常见误区 / 陷阱

  1. 拿本仓 BPE 数当生产计费 token:它是按本次 corpus 现拟合的相对值,≠ tiktoken/cl100k,也跨调用不可比(代码 CAVEAT 已警示)。
  2. 配额加满到窗口上限:要给 completion 输出与中段安全垫留余量,否则一超就丢信息。
  3. 四类一刀切截尾:不同类该用不同策略(system 别动、history 压缩/丢、tools 重设计削),无脑截尾会误删 system 约束。
  4. 只填实测列不填配额列:预算表的信息量在「配额 vs 实测」的差与触发的动作,单列 token 数等于没预算。

6. 学习资源(每条带 YYYY-MM)

  • Anthropic, Effective context engineering for AI agents(2025-09)——budget / compaction / offload / prune 的主线来源。
  • Liu et al., Lost in the Middle(2023-07,TACL)——为预算留中段安全垫的经验依据。
  • Anthropic, Claude Agent SDK(2025-2026 持续更新)——compaction 内建于主流框架的现状参照。
  • 本仓代码:src/agent/mcp/contextAudit.tscontextBudget / auditToolContext + CAVEAT 注释)、src/agent/eval/tokenizer.tstokenReport)。

SOTA检查 (2026-06 更新)

  • 当前主流方案:compaction(summarize)/ offload / prune 三策略在 2025-09 提出后,2026 仍是 SOTA,并已被主流 agent 框架(Claude Agent SDK)内建为默认。
  • 是否仍 SOTA:是。四类配额 + 超额裁剪是 2026 经营长上下文的标准动作。
  • 过时黑名单(AVOID):默认塞满窗口、靠模型自己丢信息;用相对 BPE 数冒充生产分词器计费;history 无上限单调增长不压缩。
  • 下次复查点:是否出现更细的 KV-aware budget 工具(按 KV cache 占用而非纯 token 数做预算)——若出现,本预算表应升级到 KV 维度。

衔接

  • 昨天:Day 43 — 指标树与 North Star(把 context-token 列为输入层叶子)。
  • 今天:context-budget 表把窗口拆 system/tools/检索/历史四配额,超额触发 compaction/offload/prune。
  • 明天:Day 45 — tool 重设计(合并 + 收窄),削减预算表里 tools 这一类的超额。