跳到主要内容

Token 预算作为架构约束:在硬上限下设计可靠的 Agent

· 阅读需 9 分钟
Tian Pan
Software Engineer

你的 agent 在开发环境中运行完美。它能推理多步任务,自信地调用工具,生成精美的输出。然后你设置了每次请求 $0.50 的成本上限,它就崩溃了。不是优雅地降级——而是灾难性的崩溃。它在推理过程中截断自己的思考,忘记三步前的工具结果,并基于被静默丢失的上下文自信地给出错误答案。

这就是丰裕设计的 agent 和生产受限 agent 之间的差距。大多数 agent 架构都是在无限 token 预算下原型化的——长系统提示词、冗长的工具 schema、完整的文档检索、未压缩的对话历史。当你引入硬上限(成本上限、上下文限制、延迟要求)时,这些 agent 不会优雅地降级。它们以难以检测且调试成本高昂的方式崩溃。

Token 预算不是一个调优参数。它是一个架构约束,如同系统编程中的内存限制或分布式系统中的带宽一样基本。像那些约束一样,它要求的设计在结构上与无约束版本根本不同。

丰裕陷阱

大多数 agent 框架鼓励的开发模式是这样的:把所有东西塞进上下文窗口,让模型自己去处理。预加载检索到的文档。包含完整的工具 schema。保留完整的对话历史。为每个边界情况添加详细的系统指令。

这在原型阶段有效,因为拥有 200K+ 上下文窗口的前沿模型很宽容。但它会产生三个只在生产约束下才会浮现的问题。

上下文腐化是真实且可测量的。 随着向 LLM 输入添加 token,输出质量会可预测地下降。Databricks Mosaic 的研究发现,退化大约在 32K token 后开始。"中间遗失"现象意味着模型会有效地忽略长上下文中间的信息,产生随上下文长度增长的盲区。

成本非线性增长。 处理 128K token 的成本大约是 8K token 的 64 倍,这是由于注意力矩阵的复杂度。10 轮推理循环消耗的 token 大约是单次推理的 50 倍。在主要提供商中,输出 token 的价格是输入 token 的 3-8 倍。一个不受约束的软件工程任务很容易产生 $5-8 的 API 费用。

Agent 会"死于上下文"。 Agent 读取一个文件,收到 250K token 的输出,静默地超出了上下文窗口。请求失败。Agent 永远不理解为什么。它不会崩溃或抛出异常——它只是停止工作。这种失败模式——单独合理的操作摧毁了 agent 继续运行的能力——在生产系统中很普遍。

预算分配是一个设计决策

当你接受 agent 有固定 token 预算时,第一个架构问题是:如何分配?生产 agent 需要 token 用于至少四个不同的阶段,它们之间的分配决定了 agent 能做什么和不能做什么。

规划消耗总预算的 10-30%。这包括分解用户请求、选择使用哪些工具以及决定执行策略。关于基于 LLM 的规划模块的研究表明,在无约束设置下,它们可以在分解和自我反思上消耗总 token 的 40-70%——这个比例在硬上限下是不可持续的。

执行是实际的工具调用及其结果——通常是最大的预算消费者,占 40-60%。每次函数调用的往返都会添加 schema 定义、调用和结果注入。一个拥有 500+ 工具的系统仅在定义上就可以在单个工具触发前消耗超过 100K token。

验证出乎意料地昂贵。包含显式验证的框架(如 MetaGPT 和 AgentVerse)将多达三分之二的 token 用于检查自己的工作。AgentVerse 的验证阶段本身通常超过其执行阶段的 token 成本。

输出生成需要预留 10-20% 用于最终响应。常见的建议是为输出预留总预算的 25-50%,但在紧张的上限下这是一种奢侈。结构化输出(JSON 模式)可以显著压缩这一部分。

关键洞察是这些比例不是固定的。它们应该根据任务复杂度而变化。事实查询需要最少的规划和验证,但需要大量的执行预算。多步推理任务需要大量的规划分配。硬编码比例会导致在简单任务上浪费预算,或在复杂任务上阶段预算不足。

动态重新分配:当早期步骤吃掉预算时

当现实偏离计划时,静态预算分配就会崩溃。Agent 估计一个任务需要三次工具调用,相应地分配预算,然后第一次调用返回了 50K token 的意外数据。剩余预算无法支持计划中的执行。

生产 agent 需要针对这种场景的重新分配策略。

