当 AI 拥有 200 万字的记忆:体验 Kimi 智能助手长上下文支持
如果将大语言模型比作大脑,那么「上下文窗口」(context window)就衡量着它的「记忆容量」。这个重要的参数代表模型一次性可以读取的最大文本长度。上下文窗口越大,模型在「思考」时能调用的素材就越多,理解对话和任务背景就越充分,由此生成的答复也就会更加准确和相关。
在过去两年的快速发展中,大语言模型的上下文窗口已经见证了长足的进步,也成为厂商之间比拼激烈的参数之一。以最流行的 GPT 系列模型为例,两年前的早期版本 GPT-3 还只能支持 2048 tokens 的上下文窗口。1 经过历次更新,目前版本的 GPT-3.5 Turbo 可以支持 16K [16,385 tokens],GPT-4 Turbo 可以支持 128K。
OpenAI 的主要竞争对手中,Anthropic 的 Claude 系列模型一向以长上下文支持为特色,在 2023 年 5 月就率先支持了 100K 上下文,今年初发布的 Claude 3 系列模型还进一步提升到了 200K。Google 的 Gemini 系列模型从 32K 起步,目前还在小范围内测的 1.5 Pro 则达到了 1M。
上个月,国内模型厂商月之暗面宣布实现将旗下 Kimi 智能助手的上下文窗口从 20 万字提高到 200 万字2,并开启申请内测。经过联系,我们获得了提前体验资格,并有机会直接向 Kimi 团队提出一些问题。
Kimi 团队告诉我们,之所以将长上下文作为一个优先研发方向,有一定战略上的考虑。首先,在 Kimi 团队看来,在通往通用人工智能(AGI)的过程中,无损的长上下文将会是一个很关键的基础技术;历史上所有的模型架构演进,本质上都是在提升有效的、无损的上下文长度。同时,他们认为,更长的上下文窗口可以进一步打开对 AI 应用场景的想象力。
那么,Kimi 长上下文支持的效果究竟如何呢?
之前,国外厂商在介绍具有长上下文能力的模型时,经常会选择使用一种称为「大海捞针」(Needle in a Haystack, NIAH)的基准测试。这项测试的方法是:将随机事实或陈述(「针」)放在文本中,然后向模型提问,考察其能否从文本中找到那根「针」;然后,将针的位置(「深度」)不断后移,文本不断加长,从而得到一个成绩矩阵。Gemini 1.5 和 Claude 3 的技术报告均援引了大海捞针的成绩。
Kimi 团队没有针对此次更新的长上下文能力做大海捞针测试。他们表示,这项测试刚出现时是个很好的测试指标,但随着这项测试的流行,任何模型只要稍加优化就可以做到「全绿」,也就是通过所有深度和长度组合条件下的测试,因此已经失去了对照意义;此外,大海捞针对大模型而言,实际上也是一项比较简单的任务,不能全面体现模型的能力。不过,Kimi 团队仍然表示对于相比竞品的效果很有信心。
因此,在测试和体验 Kimi 的长上下文能力时,我也没有采用基准测试的方法,而是根据过去想到过、但囿于上下文长度限制未能实现的几个需求,设计了几个具体场景来评估 Kimi 的表现。
今年以来的 IPO 中,比较引起市场关注的事件肯定包括年初蜜雪冰城、古茗同时递表,随后也出现了大量分析和对比两家公司招股书的文章。招股书属于典型的篇幅冗长、结构固定的八股文本,本身就很适合交给 AI 辅助分析;但之前囿于长度限制,一份都难以容纳,更不用说对比。
首先从港交所下载两份文件(蜜雪冰城、古茗),确认一下文件长度:
pdftotext mixue.pdf - | wc -m
# 369351
pdftotext goodme.pdf - | wc -m
# 420975
(这里的 pdftotext
命令用来从 PDF 中提取纯文本;你可以通过习惯的包管理器安装 poppler
来获得这个程序。)
即两份文件加起来字符数约 80 万。将文件上传到 Kimi,简单交代背景和一般要求。
首先问两者在品类和价格段上的区别,以及取得的成绩。这些一般会写在开头的序言部分和中间位置的「业务」一章。Kimi 找的也是比较全面的。
再看一个稍微进阶的例子:分析两家公司在供应链和物流方面的异同。
可以看到,古茗部分的总结是比较准确的,蜜雪冰城部分则稍有瑕疵:前半段的「门店网络广」并不属于「供应链」的特点,更合适的引用应当是其配送网络的相关数据。此外,原因总结部分提到业务模式和市场定位是正确的,但没有能进一步考虑这是为了适应不同类型主推饮品的需要。作为对比,晚点的文章就分析道,「蜜雪冰城的物流配送服务的特点是覆盖广、深入。[…] 古茗则拥有更强大的冷链物流能力,这和其菜单上的水果茶占比有关。」
(提示词中的「客观、中立」等要求是根据 Kimi 团队的提示添加的。如果没有这句话,Kimi 容易过于依赖公司自己的描述,导致回答有些「广告味」。另一个小瑕疵是,从这里开始,Kimi 也没有记住最初提示词中「标注页码」的要求,需要重新在后续提示词中要求一次。)
接下来关注招股书里比较重要的风险披露部分。这一部分可能是最能反映「天下文章一大抄」的,很多时候你能看到同样一段轱辘话在十几年间代代相传。但就是因为套话太多,那些真正原创的片段往往就更显重要。显然,几十页的篇幅靠人眼对比是很痛苦的,而 AI 显然比较擅长于此:
最后问的是两个法律角度会比较关心的问题:历史沿革和公司架构。
Kimi 的回答不是特别切题,主要问题在于过于宽泛地理解了「历史沿革」的含义——它在招股书语境下指的主要是集团公司历史上的设立、变更和股权交易情况,而不是「公司的发展史」(即使特别在提示词中做出了解释仍然如此)。公司架构方面则基本没有提供有效的信息,例如一般会关注的境外公司架构、老股东情况等都没有提及。
生成式 AI 辅助编程是一个非常热门的应用。但是,现有方案往往不能充分反映现有代码库的情况。即使是 GitHub Copilot 这样基于插件的方案,也只能从代码库中挑选一些片段发送给模型参考。更长的上下文窗口给送出更全的现有代码提供了可能。
这里以 GitHub 上的 oduwsdl/CarbonDate 项目为例,这是一个通过提取多种元信息,试图推测网页发布时间的有趣工具,我曾在之前的文章中以它为例说明如何从他人代码库中「取经」。下面来看看 Kimi 对它的理解程度如何。
插曲:如何让 Kimi 处理整个目录的文件
测试这个场景时遇到的一个小问题:虽然 Kimi 支持批量上传文件,但不支持上传文件夹,从而无法反映路径层级中包含的信息。因此,我写了一个简单的脚本,将指定谬中的所有文件(不含隐藏文件和隐藏目录中的文件)及其路径都汇总到一个 JSON 文件中(本例中的长度为 150 万字符,你可以自己下载测试),然后再输入给 Kimi:
#!/bin/bash
DIR=$1
echo "[" > output.json # open the outer array
find "$DIR" -type f \( ! -regex '.*/\..*' \) -print0 |\
while IFS= read -r -d $'\0' file; do
jq -n \
--arg path "$file" \
--arg content "$(cat "$file")" \
'{path: $path, content: $content}' >> output.json
echo "," >> output.json
done
sed -i '' '$ s/,$//' output.json # remove the dangling comma
echo "]" >> output.json # close the outer array
(用 shell 是因为……我只会这个。)
首先问几个简单的问题:语言、依赖项、readme 文件内容,以及稍微进阶的工作原理分析。
应该说 Kimi 的回答总体上是令人满意的。特别是第 3 问,可以看出不仅充分理解了问题,而且能根据不同程度的可用信息做合理推断。反倒是第 1 问中的依赖项总结有些瑕疵,这本来可以通过查看 requirements.txt
的内容快速找到答案,但 Kimi 似乎更多依赖于 readme 中的信息,并且杂糅了一些本质上是运行要求(prerequisites)的说明。
接着再尝试一个编程任务:额外提供另一个搜索引擎 Kagi 的 API 文档,要求仿照现有模块写一个从 Kagi 搜索结果页提取网页发布日期的新模块,并分析需要修改哪些其他文件来整合这个新模块。
就生成的代码而言,基本的结构还是正确的,但很遗憾并没有充分理解新文档中提供的响应范例——其中明确指出搜索结果存放在响应的 data
数组中,而不是生成代码试图访问的 items
数组。至于第 2 问,关于 main.py
的修改建议是合适的,其余几项就与实际情况不符了,可能是过于宽泛地套用「Python 模块」相关语料的产物。
少数派每年都会举行一次年度征文活动,历年获奖文章普遍被认为是最能代表少数派用户水平和风格的作品。从内容运营角度,我们希望能更好发挥这些文章的长尾价值,例如做更好的标签归类等;也希望从中得出一些观察和分析,进一步了解我们的作者,将以后的活动办得更好。但由于文章数量多、人力有限,过去这方面的努力做得不够。Kimi 的 200 万字上下文足够容纳 2016 年以来的所有获奖征文,这给了我用它来做些分析的动力。
先做一些数据准备工作。用 MarkDownload 工具批量将历年征文下载到本地,然后归类到按年份命名的文件夹中。然后,仍然用上一节提到的脚本,稍作修改,将所有 markdown 文件汇总到一个 2.75MB、字符数为 134.3 万的 JSON 文件中(你可以自己下载测试)。将它和对文件结构的简单介绍一起发送给 Kimi。
首先提几个简单的概括总结类问题:
其中:
接下来是一个我比较期待的场景:借助 AI,基于对文章内容的分析自动提炼主题和标签,并且以一种结构化的格式输出。如果这是可行的,就能给内容维护的自动化带来不少便利。
遗憾的是,经过反复尝试,Kimi 虽然体现出一些可能性,但现阶段还不能稳定地给出可以直接使用的结果:
// ... (Continue with the remaining articles, ensuring a total of 110 objects in the array)
。这里怀疑可能是网页版对输出长度有一些限制。还有不少情况下,Kimi 输出的 JSON 格式是错误的,例如把每行都用一对大括号包裹起来。诚然,如果是在生产环境下,肯定也需要在模型输出之后加一个有效性校验环节,但不能一步到位毕竟还是有些遗憾。
随后,我又以自己的个人博客归档(162 万字符,下载)为输入做了一些测试。
首先提问一些基础事实问题。Kimi 的表现很稳定,除了最后一篇从英文翻译的引用有点生硬,其他跟我自己会写出的问答也没什么区别。
接着还是尝试了总结和分析类的任务。其中,主题总结的结果跟我的印象是差不多的,但选择的示例文章则有一些瑕疵,特别是「生活经历」部分选择的后两篇其实是技术主题文章。
就展示长上下文的潜力而言,Kimi 已经实现了有意义的第一步。概括起来,目前版本的优点在于,能够有效读取复杂文档,准确完成事实查询和要点提炼,可以满足从长篇幅或大批量文本中提取信息的需求。但不足在于,对于文档的深度理解和逻辑推理能力、以及在多轮对话中遵守用户指令的能力,还有较大提高空间。因此,对于需要深入理解特定领域知识的任务,Kimi 还无法完全满足需求,或至少需要一定程度的人工校验和调整。
支持长上下文也对 Kimi 的算力资源提出了更高的要求。事实上,就在这一功能开始测试后不久,Kimi 就经历了一次流量增加超预期的事件,不得不短时间内多次扩容应对迅速增加的需求。对此,Kimi 团队表示,200 万字上下文确实要求进一步大幅降低推理成本,目前正在全力解决。在商业化方面,用户关心较多的付费方案也将在今年初步确定。
此外值得一提的是,Kimi 的 200 万字支持推出后,不少其他国内模型厂商也相继跟进,宣布支持 500 万甚至 1000 万字的输入。但是,相关宣传中存在一些技术细节的显著缺失——支持读取并不代表模型能一次性处理;那些看起来更惊人的指标实际上是使用 RAG(retrieval augmented generation,检索增强生成)方案达到的效果。简单来说,RAG 是先对输入文档做一次「嵌入」处理(embedding,即将文档内容转储为能反映其特征的向量)。查询时,先通过向量运算找出与查询语句最相关的文档,再将这一小部分内容输入给模型生成回答。
因此,如果说上下文窗口是模型的记忆,那么 RAG 就像是为了减轻记忆负担而准备的辅助外脑。这么做的好处是绕过了上下文窗口的限制:无论输入的文本有多长,最终输入给模型的长度都是可控的,生成速度也自然比一次性处理完整输入更快,成本开销更低;但相应的代价就是检索的准确性和完整性相对较弱。
指出这点这并不是要否认 RAG 的价值。至少目前阶段,RAG 的特性仍然使它更胜任那些对成本和速度较为敏感的应用场景,也更容易实现规模化,不需要等待模型的进化就能接受更长的输入。但是,厂商和媒体在宣传和报道时,确实应当秉持更加严谨、诚实的态度,准确向用户描述和解释技术背景,而不是简单地强调一些数字。一个理性、知情的消费者群体,也是更有助于促进 AI 服务普及、开展良性竞争的。