跳转至

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 就在代码内部。

三个机制

  1. 工具数量增加,模型准确率下降——每多一个工具,提示词就多一份 schema,模型面对的选择歧义就更大;在工具职责重叠时问题被进一步放大
  2. execute_code 把所有决策折叠成一步——让模型用编程语言的完整表达力组合各种能力,而非拼凑僵硬的工具调用
  3. 三个缓存层从同一个入口触达——模型始终在写代码,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 | Q2North 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_searchweb_crawlcreate_website 等:

get_tool_info("web_search")    返回 schema标记为"已获取"
execute_tool("web_search", )  如果未先获取则拒绝执行

已获取工具的集合即一个会话级缓存——模型加载一次 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% 路标,长尾几乎不占空间——这正是缓存层级框架所预测的分配。

三个迁移问题(任何领域适用)

电子表格只是作者的领域,这套结构可迁移到任何领域。系统提示和规格文档中的压缩,本质上是对用户分布和任务分布的编码,而你在自己的领域中最了解那种分布。工作归结为三个问题:

  1. 什么要包装进 L1? 频率曲线陡峭部分的主干操作。让它们 token 高效、能汇报变更后果。在这里投入相对集中的精力——Agent 在每个任务上都依赖这些操作
  2. 什么要推迟到 L2? 重要但不常见的能力。写成精心整理、关注常见问题的规格文档,一步发现即可加载。重点编码规范流程和约束,而非仅列出接口签名
  3. 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 架构师

  1. 执行 execute_code 原则——1 个工具 + 完整 API 库 > 30 个离散工具
  2. 为频率曲线陡峭部分精心设计 L1——每个任务都依赖它,ROI 最高
  3. 为偶发能力写"踩坑式"规格文档——不只是接口签名,是踩过坑之后才知道的规范流程
  4. L3 不必易用——只要可触达、有限步骤可找,3-6 次 grep 是可接受代价
  5. 每次 L1 升级先量化准确率——99% vs 95% 的非线性价值

对 Harness 工程师

  1. 设计 execute_code 的"diff 返回"——双重压缩(分组采样 + 问题分类)是 L1 的关键投资
  2. 实现 getXInfo 模式——按需加载规格文档,未获取就拒绝执行
  3. 维护 L3 的技能文件——100 行的 grep 速查表比 7 万行 API 全集更易被模型消化
  4. 警惕"窗口大 = 全放进去"的诱惑——窗口扩大的反效果是淹没模型
  5. 层级边界要可调——模型版本号变了,L1/L2/L3 的内容也要相应调整

对 LLM 评测者

  1. 跨任务分布评测——单一 95% 平均分掩盖了"某些任务 100%、某些 50%"的不均匀
  2. 长尾覆盖度指标——有多少原本 0% 的稀疏长尾任务被新 L2 规格文档覆盖
  3. token 效率指标——同样准确率下的平均 token 消耗(多工具 vs 单工具对比)

与现有实体的互补关系

原文存档