LLM 101 FIELD NOTE

Agent Context Economics 101|03|Tool Loadouts:为什么多加一个工具可能更贵

工具 schema 位于上下文前部时,动态增删一个工具可能让后面的长会话重新 prefill。省下少量定义 token,不一定省下完整任务成本。

工具定义也是模型输入

继续同一个 coding agent 任务:“定位失败测试、修改实现、运行完整测试并交付结果”。为了完成它,Agent 至少要能读取文件、写入补丁、执行测试。产品界面可能只显示三个按钮,模型实际看到的却不只是 readwritebash 三个名字。

一份工具定义通常还包含名称、用途描述、输入 schema、字段描述、必填项、枚举、默认值以及 strict mode 等配置。模型要先理解这些定义,才能选择工具并生成参数。因此工具表是模型可见上下文的一部分,并且通常位于对话历史之前。截至 2026-07-26OpenAI Prompt Caching 201明确把 tool definitions 列入可缓存请求前缀;Claude API 的工具与 Prompt Caching 文档则给出 tools → system → messages 的缓存层级。这里描述的是相应产品的请求渲染与缓存契约,不是所有推理服务必然采用同一布局。

工具描述也不是只给开发者看的注释。比如 bash 的描述是否强调工作目录、超时和禁止交互,会影响模型何时选择它;输入 schema 是否把 commandcwdtimeout 说清楚,会影响参数是否可执行;默认值与并行调用配置则可能改变本轮行为。工具表同时承担能力目录、调用协议和行为提示三种职责,所以不能只用“schema 有多少 token”评价它。定义过短可能增加错误调用与重试,定义过长又会扩大常驻前缀,经济性必须连同任务成功率一起评估。

这也意味着,工具变化不只等于“多了一个名字”。改写 description、调整工具顺序、修改 schema 字段,甚至改变 property / key 顺序或默认值,都可能改变最终渲染的 token 序列——前提是 Provider 的模型可见渲染保留了这项差异。两个 JSON 对象在业务代码里语义等价,也不能据此假设其缓存前缀相同。上一章要求 Context Builder 对模型可见 schema 使用稳定序列化,原因就在这里。

工具定义的 token 当然要计入输入,但真正值得警惕的是它的位置。一个 200 token 的新 schema 若被插入长历史之前,风险不是只多处理 200 token,而是把后面已经积累的对话、文件内容和测试日志都推到首个 mismatch 之后。

一个新工具怎样让旧会话落在 mismatch 之后

假设 coding agent 已经完成失败测试定位,历史里保存了测试源码、实现文件、第一次失败输出和修改思路。原来的模型可见布局可以简化为:

[system][read][write][bash][conversation]

此时产品发现任务可能需要发布,于是动态插入 deploy

[system][read][write][bash][deploy][conversation]

这两行是为了突出 mismatch 而选用的概念顺序,不是所有 Provider 的通用 wire layout。实际请求中的 tools、system 与 messages 如何排列、渲染和分层,由 Provider 的 API 契约决定;无论工具定义最终位于哪个受缓存匹配的早期区块,只要它在长历史之前发生变化,下面的 mismatch 论证就成立。

两轮请求在 deploy 位置第一次不同。即使后面的 conversation 一字未改,它也不再属于两轮连续相同的前缀。在 Provider 缓存资格、路由和匹配粒度允许的范围内,deploy 之前的部分仍可能复用;而 deploy 及其后的长会话可能需要重新 prefill。越晚给一个长任务改变早期工具表,cache miss 的爆炸半径越大。

工具表变化如何把整段会话推到 mismatch 之后

同理,删除、重排或修改已有工具也会移动 mismatch。若只是把 bash 的描述从“运行命令”改成“运行受控 shell 命令”,业务能力几乎没变,缓存相关序列仍可能变化。不能用“只改了几个 token”估算任务代价;应该看首次差异之后还有多少历史、后续多少轮会复用新前缀、是否需要重新写缓存,以及这次变化是否提升了工具选择质量或权限正确性。

这并不推出“工具表永远不能改”。错误 schema 必须修,过度授权必须收紧,新任务也确实可能需要新能力。正确做法是把变更视为一次可观测的 prefix epoch:记录工具表版本、预期冷启动,并让后续轮次重新稳定,而不是在每轮按临时状态随意拼装。

稳定工具表与选择性授权

第一种模式是:保持完整工具数组与顺序稳定,用 OpenAI allowed_tools 选择本轮可调用子集。截至 2026-07-26,在支持该行为的 OpenAI 模型与 API 上,Function Calling 文档建议在不修改 tools 列表的情况下,用 tool_choice 中的 allowed_tools 限制模型本轮可调用的工具,从而保持 Prompt Cache 友好;Prompt Caching 201也给出稳定完整工具表的用法。

