大模型入门到精通——使用Embedding API及搭建本地知识库(二)

news2024/9/20 22:36:28

搭建并使用向量数据库

前序基础知识参考链接介绍:大模型入门到精通——使用Embedding API及搭建本地知识库(一)

搭建并使用向量数据库,因此读取数据后我们省去数据处理的环节直入主题

基于 LangChain 实现 README.md 相关文档的向数据库搭建,可以按照以下步骤进行:

1. 环境准备

确保你的Python环境已经安装了LangChain和其他必要的库。可以通过以下命令安装:

pip install langchain faiss-cpu
pip install chromadb

如果你打算使用GPU加速Faiss,可以安装faiss-gpu

2. 读取和预处理文档

  • 遍历一个指定的文件夹,从中加载PDF和Markdown文档
  • 对这些文档的文本内容进行预处理,并保留处理后的文档对象
  • 最后打印出其中一个文档的类型、元数据和内容。验证结果;

1. 导入所需的库

import os 
from langchain.document_loaders.pdf import PyMuPDFLoader
from langchain.document_loaders.markdown import UnstructuredMarkdownLoader
  • os: 用于操作系统交互,主要用于遍历目录和处理文件路径。
  • PyMuPDFLoaderUnstructuredMarkdownLoader: 分别用于加载PDF和Markdown文件的文档加载器。这些加载器是langchain库的一部分,能够将文档内容加载为Document对象。

2. 初始化文件路径

file_paths = []
folder_path = './data/'
for root, dirs, files in os.walk(folder_path):
    for file in files:
        file_path = os.path.join(root, file)
        file_paths.append(file_path)
  • file_paths: 用于存储所有找到的文件的完整路径。
  • folder_path: 指定要遍历的文件夹路径。在这里是相对路径./data/
  • os.walk(folder_path): 递归遍历指定目录中的所有子目录和文件,返回每个目录的路径(root)、子目录(dirs)和文件列表(files)。
  • file_paths.append(file_path): 将每个文件的完整路径添加到file_paths列表中。

3. 初始化加载器

loaders = []
for file_path in file_paths:
    file_type = file_path.split('.')[-1]
    if file_type == 'pdf':
        loaders.append(PyMuPDFLoader(file_path))
    elif file_type == 'md':
        loaders.append(UnstructuredMarkdownLoader(file_path))
  • loaders: 用于存储不同类型文件的加载器实例。
  • file_type = file_path.split('.')[-1]: 通过文件扩展名来判断文件类型(如pdfmd)。
  • 根据文件类型,实例化对应的加载器(PyMuPDFLoaderUnstructuredMarkdownLoader),并将实例添加到loaders列表中。

4. 定义预处理函数

def preprocess_text(text):
    # 转换为小写
    text = text.lower()
    # 移除非字母数字字符(标点符号等)
    text = ''.join(char for char in text if char.isalnum() or char.isspace())
    # 其他预处理操作,如去除停用词、分词等,可以在这里添加
    return text
  • preprocess_text(text): 这是一个用于文本预处理的函数。
    • text.lower(): 将文本中的所有字符转换为小写。
    • ''.join(char for char in text if char.isalnum() or char.isspace()): 移除所有非字母数字字符(例如标点符号),仅保留字母、数字和空格。

5. 加载文件并进行预处理

documents = []
for loader in loaders: 
    raw_documents = loader.load()  # 加载文档对象
    for document in raw_documents:
        # 对文本内容进行预处理
        document.page_content = preprocess_text(document.page_content)
        # 保留预处理后的Document对象
        documents.append(document)
  • documents: 用于存储加载并预处理后的Document对象。
  • raw_documents = loader.load(): 使用加载器加载文件,得到一组Document对象。
  • document.page_content = preprocess_text(document.page_content): 对每个Document对象的文本内容(page_content属性)进行预处理,并将处理后的文本重新赋值给page_content属性。
  • documents.append(document): 将预处理后的Document对象存储到documents列表中。

6. 访问并打印文档信息

