使用langchain与你自己的数据对话(三):检索(Retrieval)

这篇具有很好参考价值的文章主要介绍了使用langchain与你自己的数据对话(三):检索(Retrieval)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

使用langchain与你自己的数据对话(三):检索(Retrieval),langchain,chatgpt,语言模型,人工智能,NLP 

之前我已经完成了使用langchain与你自己的数据对话的前两篇博客,还没有阅读这两篇博客的朋友可以先阅读一下:

  1. 使用langchain与你自己的数据对话(一):文档加载与切割
  2. 使用langchain与你自己的数据对话(二):向量存储与嵌入

今天我们来继续讲解deepleaning.AI的在线课程“LangChain: Chat with Your Data”的第四门课:检索(Retrieval)。

Langchain在实现与外部数据对话的功能时需要经历下面的5个阶段,它们分别是:Document Loading->Splitting->Storage->Retrieval->Output,如下图所示:

使用langchain与你自己的数据对话(三):检索(Retrieval),langchain,chatgpt,语言模型,人工智能,NLP

 在上一篇博客:向量存储与嵌入中我们介绍了嵌入(Embeddings)和开源向量数据库Chroma的基本原理,当文档经过切割(splitting),嵌入(embedding)后存入向量数据库以后,接下来就来到了检索(retrieval)环节:

使用langchain与你自己的数据对话(三):检索(Retrieval),langchain,chatgpt,语言模型,人工智能,NLP

检索是指根据用户的问题去向量数据库中搜索与问题相关的文档内容,当我们访问和查询向量数据库时可能会运用到如下几种技术:

  • 基本语义相似度(Basic semantic similarity)
  • 最大边际相关性(Maximum marginal relevance,MMR)
  • 过滤元数据
  • LLM辅助检索

在讨论这些新技术之前,想让我们完成一些基础性工作,比如设置一下openai的api key:

import os
import openai
import sys
sys.path.append('../..')
 
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
 
openai.api_key  = os.environ['OPENAI_API_KEY']

基本语义相似度(Basic semantic similarity)

下面我们来实现一下语义的相似度搜索,我们把三句英语的句子存入向量数据库Chroma中,然后我们提出问题让向量数据库根据问题来搜索相关答案:

from langchain.vectorstores import Chroma
from langchain.embeddings.openai import OpenAIEmbeddings

#创建open ai的embedding对象
embedding = OpenAIEmbeddings()

#需要存入数据库的文本
texts = [
    """The Amanita phalloides has a large and imposing epigeous (aboveground) fruiting body (basidiocarp).""",
    """A mushroom with a large fruiting body is the Amanita phalloides. Some varieties are all-white.""",
    """A. phalloides, a.k.a Death Cap, is one of the most poisonous of all known mushrooms.""",
]


#创建向量数据库
smalldb = Chroma.from_texts(texts, embedding=embedding)

下面我们把代码中的三句英语的文本翻译为中文,这样便于大家更好的理解其含义:

  • 1.“鹅膏菌具有巨大而雄伟的地上(地上)子实体(担子果)。”
  • 2.“具有较大子实体的蘑菇是鹅膏菌。有些品种是全白色的。”
  • 3.“鬼笔甲,又名死亡帽,是所有已知蘑菇中毒性最强的一种。”

我们可以看到前两句都是描述的是一种叫“鹅膏菌”的菌类,包括它们的特征:有较大的子实体,第三句描述的是“鬼笔甲”,一种已知的最毒的蘑菇,它的特征就是:含有剧毒。下面我们提出一个问题:“告诉我有关子实体大的全白蘑菇的信息”,然后让向量数据库用相似度(similarity)方法去搜索2个和问题最相关的答案:

#问题:告诉我有关子实体大的全白蘑菇的信息
question = "Tell me about all-white mushrooms with large fruiting bodies"

smalldb.similarity_search(question, k=2)

