【LangChain】对话式问答(Conversational Retrieval QA)

news/2024/12/19 22:48:35/

LangChain学习文档

  • 流行
    • 【LangChain】Retrieval QA
    • 【LangChain】对话式问答(Conversational Retrieval QA)

概要

本篇详细介绍:对话式问答 的内容有:

  1. 对话式问答chain是建立在问答chain的基础之上,提供了聊天历史记录的功能,对话式问答主要由ConversationBufferMemory类构建。
  2. 聊天记录我们可以使用memory来记录;在ConversationalRetrievalChain.from_llm()方法中指定;也可以在执行时候指定:qa({"question": query, "chat_history": chat_history})
  3. 针对问题答案,可以使用不同的模型;用便宜的模型来提炼问题,用昂贵的模型回答问题;提炼问题是在ConversationalRetrievalChain.from_llm()方法中指定参数:condense_question_llm
  4. 如果向量存储支持距离搜索,可以使用vectordbkwargs来指定阈值。
  5. 可以将不同类型的文档链与 ConversationalRetrievalChain 链结合使用。
  6. 想要获取历史记录,可以使用get_chat_history函数;

内容

ConversationalRetrievalQA chain 是建立在 RetrievalQAChain 之上,提供聊天历史记录的组件。
它首先将聊天记录(显式传入或从提供的内存中检索)和问题组合成一个独立的问题,然后从检索器中查找相关文档,最后将这些文档和问题传递到问答链以返回一个响应。

想要创建一个,那我们就需要retriever。在下面的示例中,我们将从向量存储创建一个,该向量存储可以从embeddings中创建。

from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.text_splitter import CharacterTextSplitter
from langchain.llms import OpenAI
from langchain.chains import ConversationalRetrievalChain# 加载文档。您可以将其替换为您想要的任何类型数据的加载器:
from langchain.document_loaders import TextLoader
loader = TextLoader("../../state_of_the_union.txt")
documents = loader.load()# 如果您想要组合多个加载器,您可以执行以下操作:
# loaders = [....]
# docs = []
# for loader in loaders:
#     docs.extend(loader.load())
# 现在,我们分割文档,为它们创建嵌入,并将它们放入矢量存储中。这使我们能够对它们进行语义搜索。
# 创建拆分器
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
# 拆分文档
documents = text_splitter.split_documents(documents)# 创建embeddings
embeddings = OpenAIEmbeddings()
# 创建向量存储,使得我们可以进行相关性搜索
vectorstore = Chroma.from_documents(documents, embeddings)

使用没有持久性的嵌入式 DuckDB:数据将是暂时的

为了追踪输入、输出,我们需要创建一个memory对象。

from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)

我们现在初始化 ConversationalRetrievalChain

qa = ConversationalRetrievalChain.from_llm(OpenAI(temperature=0), vectorstore.as_retriever(), memory=memory)query = "总统对科坦吉·布朗·杰克逊说了些什么"
result = qa({"question": query})
# 结果
""" 
总统表示,科坦吉·布朗·杰克逊是美国顶尖的法律专家之一、前私人执业顶级诉讼律师、前联邦公设辩护律师,出身于公立学校教育工作者和警察家庭。
他还表示,她是共识的缔造者,得到了从警察兄弟会到民主党和共和党任命的前法官的广泛支持。
"""query = "他有没有提到她继承了谁"
result = qa({"question": query})result['answer']""" 
科坦吉·布朗·杰克逊 (Ketanji Brown Jackson) 接替斯蒂芬·布雷耶 (Stephen Breyer) 大法官出任美国最高法院法官。
"""

小节下:我们创建了一个拥有历史记录的聊天会话

在聊天历史中传递(Pass in chat history)

在上面的示例中,我们使用 Memory 对象来追踪聊天历史记录。
我们也可以直接将其显式传递。 为了做到这一点,我们需要初始化一个没有任何历史记录的链。

qa = ConversationalRetrievalChain.from_llm(OpenAI(temperature=0), vectorstore.as_retriever())
# 这是在没有聊天记录的情况下提问的示例
chat_history = []
query = "总统对科坦吉·布朗·杰克逊说了些什么"
result = qa({"question": query, "chat_history": chat_history})
result["answer"]# 结果
""" 
总统表示,科坦吉·布朗·杰克逊是美国顶尖的法律专家之一、前私人执业顶级诉讼律师、前联邦公设辩护律师,出身于公立学校教育工作者和警察家庭。
他还表示,她是共识的缔造者,得到了从警察兄弟会到民主党和共和党任命的前法官的广泛支持。
"""# 这是一个使用一些聊天记录提问的示例
chat_history = [(query, result["answer"])]
query = "他有没有提到她继承了谁"
result = qa({"question": query, "chat_history": chat_history})
result['answer']
# 结果
""" 科坦吉·布朗·杰克逊 (Ketanji Brown Jackson) 接替斯蒂芬·布雷耶 (Stephen Breyer) 大法官出任美国最高法院法官 """