text = documents[1]
print(f"每一个元素的类型:{type(text)}.", 
    f"该文档的描述性数据:{text.metadata}", 
    f"查看该文档的内容:\n{text.page_content[0:]}", 
    sep="\n------\n")
  • text = documents[1]: 获取documents列表中的第二个文档对象。
  • type(text): 打印text变量的类型。因为text是一个Document对象,所以类型应该是Document
  • text.metadata: 打印文档的元数据,这可能包括文档的标题、作者、创建日期等信息。
  • text.page_content[0:]: 打印文档的文本内容。由于内容可能很长,这里只是示例地显示从头开始的部分内容。
    在这里插入图片描述

3. 文本分割

1. 导入 CharacterTextSplitter

from langchain.text_splitter import CharacterTextSplitter
  • CharacterTextSplitterlangchain 库中的一个文本分割器,它能够将长文本按字符数分割成较小的块。这在处理长文档时特别有用,尤其是在需要对文本进行进一步处理或分析时。

2. 定义 split_text 函数

def split_text(content, chunk_size=500, overlap=50):
    splitter = CharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=overlap)
    return splitter.split_text(content)
  • split_text 是一个用于分割文本的函数。

参数说明:

  • content: 需要分割的文本内容,类型通常是字符串。
  • chunk_size=500: 每个文本块的最大字符数。默认为500个字符。这个参数决定了分割后的每个块的大小。
  • overlap=50: 相邻块之间的重叠字符数。默认为50个字符。这个参数可以确保在处理分块文本时,相邻块之间有一定的上下文关联,避免内容断裂带来的理解困难。

函数过程:

  1. 实例化 CharacterTextSplitter

    • splitter = CharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=overlap):根据指定的块大小和重叠长度,创建一个 CharacterTextSplitter 对象。
  2. 分割文本

    • return splitter.split_text(content):使用 split_text 方法将输入的 content 按指定的块大小和重叠长度进行分割,并返回分割后的文本块列表。

应用场景

  • 大文档处理:当你需要处理非常大的文档时,将其分割成较小的块可以使得后续的处理(如语义分析、摘要生成等)更为高效。
  • 上下文相关处理:通过设定适当的重叠,可以在块之间保留部分上下文,避免因块之间的断裂导致信息丢失或理解困难。

3. 示例使用

content = "这是一个非常长的文本,需要分割成较小的块。每个块的大小为500个字符,并且相邻块之间有50个字符的重叠。"
chunks = split_text(content)
for i, chunk in enumerate(chunks):
    print(f"块 {i+1}:\n{chunk}\n")
  • 这段代码将示例文本 content 按照 chunk_size=500overlap=50 的设置进行分割,并打印出每个分割块。

4. langchain 分割工具介绍

langchain 提供了多种文本分割工具,以适应不同的文本处理需求。

1. CharacterTextSplitter
  • 功能: 按照字符数对文本进行分割。
  • 参数: chunk_size(块大小),chunk_overlap(块之间的重叠字符数)。
  • 适用场景: 需要基于字符数对文本进行分割的场景。
2. RecursiveCharacterTextSplitter
  • 功能: 递归地按字符数进行分割,先尝试按较大块分割,若失败则逐步缩小分割块的大小。
  • 参数: chunk_sizechunk_overlapseparators(分割符列表)。
  • 适用场景: 处理复杂文本,确保尽可能保留语义完整性。
3. TokenTextSplitter
  • 功能: 按照令牌(token)数对文本进行分割,常用于需要处理基于令牌的语言模型。
  • 参数: chunk_sizechunk_overlapmodel_name(指定使用的模型)。
  • 适用场景: 处理需要与语言模型(如 GPT-3、GPT-4)进行交互的文本。
4. SentenceTextSplitter
  • 功能: 按句子进行分割,确保每个分割块是完整的句子。
  • 参数: chunk_sizechunk_overlap
  • 适用场景: 需要在句子层面进行处理的文本,如摘要生成或情感分析。
5. MarkdownHeaderTextSplitter
  • 功能: 根据 Markdown 文档中的标题进行分割,每个分割块对应一个标题及其内容。
  • 参数: headers_to_split_on(标题层级列表,如 ["#", "##", "###"])。
  • 适用场景: 在不同的文本结构级别上进行分割,如处理 Markdown 格式文档时。