例如,read/write/bash/deploy 的定义和顺序始终存在。定位失败时,只允许 readbash;确认补丁后再允许 write;只有进入交付流程且满足策略时才允许 deploy。这样权限状态改变时,不必增删前部工具定义。

但要分清“可见”“可调用”和“可执行”。完整定义仍然对模型可见,allowed_tools 不是隐藏机制;模型未被允许调用某工具,也不等于执行端已经安全。真正的授权必须由服务端或工具执行器依据用户、资源、动作、审批状态重新校验,拒绝伪造、过期或越权调用。提示词、工具选择配置和模型输出都不能替代服务端 authorization。具体模型、API 和功能可用性会变化,接入时必须核对当期文档并做拒绝路径测试。

稳定完整数组适合定义不大、经常使用、权限只在可调用子集上波动的核心工具。若有几百个庞大 schema,为缓存稳定而把它们全部常驻,会增加每个任务的初始输入和模型选择负担;此时需要延后加载。

Tool Search 和 deferred loading

第二种模式是:Anthropic defer_loading: true + Tool Search + tool_reference。截至 2026-07-26Claude API Tool Reference说明,标记为 deferred 的工具定义会从初始 rendered tools section 中移除;当 Tool Search 找到它时,API 在发现位置把 tool_reference 及其完整定义内联展开到 conversation body,而不是回头改写系统提示前缀。工具与 Prompt Caching 文档据此说明既有前缀保持不变。

延后加载如何把冷门工具移出稳定前缀

第三种模式是更一般的 tool search:初始只给模型搜索能力和少量核心工具,需要时再检索专家工具。它减少的是初始工具定义,不是任务的全部成本。搜索请求、结果和 tool_reference 仍占 token,完整定义在真正使用时仍会进入后续上下文;搜索还可能增加一次延迟,并带来漏检、错选或描述不足的风险。

因此,Tool Search 最适合“工具表大而使用稀疏”的 loadout:例如 coding agent 大多数任务只用文件与 shell,偶尔才用数据库迁移、云发布或设计稿工具。在持久化且正确回放的 Claude API conversation / history 中,先前返回的 tool_reference 会随历史传回,后续轮次可以继续复用已发现工具,不必每轮重新搜索;发现成本更接近一份可用历史中的一次性成本。重复发现主要发生在新会话、引用与历史没有被回放,或自定义实现未持久化引用时,因此还要计算跨会话再发现与冷启动成本。即便如此,若某批工具在几乎每个任务都会使用,仍应根据 schema 大小、工具选择质量、发现延迟与跨会话频率,判断把它们放进常驻核心集是否更经济。上述 defer_loading、返回块格式、工具版本与 beta / 平台支持应严格限定在文档覆盖的 Claude API 行为;其他 Provider 的 tool search 即使名字相同,也未必拥有相同的前缀语义。

MCP 连接为什么容易制造缓存抖动

MCP 是工具发现与调用协议,但“某次 MCP 变化怎样影响缓存”是宿主产品的组装行为,不是 MCP 协议本身的普遍定律。第四种需要单独识别的模式是:eager MCP 工具定义位于早期 loadout,连接、断开、工具清单或 schema 动态更新会改变该前缀。如果一个 MCP server 重连后多报了一个工具,或同名工具 schema 更新,长对话可能像前面的 deploy 一样落到 mismatch 之后。

deferred MCP 工具则不同。截至 2026-07-26Claude Code 的 Prompt Caching 文档说明,在受支持模型上默认由 Tool Search 延迟加载时,server 连接、断开或改变工具列表只追加新内容,不扰动已经缓存的前缀;当 Tool Search 不可用、被关闭,工具被标记为 alwaysLoad,或阈值策略把定义保留在前部时,定义变化才会重写早期工具层。编辑 MCP 配置文件本身也不等于缓存立即变化,实际连接状态生效时才影响请求形状。

还要区分定义“加载到哪里”。eager 定义变化发生在 tools / system 前部,爆炸半径通常覆盖后续全部历史;deferred 工具被发现后,完整定义通过历史中的 tool_reference 在该位置展开。若其定义后来变化,潜在 mismatch 从这个历史加载点开始,而不是自动回到会话开头。尚未被发现的 deferred 定义变化,则不应被描述成已经改写了旧前缀。精确结果仍取决于宿主如何回放引用、Provider 缓存资格与版本支持。

也不能写成“任何 plugin 变化都会 miss”。同一份 Claude Code 文档明确区分:skills、commands、agents、hooks、LSP servers、monitors 和 themes 等非 MCP plugin 组件不会使既有前缀失效;它们追加的新内容仍有新增成本,但此前内容可以继续读取缓存。只有 plugin 提供 MCP server 时,才回到 eager / deferred 工具定义的判断。