带回退的复杂度估计。 TALE(Token-budget-Aware LLM rEasoning)框架根据推理复杂度为每个问题估计适当的 token 预算,然后使用该估计来指导过程。这在保持 5% 以内准确率的同时实现了 68% 的平均 token 使用量减少。关键是在提交到昂贵的执行计划之前有一个低成本的估计步骤。

渐进式压缩。 不保留完整的对话历史,而是在里程碑处进行总结。Anthropic 的记忆指针方法在 100 轮对话中实现了 84% 的 token 减少,通过用轻量级引用替换完整文档。权衡是压缩本身消耗 token,并且可能丢失微妙但关键的上下文。

子 agent 隔离。 将风险操作委托给隔离的上下文窗口。一个探索 50K token 文档的子 agent 只向编排器返回 2K 的摘要。这是操作系统中进程隔离的 agent 等价物——一个 agent 的上下文爆炸不会杀死父进程。

优雅降级层级。 当预算耗尽时,agent 应该有预定义的回退行为:

  • 层级 1:带验证的完整推理
  • 层级 2:不带验证的推理(跳过自检)
  • 层级 3:不带规划的直接工具执行(使用启发式路由)
  • 层级 4:返回部分结果并明确指示哪些未完成

大多数生产 agent 没有实现这些层级。它们只是失败,或者更糟的是,从截断的上下文中自信地产生错误输出。

为什么丰裕设计的 Agent 在约束下失败

失败模式是具体且可预测的。理解它们是构建受限优先架构的第一步。

工具 schema 膨胀。 为灵活性设计的 agent 随时间积累工具。超过 30 个工具后,基于检索的工具选择会非线性退化。每个工具的 schema 即使未使用也消耗上下文。在紧张的预算下,工具定义本身就可以挤占实际工作。

贪婪的文件操作。 没有安全防护的 agent 将整个文件、数据库或 API 响应读入上下文。顺序读取会不可预测地累积。大多数框架中没有原生机制可以在提交操作之前预览其 token 成本。

无压缩的对话膨胀。 每一轮都添加 token。20 轮对话很容易超过 200K token。没有压缩,运行多步工作流的 agent 纯粹因为累积的历史记录而达到上限,而不是任何单个昂贵的操作。

验证税。 验证是团队在预算紧张时首先削减的东西,但它通常是正确输出和自信地错误输出之间的区别。架构挑战是让验证更便宜,而不是消除它。

受限优先设计模式

构建在结构上为 token 约束而设计的 agent——而不是在丰裕设计的架构上改造约束——需要不同的模式。

预算感知路由。 将 90% 的工作负载路由到更小、更便宜的模型,只将真正需要前沿推理的 10% 升级。研究表明这可以实现 87% 的成本降低。路由决策本身必须低成本——一个小型分类器或基于规则的系统,而不是另一次 LLM 调用。

代码模式过滤。 不是将数据加载到上下文中让模型处理,而是让 agent 编写代码在执行环境中处理数据。Cloudflare 的基准测试显示,复杂批处理操作可节省 81% 的 token,数据过滤可减少高达 99.9%。模型推理代码,而不是数据。

带大小估计的工具元数据。 公开预期响应大小并支持空运行模式,以便 agent 可以做出明智的决定是继续还是委托。这相当于在 read() 之前执行 stat()——一种防止昂贵错误的低成本探测。

分层记忆。 在上下文中维护轻量级工作记忆(当前任务状态、近期结果),并引用存储在外部的完整文档。按需加载详细信息,而不是预加载所有内容。这反映了有经验的开发者的工作方式——他们不会将整个代码库读入脑中,而是导航到需要的地方。

带异常检测的预算护栏。 实施每次追踪的 token 上限、agent 循环的最大迭代次数上限和消费异常警报。偏离预期 token 使用量 2 个标准差应触发调查,而不是静默继续。

架构真理

Token 预算不是一个需要绕过的不便限制。它是一个产生更好架构的强制函数。在约束下设计的 agent 比它们的无约束对应物更可预测、更可观察、更具成本效益——即使在资源充裕的情况下也是如此。

与系统工程的类比是精确的。内存受限的程序比为无限内存设计的程序更高效。带宽受限的协议比假设无限吞吐量的协议更健壮。Token 受限的 agent 对它们实际需要的信息更有纪律。

在生产中发布可靠 agent 的团队不是拥有最大上下文窗口的团队。他们是那些很早就决定每个 token 都必须证明其存在价值——并从一开始就围绕这个约束构建架构的团队。

References:Let's stay in touch and Follow me for more thoughts and updates