6. ListSplitter
  • 功能: 将文本列表中的每个元素视为一个分割块。
  • 适用场景: 需要直接处理文本列表时的场景,如输入已分割的句子列表。
7. ParagraphTextSplitter
  • 功能: 按段落进行文本分割。
  • 适用场景: 适用于需要按段落级别处理的任务,如文本摘要或分类。
8. NltkTextSplitter
  • 功能: 使用 NLTK 库的分词器来进行文本分割,如按句子或单词进行分割。
  • 适用场景: 需要利用 NLTK 的自然语言处理功能进行文本分割的场景。
9. SpacyTextSplitter
  • 功能: 使用 SpaCy 库进行文本分割,通常按句子或词语进行分割。
  • 适用场景: 需要利用 SpaCy 的高级语言处理功能来进行分割时,特别是处理多语言文本的任务。
10. RegexTextSplitter
  • 功能: 使用正则表达式进行文本分割。
  • 参数: pattern(正则表达式模式)。
  • 适用场景: 在需要根据特定模式或结构进行分割的文本时非常有用。
11. LanguageSplitter
  • 功能: 根据不同语言的格式和特点进行分割,支持多语言文本分割。
  • 参数: languagechunk_sizechunk_overlap
  • 适用场景: 在处理多语言文本时,根据语言特点进行更好的分割和处理。

4. 文本向量化类定义及介绍

1. ZhipuAIEmbedding自定义

from __future__ import annotations

import logging
from typing import Dict, List, Any

from langchain.embeddings.base import Embeddings
from langchain.pydantic_v1 import BaseModel, root_validator

logger = logging.getLogger(__name__)

class ZhipuAIEmbeddings(BaseModel, Embeddings):
    """`Zhipuai Embeddings` embedding models."""

    client: Any
    """`zhipuai.ZhipuAI"""

    @root_validator()
    def validate_environment(cls, values: Dict) -> Dict:
        """
        实例化ZhipuAI为values["client"]

        Args:

            values (Dict): 包含配置信息的字典,必须包含 client 的字段.
        Returns:

            values (Dict): 包含配置信息的字典。如果环境中有zhipuai库,则将返回实例化的ZhipuAI类;否则将报错 'ModuleNotFoundError: No module named 'zhipuai''.
        """
        from zhipuai import ZhipuAI
        _ = load_dotenv(find_dotenv())
        api_key = os.environ["API_key"]
        values["client"] = ZhipuAI(api_key=api_key)
        return values
    
    def embed_query(self, text: str) -> List[float]:
        """
        生成输入文本的 embedding.

        Args:
            texts (str): 要生成 embedding 的文本.

        Return:
            embeddings (List[float]): 输入文本的 embedding,一个浮点数值列表.
        """
        embeddings = self.client.embeddings.create(
            model="embedding-2",
            input=text
        )
        return embeddings.data[0].embedding
    
    def embed_documents(self, texts: List[str]) -> List[List[float]]:
        """
        生成输入文本列表的 embedding.
        Args:
            texts (List[str]): 要生成 embedding 的文本列表.

        Returns:
            List[List[float]]: 输入列表中每个文档的 embedding 列表。每个 embedding 都表示为一个浮点值列表。
        """
        return [self.embed_query(text) for text in texts]
    
    
    async def aembed_documents(self, texts: List[str]) -> List[List[float]]:
        """Asynchronous Embed search docs."""
        raise NotImplementedError("Please use `embed_documents`. Official does not support asynchronous requests")

    async def aembed_query(self, text: str) -> List[float]:
        """Asynchronous Embed query text."""
        raise NotImplementedError("Please use `aembed_query`. Official does not support asynchronous requests")
    
def vectorize_text(embeddings_model,chunks):
   
    return embeddings_model.embed_documents(chunks)

1. ZhipuAIEmbeddings
  • 该类继承了 BaseModelEmbeddings,表示这是一个用于生成文本嵌入的模型。
  • client: Any: 用于存储 ZhipuAI 的实例,这个实例是用来与 ZhipuAI 的 API 进行交互的。