使用langchain与你自己的数据对话(三):检索(Retrieval),langchain,chatgpt,语言模型,人工智能,NLP

 我们看到向量数据库返回了2个文档,就是我们存入向量数据库中的第一句和第二句。这里我们很明显的就可以看到chroma的similarity_search方法可以根据问题的语义去数据库中搜索与之相关性最高的文档也就是搜索到了第一句和第二句的文本,但这似乎有存在一些问题,因为第一句和第二句的含义非常接近,他们都是描述“鹅膏菌”及其“子实体”的,所以假如只返回其中的一句就足以满足要求了,如果返回两句含义非常接近的文本感觉是一种资源的浪费,下面我们来看一下max_marginal_relevance_search的搜索结果:

smalldb.max_marginal_relevance_search(question,k=2, fetch_k=3)

使用langchain与你自己的数据对话(三):检索(Retrieval),langchain,chatgpt,语言模型,人工智能,NLP

这里我们看到 max_marginal_relevance_search返回了第二和第三句的文本,尽管第三句与我们的问题的相关性不太高,但是这样的结果其实应该是更加的合理,因为第一句和第二句文本本来就有着相似的含义,所以只需要返回其中的一句就可以了,另外再返回一个与问题相关性弱一点的答案(第三句文本),这样似乎增强了答案的多样性,相信用户也会更加偏爱max_marginal_relevance_search 的结果,因为它兼顾了答案的相关性和多样性,下面我们就来讨论“最大边际相关性(Maximum marginal relevance ,MMR)”的问题。

最大边际相关性(Maximum marginal relevance ,MMR)

