如何用 30秒和 5 行代码写个 RAG 应用?

花 30 秒用 5 行代码写个 RAG 应用

这个点子不是我想出来的,是 llamaindex 想出来的。 llamaindex 是啥?

LlamaIndex 是一个框架,用于使用 llm(包括 agents 和 workflows)构建上下文增强的生成式人工智能应用程序。

当然也包括创建 RAG 应用,因为最流行的上下文增强示例就是 RAG(Retrieval-Augmented Generation, RAG),也就是在推理时将上下文与 llm 结合起来的检索增强。

如果是对 RAG 还不了解的朋友,那么可以参考之前几篇文章中的相关介绍:

简单来说:RAG(Retrieval-Augmented Generation)是一种结合检索和生成技术的人工智能方法,通过从外部知识源检索相关信息,增强语言模型的生成能力,提高输出的准确性和相关性。

LlamaIndex

在进入正题前,关于 LlamaIndex 我还是要再多说几句。

LlamaIndex 是一个开源框架:github.com/run-llama/l...

  • 它是用 Python 写的

  • 最新版本是:0.11.14

  • 官网地址是:https://www.llamaindex.ai/

在今年夏天的某个会议上,从 LlamaIndex 团队成员那儿得知,他们是一个规模很小的创业公司,当时团队成员大概 15 人左右。

30 秒 5 行代码

前文说了 30 秒 5 行代码的主意不是我想到的,而是来源于 LlamaIndex ,具体说是 LlamaIndex 的文档中写的:

事实也的确如此,但是,这里有一些前提条件。

首先,从字面上你也能看出来,运行这 5 行代码需要 OpenAI 的 API key。

