Datawhale AI夏令营 RAG入门 task3~~~
配置模型
这一步已经比较套路了,参照之前的几个任务。
主要是加载API、设置我们要调用的模型、配置我们所需要的嵌入模型
我这里和教程不太一样的是,模型用的是智谱的glm-4-air
import os
from dotenv import load_dotenv
# 加载环境变量
load_dotenv()
# 从环境变量中读取api_key
api_key = os.getenv('ZHIPU_API_KEY')
base_url = "https://open.bigmodel.cn/api/paas/v4/"
chat_model = "glm-4-air"
emb_model = "embedding-2"
# 配置对话模型
from llama_index.llms.zhipuai import ZhipuAI
llm = ZhipuAI(
api_key = api_key,
model = chat_model,
)
# 配置嵌入模型
from llama_index.embeddings.zhipuai import ZhipuAIEmbedding
embedding = ZhipuAIEmbedding(
api_key = api_key,
model = emb_model,
)
emb = embedding.get_text_embedding("测试测试测试")
文本准备
我这里选取“强化学习入门指南.txt“作为示例文本
这里注意文本路径名的设置
下面三种写法有什么不一样?
'docs/强化学习入门指南.txt'
'/docs/强化学习入门指南.txt'
'./docs/强化学习入门指南.txt'
'docs/强化学习入门指南.txt'
最常见的相对路径写法。Python 会从当前工作目录(也就是你运行 Python 脚本的那个目录)开始查找 docs 文件夹,然后在其下寻找 强化学习入门指南.txt 文件。
'/docs/强化学习入门指南.txt'
一种绝对路径的写法。开头的斜杠 / 表示从根目录开始查找。在类 Unix 系统(如 Linux 和 macOS)中,这代表了文件系统的顶层。在 Windows 系统中,这通常会解析到当前驱动器的根目录(例如 C:\)
显然,在该项目中,我们要的不是绝对路径的写法
'./docs/强化学习入门指南.txt'
也是一种相对路径写法,大多数情况下和第一种写法等价
# 读取本地的文本
from llama_index.core import SimpleDirectoryReader,Document
documents = SimpleDirectoryReader(input_files=['../docs/强化学习入门指南.txt']).load_data()
索引的构建
方法一:最简方法 - 从文档直接构建索引
使用LlamaIndex的 VectorStoreIndex.from_documents()函数来帮助我们完成
- 自动对传入的documents进行切块(默认使用SentenceSplitter)。
- 调用指定的embed_model将每个文本块转换成向量。
- 使用一个默认的、内存中的简单向量存储库来存放这些向量。
- index.as_query_engine() 会自动配置好检索器和回答合成器。
不过,简单的方法通常意味着它可能不太灵活
from llama_index.core import VectorStoreIndex
index = VectorStoreIndex.from_documents(documents,embed_model=embedding,show_progress=True)
方法二:构建节点,然后构建索引(使用Faiss)
首先解析文档为节点
# 构建节点
from llama_index.core.node_parser import SentenceSplitter
transformations = [SentenceSplitter(chunk_size = 512)]
from llama_index.core.ingestion.pipeline import run_transformations
nodes = run_transformations(documents, transformations=transformations)
接下来,根据节点来进行索引的构建
执行完毕后,index 对象就创建完成了。它是一个包含了所有节点信息和向量信息,并使用Faiss作为底层向量引擎的完整索引。
from llama_index.vector_stores.faiss import FaissVectorStore
import faiss
from llama_index.core import StorageContext, VectorStoreIndex
dimensions = len(emb)
vector_store = FaissVectorStore(faiss_index=faiss.IndexFlatL2(dimensions))
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex(
nodes = nodes,
storage_context=storage_context,
embed_model = embedding,
)
接下来,我们可以进行索引的持久化,即调用index.storage_context.persist(persist_dir)方法,把索引存储到硬盘
persist_dir = "./storage"
index.storage_context.persist(persist_dir)
如何读取之前保存到硬盘的索引呢?如下所示:
from llama_index.vector_stores.faiss import FaissVectorStore
import faiss
from llama_index.core import StorageContext, load_index_from_storage
vector_store = FaissVectorStore.from_persist_dir(persist_dir)
storage_context = StorageContext.from_defaults(
vector_store=vector_store, persist_dir=persist_dir
)
index = load_index_from_storage(storage_context=storage_context,embed_model = embedding)
让我们来测试一下:
query_engine = index.as_query_engine(llm=llm)
# 回答提问
response = query_engine.query("怎么入门强化学习?")
response
方法三:检索器 + 合成器
# 构建检索器
from llama_index.core.retrievers import VectorIndexRetriever
kwargs = {'similarity_top_k': 5, 'index': index, 'dimensions': dimensions} # 必要参数
retriever = VectorIndexRetriever(**kwargs)
# 构建合成器
from llama_index.core.response_synthesizers import get_response_synthesizer
response_synthesizer = get_response_synthesizer(llm=llm)
# 构建问答引擎
from llama_index.core.query_engine import RetrieverQueryEngine
engine = RetrieverQueryEngine(
retriever=retriever,
response_synthesizer=response_synthesizer
)
我们来测试一下,来个提问
# 提问
question = "请问商标注册需要提供哪些文件?"
answer = engine.query(question)
print(answer.response)
方法四:利用Qdrant向量库
先安装需要的一些组件和库
%pip install qdrant-client
%pip install llama-index-vector-stores-qdrant
%pip install llama-index-readers-file
这一步就来加载文档
import qdrant_client
from llama_index.core import SimpleDirectoryReader
# load documents
documents = SimpleDirectoryReader(
input_files=['./docs/问答手册.txt']
).load_data()
print("Document ID:", documents[0].doc_id)
使用 Qdrant 构建标准 RAG 流程
先来构建索引
from llama_index.core import VectorStoreIndex, StorageContext
from llama_index.vector_stores.qdrant import QdrantVectorStore
qclient = qdrant_client.QdrantClient(path="qdrant")
vector_store = QdrantVectorStore(client=qclient, collection_name="wenda")
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(
documents,
storage_context=storage_context,
embed_model = embedding
)
接下来,让我们构建问答引擎
# 构建检索器
retriever = VectorIndexRetriever(**kwargs)
# 构建合成器
response_synthesizer = get_response_synthesizer(llm=llm)
# 构建问答引擎
engine = RetrieverQueryEngine(
retriever=retriever,
response_synthesizer=response_synthesizer,
)
接下来我们来提示问问看
# 提问
question = "What are the applications of Agent AI systems ?"
answer = engine.query(question)
print(answer.response)
Qdrant支持metadata filter的
这一步是用来给每个文档添加metadata。在查询的时候,指定metadata filter。
from llama_index.core.schema import TextNode
nodes = [
TextNode(
text="The Shawshank Redemption",
metadata={
"author": "Stephen King",
"theme": "Friendship",
"year": 1994,
},
),
TextNode(
text="The Godfather",
metadata={
"director": "Francis Ford Coppola",
"theme": "Mafia",
"year": 1972,
},
),
TextNode(
text="Inception",
metadata={
"director": "Christopher Nolan",
"theme": "Fiction",
"year": 2010,
},
),
TextNode(
text="To Kill a Mockingbird",
metadata={
"author": "Harper Lee",
"theme": "Mafia",
"year": 1960,
},
),
TextNode(
text="1984",
metadata={
"author": "George Orwell",
"theme": "Totalitarianism",
"year": 1949,
},
),
TextNode(
text="The Great Gatsby",
metadata={
"author": "F. Scott Fitzgerald",
"theme": "The American Dream",
"year": 1925,
},
),
TextNode(
text="Harry Potter and the Sorcerer's Stone",
metadata={
"author": "J.K. Rowling",
"theme": "Fiction",
"year": 1997,
},
),
]
接下来,构建支持过滤的索引
这里创建了一个新的 Qdrant 集合 collection_name="filter",并将上面带有元数据的 nodes 存入其中。
vector_store = QdrantVectorStore(client=qclient, collection_name="filter")
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex(
nodes,
storage_context=storage_context,
embed_model = embedding
)
构建metadata filter,使用LlamaIndex 标准过滤器
from llama_index.core.vector_stores import (
MetadataFilter,
MetadataFilters,
FilterOperator,
)
filters = MetadataFilters(
filters=[
MetadataFilter(key="theme", operator=FilterOperator.EQ, value="Mafia"),
]
)
进行检索,检察一下结果
retriever = index.as_retriever(filters=filters, llm=llm)
retriever.retrieve("What is inception about?")
接下来是组合多个filter方法
from llama_index.core.vector_stores import FilterOperator, FilterCondition
filters = MetadataFilters(
filters=[
MetadataFilter(key="theme", value="Fiction"),
MetadataFilter(key="year", value=1997, operator=FilterOperator.GT),
],
condition=FilterCondition.AND,
)
retriever = index.as_retriever(filters=filters, llm=llm)
retriever.retrieve("Harry Potter?")
直接把filter的字典作为参数,构建retriever。构建一个更复杂的filter
retriever = index.as_retriever(
vector_store_kwargs={"filter": {"theme": "Mafia"}},
llm=llm
)
retriever.retrieve("What is inception about?")
也可以利用Qdrant自带的检索能力
nodes = [
TextNode(
text="りんごとは",
metadata={"author": "Tanaka", "fruit": "apple", "city": "Tokyo"},
),
TextNode(
text="Was ist Apfel?",
metadata={"author": "David", "fruit": "apple", "city": "Berlin"},
),
TextNode(
text="Orange like the sun",
metadata={"author": "Jane", "fruit": "orange", "city": "Hong Kong"},
),
TextNode(
text="Grape is...",
metadata={"author": "Jane", "fruit": "grape", "city": "Hong Kong"},
),
TextNode(
text="T-dot > G-dot",
metadata={"author": "George", "fruit": "grape", "city": "Toronto"},
),
TextNode(
text="6ix Watermelons",
metadata={
"author": "George",
"fruit": "watermelon",
"city": "Toronto",
},
),
]
vector_store = QdrantVectorStore(client=qclient, collection_name="default")
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex(
nodes,
storage_context=storage_context,
embed_model = embedding
)
这里的语法完全是 Qdrant 的
from qdrant_client.http.models import Filter, FieldCondition, MatchValue
filters = Filter(
should=[
Filter(
must=[
FieldCondition(
key="fruit",
match=MatchValue(value="apple"),
),
FieldCondition(
key="city",
match=MatchValue(value="Tokyo"),
),
]
),
Filter(
must=[
FieldCondition(
key="fruit",
match=MatchValue(value="grape"),
),
FieldCondition(
key="city",
match=MatchValue(value="Toronto"),
),
]
),
]
)
retriever = index.as_retriever(
vector_store_kwargs={"qdrant_filters": filters},
llm=llm
)
response = retriever.retrieve("Who makes grapes?")
for node in response:
print("node", node.score)
print("node", node.text)
print("node", node.metadata)

浙公网安备 33010602011771号