
尽管ChatGPT 4.1因其速度稳定且指令执行率高,仍然是我大多数内部工作流程的首选模型,但即使是它 1,047,576 个 token 的上下文窗口也可能出现空间不足的情况。当上下文窗口空间不足时,代理要么需要放弃,要么需要将这个大的上下文窗口压缩成一个更小的窗口。以下是我们关于实现压缩的说明。
这是“打造内部代理”系列文章的一部分。
为什么压实很重要
长时间运行且包含大量工具调用或用户消息的工作流,以及任何处理大型文件的工作流,其上下文窗口空间经常会耗尽。虽然在大多数情况下,内部代理程序不会遇到上下文窗口空间不足的问题,但最终,如果不解决这个问题,就无法实现一个健壮可靠的代理程序,而压缩则是一种直接有效的解决方案。
我们是如何实施的
最初,在我们天真地认为压缩不会影响内部工作流程的时候,我们采用了一种极其简单的压缩方案:如果令牌耗尽,我们就丢弃较旧的工具响应,直到腾出更多空间后再继续。由于我们很少遇到需要压缩的情况,所以这种方案效果不佳的问题并不严重。但随着我们开始处理更多包含大型文件的工作流程,这种笨拙的做法最终让我感到不安。
在我们第二次迭代压缩的最初头脑风暴中,我最初的想法是,压缩应该在实现对子代理的支持之后进行,但最终证明这并不准确。
我们压实方法的核心是:
- 在每次用户消息(包括工具响应)之后,在上下文窗口中添加一条系统消息,其中包含已消耗和可用的令牌。在该系统消息中,我们还会包含可读取的可用“虚拟文件”的更新列表。
- 用户消息(包括工具响应)如果超过 10,000 个令牌,则会以新的“虚拟文件”形式显示,上下文窗口中仅包含前 1,000 个令牌。代理必须使用文件操作工具才能读取超过这 1,000 个令牌的内容。
- 添加一套始终可供代理使用的“基础工具”,特别是虚拟文件操作工具,因为我们最终发现,大多数代理如果没有大量大多不可见的内部工具,根本无法运行。
- 如果消息占用的窗口大小超过模型可用上下文窗口的 80%(可配置值),则使用Reddit 上声称 Claude Code 使用的压缩提示。这个提示本身并没有什么特别之处,它只是现成的,而且看起来相当不错。
- 压缩后,将之前的上下文窗口添加为虚拟文件,以便代理能够检索可能丢失的上下文片段。
- 新增工具
file_regex,允许代理对文件(包括之前的上下文窗口)执行正则表达式搜索。
这些步骤本身都很简单,但它们结合起来确实能为处理复杂、耗时的工作流程提供相当强大的功能。诚然,我们仍然对工作流程中可调用的工具数量设置了可配置的上限(以避免代理程序崩溃),但这也就意味着,处理大型或复杂数据的代理程序更有可能高效运行。
运行情况如何?/下一步是什么?
虽然我们大多数新的内部代理功能都存在明显的缺陷或需要改进的地方,但这个功能感觉已经足够好,可以长期不用再管它了。原因有二:首先,我们的大多数工作流程并不需要很大的上下文窗口;其次,说实话,这个功能目前运行得相当不错。
如果未来上下文窗口显著增大(目前我看不出太多迹象表明这种情况会发生),那么我们将简单地增加一些默认值以使用更多标记,但这里的核心算法似乎已经足够好了。