使用 Python 将 LangChain 与 Ollama 结合使用¶
假设我们正在研究如 荷马 的 奥德赛 这样的经典作品。我们可能对涅柳斯及其家族有疑问。如果你向llama2询问这些信息,你可能会得到这样的回答:
对不起,我是一个大型语言模型,我无法提供关于现实中不存在的个人或家庭的信息。涅柳斯不是一个真实的人物或角色,因此没有家庭或其他个人细节。对于任何混淆,我表示歉意。还有其他我可以帮忙的吗?
这听起来像是一个典型的审查回应,但即使是未经审查的llama2也只能给出一个普通的回答:
涅柳斯是皮洛斯的传说中的国王,是阿尔戈英雄之一涅斯托的父亲。他的母亲是海仙女克里墨涅,而他的父亲是海神尼普顿。
那么,让我们看看如何使用 LangChain 和 Ollama 向 荷马的奥德赛 这本真实的文档提问,我们使用 Python 来实现这一点。
首先,我们尝试提出一个能够从 Llama2 模型中得到答案的简单问题。首先,我们需要安装 LangChain 包:
pip install langchain
然后我们可以创建一个模型并提出问题:
from langchain.llms import Ollama
ollama = Ollama(base_url='http://localhost:11434',
model="llama2")
print(ollama("why is the sky blue"))
注意,我们正在定义模型和 Ollama 的基本 URL。
现在让我们加载一个文档来提出问题。我将加载荷马的《奥德赛》,你可以在古腾堡计划中找到。我们需要 LangChain 的 WebBaseLoader 来从任何网页加载文本。在我的机器上,我还需要安装 bs4 来使其工作,所以运行 pip install bs4
。
from langchain.document_loaders import WebBaseLoader
loader = WebBaseLoader("https://www.gutenberg.org/files/1727/1727-h/1727-h.htm")
data = loader.load()
这个文件相当大。仅序言就有3000个令牌。这意味着整个文档不会适合模型的上下文。所以我们需要将其分割成更小的片段。
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter=RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=0)
all_splits = text_splitter.split_documents(data)
文件被分割后,我们必须找到相关的分割部分,然后将它们提交给模型。我们可以通过创建嵌入并将它们存储在向量数据库中来实现这一点。我们可以直接使用 Ollama 实例化一个嵌入模型。在此示例中,我们将使用 ChromaDB 作为向量数据库。pip install chromadb
from langchain.embeddings import OllamaEmbeddings
from langchain.vectorstores import Chroma
oembed = OllamaEmbeddings(base_url="http://localhost:11434", model="nomic-embed-text")
vectorstore = Chroma.from_documents(documents=all_splits, embedding=oembed)
现在让我们从文档中提问。涅柳斯是谁,他的家族有谁? 涅柳斯是《奥德赛》中的一个角色,答案可以在我们的文本中找到。
question="Who is Neleus and who is in Neleus' family?"
docs = vectorstore.similarity_search(question)
len(docs)
这将输出与搜索相似的数据块的匹配数量。
接下来的事情是将问题和文档的相关部分发送给模型,看看我们是否能得到一个好的答案。但我们是在将两部分过程拼接在一起,这称为链。这意味着我们需要定义一个链:
from langchain.chains import RetrievalQA
qachain=RetrievalQA.from_chain_type(ollama, retriever=vectorstore.as_retriever())
qachain.invoke({"query": question})
这个链返回的答案是:
涅柳斯是荷马的《奥德赛》中的一个角色,在描述佩涅洛珀的求婚者时被提及。涅柳斯是克洛里斯的父亲,克洛里斯嫁给了涅柳斯,为他生了几个孩子,包括涅斯托、克罗米乌斯、珀里克吕门努斯和珀罗。阿姆菲诺穆斯是尼休斯的儿子,也是佩涅洛珀的求婚者之一,以其良好的自然性格和令人愉快的谈吐而闻名。
答案不完美,因为它暗示涅柳斯娶了他的女儿,实际上克洛里斯是“Iasus之子、米尼安奥尔科墨诺斯国王Amphion的最年轻的女儿,是皮洛斯的王后”。
我将文本分割器的 chunk_overlap 更新为20,再次尝试,得到了一个更好的答案:
涅柳斯是荷马史诗诗篇《奥德赛》中的一个角色。他是克洛里斯的丈夫,克洛里斯是Iasus之子、米尼安奥尔科墨诺斯国王Amphion的最年轻女儿。涅柳斯与克洛里斯一起有几个孩子,包括涅斯托、克罗米乌斯、珀里克吕门努斯和珀罗。
这是一个更好的答案。