💰 点进来就是赚到知识点!本文带你了解基于上下文窗口的 LLM 优化策略,点赞、收藏、评论更能促进消化吸收!
🚀 想解锁更多 Web AI 的强大能力吗?快来订阅专栏「Web AI 进化录」!
相同的名字,迥异的命运
最近在 arxiv 上翻到了这两篇论文:
- Don't Do RAG: When Cache-Augmented Generation is All You Need for Knowledge Tasks
- CAG: Chunked Augmented Generation for Google Chrome's Built-in Gemini Nano
这二者单拿出任意一个来看,都是严谨的专业材料,但放到一起看就非常抓马了:
- 它们论述的都是优化 LLM 生成质量的技术;
- 技术的缩写名字一模一样,都是 CAG;
- 两篇论文的发布时间也紧贴着,都在 2024 年 12 月底,前后脚只差 4 天;
- 但二者的出发点完全相反:一个是因为上下文窗口太宽了所以要如何如何,而另一个则是因为上下文窗口太窄了所以要怎样怎样。
机缘巧合之中透着一丝冥冥天注定,简直戏剧性拉满。作为热爱吃瓜的乐子人,这热闹咱不能不往前凑凑吧?来来来,前排坐好,咱们一起瞧瞧。
上下文窗口是怎么个事儿?
在各个 AI 大厂发布模型的新闻里,总能看到类型「上下文窗口达到 xxxx」之类的术语。所以「上下文窗口」是什么?窗口大小有什么区别?
现在想象你面前有一条金鱼,在鱼缸里无忧无虑地游来游去。它之所以无忧无虑,是因为它只有 7 秒钟的记忆(非严谨科学结论)。无论吐过多少泡泡,它也只对最新的 7 秒有印象。这 7 秒,就是金鱼的上下文窗口。但鱼和鱼是不一样的,北冥有鱼,其名为鲲,脑容量之大,不知其几千里也。它能记住的事儿,绝对早于战国时期。
大模型也是一样,被训练出来后,上下文窗口也是固定的,只不过它的窗口不是时间长短,而是 token 数量。我们可以把 token 理解为大模型能计算的最小单元,可以类比于英文中最小单位是英文字母。大模型的生成原理是根据前面的内容循环生成下一个 token。
假如一个大模型的上下文窗口是 2 个 token(实际上没有这么废柴的 LLM),你问它一句话 「How are you?」,这句话一共 12 个字符,粗略计算约等于 3 个 token。这肯定就超出窗口极限了,模型在生成回答内容时,只记得你说了「are you?」,超出的部分就被甩在脑后了,会以为你想和它合唱一首《Are you OK》。
不同的大模型,其上下文窗口尺寸也是不同的。目前主流的云端大模型中,GPT-4 Turbo 窗口是 128K;Gemini 1.5 Pro 窗口是两百万。而部署在用户端设备上的本地模型,出于轻量化和效率考量,窗口会小一些,比如内置在 Chrome 中的 Gemini Nano,窗口尺寸是 6144 个 token。
需要说明的是,上下文窗口大小和模型的推理能力并无直接关系,只决定了大模型最多能”记住“多少东西。
开头提到了两个 CAG 技术,二者的出发点都与模型的上下文窗口密切相关,但场景和处理策略却截然相反。
心多大舞台就多大:缓存增强生成
第一篇论文讲的是 Cache-augmented Generation,意思是用缓存策略来提升生成质量,简称 CAG。
这个名字相当于是直接给 RAG 下了战书。RAG —— Retrieval-augmented Generation,意为「检索增强生成」,简单说就是在向大模型提问前,先拿问题去知识库里检索出相关的背景知识,再把问题和背景知识一起丢给大模型生成回答,避免因幻觉而瞎编。
CAG 的作者团队认为,RAG 会增加对话的延迟,而且也让技术架构更复杂了。他们想,既然现在大模型的上下文窗口都宽得能跑马,何不把知识库处理一下,缓存到模型的上下文中?这样一来,模型上下文中自带知识库,即降低了延迟,又因为缓存知识库是一次性成本,后续问答不再需要每次先查库。
在论文原文中,作者展示了 CAG 和 RAG 的对照实验报告和实现代码,在一系列的基准测试中,CAG 的表现确实要领先 RAG 一筹。
螺狮壳里做道场:分块增强生成
第二篇论文的主角是 Chunked Augmented Generation,意思是将输入文本分块压缩,以应对端侧模型上下文窗口过窄带来的限制。
与云端模型的大开大阖不同,集成在 Chrome 浏览器里的 Gemini Nano 上下文窗口仅有 6144 个 token,这在处理长文本或者记忆长对话的时候,难免会捉襟见肘,生成内容会有缺失和不准确。于是论文作者提出了一种分块策略,来提升生成质量,并实现了一个开箱即用的 JavaScript 库 —— cag-js。
假设有一篇文档,为了方便计算,我们假设它的长度是 61440 个 token,相当于 Chrome 内置模型的窗口的 10 倍。现在我们想让 Chrome 内置模型帮我们总结一下文档内容。如果直接把原文丢给模型,那模型生成的结果里可能只会涵盖文档中最后 6144 个 token 的内容,前面的都会遗漏掉。
cag-js 的应对策略是先把原始文本按窗口尺寸分块,每块恰好适合窗口尺寸;然后让模型依次处理每个分块;最后把每个分块的生成内容合并起来。
回到上面举例的场景来解释,就是这样的过程:
-
先用
@langchain/textsplitters的RecursiveCharacterTextSplitter将原始文本分成 10 块。 -
接下来对分块各个击破,这里有两种可选策略:
- 线性处理策略:按顺序依次把分块传给模型进行总结,得到 10 个总结文本块,拼接成最终结果。
- 递归处理策略:预先设定递归轮数或者生成内容的目标 token 数量。循环总结每个分块,每一轮循环后继续迭代处理生成的内容块,直到达到轮数限制,或者生成内容小于目标 token 数量。
这样,即使输入文本超出窗口大小,生成内容也是相对完整而准确的。
结语
深入挖了一下这对撞脸兄弟的来龙去脉,这个瓜咱们算是吃明白了。两个性质截然相反的技术方案,竟然在命名让殊途同归,嗯……很值得玩味。
值得感叹一句:云端模型在当前阶段已经得到长足发展,开始卷专家能力、卷多模态、卷上下文窗口,而从业者也有闲暇的注意力开始优化工程节点。而端侧模型还只是刚刚迈开步子,在不太宽裕的应用场景里奋力挤开自己的一席之地。虽然端侧智能也是必然趋势,但成熟度还远远不够。不过荒野也是蓝海,可玩可做的东西还是非常多的。我们在等的,或者说在努力达成的,就是属于端侧智能自己的「iPhone moment」。
📣 我是 Jax,在畅游 Web 技术海洋的又一年,我仍然是坚定不移的 JavaScript 迷弟,Web 技术带给我太多乐趣。如果你也和我一样,欢迎关注、私聊!