2. validate_environment 方法
  • 这是一个 root_validator 方法,用于在实例化类时对环境进行检查。
  • 通过加载 .env 文件中的 API 密钥,实例化 ZhipuAI 客户端,并将其存储在 values["client"] 中。如果 zhipuai 模块不存在,则抛出错误。
3. embed_query 方法
  • 功能: 生成输入文本的嵌入向量。
  • 输入: text,一个字符串。
  • 返回: 生成的嵌入向量,一个浮点数列表。该方法调用 client.embeddings.create(),使用指定的模型生成文本的嵌入。
4. embed_documents 方法
  • 功能: 生成多个文本的嵌入向量。
  • 输入: texts,一个字符串列表。
  • 返回: 返回每个输入文本的嵌入向量,嵌入向量是浮点数列表的列表。方法内部循环调用 embed_query 方法来生成每个文本的嵌入。
5. 异步方法 (aembed_documentsaembed_query)
  • 这些方法被设计为异步版本,但目前没有实现。它们抛出 NotImplementedError,提示官方不支持异步请求。
6. vectorize_text 函数
  • 功能: 使用 ZhipuAIEmbeddings 类的实例生成输入文本块的嵌入向量。
  • 输入: embeddings_modelZhipuAIEmbeddings 的实例,chunks 是待处理的文本块。
  • 返回: 通过调用 embed_documents 方法,返回每个文本块的嵌入向量列表。

2. 词向量生成及存储

# 使用 OpenAI Embedding
# from langchain.embeddings.openai import OpenAIEmbeddings
# 使用百度千帆 Embedding
# from langchain.embeddings.baidu_qianfan_endpoint import QianfanEmbeddingsEndpoint
# 使用封装的智谱 Embedding,需要将封装代码下载到本地使用

# 定义 Embeddings
# embedding = OpenAIEmbeddings() 
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())

embedding = ZhipuAIEmbeddings()
# embedding = QianfanEmbeddingsEndpoint()

# 定义持久化路径
persist_directory = './data_base/vector_db/chroma'
os.makedirs(persist_directory,exist_ok=True)
1. 加载环境变量
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())
  • 功能: 使用 dotenv 库加载 .env 文件中的环境变量。这通常用于获取 API 密钥等配置信息。
  • find_dotenv() 会在项目目录中查找 .env 文件,而 load_dotenv() 则会将文件中的内容加载到环境变量中。
2. 定义 Embedding 模型
embedding = ZhipuAIEmbeddings()
  • 这行代码初始化了一个 ZhipuAIEmbeddings 实例,用于生成文本的嵌入向量。可以根据需要切换到其他嵌入模型,如 OpenAIEmbeddingsQianfanEmbeddingsEndpoint
  • ZhipuAIEmbeddings 是一个自定义的嵌入模型类,使用智谱AI的服务来生成文本嵌入。
3. 定义持久化路径
from langchain.vectorstores.chroma import Chroma
persist_directory = './data_base/vector_db/chroma'
os.makedirs(persist_directory, exist_ok=True)
# import faiss

vectordb = Chroma.from_documents(
    documents=split_docs[:20], # 为了速度,只选择前 20 个切分的 doc 进行生成;使用千帆时因QPS限制,建议选择前 5 个doc
    embedding=embedding,
    persist_directory=persist_directory  # 允许我们将persist_directory目录保存到磁盘上
)

print(f"向量库中存储的数量:{vectordb._collection.count()}")
  • 功能: 定义了一个用于持久化存储的目录路径。这个路径通常用于保存生成的向量数据库。
  • os.makedirs(persist_directory, exist_ok=True) 会在指定路径上创建目录,如果目录已经存在,exist_ok=True 选项会防止抛出错误。

3. langchain.embeddings相关介绍

langchain.embeddings 模块提供了多种嵌入模型的接口,这些模型用于将文本转换为向量表示,这在自然语言处理任务中非常常见。是一些常用的嵌入模型及其简介:

1. OpenAIEmbeddings
  • 简介: 这是一个基于 OpenAI 提供的嵌入服务的模型。它通常用于生成高质量的文本嵌入,适用于需要处理复杂自然语言任务的场景。
  • 适用场景: 文本分类、语义搜索、问答系统等。
  • 示例代码:
    from langchain.embeddings.openai import OpenAIEmbeddings
    embedding = OpenAIEmbeddings()
    