使用不同的模型来凝练问题(Using a different model for condensing the question)

该链有两个步骤:
首先,它将当前问题和聊天历史凝练为一个独立的问题。这是创建用于检索的独立向量所必需的。

之后,它进行检索,然后使用单独模型的检索增强生成来回答问题。 LangChain 声明性特性的部分强大之处在于,您可以轻松地为每个调用使用单独的语言模型。

这样会有一个非常大的好处:我们可以使用更便宜、更快的模型来完成问题的凝练工作,然后再使用昂贵的模型来回答问题。

from langchain.chat_models import ChatOpenAI
# 构建一个组合
qa = ConversationalRetrievalChain.from_llm(ChatOpenAI(temperature=0, model="gpt-4"),vectorstore.as_retriever(),condense_question_llm = ChatOpenAI(temperature=0, model='gpt-3.5-turbo'),
)chat_history = []
query = "总统对科坦吉·布朗·杰克逊说了些什么"
result = qa({"question": query, "chat_history": chat_history})chat_history = [(query, result["answer"])]
query = "他有没有提到她继承了谁"
result = qa({"question": query, "chat_history": chat_history})

返回源文件(Return Source Documents)

您还可以轻松地从 ConversationalRetrievalChain 返回源文档。当您想要检查返回的文档时,这非常有用。

qa = ConversationalRetrievalChain.from_llm(OpenAI(temperature=0), vectorstore.as_retriever(), return_source_documents=True)result['source_documents'][0]Document(page_content='Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. \n\nTonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. \n\nOne of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. \n\nAnd I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.', metadata={'source': '../../state_of_the_union.txt'})

带有 search_distance 的 ConversationalRetrievalChain

如果您使用的向量存储支持按搜索距离来过滤,则可以添加阈值参数。

# 这里设置了阈值
vectordbkwargs = {"search_distance": 0.9}qa = ConversationalRetrievalChain.from_llm(OpenAI(temperature=0), vectorstore.as_retriever(), return_source_documents=True)
chat_history = []
query = "What did the president say about Ketanji Brown Jackson"
result = qa({"question": query, "chat_history": chat_history, "vectordbkwargs": vectordbkwargs})

带有map_reduce的ConversationalRetrievalChain

我们还可以将不同类型的文档链与 ConversationalRetrievalChain 链结合使用。

from langchain.chains.qa_with_sources import load_qa_with_sources_chain
llm = OpenAI(temperature=0)
question_generator = LLMChain(llm=llm, prompt=CONDENSE_QUESTION_PROMPT)
doc_chain = load_qa_with_sources_chain(llm, chain_type="map_reduce")chain = ConversationalRetrievalChain(retriever=vectorstore.as_retriever(),question_generator=question_generator,combine_docs_chain=doc_chain,
)chat_history = []
query = "What did the president say about Ketanji Brown Jackson"
result = chain({"question": query, "chat_history": chat_history})
result['answer']
""" 
The president said that Ketanji Brown Jackson is one of the nation's top legal minds, a former top litigator in private practice, a former federal public defender, from a family of public school educators and police officers, a consensus builder, and has received a broad range of support from the Fraternal Order of Police to former judges appointed by Democrats and Republicans. 
\nSOURCES: ../../state_of_the_union.txt
"""

ConversationalRetrievalChain 流式传输到标准输出

在此示例中,chain的输出将按token流式传输到标准输出token。

from langchain.chains.llm import LLMChain
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
from langchain.chains.conversational_retrieval.prompts import CONDENSE_QUESTION_PROMPT, QA_PROMPT
from langchain.chains.question_answering import load_qa_chain# 使用流式 llm 构造一个 ConversationalRetrievalChain 来合并文档
# 以及一个用于问题生成的独立的非流式 llm
llm = OpenAI(temperature=0)
streaming_llm = OpenAI(streaming=True, callbacks=[StreamingStdOutCallbackHandler()], temperature=0)question_generator = LLMChain(llm=llm, prompt=CONDENSE_QUESTION_PROMPT)
doc_chain = load_qa_chain(streaming_llm, chain_type="stuff", prompt=QA_PROMPT)qa = ConversationalRetrievalChain(retriever=vectorstore.as_retriever(), combine_docs_chain=doc_chain, question_generator=question_generator)chat_history = []
query = "总统对科坦吉·布朗·杰克逊说了些什么"
result = qa({"question": query, "chat_history": chat_history})
# 结果
""" 
总统表示,科坦吉·布朗·杰克逊是美国顶尖的法律专家之一、前私人执业顶级诉讼律师、前联邦公设辩护律师,出身于公立学校教育工作者和警察家庭。
他还表示,她是共识的缔造者,得到了从警察兄弟会到民主党和共和党任命的前法官的广泛支持。
"""chat_history = [(query, result["answer"])]
query = "Did he mention who she suceeded"
result = qa({"question": query, "chat_history": chat_history})
# 结果
"""
科坦吉·布朗·杰克逊 (Ketanji Brown Jackson) 接替斯蒂芬·布雷耶 (Stephen Breyer) 大法官出任美国最高法院法官。
"""

