WoW-RAG
Wow-RAG
手搓一个土的RAG
-
安装相关库:faiss-gpu、scikit-learn、scipy、openai、python-dotenv;配置api_key、base_url、chat_model、emb_model。
-
加载APIkey,配置环境:
import os from dotenv import load_dotenv # 加载环境变量 load_dotenv() # 从环境变量中读取api_key api_key = os.getenv(...) base_url = ... chat_model = ... emb_model = ...
-
构造client:
from openai import OpenAI client = OpenAI( api_key = api_key, base_url = base_url )
-
构造文档,并将文档向量化:
from sklearn.preprocessing import normalize import numpy as np import faiss embedding_text = "..." # 设置每个文本块的大小为 150 个字符 chunk_size = 150 # 使用列表推导式将长文本分割成多个块,每个块的大小为 chunk_size (将文本分段,是因为API输入有长度限制) chunks = [embedding_text[i:i + chunk_size] for i in range(0, len(embedding_text), chunk_size)] # 初始化一个空列表来存储每个文本块的嵌入向量 embeddings = [] # 遍历每个文本块 for chunk in chunks: # 使用 OpenAI API 为当前文本块创建嵌入向量 response = client.embeddings.create( model=emb_model, input=chunk, ) # 将嵌入向量添加到列表中 embeddings.append(response.data[0].embedding) # 使用 sklearn 的 normalize 函数对嵌入向量进行归一化处理 normalized_embeddings = normalize(np.array(embeddings).astype('float32')) # 获取嵌入向量的维度 d = len(embeddings[0]) # 创建一个 Faiss 索引,用于存储和检索嵌入向量(使用faiss创建向量索引,可以降低向量匹配检索的时间复杂度,且无需训练、是精确检索、无近似误差,在更大规模数据的检索中可以使用更高效的索引类型代替) index = faiss.IndexFlatIP(d) # 将归一化后的嵌入向量添加到索引中 index.add(normalized_embeddings) # 获取索引中的向量总数 n_vectors = index.ntotal print(n_vectors)
-
定义input_text向量化并匹配相似文本:
from sklearn.preprocessing import normalize def match_text(input_text, index, chunks, k=2): """ 在给定的文本块集合中,找到与输入文本最相似的前k个文本块。 参数: input_text (str): 要匹配的输入文本。 index (faiss.Index): 用于搜索的Faiss索引。 chunks (list of str): 文本块的列表。 k (int, optional): 要返回的最相似文本块的数量。默认值为2。 返回: str: 格式化的字符串,包含最相似的文本块及其相似度。 """ # 确保k不超过文本块的总数 k = min(k, len(chunks)) # 使用OpenAI API为输入文本创建嵌入向量 response = client.embeddings.create( model=emb_model, input=input_text, ) # 获取输入文本的嵌入向量 input_embedding = response.data[0].embedding # 对输入嵌入向量进行归一化处理 input_embedding = normalize(np.array([input_embedding]).astype('float32')) # 在索引中搜索与输入嵌入向量最相似的k个向量 distances, indices = index.search(input_embedding, k) # 初始化一个字符串来存储匹配的文本 matching_texts = "" # 遍历搜索结果 for i, idx in enumerate(indices[0]): # 打印每个匹配文本块的相似度和文本内容 print(f"similarity: {distances[0][i]:.4f}\nmatching text: \n{chunks[idx]}\n") # 将相似度和文本内容添加到匹配文本字符串中 matching_texts += f"similarity: {distances[0][i]:.4f}\nmatching text: \n{chunks[idx]}\n" # 返回包含匹配文本块及其相似度的字符串 return matching_texts
-
获得匹配文块并构造prompt:
input_text = "What are the applications of Agent AI systems ?" matched_texts = match_text(input_text=input_text, index=index, chunks=chunks, k=2) prompt = f""" 根据找到的文档 {matched_texts} 生成 {input_text} 的答案,尽可能使用文档语句的原文回答。不要复述问题,直接开始回答。 """
-
构建prompt:
def get_completion_stream(prompt): """ 使用 OpenAI 的 Chat Completions API 生成流式的文本回复。 参数: prompt (str): 要生成回复的提示文本。 返回: None: 该函数直接打印生成的回复内容。 """ # 使用 OpenAI 的 Chat Completions API 创建一个聊天完成请求 response = client.chat.completions.create( model=chat_model, # 填写需要调用的模型名称 messages=[ {"role": "user", "content": prompt}, ], stream=True, ) # 如果响应存在 if response: # 遍历响应中的每个块 for chunk in response: # 获取当前块的内容 content = chunk.choices[0].delta.content # 如果内容存在 if content: # 打印内容,并刷新输出缓冲区 print(content, end='', flush=True)
-
使用prompt
get_completion_stream(prompt)