2. HuggingFaceEmbeddings
  • 简介: 基于 Hugging Face 提供的预训练模型,可以选择多种模型(如 BERT、RoBERTa)来生成嵌入。这些模型广泛应用于各类 NLP 任务。
  • 适用场景: 句子相似度、情感分析、文本摘要等。
  • 示例代码:
    from langchain.embeddings.huggingface import HuggingFaceEmbeddings
    embedding = HuggingFaceEmbeddings(model_name="distilbert-base-uncased")
    
3. SentenceTransformersEmbeddings
  • 简介: 使用 SentenceTransformers 库中的模型生成文本嵌入,这些模型经过特定任务的微调,如语义相似度和聚类。
  • 适用场景: 文本聚类、信息检索、语义搜索等。
  • 示例代码:
    from langchain.embeddings.sentence_transformers import SentenceTransformersEmbeddings
    embedding = SentenceTransformersEmbeddings(model_name="all-MiniLM-L6-v2")
    
4. BaiduQianfanEmbeddings
  • 简介: 这是一个基于百度千帆平台的嵌入模型,主要面向中文 NLP 任务,支持生成高质量的中文文本嵌入。
  • 适用场景: 中文文本处理、中文语义搜索、中文文本分类等。
  • 示例代码:
    from langchain.embeddings.baidu_qianfan_endpoint import QianfanEmbeddingsEndpoint
    embedding = QianfanEmbeddingsEndpoint(endpoint_url="your_endpoint_url", api_key="your_api_key")
    
5. ZhipuAIEmbeddings
  • 简介: 基于智谱 AI 提供的嵌入服务,主要用于生成中文和英文文本的嵌入表示,适合多语言环境。
  • 适用场景: 多语言文本处理、跨语言信息检索等。
  • 示例代码:
    embedding = ZhipuAIEmbeddings()
    
6. CohereEmbeddings
  • 简介: 使用 Cohere 提供的嵌入模型,该模型支持多种语言,适用于需要大规模处理的任务。
  • 适用场景: 语义搜索、问答系统、多语言文本处理等。
  • 示例代码:
    from langchain.embeddings.cohere import CohereEmbeddings
    embedding = CohereEmbeddings(api_key="your_api_key")
    
7. AzureEmbeddings
  • 简介: 基于微软 Azure 提供的认知服务的嵌入模型,集成了 Azure 的各种 NLP 服务,适合企业级应用。
  • 适用场景: 企业级应用、定制化 NLP 解决方案等。

示例代码:

from langchain.embeddings.azure_openai import AzureEmbeddings
embedding = AzureEmbeddings(deployment_name="your_deployment_name", api_key="your_api_key")

5.内容检索

5.1 相似度检索

相似度检索是通过计算查询与文档之间的相似度来找到相关内容的过程。余弦相似度是常用的相似度度量方法,通过点积和范数计算两个向量之间的夹角余弦值,值越接近 1,表示文档与查询越相关。

1. 相似度检索的原理

相似度检索是一种用于从大量文档中找到与查询最相关内容的技术。其核心思想是将文档和查询都转换为向量,然后计算这些向量之间的相似度。相似度越高,文档与查询越相关。

2. 文本向量化

首先,需要将文本转换为向量。文本向量化可以通过多种方法实现,比如词袋模型 (Bag of Words)、TF-IDF、Word2Vec、BERT 等嵌入模型。在这个过程中,每个文档和查询都会被表示为一个高维向量。

3. 余弦相似度

Chroma的相似度搜索使用的是余弦距离, 即:

 similarity  = cos ⁡ ( A , B ) = A ⋅ B ∥ A ∥ ∥ B ∥ = ∑ 1 n a i b i ∑ 1 n a i 2 ∑ 1 n b i 2 \text { similarity }=\cos (A, B)=\frac{A \cdot B}{\|A\|\|B\|}=\frac{\sum_1^n a_i b_i}{\sqrt{\sum_1^n a_i^2} \sqrt{\sum_1^n b_i^2}}  similarity =cos(A,B)=A∥∥BAB=1nai2 1nbi2 1naibi

