博客

让长时间的代理回合保持在上下文窗口之内

模型一次能读取的内容有限,这就是它的上下文窗口。Mythex 的代理会进行长时间的工作:读取大量文件、运行命令,并把有界的任务交给子代理。我们发现长时间工作会以三种方式出问题:子代理不断增长,直到模型拒绝每一个请求;一个子代理因为以为自己的空间不够而提前停止;以及我们对俄语、中文和日语文本的 token 计数严重失准。以下是我们做出的改变。

先了解几个术语

  • Token 是模型读取的文本块。限制和成本都以 token 计算,而不是以字符或单词计算。
  • 上下文窗口是模型在一次请求中最多能读取的内容。我们还为每次请求设置了自己更低的预算,以使成本和速度保持合理。
  • 工具结果是代理从工具那里取回的内容:它读取的文件内容,或它运行的命令输出。在长时间的工作中,它们占了所发送内容的大部分。
  • 子代理是主代理为一个独立的任务启动的帮手,例如「对照笔记检查这些章节」。它只获得一条指令,然后自己通过许多次工具调用来完成工作。

问题一:子代理不断增长,直到模型拒绝它们

每一步,代理都会把到目前为止的对话发送给模型。当对话变得太大时,我们的代码会裁剪它,但只在用户消息的开头进行裁剪,从而确保工具调用和它的结果从不被拆开。它保留第一条消息,添加一条说明已裁剪更早对话的备注,并保留能放下的最新完整回合。

子代理只有一条用户消息:它的指令。没有地方可以裁剪。因此,它每一步都会发送整个历史记录,并且每次都会变得更大,直到请求超过模型所能接受的大小,大约一百万个 token。在一项包含 8 个这样的子代理的测试中,8 个全部被拒绝。

修复:先清除旧的工具结果

现在,请求会通过三个步骤来适配预算,只有在前一步不够时才尝试下一步:

  1. 清除最旧的工具结果。 它们的内容会被替换为一段简短的说明:该结果为了让对话保持在模型的上下文范围内已被清除,如果代理需要,可以重新运行该工具。一小时前读取的文件通常是请求中最大、也最没用的东西,而且文件仍然可以再次读取。最新的结果保持完整。
  2. 保留完整的用户回合。 与之前相同:第一条消息、一条说明,以及能放下的最新完整回合。
  3. 保留完整的工具轮次。 在一个长回合内部(子代理只有这一种回合),保留第一条消息、一条说明,以及最新的完整轮次,即「调用一个工具,获得其结果」。

这只影响发送的内容。代理保存的历史记录保留了所有内容。在同一项测试中,8 个中有 0 个被拒绝,全部完成。

分批清除,让缓存继续生效

模型提供商可以复用请求开头的工作,前提是它与上一次请求完全相同,这被称为前缀缓存。如果我们每次调用都多清除一个结果,请求的开头每次都会改变,缓存就永远不会起作用。

因此,最旧的结果是每次清除四个,而不是一个。这样,被清除的部分在多次调用之间保持不变。与备注相比,如果某个结果并没有大多少,就保持不动:清除它几乎节省不了什么,却仍会改变请求的开头。保留多少完整内容由大小而不是数量决定:能放进预算四分之一的最新结果会被保留,并且至少保留一个。之前的版本固定保留六个完整结果,这对于较短的命令输出是合适的,但在读取长文件时,却让大部分预算被旧结果占据。

拒绝时现在会说明原因

被模型判定为无效的请求不会再被重试;再次发送同一请求只会得到同样的答案。如果对话对模型来说太长,用户会看到:「这段对话太长,模型无法一次读完。请为下一步开始一个新的聊天,目前为止构建的所有内容都会保留。」这是用户需要采取行动的事情,而不是服务故障,因此不会通知我们值班。

问题二:代理为了「节省空间」而停止

一个子代理被要求读取 40 个长章节,结果只读了 2 个就停了,并说它想节省空间。它大约用了 400,000 token 预算中的 100,000 个 token。

它无从知道旧的结果现在会为它被清除。因此,我们告诉了它。代理的指令现在会说明:当对话增长到超过模型所能容纳的范围时,最旧的工具结果会被清除,最新的结果保持完整。因此,不要为了节省空间而中止长时间的任务,继续进行即可,如果你需要被清除的内容,可以重新读取文件。

模型看不见的修复,从模型的角度来看并不是修复。这种机制只有在代理信任它时才有帮助。

问题三:把所有语言都当作英语来计算 token

我们在不运行分词器的情况下估算 token,即字符数除以四。这对英语来说是合理的经验法则,但对其他文字并不适用:俄语大约每个 token 2.2 个字符,中文或日语大约每个 token 1 个字符。

因此,读取俄语章节的子代理发送了一个约 640,000 token 的请求,而我们的估算却认为它低于 400,000 的预算。这种估算同样可能让请求超过模型的硬性上限。

现在估算会按文字类型来计算:普通 ASCII 为每 token 四个字符,中文、日文和韩文为每 token 一个字符,其他所有文字(西里尔字母、希腊字母、阿拉伯字母、带重音的字母、表情符号)为每 token 两个字符。它的设计目标是偏高估计。以一章俄语为例,现在估算为 43,423 个 token,实际测得约 44,600 个;之前的估算只有 25,023 个。由于一条消息一旦写入就不会再改变,它的估算只计算一次并记住,而不是每一步都重新计算。

我们从中得到的经验

  • 在真正占空间的地方裁剪。 在代理工作中,那是工具结果,而不是用户消息。
  • 告诉代理它的安全网。 否则它会围绕已经不再适用的限制进行规划。
  • 「字符数除以四」是基于英语的假设。 任何为多语言用户计算 token 的系统,都需要按文字类型计算,或者使用真正的分词器。
  • 注意缓存。 每次调用开头都会改变的请求,成本更高,运行也更慢。

如果你要在自己的应用中加入 AI 功能,我们的指南什么是大语言模型和如何使用大语言模型 API从一开始就介绍了上下文窗口和 token。关于子代理在 Mythex 中如何工作的更多信息,请参阅子代理文档。

Mythex · Pricing · 用 AI 构建任何东西 · 网站和应用模板 · Mythex 对比 · AI 应用构建术语表 · 免费的 AI 应用构建工具 · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Brasil) Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 繁體中文(香港) 繁體中文(台灣)