最大边际相关性(Maximum marginal relevance ,MMR)在论文:《The Use of MMR, Diversity-Based Reranking for Reordering Documents and Production Summaries》中有详细的介绍,MMR 尝试减少结果的冗余,同时保持结果与查询条件相关性和多样性的平衡(。作者在论文中提出了如下的公式:

使用langchain与你自己的数据对话(三):检索(Retrieval),langchain,chatgpt,语言模型,人工智能,NLP

 其中:

  • Q: 查询条件
  • R: 与查询Q相关的所有文档集
  • D: 与查询条件相关的文档集
  • S: R中已选择的文档子集
  • R\S: R中未选择的文档子集
  • λ:[0–1] 范围内的常数,用于结果的多样化
  • Sim1,Sim2: 用来度量查询Q与文档相似度的指标,如余弦相似度等。

使用langchain与你自己的数据对话(三):检索(Retrieval),langchain,chatgpt,语言模型,人工智能,NLP

有兴趣的读者可以仔细研读该篇论文,幸运的是我们不需要手动去实现MMR算法,Langchain的内置方法max_marginal_relevance_search已经帮我们首先了该算法,在执行max_marginal_relevance_search方法时,我们需要设置fetch_k参数,用来告诉向量数据库我们最终需要k个结果,向量数据库在搜索时会获取一个和问题相关的文档集,该文档集中的文档数量大于k,然后从中过滤出k个具有相关性同时兼顾多样性的文档。

使用langchain与你自己的数据对话(三):检索(Retrieval),langchain,chatgpt,语言模型,人工智能,NLP

下面我们来测试一下max_marginal_relevance_search方法,还记得在上一篇博客(向量存储与嵌入)中我们介绍了两种向量数据在查询时的失败场景吗?当向量数据库中存在相同的文档时,而当用户的问题又与这些重复的文档高度相关时,向量数据库会出现返回重复的文档情况,现在我们就可以运用Langchain的max_marginal_relevance_search来解决这个问题,不过首先我们需要先加载一下上一篇博客中保存在本地的关于吴恩达老师的机器学习课程cs229课程讲义的向量数据库:

#向量数据库地址
persist_directory = 'docs/chroma/'

embedding = OpenAIEmbeddings()

vectordb = Chroma(
    persist_directory=persist_directory,
    embedding_function=embedding
)

#打印向量数据库中的文档数量
print(vectordb._collection.count())

 使用langchain与你自己的数据对话(三):检索(Retrieval),langchain,chatgpt,语言模型,人工智能,NLP

 这里我们加载了之前保存在本地的向量数据库,并查询了数据库中的文档数量为209,这与我们之前创建该数据库时候的文档数量是一致的,接下来我们提出了和上篇博客中相同的问题,然后先用similarity_search方法来查询一下,它应该会返回两篇相同的文档:

question = "what did they say about matlab?"
docs_ss = vectordb.similarity_search(question,k=3)

docs_ss 

使用langchain与你自己的数据对话(三):检索(Retrieval),langchain,chatgpt,语言模型,人工智能,NLP

 这里我们看到向量数据库返回了两篇相同的文档,这是因为在上一篇博客中我们在创建向量数据库时加载了两篇相同的文档(Lecture01.pdf),所以这回通过similarity_search方法搜索相似文档时它们被同时搜索到并返回给了用户。下面我们使用max_marginal_relevance_search方法来搜索:

docs_mmr = vectordb.max_marginal_relevance_search(question,k=3)

docs_mmr

使用langchain与你自己的数据对话(三):检索(Retrieval),langchain,chatgpt,语言模型,人工智能,NLP这里我们看到向量数据库返回了3篇完全不同的文档,这是因为我们使用的是MMR搜索,它把搜索结果中相似度很高的文档做了过滤,所以它保留了结果的相关性又同时兼顾了结果的多样性。

过滤元数据

 在上一篇博客中的“失败的应用场景”的章节中我们还提出了一个问题:我们要求向量数据库在第三篇原始文档(Lecture03.pdf)中搜索相关答案,结果向量数据库的返回结果中除了第三篇文档的结果以外还包含了第一篇(Lecture01.pdf)和第二篇文档(Lecture02.pdf)的内容,这是我们所不希望看到的结果,之所以产生这样的结果是因为当我们向向量数据库提出问题时,数据库并没有很好的理解问题的语义,所以返回的结果不如预期,要解决这个问题,我们可以通过过滤元数据的方式来实现精准搜索,当前很多向量数据库都支持对元数据的操作:

question = "what did they say about regression in the third lecture?"

docs = vectordb.similarity_search(
    question,
    k=3,
    filter={"source":"docs/cs229_lectures/MachineLearning-Lecture03.pdf"}
)

for d in docs:
    print(d.metadata)

使用langchain与你自己的数据对话(三):检索(Retrieval),langchain,chatgpt,语言模型,人工智能,NLP

 这里我们可以看到通过我们在代码中设置了filter过滤条件后,向量数据库返回的3个答案呢都是基于第三篇文档的(Lecture03.pdf),这就符合我们的要求了,通过在similarity_search方法中加入filter参数,就可以指定需要搜索的原始文档,因为所有原始文档的文件名信息都保存在切割后文档的元数据信息中,通过过滤元数据信息就可以使向量数据库在指定的文档中搜索和问题相关的答案了。

LLM辅助检索

上面我们使用的是手动设置元数据的过滤参数filter来实现过滤指定文档的功能,其实这也不是很方便,因为我们每次都需要手动去设置过滤条件,这会非常的麻烦。有没有方法可以准确识别问题中的语义(因为在用户的问题中已经指出了需要过滤的文档)从而自动实现元数据过滤呢?也就是说是否有一种方法可以从用户问题的语义中自动推断出需要过滤的元数据信息呢?Langchain为我们提供了这样的方法,我们可以使用 SelfQueryRetriever,它使用 LLM 从用户原始问题中抽取取:

  • 用于向量搜索的查询字符串(search term)
  • 用于过滤元数据的信息(Filter)

其原理如下图所示:

使用langchain与你自己的数据对话(三):检索(Retrieval),langchain,chatgpt,语言模型,人工智能,NLP

 下面我们就来实现一下LLM辅助检索:

from langchain.llms import OpenAI
from langchain.retrievers.self_query.base import SelfQueryRetriever
from langchain.chains.query_constructor.base import AttributeInfo

#定义元数据的过滤条件
metadata_field_info = [
    AttributeInfo(
        name="source",
        description="The lecture the chunk is from, should be one of `docs/cs229_lectures/MachineLearning-Lecture01.pdf`, `docs/cs229_lectures/MachineLearning-Lecture02.pdf`, or `docs/cs229_lectures/MachineLearning-Lecture03.pdf`",
        type="string",
    ),
    AttributeInfo(
        name="page",
        description="The page from the lecture",
        type="integer",
    ),
]

#创建SelfQueryRetriever
document_content_description = "Lecture notes"
llm = OpenAI(temperature=0)
retriever = SelfQueryRetriever.from_llm(
    llm,
    vectordb,
    document_content_description,
    metadata_field_info,
    verbose=True
)

这里我们首先定义了metadata_field_info ,它包含了元数据的过滤条件source和page, 其中source的作用是告诉LLM我们想要的数据来自于哪里,page告诉LLM我们还需要提取相关的内容在原始文档的第几页。有了metadata_field_info信息后,LLM会自动从用户的问题中提取出上图中的Filter和Search term两项,然后向量数据库基于这两项去搜索相关的内容。下面我们看一下查询结果:

#问题
question = "what did they say about regression in the third lecture?"

#搜索相关文档
docs = retriever.get_relevant_documents(question)

#打印结果中的元数据信息
for d in docs:
    print(d.metadata)

使用langchain与你自己的数据对话(三):检索(Retrieval),langchain,chatgpt,语言模型,人工智能,NLP

 由于我们在定义SelfQueryRetriever时设置了verbose=True,所以我们可以看到一些SelfQueryRetriever执行的中间结果,从上面的返回结果中我们看到query和filter这两项,其中query=‘regression’就是从用户问题中提取出来的搜索项,搜索内容为“regression”, 而filter项是LLM根据metadata_field_info中定义的信息对向量数据库中的文档块的元数据进行过滤的条件。最后我们看到返回结果均来自于第三个文档(Lecture03.pdf),完全符合我们的要求。

附加技巧:压缩(compression)

所谓压缩是指提高文档检索质量的一种方法,当我们根据用户的问题使用检索器(Retriever)去检索向量数据库时,向量数据库一般会返回与问题相关文档块(chunks)中的所有内容,即把整个文档块的内容全部输出,这就可能会产生一些资源浪费的情况,因为和问题相关的文档内容可能只占该文档块的一小部分,可我们却输出了整个文档块的全部内容,这样会增加token成本,因为我们使用的openai的LLM不是免费的,它是根据token数量来收费的,因此输出整个文档块的内容其实是一种资源的浪费,幸运的是Langchain为我们提供给了ContextualCompressionRetriever,其原理如下图所示:

使用langchain与你自己的数据对话(三):检索(Retrieval),langchain,chatgpt,语言模型,人工智能,NLP

 从上图中我们看到,当向量数据库返回了所有与问题相关的所有文档块的全部内容后,会有一个Compression LLM来负责对这些返回的文档块的内容进行压缩,所谓压缩是指仅从文档块中提取出和用户问题相关的内容,并舍弃掉那些不相关的内容。

from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor

def pretty_print_docs(docs):
    print(f"\n{'-' * 100}\n".join([f"Document {i+1}:\n\n" + d.page_content for i, d in enumerate(docs)]))
    
# Wrap our vectorstore
llm = OpenAI(temperature=0)
compressor = LLMChainExtractor.from_llm(llm)

compression_retriever = ContextualCompressionRetriever(
    base_compressor=compressor,
    base_retriever=vectordb.as_retriever()
)

在上面的代码中我们定义了一个LLMChainExtractor,它是一个压缩器,它负责从向量数据库返回的文档块中提取相关信息,然后我们还定义了ContextualCompressionRetriever,它有两个参数:base_compressor和base_retriever,其中base_compressor为我们前面定义的LLMChainExtractor的实例,base_retriever为早前定义的vectordb产生的检索器。下面我们来看一下执行结果:

question = "what did they say about matlab?"
compressed_docs = compression_retriever.get_relevant_documents(question)
pretty_print_docs(compressed_docs)

使用langchain与你自己的数据对话(三):检索(Retrieval),langchain,chatgpt,语言模型,人工智能,NLP

从上面的返回结果中我们看到,返回结果并不是整个文档块的内容,而只是文档块中的部分内容,这些内容与用户的问题是直接相关的,文档块中与问题不相关的内容都已经被舍弃了,这样就大大节省了使用LLM的成本。

其他类型的检索

值得注意的是,vectordb 并不是Langchain中唯一的一种检索器 。LangChain还提供了其他检索文档的方式,例如TF-IDF或SVM。

from langchain.retrievers import SVMRetriever
from langchain.retrievers import TFIDFRetriever
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter


# Load PDF
loader = PyPDFLoader("docs/cs229_lectures/MachineLearning-Lecture01.pdf")
pages = loader.load()
all_page_text=[p.page_content for p in pages]
joined_page_text=" ".join(all_page_text)

# Split
text_splitter = RecursiveCharacterTextSplitter(chunk_size = 1500,chunk_overlap = 150)
splits = text_splitter.split_text(joined_page_text)


# Retrieve
svm_retriever = SVMRetriever.from_texts(splits,embedding)
tfidf_retriever = TFIDFRetriever.from_texts(splits)

这里我们定义了SVMRetriever,和TFIDFRetriever两个检索器,下面我们使用这两个检索器来检索向量数据库:

question = "What are major topics for this class?"
docs_svm=svm_retriever.get_relevant_documents(question)
docs_svm[0]

使用langchain与你自己的数据对话(三):检索(Retrieval),langchain,chatgpt,语言模型,人工智能,NLP

question = "what did they say about matlab?"
docs_tfidf=tfidf_retriever.get_relevant_documents(question)
docs_tfidf[0]

使用langchain与你自己的数据对话(三):检索(Retrieval),langchain,chatgpt,语言模型,人工智能,NLP

关于SVM和TF-IDF的相关技术不会在本文中讨论,读者可以执行查阅相关技术资料。

总结

今天我们学习了很多有用的新技术比如最大边际相关性(MMR),MMR可以让搜索结果保持相关性和多样性,这样可以避免出现冗余的搜索结果,除此之外我们可以定义元数据的过滤条件,这样向量数据库可以更加精准的搜索和问题相关的答案。另外我们还学习了LLM辅助检索,通过定义元数据字段信息metadata_field_info ,我们可以使用SelfQueryRetriever自动推断出用户问题中的搜索项和过滤项,这样可以避免手动设置元数据过滤条件带来的麻烦,后面我们还介绍了内容压缩检索器ContextualCompressionRetriever,通过ContextualCompressionRetriever我们可以从返回的整个文档块抽取和用户问题相关的内容,抛弃掉和问题无关的内容,这样可以大大节省LLM的使用成本。最后我们还简单介绍了SVM和TF-IDF检索器的使用方法,希望今天的内容对大家有所帮助!

参考资料

《The Use of MMR, Diversity-Based Reranking for Reordering Documents and Production Summaries》

Vector stores | 🦜️🔗 Langchain

Self-querying | 🦜️🔗 Langchain

Contextual compression | 🦜️🔗 Langchain文章来源地址https://www.toymoban.com/news/detail-611099.html

到了这里,关于使用langchain与你自己的数据对话(三):检索(Retrieval)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring AI - 使用向量数据库实现检索式AI对话

     Spring AI 并不仅限于针对大语言模型对话API进行了统一封装,它还可以通过简单的方式实现LangChain的一些功能。本篇将带领读者实现一个简单的检索式AI对话接口。  在一些场景下,我们想让AI根据我们提供的数据进行回复。因为对话有最大Token的限制,因此很多场景下我们

    2024年04月14日
    浏览(49)
  • 使用Langchain+GPT+向量数据库chromadb 来创建文档对话机器人

    使用Langchain+GPT+向量数据库chromadb 来创建文档对话机器人 文件存放地址 参考: https://python.langchain.com/docs/use_cases/chatbots https://python.langchain.com/docs/integrations/vectorstores/chroma https://blog.csdn.net/v_JULY_v/article/details/131552592?ops_request_misc=%257B%2522request%255Fid%2522%253A%252216945020581680022659096

    2024年02月03日
    浏览(40)
  • Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (四)

    这篇博客是之前文章: Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (一) Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (二) Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (三) 的续篇。在这篇文章中,我们将学

    2024年02月05日
    浏览(47)
  • Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (三)

    这是继之前文章: Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (一) Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (二) 的续篇。在今天的文章中,我将详述如何使用 ElasticsearchStore。这也是被推荐的使用方法。如果你还没有设置好

    2024年02月08日
    浏览(41)
  • Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (一)

    最近看了一个同事的几个视频。他总结的很好。在使用 LangChain 时,根据 LangChain 的官方文档 https://integrations.langchain.com/vectorstores,目前有三种方法可以进行使用:ElasticVectorSearch,ElasticsearchStore 及 ElasticKnnSearch。 我们从上面的 小红心 来看,Elasticsearch 无疑是最受欢迎的向量

    2024年02月03日
    浏览(37)
  • OpenAI推出的ChatGPT与你对话

    前几天,OpenAI 推出超神 ChatGPT,非常火爆。但是呢,因为不可抗力原因,大部分人无法体验到。ChatGPT 最近是大火了,引起的广泛讨论,大有破圈之势,简单来说,它是基于自然语言生成式 AI 模型,打造的一款聊天机器人;是 OpenAI 于 2022 年11 月 30 日推出的最新作品,供公众

    2023年04月18日
    浏览(38)
  • Azure Machine Learning - 使用自己的数据与 Azure OpenAI 模型对话

    在本文中,可以将自己的数据与 Azure OpenAI 模型配合使用。 对数据使用 Azure OpenAI 模型可以提供功能强大的对话 AI 平台,从而实现更快、更准确的通信。 关注TechLead,分享AI全维度知识。作者拥有10+年互联网服务架构、AI产品研发经验、团队管理经验,同济本复旦硕,复旦机器

    2024年02月04日
    浏览(41)
  • Langchain使用介绍之 - 基于向量存储进行检索

    Text Embedding Models   如何将一段Document转换成向量存储到向量数据库中,首先需要了解Langchain提供了哪些将文本转换成向量的model,langchian提供了很多将自然语言转换成向量的的模型,如下图所示,除了下图列举的model,更多支持的model可参考官网信息。    这里将以Langchain提供

    2024年02月09日
    浏览(41)
  • Langchain 与 Elasticsearch:创新数据检索的融合实战

    在信息爆炸的时代,有效地检索和处理数据变得至关重要。Langchain 和 Elasticsearch 的结合,为我们提供了一个强大的工具,以更智能的方式进行数据检索和分析。 作为一名拥有多年 Elasticsearch 实战经验的技术博主,我将在本文中详细介绍这两种技术的整合应用。 Langchain是一个

    2024年01月19日
    浏览(41)
  • 基于自然语言描述的行人检索 Text-based Person Retrieval - 常用数据集 CUHK-PEDES、ICFG-PEDES、RSTPReid

    博主是做多模态相关的,最近刚刚接触了 语言行人检索 (Text-based Person Retrieval) 这个任务,觉得挺有意思,开一个专栏来记录一下该任务的常用数据集和一些经典工作。 语言行人检索应该算是 多模态检索 和 行人重识别 两个任务的交叉子任务,任务本身并不难理解,就是给定

    2024年02月08日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包