其中 a i a_i ai b i b_i bi 分别是向量 A A A B B B 的分量。
当你需要数据库返回严谨的按余弦相似度排序的结果时可以使用 similarity_search 函数。

4. 相似度检索过程
  1. 向量化:将查询和文档集合中的每个文档都转换为向量。
  2. 计算相似度:使用余弦相似度计算查询向量与每个文档向量之间的相似度。
  3. 排序:将文档按照相似度得分从高到低排序,返回前 (k) 个与查询最相关的文档。
5. 代码示例解释
question="什么是大语言模型"
sim_docs = vectordb.similarity_search(question,k=3)
  • question:用户的查询,例如“什么是大语言模型”。
  • similarity_search:根据相似度检索相关文档的方法。
  • k=3:表示返回最相关的 3 个文档。

在检索过程中,代码将查询转换为向量,与向量数据库中的所有文档进行相似度计算,并返回相似度最高的 3 个文档。
在这里插入图片描述

5.2 MMR检索

1. 最大边际相关性 (MMR) 检索的原理

最大边际相关性 (MMR, Maximum Marginal Relevance) 是一种在信息检索中常用的方法,用来平衡文档的相关性和多样性。传统的相似度检索通常会返回内容相似性最高的几个文档,但这些文档可能在信息上有较大重叠,导致结果的单一性。MMR 通过引入多样性来改善这一点。MMR 检索通过在相关性和多样性之间找到平衡,能够返回更为丰富和全面的文档集,避免了单一化的问题。这在需要覆盖多个信息面向的复杂查询中尤其有用。

2. MMR 的核心思想

MMR 的核心在于在每一步选择下一个文档时,不仅考虑该文档与查询的相关性,还要考虑该文档与已经选择的文档集合的相似性。选择与已有文档相似性低的文档,以增加结果的多样性。MMR 通过以下公式来计算得分:

MMR = arg ⁡ max ⁡ D i ∈ Documents [ λ ⋅ Sim ( D i , Q ) − ( 1 − λ ) ⋅ max ⁡ D j ∈ S Sim ( D i , D j ) ] \text{MMR} = \arg\max_{D_i \in \text{Documents}} \left[\lambda \cdot \text{Sim}(D_i, Q) - (1 - \lambda) \cdot \max_{D_j \in S} \text{Sim}(D_i, D_j)\right] MMR=argDiDocumentsmax[λSim(Di,Q)(1λ)DjSmaxSim(Di,Dj)]

