- 作者:老汪软件技巧
- 发表时间:2024-10-05 00:01
- 浏览量:
认认真真把其中一个资料看完。 一般来说,用 2 个星期,每天 1-2 个小时左右,快的话甚至一个星期你就能基本掌握这门语言了。
我知道很多朋友不满足只是基本掌握,想更精进,那么就需要再加码了,这里我推荐系统地看一些书,因为书籍会相对系统地讲解知识,这样你对 Python 以及 Python 相关的技术就会有一个全面而深入的了解了。
说实话我看的书并不多,也不好意思过多推荐,这里推荐一本我最喜欢的,豆瓣 9.1 分。
写得确实很好,很实用,不讲虚的。读起来也很流畅、舒服。是市面上难得的原创 Python 进阶图书。
编程
现在我们假设你已经有了一个 Python 的运行环境及开发工具。那么接下来我们就要正式开始编写这 5 行代码了(铺垫这么多终于要写代码了~)
首先我们要建一个工程,这很简单,不多说。
然后根据文档所示,我们要安装 llama-index 的依赖包,在项目根路径下执行
pip install llama-index
当然,如果你使用的是 Python3 ,可以这样安装:
pip3 install llama-index
安装好依赖包以后我们创建 main.py 文件,并编写程序:
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 在哪里
documents = SimpleDirectoryReader("data").load_data()
data 是一个文件夹,需要我们在项目的根路径下创建,名字就叫 data。而在 data 文件夹中我们是要下载测试文本的,通过这个地址下载测试文本:
文件类型当然就是 .txt 文件。原文是英文的,但因为我想做中文的测试,所以,我把内容全部翻译成了中文并保存。(如果你看过《黑客与画家》 这本书,你一定会对文本内容感兴趣的!) 这个文件的文件名你可以随意取。
第三个问题是:用哪个 embedding 模型?
前面我们说了,我们不用 OpenAI 的 API 了,这样的话,其实整个代码结构会发生变化 ,就不是原始的那 5 行代码了,而会变成下面这样(别担心,只多了一行)
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
以上三个问题都解决了以后,我们看一下最终的代码成品:
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 了。
以下是我加入注释以后的,方便你理解它:
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 秒左右。
当然,你还可以基于测试文本进行其他查询,看看它分析的是否准确。
以上图片中的输出每一步都有时间,是因为我对程序做了重构,用装饰器加上了每一步执行时间的打印输出,代码如下:
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 文件,文件内容如下:
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 ,感谢开源和为开源做出贡献的人们。有了他们我们才能够如此享受技术带来的红利。