其次,无论你懂不懂编程,我告诉你这 5 行代码是 Python 语言写的。那么你要有一个 Python 语言的运行环境,以及你最好懂得如何用 Python 编程。关于这一点,对于不懂编程的朋友确实不太友好了。不过值得庆幸的是,Python 语言本身很强大,很好上手,容易学习。门槛并不算太高。虽然我们要开发的应用是跟人工智能(AI)相关的,但也不要被吓到了,以为会多么难。其实有很大一部分所谓的 AI 产品也只是 AI、大模型的应用产品。开发那些产品的工程师甚至也只是能算是大模型应用开发工程师,还用不到多么艰深的技术呢。(这里并没有拉踩的意思,只是客观表述。能把技术应用的很好,做出满足用户需求的创新性产品也是非常有价值的,做出这样产品的人也当然值得尊重

安装 Python

我们先解决 Python 的问题,对于已经熟练掌握 Python 开发的就可以跳过了。对于编程小白或其他语言开发者(如 Java) 可以看看。

我们得搭建一个 Python 的开发和运行环境。关于 Python 的安装网上教程一大堆,无论你的操作系统是 Windows、Mac 还是 Linux 都很容易。我就不罗嗦了。

我的操作系统是 MacOS, 后文的具体操作细节都是基于我本地的 Mac 电脑,所以请大家注意,下图是我的的电脑系统情况:

Python 比较常见的大版本有 Python2Python3 , 我使用的版本是 Python3,具体来说是 3.12.4 算是个比较新的版本了

关于 Python 的安装,我更建议用 Conda ,它可以创建多个不同 Python 版本的环境,相当于一个 Python 环境和版本管理工具。这样你就可以创建多个不同 Python 版本的环境,相互之间隔离,互不影响。因为有时候不同的项目用到不同的 Python 版本,混在一起比较麻烦,有了 Conda 就方便多了。

Conda 可以到这里下载安装:docs.anaconda.com/free/minico...

安装好以后记得设置一下镜像源,不然下载比较慢:

ruby 复制代码
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/pro/  
conda config --set show_channel_urls yes

以下是一些基础命令:

arduino 复制代码
//创建虚拟环境
conda create -n xinference python=3.11.0

//激活虚拟环境
conda activate xinference

//退出虚拟环境
conda deactivate

//删除虚拟环境
conda remove -n xinference --all

//查看虚拟环境
conda env list

Python 安装好以后,我们还需要一个开发工具,即 IDE,你可以选择 VSCode,PyCharm,Cursor,Zed 等等。这里我推荐 Cursor,因为借用 claude 及 gpt 等大模型的能力,你可以一边快速开发一边快速学习,高效产出的同时高效吸收,简直太爽啦。

学习 Python

关于 Python 的学习,我这里对于特别小白的,尤其是从来没有接触过编程的朋友没有什么具体的建议,因为我从未指导过类似情况的朋友,所以没有经验,不能乱说,怕误人子弟。因为我既不知道用什么样的方式也不知道用什么样的资料指导有用。不过我觉得对于小白,能持续学习下去是最重要的,不要找太难的资料,可以找一些你容易上手,容易看懂的资料来学习,有持续的正反馈,计算机相关的知识很多,有些确实难懂,有持续的正反馈你才不至于半途而废。

而对于其他语言的开发者,其实已经具备了基础的计算机知识,甚至也已经是某些编程语言的专家了。那么学习 Python 对于你来说就比较容易了,一理通百理明。都大差不差的。

我这里把之前收藏的一些学习资料分享一下:

认认真真把其中一个资料看完。 一般来说,用 2 个星期,每天 1-2 个小时左右,快的话甚至一个星期你就能基本掌握这门语言了。

我知道很多朋友不满足只是基本掌握,想更精进,那么就需要再加码了,这里我推荐系统地看一些书,因为书籍会相对系统地讲解知识,这样你对 Python 以及 Python 相关的技术就会有一个全面而深入的了解了。

说实话我看的书并不多,也不好意思过多推荐,这里推荐一本我最喜欢的,豆瓣 9.1 分。

写得确实很好,很实用,不讲虚的。读起来也很流畅、舒服。是市面上难得的原创 Python 进阶图书。

编程

现在我们假设你已经有了一个 Python 的运行环境及开发工具。那么接下来我们就要正式开始编写这 5 行代码了(铺垫这么多终于要写代码了~)

首先我们要建一个工程,这很简单,不多说。

然后根据文档所示,我们要安装 llama-index 的依赖包,在项目根路径下执行

perl 复制代码
pip install llama-index

当然,如果你使用的是 Python3 ,可以这样安装:

perl 复制代码
pip3 install llama-index

安装好依赖包以后我们创建 main.py 文件,并编写程序:

python 复制代码
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader

documents = SimpleDirectoryReader("data").load_data()
index = VectorStoreIndex.from_documents(documents)
query_engine = index.as_query_engine()
response = query_engine.query("Some question about the data should go here")
print(response)

别看这段只有几行代码,却有好几个问题,我们一个一个地说。

第一个问题是 :如果你直接运行 main.py 这个文件会报错,错误总结来说就是你没有 OpenAI 的 Api Key 。是啊,我们压根就没有设置,其实我也不想设置,因为这个 key 是要花钱的,我不想花钱,那怎么办?

OPENAI_API_KEY 的目的就是要通过 OpenAI 的 API 调用 OpenAI 的大语言模型。我们知道那是收费的,所以我们要用开源免费的模型,将模型安装到本地使用,这样就不用花钱了。所以我们要用 Ollama 安装开源模型到本地进行调用。关于 Ollama 以及模型的安装我在之前的文章中有详细说明,这里就不赘述了。大家可以参考。

我这里下载使用的是 Qwen2:7b 的模型

第二个问题是 : 代码中的 data 在哪里

ini 复制代码
documents = SimpleDirectoryReader("data").load_data()

data 是一个文件夹,需要我们在项目的根路径下创建,名字就叫 data。而在 data 文件夹中我们是要下载测试文本的,通过这个地址下载测试文本:

文件类型当然就是 .txt 文件。原文是英文的,但因为我想做中文的测试,所以,我把内容全部翻译成了中文并保存。(如果你看过《黑客与画家》 这本书,你一定会对文本内容感兴趣的!) 这个文件的文件名你可以随意取。

第三个问题是 :用哪个 embedding 模型?

前面我们说了,我们不用 OpenAI 的 API 了,这样的话,其实整个代码结构会发生变化 ,就不是原始的那 5 行代码了,而会变成下面这样(别担心,只多了一行)

python 复制代码
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.llms.ollama import Ollama

documents = SimpleDirectoryReader("data").load_data()

# bge-base embedding model
Settings.embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-base-en-v1.5")

# ollama
Settings.llm = Ollama(model="llama3", request_timeout=360.0)

index = VectorStoreIndex.from_documents(documents,)

可以看到代码中写的 embedding 模型是 BAAI/bge-base-en-v1.5

接触过 RAG 的朋友对 embedding 模型比较熟悉,这里简单地为不了解的朋友解释一下:

Embedding 模型是将离散的输入(如单词或文档)转换为连续向量表示的模型,在 RAG 中用于将查询和检索到的文档片段映射到同一向量空间,以便计算相似度和生成相关响应。

它和 RAG 的关系,可以参考下图:

我们这 5 行代码想实现的就是 RAG,所以一定少不了 embedding 模型。embedding 模型也分收费的和开源免费的,另外上文中提到的 BAAI/bge-base-en-v1.5 是一个处理英文的模型,我想处理的是中文,所以不适用。我们要找一个免费开源且支持中文的 embedding 模型。到哪里找呢? Hugging Face!(Hugging Face 你可以把它理解成大模型领域的 GitHub)

从 Hugging Face 上可以找到大量的开源免费的 embedding 模型,数量很多,选哪一个呢? 我们可以从 huggingface.co/spaces/mteb... 这个大规模文本嵌入基准(MTEB)排行榜中,根据你的需求来挑选。

比如我选择的是支持中文的,模型大小不是特别大的

最终我选择的模型是 :BAAI/bge-base-zh-v1.5

以上三个问题都解决了以后,我们看一下最终的代码成品:

python 复制代码
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.llms.ollama import Ollama

documents = SimpleDirectoryReader("data").load_data()

Settings.embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-base-zh-v1.5")

Settings.llm = Ollama(model="qwen2:7b", request_timeout=360.0)
index = VectorStoreIndex.from_documents(documents,)
query_engine = index.as_query_engine()
response = query_engine.query("作者学习过的编程语言有哪些?")
print(response)

实话实说,是比 5 行多了 2 行。但也已经很精练了,因为这是 LlamaIndex 做过高级别封装以后的 API,如果想做具体而细致的编程控制,可以使用低级别封装的 API。

代码我没有写注释,因为是想让读者看看它有多精练。用 LlamaIndex 就这么简单,几行代码就可以实现 RAG 了。

以下是我加入注释以后的,方便你理解它:

python 复制代码
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.llms.ollama import Ollama

# 从指定目录加载文档数据
documents = SimpleDirectoryReader("data").load_data()

# 设置嵌入模型,使用北京智源人工智能研究院的中文嵌入模型
Settings.embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-base-zh-v1.5")

# 设置语言模型,使用 Ollama 提供的 Qwen2 7B 模型,并设置请求超时时间
Settings.llm = Ollama(model="qwen2:7b", request_timeout=360.0)

# 使用加载的文档创建向量存储索引
index = VectorStoreIndex.from_documents(documents)

# 从索引创建查询引擎
query_engine = index.as_query_engine()

# 使用查询引擎执行特定查询
response = query_engine.query("作者学习过的编程语言有哪些?")

# 打印查询结果
print(response)

运行这段代码会自动下载 embedding 模型,你可能会关心模型下载到哪里了,在我电脑上是这个路径 :~/Library/Caches/llama_index

代码 第一次执行时间比较长,大概有个几十秒。

但再次执行应该是有缓存了,就会比较快了,下图就只执行了 10 秒左右。

当然,你还可以基于测试文本进行其他查询,看看它分析的是否准确。

以上图片中的输出每一步都有时间,是因为我对程序做了重构,用装饰器加上了每一步执行时间的打印输出,代码如下:

python 复制代码
import time
from functools import wraps
from typing import Callable, Any
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings, Document
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.llms.ollama import Ollama

def time_it(func: Callable[..., Any]) -> Callable[..., Any]:
    @wraps(func)
    def wrapper(*args: Any, **kwargs: Any) -> Any:
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"{func.__name__} 耗时:{end_time - start_time:.2f} 秒")
        return result
    return wrapper