其中:

  • D i D_i Di 是待选的文档。
  • Q Q Q 是查询。
  • S S S 是已选择的文档集合。
  • Sim ( D i , Q ) \text{Sim}(D_i, Q) Sim(Di,Q) 是文档 D i D_i Di 与查询 Q Q Q 的相似度。
  • Sim ( D i , D j ) \text{Sim}(D_i, D_j) Sim(Di,Dj) 是文档 D i D_i Di 与已选文档集合 S S S` 中某个文档 D j D_j Dj 的相似度。
  • λ \lambda λ 是一个权衡参数,用于调整相关性和多样性之间的平衡。
3. 选择过程
  1. 初始化:首先选取与查询 (Q) 相关性最高的文档作为初始集合。
  2. 迭代选择:在每一步中,从剩余文档中选择一个能够最大化 MMR 公式的文档,并将其加入已选择的文档集合。
  3. 停止条件:重复上述步骤,直到选取了 (k) 个文档。
4. 代码示例解释
mmr_docs = vectordb.max_marginal_relevance_search(question, k=3)
  • max_marginal_relevance_search: 使用 MMR 算法来进行检索的方法。
  • k=3: 表示希望返回 3 个结果。
  • question: 用户的查询,如“什么是大语言模型”。

在这个过程中,代码首先根据相关性选择一个文档,然后逐步添加其他与已选文档多样性更高的文档,从而避免了内容单一的问题。

5. MMR 的优势
  • 丰富性:通过增加检索结果的多样性,避免了结果集中内容的重复。
  • 信息覆盖:能够更全面地覆盖查询相关的不同方面的信息。
  • 定制化调节:通过调整 (\lambda) 参数,可以定制相关性和多样性之间的平衡,适应不同应用场景的需求。
6. 结果示例
print("-"*100)
for i, sim_doc in enumerate(mmr_docs):
    print(f"MMR 检索到的第{i}个内容: \n{sim_doc.page_content[:200]}", end="\n--------------\n")
  • sim_doc.page_content[:200]: 打印每个检索到的文档的前 200 个字符,以展示 MMR 选择的文档内容。
  • 结果输出:MMR 检索到的内容会比单纯的相似度检索结果更加多样化,涵盖了查询问题的多个角度。

在这里插入图片描述

6. 结果示例
print("-"*100)
for i, sim_doc in enumerate(mmr_docs):
    print(f"MMR 检索到的第{i}个内容: \n{sim_doc.page_content[:200]}", end="\n--------------\n")
  • sim_doc.page_content[:200]: 打印每个检索到的文档的前 200 个字符,以展示 MMR 选择的文档内容。
  • 结果输出:MMR 检索到的内容会比单纯的相似度检索结果更加多样化,涵盖了查询问题的多个角度。

参考

https://datawhalechina.github.io/llm-universe/#/C3/4.搭建并使用向量数据库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2075518.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小工具网址集合(不定期更新)

1、网络小说聚合工具 网址:https://502book.com/ 一个挺不错的搜索工具,聚合了多个网站的小说搜索工具,直接搜索就可以了,自动解析多个站点的内容,可以直接在网页上观看,比较方便。 2、图片水印工具 网址&a…

高效遍历受限秩树:DFS算法设计与C语言实现

高效遍历受限秩树:DFS算法设计与C语言实现 前言算法设计伪代码C语言代码示例算法分析扩展应用结论前言 给定一个树(或图),其中每个节点的秩(可以理解为子节点数量或某种复杂度度量)最多为 [lgn],其中 n 是树中节点的总数。我们需要设计一个算法来高效遍历或处理这样的树…

SAP如何定义跨不同服务器系统实现 表数据自动传输

一.首先定义一个表 二.定义表维护生成器生成视图 三.SOBJ更改传输配置 最后检查下业务配置情况即可 End:如果不能自动传输可以包请求传输 1.创建请求 2.选中要传输的数据 3.包含请求 点击保存 不点保存请求包的是空的(示例图片是灰的是我没有创建请求&…

兰州大学和南京农业大学等研究团队《Nature Communications 》揭示升高的温度和CO2强烈影响土壤细菌的生长策略!

本文首发于“生态学者”微信公众号! 微生物基于特征的策略似乎在系统发育上是保守的,但对气候变化的适应可能会使情况复杂化。为了研究系统发育和环境在细菌对湿度突然增加的响应中的作用,本研究团队在土壤中通过18O-DNA定量稳定同位素探测(1…

Android12平台上支持spi屏处理

对于Android平台默认是没有支持spi屏的。通常是支持显示接口的屏,例如:rgb,lvds,edp,lvds,mipi等lcd屏。 对于spi屏我们该如何进行适配,以我手上这款oled的spi屏介绍 一、spi平常规原理图及屏端接口介绍 对于软件开发来说,主要用到RS,CS,CLK,SDA,TE几个脚,其他电压管脚交…

滴水逆向三期笔记与作业——02C语言——11 指针(1)

接着水。 滴水逆向三期笔记与作业——02C语言——11 指针(1) 一、指针的宽度1.1 基础类型宽度1.2 一级指针宽度1.3 二级指针宽度1.4 四级指针宽度1.5 总结 二、指针声明三、指针赋值四、指针的运算4.1 或--运算4.2 加减一个整数4.3 求差值4.4 比较 五、作…

【总结】技术总监说nginx配置https都不会,立即、马上开掉!

原文:https://mp.weixin.qq.com/s/7mAH6XyME8ixy8l5-ACpvg 工作中经常会遇到需要手动安装部署nginx,为了安全起见,上线后都需要开启https,本文将从安装部署,一步一步操作,最终实现nginx编译安装&#xff0…

ai写作生成器免费哪个好?这4个ai写作生成器嘎嘎好使

秋雨绵绵,云南的山水间仿佛被施了魔法,每一滴雨珠都像是大自然赋予的buff,让这片土地的美景更加动人。在这诗意盎然的季节里,如果写作也能像这秋雨一样,自然而富有魔力,那该有多好~ 幸运的是,现…

idea怎么从commit信息中打开对应文件

点击Commit 右击想要打开的文件,点击Jump to Source

Veeco电源维修RF600 RF全系列射频电源维修

美国维易科VEECO RF600是为实验室设计的600W可编程直流电源, 研究开发和生产环境,功率要求从10 mW到600 W不等。无论负载或线路条件如何,它都能提供高度准确和稳定的直流输出功率, 使其非常适合各种高功率实验和生产测试应用。 RF600具有广泛的输出电压和电流值选择,以及一系列…

vuejs 源代码启动 调试

vuejs源代码启动 调试 1.项目启动 下载pnpm npm install pnpm -g安装依赖 pnpm install启动 npm run dev启动后会生成packages\vue\dist\vue.global.js,这个文件为实时更新的源码打包文件,我们调试源码需要引入这个文件 2.创建study/myVue.vue文件&…

Improved Baselines with Visual Instruction Tuning

总结 1. 改进:LLAVA-1.5 基于LLAVA架构,提出了LLAVA-1.5,通过简单的修改(如使用MLP投影和增加学术任务相关数据)建立了更强的基线。在11个基准测试中,LLAVA-1.5实现了最先进的性能,尽管仅使用…

openGuass——管理用户安全

一、默认权限机制 二、管理员 1、核心管理员 2、辅助管理员 三、三权分立 1、思想 2、实践 四、权限操作 1、用户的创建与删除 2、用户的修改与信息查看 五、角色 1、创建、修改和删除角色 六、GRANT 七、REVOKE 八、设置用户安全策略 自动锁定和解锁用户 手动锁…

输入与输出(12)

在 C 语言中,标准输入输出库(stdio.h)是用来处理输入和输出操作的主要工具。这个库提供了一系列功能强大的函数来读写各种数据类型,这对任何C程序都是至关重要的。下面是对 C 中输入和输出功能的更详细解释。 1.stdio.h 库 通过包…

9:00面试,9:05就出来了,问的问题有点出乎意料!

从小厂跳槽出来,本以为能在新公司大展拳脚,没想到没多久就再次遭遇困境。 入职初期,加班成了家常便饭,尽管如此,考虑到薪酬还算可观,我并没有过多抱怨。然而,到了六月,一纸通知打破…

第十二章、 集合

第十二章、 集合 12.1 集合的理解和好处 数组 (1). 长度开始时必须指定,而且一旦指定,不能修改 (2). 保存的必须为同一类型的元素 (3). 使用数组进行增加/删除元素的示意代码—比较…

力扣刷题(复习版)

文章目录 题目:最大重复子字符串题解 题目: 面试题 16.07. 最大数值题解 题目: 最大字符串配对数目题解 题目: 字符串中第二大的数字题解 总结 题目:最大重复子字符串 原题链接:最大重复子字符串 题解 …

JetBrains RubyMine 2024.2 (macOS, Linux, Windows) - 最智能的 Ruby 与 Rails IDE

JetBrains RubyMine 2024.2 (macOS, Linux, Windows) - 最智能的 Ruby 与 Rails IDE JetBrains 跨平台开发者工具 请访问原文链接:https://sysin.org/blog/jetbrains-rubymine/,查看最新版。原创作品,转载请保留出处。 作者主页&#xff1…

等保测评中的安全测试方法

等保测评,即信息安全等级保护测评,是我国网络安全领域的重要评估机制,用于验证网络系统或应用是否满足相应的安全保护等级要求。在等保测评中,安全测试方法扮演着至关重要的角色。本文将详细介绍等保测评中常用的安全测试方法及其…

自定义@Resource注解功能

文章目录 1.目录2.Resource.java3.MonsterController.java 依赖注入Service调用方法4.SunWebApplicationContext.java1.executeResource方法完成依赖注入,先按照名字再按照类型2.init方法调用 5.测试 1.目录 2.Resource.java package com.sunxiansheng.springmvc.a…