WoW-RAG

Wow-RAG

手搓一个土的RAG

  1. 安装相关库:faiss-gpu、scikit-learn、scipy、openai、python-dotenv;配置api_key、base_url、chat_model、emb_model。

  2. 加载APIkey,配置环境:

    import os
    from dotenv import load_dotenv
    
    # 加载环境变量
    load_dotenv()
    # 从环境变量中读取api_key
    api_key = os.getenv(...)
    base_url = ...
    chat_model = ...
    emb_model = ...
    
  3. 构造client:

    from openai import OpenAI
    client = OpenAI(
        api_key = api_key,
        base_url = base_url
    )
    
  4. 构造文档,并将文档向量化:

    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)
    
  5. 定义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
    
  6. 获得匹配文块并构造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}
    的答案,尽可能使用文档语句的原文回答。不要复述问题,直接开始回答。
    """
    
  7. 构建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)
    
  8. 使用prompt

    get_completion_stream(prompt)
    
posted @ 2025-07-15 22:51  LPF05  阅读(13)  评论(0)    收藏  举报