CPU 缓存类比下的 Agent 上下文管理:L1/L2/L3 层级架构与 execute_code 单工具设计¶
Ch04.508 CPU 缓存类比下的 Agent 上下文管理:L1/L2/L3 层级架构与 execute_code 单工具设计¶
📊 Level ⭐⭐⭐ | 23.5KB |
entities/cpu-cache-analogy-agent-context-management-liwen.md
CPU 缓存类比下的 Agent 上下文管理:L1/L2/L3 层级架构与 execute_code 单工具设计¶
本实体整理自 原文存档。 把 CPU 缓存的 L1/L2/L3 层级结构直接迁移到 Agent 上下文管理,配套"一个工具而不是三十个"的设计原则、读取区间的三重压缩、写入 diff 的分组采样 + 问题分类等具体工程模式。
一句话总结¶
CPU 面对的是同样的问题——一个程序可能触碰几 GB 数据,但紧贴处理器的存储空间极小。Agent 上下文管理应当采用同样的 L1/L2/L3 层级结构:L1 常驻(80% 覆盖)/ L2 按需规格文档(15% 覆盖)/ L3 原始 API 大全 + 检索技能(5%+ 兜底)。配合 execute_code 单工具原则(1 个工具 = 0 工具税 + 编程语言表达力),构建在常见场景下响应高效、偶发场景能力完整、罕见场景不会止步的 Agent。
核心命题¶
Agent 开发,假设你不拥有运行环境,也没有训练模型,那么你能设计的东西只有三样:系统提示、工具,以及各类产出物(skill 文件、精心整理的文档、参考资料)。这三样东西本质上是一回事:Agent 的上下文。
模型固定之后,准确率就是上下文质量的函数。99% 准确率的任务,其价值是 95% 任务的十倍——这个关系不是线性的。
但用户问题呈长尾分布: - 80% 是高频主干任务(bread-and-butter) - 15% 是偶发重要任务(crucial-but-occasional) - 5%+ 是稀疏长尾(the long tail)
Agent 必须覆盖所有场景,但不可能把一切同时塞进上下文——那正是"提示词臃肿"的失败模式。真正要解决的问题:在整条任务分布曲线上,最小化每个任务平均消耗的上下文开销。
L1/L2/L3 三层架构¶
L1 — 常驻内容(80% 覆盖)¶
- 极小、即时可用
- 放在系统提示里
- 每次调用常驻
- 未命中代价:一次廉价调用
L2 — 按需加载(15% 覆盖)¶
- 精心整理的规格文档
- 一步发现即可加载(
console.log(getXInfo(...))) - 未命中代价:读 skill 文件 + 搜索
L3 — 兜底路径(5%+ 覆盖)¶
- 原始 API 全集
- 覆盖长尾
- 3-6 次 grep 即可定位
几乎所有优化都围绕"信息压缩"与"发现速度"之间的权衡¶
把某项能力放进 L1,即时可用但无论是否需要都消耗 token;推到 L3,不用时零成本,一旦需要付出多次工具调用代价。工作是把每项能力放到跨分布总成本最低的那一层。
execute_code 单工具原则(vs Anthropic "5-10 个工具")¶
核心论断¶
所有电子表格能力都通过一个工具 execute_code:
async function execute() {
const data = await sheet.getCellRange("Sheet1!A1:D200");
// ...读取、计算、写入...
}
Agent 写代码 → 代码调函数 → 函数操作电子表格。没有 read_range / write_range / make_chart 工具——只有一个工具,API 就在代码内部。
三个机制¶
- 工具数量增加,模型准确率下降——每多一个工具,提示词就多一份 schema,模型面对的选择歧义就更大;在工具职责重叠时问题被进一步放大
- execute_code 把所有决策折叠成一步——让模型用编程语言的完整表达力组合各种能力,而非拼凑僵硬的工具调用
- 三个缓存层从同一个入口触达——模型始终在写代码,L1/L2/L3 只决定它知道哪些函数可调用,以及找到这些函数要付出多少代价
与 Anthropic 工具数量陷阱 的对比¶
| 维度 | Anthropic 答案 | 本文答案 |
|---|---|---|
| 工具上限 | 5-10 个边界清楚的工具 | 1 个 execute_code 工具 |
| 作用域 | 整个 Agent 工具集 | 把"API 集合"折叠进 execute_code 内部 |
| token 税 | 134K / 99 工具 | 接近 0——只付 execute_code schema 的 token |
| 决策压力 | 模型选哪个工具 | 模型写什么代码 |
| 表达力 | 受限于工具 API 的固定形态 | 编程语言的完整表达力 |
1 个 execute_code 工具 = 0 工具税 + 编程语言表达力 + L1/L2/L3 通过代码自然分层。
L1 实战:读取区间的三重压缩¶
读取 200 行营收表,把六百个公式 + 四百个样式单元格压缩到原 dump 的一小部分 token:
压缩 1:公式别名化¶
500 个 =A2*B2、=A3*B3... 几乎相同 → 规范化为 R1C1 格式 → =A2*B2 和 =A3*B3 都变成 =RC[-2]*RC[-1]。统计模式出现次数,超过十次的模式折叠成短别名如 F1。模型看到的是反复出现的 F1 加一行说明,而非 500 个公式。token 大幅节省,信息零损失。
压缩 2:自动补充行列语义¶
读取 C5:E20 时,那些裸数字代表什么?向左扫描行标签、向上扫描标题行(通过投票选出文本单元格最多的附近行作为标题),将它们一并附加。模型自动获得 Region | Q1 | Q2 和 North America | ... 这样的语义。
压缩 3:样式压缩¶
格式也是信息——粗体红色 + 0.00% 数字格式传递某种信号。但逐个列出每个单元格样式会淹没数值本身。按相同样式对单元格分组,每组折叠为连续区间,打印一行。
结果:六百个公式变成一行说明,四百个样式单元格变成两行,模型从未要求的标题行附在末尾。整张表无损压缩,只占原始 dump 一小部分 token。
L1 实战:写入 diff 的双重压缩¶
一次 execute_code 调用可能改变数百个单元格。代码运行后,返回结构化 diff,列出每个变更单元格,同时压缩 + 分级。
压缩机制 1:分组采样而非全量 dump¶
变更单元格按工作表和行分组,每行以带计数的列区间呈现(第 2 行(D):1 个单元格),只打印确定性采样的若干单元格,其余用"...以及另外 N 行"代替。两百次写入变成寥寥几条,Agent 仍能掌握总量。
压缩机制 2:问题分类¶
- 无问题的变更:正常写入归入此类
- 需要审查的单元格:可疑内容(
#REF!这类无效公式、未标注的硬编码数字、嵌在公式里的硬编码数字、异常大的百分比)归入此类 - 必须修复:最严重的问题单独标注并置顶
反馈循环从"这是变更内容"变为"这是变更内容,以及其中需要关注的部分"——相当于 Agent 自身编辑行为的内置 linter。
L2 实战:规格文档按需加载¶
条件格式、数据透视表、图表、数据验证、复制/移动语义——每项都重要,每次会话用几次,但文档量足够大。典型的 L2 场景。
模型从代码内部调用:
console.log(general.getConditionalFormattingInfo());
console.log(general.getPivotTableInfo());
console.log(general.getChartInfo());
console.log(general.getDataValidationInfo());
console.log(general.getAPIInfo("addSpanAt")); // 按名称获取任意单个函数
这些不是类型签名的 dump,而是手写的文档,每份几百行,描述完成任务的规范方式——包含原始 API 不会直接告诉你的知识:
const pt = sheet.originalSheet.pivotTables.add("SalesPivot", "SalesData", 0, 0, ...);
pt.suspendLayout();
pt.add("Region", "Region", rowField);
pt.add("Quarter", "Quarter", columnField);
pt.add("Amount", "Sum of Amount", valueField, 8); // 8 = sum
pt.resumeLayout();
把只有踩坑之后才能学到的东西写进去:批量修改必须用 suspendLayout()/resumeLayout() 包裹;值字段聚合方式必须传入原始整数(sum 是 8),因为友好枚举运行时不存在。
关键属性:在任务需要它之前,这些文档的 token 成本为零。不涉及数据透视表的任务,不必为透视表文档买单。
L2 实战:延迟工具(Deferred Tools)¶
L2 不只用于文档。把模式应用于延迟工具——web_search、web_crawl、create_website 等:
已获取工具的集合即一个会话级缓存——模型加载一次 schema,从此保持可用。提示词保持精简,只在真正需要时付出一步未命中的代价。
这与 Claude 的延迟工具思路相同,但不依赖特定厂商的工具加载特性——可移植的设计。
L3 实战:原始全集 + 检索技能文件¶
长尾:从未被包装、也从未有过规格文档的偏门需求。这类需求无法预见,定义上如此。但 Agent 必须能处理它们,否则会在任务中止步:
- "给每行加一个 sparkline"(真实但少被触碰的 API 面)
- "把图表的副坐标轴设为对数刻度,并只给第三个系列重新着色"(深入三层的图表属性)
- "插超链接到命名区间,并把这些图形组合起来"(绘图/图形/超链接的角落地带)
L3 = 完整的原始 API 全文 + 教 Agent 如何检索的技能文件(约 100 行):
grep -n '"charts.add"' api-reference.json -A 5 # 查找一个方法
grep -n '"pivots\.' api-reference.json | head # 列出一个命名空间
grep -n '"ChartConfig"' api-reference.json -A 10 # 解析一个类型
grep -n '"isEnum": true' api-reference.json -B2 -A10 # 枚举所有枚举值
通过 3-6 次 grep 定位到所需签名。L3 的访问代价真实存在,但有上限,且只有深入到这一层的罕见任务才需要承担。
提示词预算分配¶
| 层级 | 系统提示中占多少 | 内容 |
|---|---|---|
| L1 | 几百行 | 核心读写操作、execute_code 契约、关键类型、执行和安全指南——每次调用常驻 |
| L2 | 约 50 行 | 不是规格文档本身,是"受认可"方法白名单 + 指向 getXInfo(...) 规格文档的说明 |
| L3 | 5 行 | 技能文件名称和描述 + 散落各处的几行引用 |
原始参考文档 7 万行完全放在磁盘,从不进入提示词。常驻的只有短小的技能文件和 API 层级那一节里指向它的一行。
预算分配与频率曲线吻合:大部分 token 花在 80% 情况上,少量用于指向 15% 路标,长尾几乎不占空间——这正是缓存层级框架所预测的分配。
三个迁移问题(任何领域适用)¶
电子表格只是作者的领域,这套结构可迁移到任何领域。系统提示和规格文档中的压缩,本质上是对用户分布和任务分布的编码,而你在自己的领域中最了解那种分布。工作归结为三个问题:
- 什么要包装进 L1? 频率曲线陡峭部分的主干操作。让它们 token 高效、能汇报变更后果。在这里投入相对集中的精力——Agent 在每个任务上都依赖这些操作
- 什么要推迟到 L2? 重要但不常见的能力。写成精心整理、关注常见问题的规格文档,一步发现即可加载。重点编码规范流程和约束,而非仅列出接口签名
- L3 是什么? 完整的原始底层基础 + 教 Agent 如何检索的技能文件。不必设计易用,只要内容完整、可以触达、有限步骤内能找到即可
三个层级到位 → 常见场景响应高效、偶发场景能力完整、罕见场景不会止步,同时上下文控制在紧凑范围内。
深度分析¶
1. 99% vs 95% 准确率的非线性价值¶
一个达到 99% 准确率的任务,其价值是 95% 任务的十倍。
这个非线性关系在 L1/L2/L3 设计中的体现是:L1 建设成本再高也值得——因为 Agent 在每个任务上都依赖 L1。L1 哪怕只提升 1% 准确率,乘以所有任务的总和,价值就远超 L2/L3 的零散提升。L1 的 ROI 远高于 L2/L3。
2. 压缩 vs 发现的本质权衡¶
| 选择 | 优势 | 代价 |
|---|---|---|
| 压缩优先 | 信息密度高,token 消耗低 | 失真风险——压缩错误信息变成"看起来对"的垃圾 |
| 发现优先 | 信息完整,未失真 | 多次工具调用,每次都有延迟成本 |
L1 偏压缩、L3 偏发现、L2 折中。这不是工程选择,而是频率曲线决定的自然结果——L1 的高频值得花大力气压缩;L3 的稀疏负担不起发现成本。
3. execute_code 单工具的革命性¶
如果说 Anthropic "5-10 工具"是对多工具 Agent 的约束,那 execute_code 是对工具概念的消解——把"工具 = 离散 API 调用"换成"工具 = 编程语言本身"。
关键转换:
- 离散 API → 受限于工具设计者的想象力
- 编程语言 → 受限于模型写代码的能力
当模型能写代码时,把"读写单元格 + 排序 + 筛选 + 透视"这些离散操作压成"getCellRange() + Array.prototype.filter() + reduce()"——一个工具调用 = 任意表达力。
这也意味着:execute_code 的边界 = 沙箱安全的边界——只要 LLM 写的代码能在沙箱里跑,就能完成任何 API 允许的操作。沙箱 = 唯一的权限边界。
4. 层级会移动但不会消失¶
早期模型需要小而单一的工具,今天的模型能一次处理更大的 L2 规格文档。随着模型能力提升,昨天的 L3 成了今天的 L2,昨天的 L2 折叠进 L1。
这一观察意味着 L1/L2/L3 的边界是模型版本号的函数——Claude 4 时代放进 L1 的内容,到 Claude 6 可能折叠成单行 hint;昨天依赖 L3 的偏门能力,今天可能成为 L2 规格文档的主条目。
但层级结构本身不会消失——因为相对于所有可以放入的内容,上下文始终稀缺,多余内容始终损耗准确率。没有任何模型强大到让"在正确时机把正确内容放在它面前"失去意义。
这是 注意力机制 的 LLM 时代回响——CPU 时代有缓存层级;LLM 时代有上下文层级;都是"在正确的层放正确的内容"。
5. "摘要放在缓存,细节按需取用,原始底层兜底"的工程化¶
更大的上下文窗口容易让人倾向于放入更多内容。但更有效的做法是 CPU 数十年前已验证的方案。
这是对 1M 上下文窗口的隐性批判——窗口扩大不等于"都放进去"。L1/L2/L3 在窗口扩大时反而更显重要:当 L3 体积从 7 万行扩到 70 万行时,没有层级结构,模型就被淹没在长尾里。层级结构 = 任意窗口大小下的可扩展性保障。
实践启示¶
对 Agent 架构师¶
- 执行 execute_code 原则——1 个工具 + 完整 API 库 > 30 个离散工具
- 为频率曲线陡峭部分精心设计 L1——每个任务都依赖它,ROI 最高
- 为偶发能力写"踩坑式"规格文档——不只是接口签名,是踩过坑之后才知道的规范流程
- L3 不必易用——只要可触达、有限步骤可找,3-6 次 grep 是可接受代价
- 每次 L1 升级先量化准确率——99% vs 95% 的非线性价值
对 Harness 工程师¶
- 设计 execute_code 的"diff 返回"——双重压缩(分组采样 + 问题分类)是 L1 的关键投资
- 实现 getXInfo 模式——按需加载规格文档,未获取就拒绝执行
- 维护 L3 的技能文件——100 行的 grep 速查表比 7 万行 API 全集更易被模型消化
- 警惕"窗口大 = 全放进去"的诱惑——窗口扩大的反效果是淹没模型
- 层级边界要可调——模型版本号变了,L1/L2/L3 的内容也要相应调整
对 LLM 评测者¶
- 跨任务分布评测——单一 95% 平均分掩盖了"某些任务 100%、某些 50%"的不均匀
- 长尾覆盖度指标——有多少原本 0% 的稀疏长尾任务被新 L2 规格文档覆盖
- token 效率指标——同样准确率下的平均 token 消耗(多工具 vs 单工具对比)
与现有实体的互补关系¶
- AI Agent 工具数量陷阱 — "5-10 工具"是 Anthropic 答案;"1 execute_code"是本文答案(更激进的同向论述)
- Agent Harness 上下文管理工作集视角 — 工作集是 L1 内部的精细化设计;本文是工作集的 L1/L2/L3 宏观扩展
- 智能体编排层中的上下文管理架构 — 框架主动约束 vs 模型自主管理的权衡;本文是同向的更激进的 execute_code 推论
- Context Engineering — 上下文工程的概念基础
- Code as Agent Harness Survey — 编程语言作为 Agent 接口的更广义论述
- Claude Code 工具设计演进 — Anthropic 工具设计的演进
- 上下文工程三种记忆范式对比 — 记忆/上下文/信息的层级
- Claude Code 上下文工程 Thariq — 官方 Anthropic 视角
- Codex 上下文工程 LastWhisper — 另一家 Code 厂商的上下文视角
- 上下文工程系列 — 系列化上下文工程讨论
→ 原文存档