哪些工具应该常驻,哪些应该延后加载

对贯穿任务,readwritebash 往往是常驻核心:使用频率高,schema 相对小,三者共同完成“定位—修改—测试”闭环。deploy、生产数据库操作、外部通知和设计系统同步更像专家工具:低频、schema 可能很大,权限与连接状态也更易变化,适合延后发现或放进独立阶段。

判断时至少同时看六个维度:

  • **工具数量与 schema 大小:**少量小定义常驻成本低;大量嵌套 schema 更值得搜索。
  • **使用频率:**几乎每个任务都会用的工具不必反复发现;低频长尾适合 deferred。
  • **权限波动:**权限经常按用户、环境或审批改变时,优先保持定义稳定并在调用与执行层控制;不要靠删 schema 充当唯一安全边界。
  • **延迟与可靠性:**关键路径工具若搜索服务不稳定,常驻更稳;慢速或易失联的专家能力可延后,并提供失败回退。
  • **发现质量:**名称、描述和检索语料能否让模型稳定找对工具;若经常漏检,节省的初始定义可能换来更多重试。
  • **miss 爆炸半径:**会话越长,越应避免在早期动态增删 eager 工具;新能力可以在新阶段、新会话或 deferred 加载点引入。

第五种贯穿所有模式的规则仍是:服务端授权永远是权威边界。常驻不等于授权,deferred 不等于隔离,Tool Search 找到工具不等于用户有权执行。loadout 设计解决模型上下文与选择问题;身份、权限、审批、参数约束和资源所有权由执行端解决。

工具装载决策表

场景信号 推荐装载方式 缓存与任务级理由 必须防范
少量小 schema,几乎每轮使用 稳定常驻、固定顺序 初始定义成本可预测,避免重复搜索 schema 发布仍需版本化
定义稳定,但本轮可调用权限常变 稳定完整数组 + 支持时使用 allowed_tools 不靠增删工具表表达每轮选择 定义仍可见;执行端必须再授权
工具很多、单任务只用少数 Tool Search + deferred loading 降低初始定义量,发现后在较晚位置扩展 搜索 token、延迟、漏检与错选
低频、schema 大、权限敏感的专家工具 延后加载或拆到独立阶段 避免所有任务承担大前缀,并缩小变化影响 不能把 deferred 当安全沙箱
高频关键工具,搜索延迟或可靠性差 常驻核心集 减少关键路径发现失败和重试 控制核心集规模与描述质量
eager MCP server 的列表或 schema 会动态变化 优先 deferred;否则在阶段边界更新 避免连接抖动持续改写早期 loadout 监控重连、动态 list update 与 prefix epoch
工具已通过 tool_reference 在历史中加载 保持定义版本稳定;升级时记录加载点 变化影响从内联位置起算,通常小于改写系统前缀 回放语义和 Provider 支持需实测

最终指标不是“工具定义 token 最少”,而是整个“定位失败测试、修改实现、运行完整测试并交付结果”任务是否以更少等待、更少重试和可接受成本正确完成。一个更短但频繁搜索失败的 loadout,可能比稳定常驻更贵;一个定义略长却能避免深会话 cache miss 的核心集,也可能更经济。应同时记录工具表版本、首个 mismatch、缓存读写量、Tool Search 次数与命中质量、TTFT、失败重试和最终交付率,再做选择。

一个实用的验证方法是用同一批真实任务做三组回放。A 组固定全部工具;B 组固定核心数组,并在支持时按轮使用 allowed_tools;C 组只常驻核心工具,其余通过 Tool Search 延后加载。三组使用相同模型、任务输入和权限策略,分别记录首次请求输入、深会话中的缓存读写、发现耗时、错误工具选择、测试重跑次数与最终交付是否正确。若 C 组初始 token 更少,却因两次漏检而重读文件、重跑完整测试,就不能宣布 deferred 更省;若 B 组保持了长历史命中,同时服务端拒绝了越权动作,它才同时满足缓存与安全目标。

发布时还应给每份模型可见工具表生成稳定版本或 digest,并把变更分成三类:只改变执行端而不改变模型定义、改变可调用子集但保持定义稳定、真正改变名称 / 描述 / schema。只有第三类应预期新的前缀 epoch;前两类也要验证 Provider 的实际渲染与 usage,而不能仅凭代码对象相同下结论。这样一次工具升级究竟省了定义、制造了 miss,还是改善了任务成功率,才有证据可追。


上一篇:Stable Prefix:缓存命中首先是一个架构问题

下一篇:Sessions Are Trees:会话、分支与缓存并不是一回事

参考资料