在使用大语言模型(LLM)作为编程代理时,成本会随着对话长度的增加而呈现近似二次方增长。这一现象的主要原因是缓存读取成本的累积,在上下文长度达到 5 万至 10 万个令牌(token)时,缓存读取费用甚至可能占到下一次 API 调用成本的一半以上。为了有效控制开销,开发者需要考虑分割任务、使用子代理或重新开启对话等策略。
LLM 代理的成本构成
当一个 LLM 代理工作时,它会持续地将整个对话历史发送给模型,这个过程会循环往复。在此过程中,LLM 服务提供商会对多个环节进行计费:
- 输入令牌 (Input tokens): 用户输入或工具调用的新内容。
- 缓存写入 (Cache writes): 将上一次模型的输出和新的输入写入缓存,以便后续调用。
- 输出令牌 (Output tokens): 模型生成的新回复。
- 缓存读取 (Cache reads): 在每次新调用时,从缓存中读取此前的全部对话历史。
缓存读取的成本是导致总费用急剧上升的关键。其成本约等于调用次数与上下文长度的乘积,这正是形成“二次方”增长曲线的原因。
成本增长的可视化分析
在一个花费了约 12.93 美元的实际对话案例中,成本结构的变化非常明显。随着对话的进行,代表缓存读取成本的部分在总成本中的占比越来越大。
- 当对话上下文达到 27,500 个令牌时,缓存读取的成本已经占据了总成本的一半。
- 在对话结束时,缓存读取的成本占比飙升至 87%。
对 250 个不同对话的随机抽样分析也证实了这一趋势。尽管每个对话的具体成本曲线因任务不同(例如,编写大量代码会增加昂贵的输出令牌成本)而有所差异,但缓存读取成本随上下文增长而主导总成本的模式是普遍存在的。
如何控制失控的成本?
既然成本与 调用次数 和 上下文长度 直接相关,减少其中任何一个都可以降低开销。虽然减少 LLM 的调用次数最直接,但这可能会牺牲代理获取反馈的机会,从而影响任务的准确性。以下是一些更精细的成本管理策略:
- 使用子代理或专用工具: 将复杂的任务分解,让子代理在主对话窗口之外进行迭代。例如,使用一个由 LLM 辅助的搜索工具来代替直接在主对话中处理大量文件内容。
- 限制工具返回的内容大小是错误的: 有些代理会限制工具一次性返回的内容大小,试图降低成本。但这通常适得其反,因为代理最终还是需要读取所有内容,分多次读取只会增加总的调用次数和缓存读取成本。
- 适时重新开始对话: 重新开启一个新对话看似浪费,因为需要重建上下文。但与持续在一个超长对话中累积高昂的缓存读取成本相比,重建上下文的成本通常更低。这类似于我们在处理不同开发任务时,会从干净的代码仓库版本开始,而不是无限期地延续同一个工作流。
最终,成本管理、上下文管理和代理编排可能是同一个核心问题的不同方面,这为如何构建更高效、更经济的 LLM 代理提出了重要挑战。