class IndexBuilder:
    @time_it
    def load_documents(self) -> list[Document]:
        return SimpleDirectoryReader("data").load_data()

    @time_it
    def set_embed_model(self) -> None:
        Settings.embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-base-zh-v1.5")

    @time_it
    def set_llm_model(self) -> None:
        Settings.llm = Ollama(model="qwen2:7b", request_timeout=360.0)

    @time_it
    def create_index(self, documents: list[Document]) -> VectorStoreIndex:
        return VectorStoreIndex.from_documents(documents)

    @time_it
    def perform_query(self, index: VectorStoreIndex, query: str) -> str:
        query_engine = index.as_query_engine()
        return query_engine.query(query)

@time_it
def main() -> None:
    builder = IndexBuilder()
    
    documents = builder.load_documents()
    builder.set_embed_model()
    builder.set_llm_model()
    
    index = builder.create_index(documents)
    
    response = builder.perform_query(index, "作者跟 Sam 的关系是怎样的?")
    
    print("查询结果:")
    print(response)

if __name__ == "__main__":
    main()

由于后续除了 LlamaIndex 又安装了几个依赖库,所以在项目根路径下创建了 requirements.txt 文件,文件内容如下:

perl 复制代码
llama-index
python-dotenv
llama-index-llms-ollama
llama-index-embeddings-huggingface

