Skip to main content

合并代理和向量存储

本笔记本介绍了如何合并代理和向量存储。这样做的用例是,您已经将数据摄入向量存储中,并希望以代理方式与之交互。

推荐的方法是创建一个RetrievalQA,然后将其作为整体代理中的工具。让我们来看看如何在下面进行操作。您可以使用多个不同的向量数据库来执行此操作,并使用代理作为它们之间的路由器的一种方式。有两种不同的方法可以实现这一点 - 您可以让代理像正常工具一样使用向量存储,或者您可以设置return_direct=True,以便将代理真正用作路由器。

创建向量存储

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 RetrievalQA

llm = OpenAI(temperature=0)

API参考:

from pathlib import Path

relevant_parts = []
for p in Path(".").absolute().parts:
relevant_parts.append(p)
if relevant_parts[-3:] == ["langchain", "docs", "modules"]:
break
doc_path = str(Path(*relevant_parts) / "state_of_the_union.txt")
from langchain.document_loaders import TextLoader

loader = TextLoader(doc_path)
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_documents(documents)

embeddings = OpenAIEmbeddings()
docsearch = Chroma.from_documents(texts, embeddings, collection_name="state-of-union")

API参考:

Running Chroma using direct local API.
Using DuckDB in-memory for database. Data will be transient.
state_of_union = RetrievalQA.from_chain_type(
llm=llm, chain_type="stuff", retriever=docsearch.as_retriever()
)
from langchain.document_loaders import WebBaseLoader

loader = WebBaseLoader("https://beta.ruff.rs/docs/faq/")

API参考:

docs = loader.load()
ruff_texts = text_splitter.split_documents(docs)
ruff_db = Chroma.from_documents(ruff_texts, embeddings, collection_name="ruff")
ruff = RetrievalQA.from_chain_type(
llm=llm, chain_type="stuff", retriever=ruff_db.as_retriever()
)
Running Chroma using direct local API.
Using DuckDB in-memory for database. Data will be transient.

创建代理

# 导入通用所需的工具
from langchain.agents import initialize_agent, Tool
from langchain.agents import AgentType
from langchain.tools import BaseTool
from langchain.llms import OpenAI
from langchain import LLMMathChain, SerpAPIWrapper

API参考:

tools = [
Tool(
name="State of Union QA System",
func=state_of_union.run,
description="用于回答关于最近国情咨文的问题。输入应该是一个完整的问题。",
),
Tool(
name="Ruff QA System",
func=ruff.run,
description="用于回答关于ruff(一个Python linter)的问题。输入应该是一个完整的问题。",
),
]
# 构建代理。我们将在这里使用默认的代理类型。
# 有关选项的完整列表,请参阅文档。
agent = initialize_agent(
tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True
)
agent.run(
"拜登在国情咨文中提到了Ketanji Brown Jackson什么?"
)
> 进入新的AgentExecutor链...
我需要找出拜登在国情咨文中提到了Ketanji Brown Jackson什么。
操作:State of Union QA System
操作输入:拜登在国情咨文中提到了Ketanji Brown Jackson什么?
观察:拜登说Jackson是全国顶级法律人才之一,她将继续Justice Breyer的卓越传统。
思考:我现在知道最终答案了
最终答案:拜登说Jackson是全国顶级法律人才之一,她将继续Justice Breyer的卓越传统。
> 完成链。

"Biden说Jackson是全国顶级法律人才之一,她将继续Justice Breyer的卓越传统。"
agent.run("为什么选择ruff而不是flake8?")
> 进入新的AgentExecutor链...
我需要找出为什么选择ruff而不是flake8的优势
操作:Ruff QA System
操作输入:为什么选择ruff而不是flake8的优势?
观察:当使用(1)没有或只有少量插件,(2)与Black一起以及(3)在Python 3代码上时,Ruff可以作为Flake8的即插即用替代品。它还本地重新实现了一些最受欢迎的Flake8插件和相关代码质量工具,包括isort、yesqa、eradicate以及pyupgrade中实现的大多数规则。Ruff还支持自动修复自己的lint违规,而Flake8不支持。
思考:我现在知道最终答案了
最终答案:当使用(1)没有或只有少量插件,(2)与Black一起以及(3)在Python 3代码上时,Ruff可以作为Flake8的即插即用替代品。它还本地重新实现了一些最受欢迎的Flake8插件和相关代码质量工具,包括isort、yesqa、eradicate以及pyupgrade中实现的大多数规则。Ruff还支持自动修复自己的lint违规,而Flake8不支持。
> 完成链。

