核心概念
RAG
RAG,Retrieval-Augmented Generation,即检索增强生成。
大模型是个生成模型,他是基于既有知识来生成回答的。如果我们问一些在他既有知识领域以外的问题,他也许会承认不知道,但更可能会胡言乱语,还异常自信,好像他很懂一样。
可能你会问,明知道他不懂,你问他干嘛?
好问题,这就涉及到大模型的能力了,除了知识,他还有“智慧”,他能学习,学习了自己不懂的知识以后,他能比普通人更快更好的利用这些知识。
RAG 就是把一些可能是答案的知识和问题一起给他,让他自行判断哪些知识是问题的正确答案,并组织语言,返回结果。
当然,我们也可以把这些知识提前教给他,这样他就是在既有知识里回答问题了。对大模型进行微调可以达成这个目标,不过其投入的成本比 RAG 大得多,经济上可能不划算。
文本向量
embedding 是大模型领域的一个重要概念,也很难理解。
我自己的理解,所谓 embedding,就是将数据(文本、图片、视频、……)转换为 N 维向量(说人话,就是一个实数数组,N 是数组的长度),嵌入到一个 N 维的向量空间去。在这个空间里,可以计算出向量之间的距离,用以表示他们是否相似。
大模型处理的是自然语言,也就是文本,所以 word embedding 就是将文本向量化。
文本向量化以后,我们就可以根据距离找到相似的文本了。
举个例子,你输入了单词“香蕉”进行搜索。候选的结果是“苹果”,“秦香莲”
- 搜索引擎可能返回“秦香莲”,因为都有个“香”字。
- 向量数据库更可能给你返回“苹果”,因为他们都是水果,在向量空间里距离比较近。
检索
现在有一些大模型的应用,自带联网搜索功能,当你的问题超出了他的既有知识,他可以自行调用搜索引擎,阅读搜索引擎返回的结果,并根据这些结果来生成答案。
这是“搜索增强生成”,而搜索也可以算检索的一种,从这个角度来说,这也算是 RAG。不过,这种 RAG 有 2 个问题
- 你的问题,搜索引擎也可能没有答案
- 搜索引擎返回的结果,仅仅是字面上的匹配,不能搜索到到逻辑上相似,但字面不同的内容。
狭义来说,搜索引擎的搜索,并不被当作 RAG 里的 R,当我们说 RAG 时,一般是指的基于向量之间相似性的检索增强,不包括这种搜索增强。
RAG 流程
- 数据准备
- 这一步是将大模型既有领域以外的知识,向量化并存储到向量数据库。
- RAG
- 当用户发起一个问题时,首先将用户的问题向量化,然后到向量数据库里查找相似的向量,根据数据库返回的结果,获得原始的文本
- 将检索得到的原始文本作为知识,加上用户的问题,发送给大模型,让大模型基于知识回答问题。
实战
我们来做一个 RAG 的应用,体会一下。
需求
这个应用呢,是一个小说推理机器人,它能根据小说的内容进行推理并返回答案。小说呢,我选择迟子建老师的短篇小说《一罐猪油》。
技术选型
- 大模型
- 智谱的 GLM-4,我之前已经评测过他是当前国产大模型性价比之选。
- 如何把文本向量化
- 智谱的 embedding-2 向量模型,支持将不超过 512 个字符的文本 embedding 成 1024 维的向量。既然用了智谱的大模型,那么顺便使用智谱的向量模型也是顺理成章。
- 向量数据库
- 我选用 milvus,你可以下载其 docker 镜像安装一个,不过 milvus 也提供云服务,注册以后可以创建免费的云端数据库,使用 restapi 进行增删改查,非常方便。我这里采用 milvus 的云数据库。地址在 https://cloud.zilliz.com/
实际体验
这个应用我已经实现了,体验地址 https://read.refusea.com/pan.html
下图显示了他的体验效果
一些体会
文档切片
在准备阶段,要将小说保存到向量数据库,而 embedding-2 模型最多只支持 512 个字符的向量化。所以我们只能把小说切片,每一片不超过 512 个字符。
这就带了了第一个问题:如何切片?
我最初是每 500 个字符一个切片,这样又可能造成一个问题:一段完整的句子,被拆到 2 个切片里,导致含义不完整。
我的解决方案是,先按每个切片 400 个字符进行切片,切片完成后,每一片都添加下一片的前 100 个字符。
切片大小
每片 500 个字符,经过验证不太好用。因为大模型接受的输入长度是有限的,且越长的输入,费用越高。
单个切片太大,那么可以给大模型的切片数量就要减少。对于一些复杂问题,切片数不够,可能就得不到正确答案。
比如,“戒指的来龙去脉”这个问题,如果你只能给他 3 个切片,大模型是无法推理出正确答案的。
后来我把切片大小修改成 240 个字符,就可以给大模型传入更多的切片。实际效果就相对好些。
使用知识库
智谱后台可以上传文档,创建知识库,其 api 接口可以传入知识库 id,进行检索。
经过验证,将小说上传到知识库,在调用大模型时指定知识库,效果不错,比我最初采用 500 个字符的切片时效果要好。
智谱后台应该也是将小说切片后嵌入了向量空间。但是其切片逻辑是不可控的,比如
- 单个切片多少个字符?
- 每次回答问题,检索出多少个切片来增强大模型?
我相信,智谱也是用 embedding-2 来生成文本向量的。为什么智谱的知识库效果可能比自己 RAG 更好呢?我觉得有 2 个原因
- 回答问题时,智谱给大模型的切片更多,智谱的知识库切片是可以预览的,看上去是 300 字以内一个切片。我采用 500 字一个切片时,只给大模型提供 3 个切片。
- 智谱可能是顶着 token 数上限给大模型提供切片数据,而我出于节约成本的考虑,给大模型的数据基本不超过 3k 字符。
所以,如果不追求更强的控制,且你的知识库大小不超过智谱的限制(最多 50 万字),直接使用智谱的知识库也是个不错的选择。