执行以下命令一次性安装所有依赖:pip3 install -r requirements.txt 这样方便一些。

RAG 应用创建完成

有了以上的代码基础,其实一个小型的 RAG 应用的核心就完成了,我可以基于本地知识库结合大语言模型进行自然语言的查询了。

比如我问:"作者跟 Sam 的关系是怎样的?"

回答是:"作者与 Sam Altman 的关系是在 2013 年决定让他成为 YC(Y Combinator)的总裁。在那之前,他们可能有某种工作或业务上的联系,因为他们讨论了重组 YC 并让 Sam 接任总裁职位的事情。通过这个决策,可以看出作者认为 Sam 适合领导 YC,并且在 Sam 最初拒绝后,作者坚持不懈地说服他接受这一角色。最终,在 2013 年 10 月,Sam 同意从 2014 年冬季开始接管 YC。这表明两人之间有某种程度的合作和信任关系。"

你看,基于本地知识库的回答比单纯用 LLM 靠谱多了吧。

然后呢? 是的,我们只有一个内核还远远不够,我们还需要漂亮的 UI,更加易用和丰富的功能,程序性能还要强,把它做成一个产品。然后产品还要宣传、推广、积累用户、产品迭代。我们还要赚钱,还要考虑如何盈利。.....

差不多了,真的。想到这里,你再看看市面上那些 AI 产品是不是相似的配方?

最后

行文至此,关于这 5 行代码的事情我觉得已经说清楚了。最后感慨一下:AI 赛道真是越来越卷了,但无论无何,感谢 Python , 感谢 LlamaIndex ,感谢开源和为开源做出贡献的人们。有了他们我们才能够如此享受技术带来的红利。

相关推荐
新晓·故知6 分钟前
<使用生成式AI对四种冒泡排序实现形式分析解释的探讨整理>
c++·经验分享·笔记·算法·aigc·排序算法
luoganttcc38 分钟前
基于keras 的神经网络股价预测模型
人工智能·神经网络·keras
正义的彬彬侠1 小时前
矩阵的特征值和特征向量
人工智能·线性代数·机器学习·矩阵
l89479431 小时前
微调大模型(Finetuning Large Language Models)—Evaluation(六)
人工智能·语言模型·自然语言处理
赋创小助手1 小时前
下一代性能怪兽RTX 5090最新规格更新与Blackwell架构解析
人工智能·科技·深度学习·机器学习·架构
技术无疆1 小时前
【Python】Daphne:Django 异步服务的桥梁
开发语言·人工智能·后端·python·机器学习·数据挖掘·django
Tunny_yyy1 小时前
李宏毅机器学习2022-HW9--Explainable AI
人工智能·机器学习
简简单单做算法2 小时前
基于贝叶斯优化CNN-GRU网络的数据分类识别算法matlab仿真
人工智能·深度学习·gru·cnn-gru·贝叶斯优化·数据分类识别
刘承卓2 小时前
【Text2SQL】当前在BIRD基准测试集上取得SOTA的论文
gpt·自然语言处理·prompt·aigc·llama
开始King2 小时前
Tensorflow 2.0 cnn训练cifar10 准确率只有0.1 [已解决]
人工智能·cnn·tensorflow