'Ruff可以作为Flake8的即插即用替代品,当使用(1)没有或只有少量插件,(2)与Black一起以及(3)在Python 3代码上时。它还本地重新实现了一些最受欢迎的Flake8插件和相关代码质量工具,包括isort、yesqa、eradicate以及pyupgrade中实现的大多数规则。Ruff还支持自动修复自己的lint违规,而Flake8不支持。'

仅将代理用作路由器

如果您打算将代理用作路由器,并且只想直接返回RetrievalQAChain的结果,您还可以设置return_direct=True

请注意,在上面的示例中,代理在查询RetrievalQAChain之后做了一些额外的工作。您可以避免这样做,直接返回结果。

tools = [
Tool(
name="State of Union QA System",
func=state_of_union.run,
description="用于回答关于最近国情咨文的问题。输入应该是一个完整的问题。",
return_direct=True,
),
Tool(
name="Ruff QA System",
func=ruff.run,
description="用于回答关于ruff(一个Python linter)的问题。输入应该是一个完整的问题。",
return_direct=True,
),
]
agent = initialize_agent(
tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True
)
agent.run(
"拜登在国情咨文中提到了Ketanji Brown Jackson什么?"
)
> 进入新的AgentExecutor链...
我需要找出拜登在国情咨文中提到了Ketanji Brown Jackson什么。
操作:State of Union QA System
操作输入:拜登在国情咨文中提到了Ketanji Brown Jackson什么?
观察:拜登说Jackson是全国顶级法律人才之一,她将继续Justice Breyer的卓越传统。

> 完成链。

"拜登说Jackson是全国顶级法律人才之一,她将继续Justice Breyer的卓越传统。"
agent.run("为什么选择ruff而不是flake8?")
> 进入新的AgentExecutor链...
我需要找出为什么选择ruff而不是flake8的优势
操作:Ruff QA System
操作输入:为什么选择ruff而不是flake8的优势?
观察:当使用(1)没有或只有少量插件,(2)与Black一起以及(3)在Python 3代码上时,Ruff可以作为Flake8的即插即用替代品。它还本地重新实现了一些最受欢迎的Flake8插件和相关代码质量工具,包括isort、yesqa、eradicate以及pyupgrade中实现的大多数规则。Ruff还支持自动修复自己的lint违规,而Flake8不支持。

> 完成链。

' Ruff可以作为Flake8的即插即用替代品,当使用(1)没有或只有少量插件,(2)与Black一起以及(3)在Python 3代码上时。它还本地重新实现了一些最受欢迎的Flake8插件和相关代码质量工具,包括isort、yesqa、eradicate以及pyupgrade中实现的大多数规则。Ruff还支持自动修复自己的lint违规,而Flake8不支持。'

多跳向量存储推理

由于向量存储可以轻松用作代理中的工具,因此可以使用现有的代理框架回答依赖于向量存储的多跳问题。

tools = [
Tool(
name="State of Union QA System",
func=state_of_union.run,
description="用于回答关于最近国情咨文的问题。输入应该是一个完整的问题,不引用之前对话中的任何模糊代词。",
),
Tool(
name="Ruff QA System",
func=ruff.run,
description="用于回答关于ruff(一个Python linter)的问题。输入应该是一个完整的问题,不引用之前对话中的任何模糊代词。",
),
]
# 构建代理。我们将在这里使用默认的代理类型。
# 有关选项的完整列表,请参阅文档。
agent = initialize_agent(
tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True
)
agent.run(
"ruff使用什么工具来运行Jupyter Notebooks?总统在国情咨文中提到了那个工具吗?"
)
> 进入新的AgentExecutor链...
我需要找出ruff使用什么工具来运行Jupyter Notebooks,并且总统是否在国情咨文中提到了它。
操作:Ruff QA System
操作输入:ruff使用什么工具来运行Jupyter Notebooks?
观察:Ruff集成到nbQA中,nbQA是一个用于在Jupyter Notebooks上运行linter和代码格式化工具的工具。安装ruff和nbqa后,您可以像这样在笔记本上运行Ruff:> nbqa ruff Untitled.html
思考:我现在需要找出总统是否在国情咨文中提到了这个工具。
操作:State of Union QA System
操作输入:总统是否在国情咨文中提到了nbQA?
观察:不,总统在国情咨文中没有提到nbQA。
思考:我现在知道最终答案。
最终答案:不,总统在国情咨文中没有提到nbQA。
> 完成链。

'不,总统在国情咨文中没有提到nbQA。'