get_chat_history 函数

您还可以指定 get_chat_history 函数,该函数可用于格式化 chat_history 字符串。

def get_chat_history(inputs) -> str:res = []for human, ai in inputs:res.append(f"Human:{human}\nAI:{ai}")return "\n".join(res)
qa = ConversationalRetrievalChain.from_llm(OpenAI(temperature=0), vectorstore.as_retriever(), get_chat_history=get_chat_history)chat_history = []
query = "What did the president say about Ketanji Brown Jackson"
result = qa({"question": query, "chat_history": chat_history})result['answer']
""" 
总统表示,科坦吉·布朗·杰克逊是美国顶尖的法律专家之一、前私人执业顶级诉讼律师、前联邦公设辩护律师,出身于公立学校教育工作者和警察家庭。
他还表示,她是共识的缔造者,得到了从警察兄弟会到民主党和共和党任命的前法官的广泛支持。
"""

参考地址:

Conversational Retrieval QA


http://www.ppmy.cn/news/829836.html

相关文章

常用C标准库函数的说明

如下为C标准库函数的声明&#xff1a;&#xff08;写得不错&#xff0c;但是对于初级应用工程师&#xff0c;初看的时候&#xff0c;容易增加压力&#xff09; // // vcruntime_string.h // // Copyright (c) Microsoft Corporation. All rights reserved. // // <str…

新ipad 充电测试软件,你的充电器能喂饱新iPad Pro吗?新iPad Pro充电大对决

使用USB-C接口的优点不言而喻&#xff0c;首先是更快的数据传输速度&#xff0c;新iPad Pro支持USB3.1数据传输&#xff0c;另外还支持USB PD快速充电。苹果为iPad Pro标配了一个18W的USB-C PD充电器&#xff0c;这个充电器能喂饱新iPad Pro的胃口吗&#xff1f; 小编用新iPad …

怎样选择正确的MacBook充电器?如何才能延长电池寿命?

大多数人会认为Mac充电器的使用寿命不及笔记本电脑。他们破裂&#xff0c;迷路&#xff0c;甚至被盗。这意味着您很有可能必须在某个时候更换旧的MacBook充电器。那你会怎样选择呢&#xff1f;MacBook充电器的本质区别 查看MacBook Air和MacBook Pro电源适配器的所有变化&#…

假冒Macbook充电器拆解:外表令人信服但内部却非常危险

作者&#xff1a;Ken&#xff0c;排版&#xff1a;晓宇 微信公众号&#xff1a;芯片之家&#xff08;ID&#xff1a;chiphome-dy&#xff09; 假冒 Macbook 充电器里面有什么&#xff1f;一位读者寄给我一个他怀疑是假冒的充电器。从外观上看&#xff0c;这款充电器几乎是苹果充…

如何识别真假充电器

本帖最后由 口袋评测 于 2018-8-26 18:48 编辑一,真假鉴定 在我身边&#xff0c;凡是愿意、喜欢用苹果的果粉&#xff0c;都对品质有一种执念&#xff0c;那就是任何配件都要是正品、必须是正品&#xff01;且不说山寨配件对电脑和手机的伤害&#xff0c;单单用脚趾头想一想正品…

苹果充电器怎么辨别真假_如何为iPhone12系列选择充电器?

苹果于北京时间2020年10月14日凌晨一点发布了四款新iPhone&#xff0c;分别为&#xff1a; 5.4寸的iPhone12mini 6.1寸的iPhone12 6.1寸的iPhone12 Pro 6.7寸的iPhone12 Pro max 为了“环保”&#xff0c;今年的四款iPhone均没有配备充电器&#xff0c;用户在购买iPhone12之前必…

java内存区 || 并发

目录 什么是线程&#xff1f; 线程的创建和上下文切换&#xff1a; 线程的入栈和出栈&#xff1a; 堆栈的作用&#xff1a; CPU核心数概念 线程的start状态 就绪队列 操作系统的时间片 线程中代码执行顺序 实际中内存图 什么是线程&#xff1f; 线程的创建和上下文切换…

spring boot+MySQL实现班级综合测评管理系统

随着电子技术的普及和快速发展&#xff0c;线上管理系统被广泛的使用&#xff0c;有很多事业单位和商业机构都在实现电子信息化管理&#xff0c;班级综合测评管理也不例外&#xff0c;由比较传统的人工管理转向了电子化、信息化、系统化的管理。 传统的班级综合测评管理系统&am…