本文将会介绍LangChain框架,并以python代码示例来解释该框架的作用,使用到了OpenAI的API,并附上代码和结果,感兴趣的读者可以跟着跑代码。
LangChain 是一个用于构建和部署基于语言模型(如大型语言模型,LLM)的应用程序的框架。想象一下,LangChain 就像是一个工具箱,里面装满了各种工具和指导手册,帮助你更容易地创建和优化与语言相关的软件项目。
LangChain框架的实际作用主要体现在以下几个方面:
1. 开发LLM应用:
2. 集成不同模型和数据:
3. 提供模板和工具:
4. 调试、测试和监控:
5. 部署为API:
6. 处理文档和数据:
7. 构建复杂的工作流:
LangChain 是⽤于不同 LLM 的通⽤接⼝,你可以查阅其⽂档以了解更多信 息。LangChain 的⽂档包含⼀份集成列表,其中涉及 OpenAI 和其他许多 LLM 提供商。⼤多数集成需要 API 密钥才能建⽴连接。对于 OpenAI 模 型,可以在环境变量 OPENAI_API_KEY 中设 置 API 密钥。
from langchain.chat_models import ChatOpenAI
from langchain import PromptTemplate, LLMChain
template = ""
"Question: {question}
Let's think step by step.
Answer: """
prompt = PromptTemplate(template=template,
input_variables=["question"])
llm = ChatOpenAI(model_name="gpt-4")
llm_chain = LLMChain(prompt=prompt, llm=llm)
question = """ What is the population of the capital of the country
where the Olympic Games were held in 2016? """
llm_chain.run(question)
PromptTemplate 负责构建模型的输⼊。也就是说,它能以可复制的⽅式 ⽣成提⽰词。它包含⼀个名为 template 的输⼊⽂本字符串,其中的值可 以通过 input_variables 进⾏指定。在本例中,我们定义的提⽰词会⾃ 动将 “Let's think step by step” 部分添加到问题中。
本例使⽤的 LLM 是 gpt-4 。⽬前默认模型是 gpt-3.5-turbo 。ChatOpenAI 函数将模型的名称赋给变量 llm 。这个函数假定⽤户在环境变量OPENAI_API_KEY 中设置了 API 密钥 。
提⽰词和模型由 LLMChain 函数组合在⼀起,形成包含这两个元素的⼀条 链。最后,我们需要调⽤ run 函数来请求补全输⼊问题。当运⾏ run 函数 时, LLMChain 使⽤提供的输⼊键值(以及可⽤的记忆键值)格式化提⽰词模板,随后将经过格式化的字符串传递给 LLM ,并返回 LLM 输出。我 们可以看到,模型运⽤ “ 逐步思考 ” 的技巧⾃动回答问题。
智能体及⼯具是 LangChain 框架提供的关键功能:它们可以使应⽤程序变 得⾮常强⼤,让 LLM 能够执⾏各种操作并与各种功能集成,从⽽解决复杂 的问题。
这⾥所指的 “ ⼯具 ” 是围绕函数的特定抽象,使语⾔模型更容易与之交互。智能体可以使⽤⼯具与世界进⾏交互。具体来说,⼯具的接⼝有⼀个⽂本 输⼊和⼀个⽂本输出。LangChain 中有许多预定义的⼯具,包括⾕歌搜索、 维基百科搜索、 Python REPL 、计算器、世界天⽓预报 API 等。要获取完整 的⼯具列表,请查看 LangChain ⽂档中的⼯具⻚⾯。除了使⽤预定义的⼯ 具,你还可以构建⾃定义⼯具并将其加载到智能体中,这使得智能体⾮常 灵活和强⼤。
本节介绍⼀种适⽤于应⽤程序的智能体,它需要⼀系列中间步骤。该智能 体安排执⾏这些步骤,并可以⾼效地使⽤各种⼯具响应⽤户的查询。从某 种意义上说,因为 “ 逐步思考 ” ,所以智能体有更多的时间来规划⾏动,从 ⽽完成更复杂的任务。
智能体安排的步骤如下所述。
智能体收到来⾃⽤户的输⼊。
智能体决定要使⽤的⼯具(如果有的话)和要输⼊的⽂本。
使⽤该输⼊⽂本调⽤相应的⼯具,并从⼯具中接收输出⽂本。
将输出⽂本输⼊到智能体的上下⽂中。
重复执⾏步骤 2 〜步骤 4 ,直到智能体决定不再需要使⽤⼯具。此时, 它将直接回应⽤户。
使用工具的好处
就本节⽽⾔,我们希望模型能够回答以下问题:2016 年奥运会举办国⾸都 的⼈⼝的平⽅根是多少?这个问题并没有特殊的含义,但它很好地展⽰了 LangChain 智能体及⼯具如何提⾼ LLM 的推理能⼒。
如果将问题原封不动地抛给 GPT-3.5 Turbo ,那么我们会得到以下回答:
The capital of the country where the Olympic Games were held in 2016 is Rio de Janeiro, Brazil. The population of Rio de Janeiro is approximately 6.32 million people as of 2021. Taking the square root of this population, we get approximately 2,513.29. Therefore, the square root of the population of the capital of the country where the Olympic Games were held in 2016 is approximately 2,513.29
这个回答⾄少有两处错误:巴⻄的⾸都是巴⻄利亚,⽽不是⾥约热内卢;6 320 000 的平⽅根约等于 2513.96 ,⽽不是 2513.29 。我们可以通过运⽤ “ 逐 步思考 ” 或其他提⽰⼯程技巧来获得更好的结果,但由于模型在推理和数学 运算⽅⾯存在困难,因此我们很难相信结果是准确的。使⽤ LangChain 可 以给我们更好的准确性保证。
如以下代码所⽰, LangChain 智能体可以使⽤两个⼯具:维基百科搜索和计 算器。在通过 load_tools 函数创建⼯具之后,我们使⽤ initialize_agent 函数创建智能体。智能体的推理功能需要⽤到⼀个 LLM ,本例使⽤的是 gpt-3.5-turbo 。参数 ZERO_SHOT_REACT_DESCRIPTION 定义了智能体如何在每⼀步中选择⼯ 具。通过将 verbose 的值设置为 True ,我们可以查看智能体的推理过 程,并理解它是如何做出最终决策的。
from langchain.chat_models import ChatOpenAI
from langchain.agents import load_tools, initialize_agent, AgentType
llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)
tools = load_tools(["wikipedia", "llm-math"], llm=llm)
agent = initialize_agent(
tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True
)
question = """What is the square root of the population of the capital of the Country where the Olympic Games were held in 2016?"""
agent.run(question)
在使⽤维基百科搜索⼯具之前,需要安装相应的 Python 包 wikipedia 。可以使⽤ pip install wikipedia 来安装这个包。
正如你所看到的,智能体决定查询维基百科以获取有关 2016 年奥运会的信息:
> Entering new chain...
I need to find the country where the Olympic Games were held in 2016 and then find the population of its capital city. Then I can take the square root of that population.
Action: Wikipedia
Action Input: "2016 Summer Olympics"
Observation: Page: 2016 Summer Olympics
[...]
输出的下⼀⾏包含维基百科关于奥运会的摘录。接下来,智能体使⽤维基 百科搜索⼯具⼜进⾏了两次额外的操作:
Thought:I need to search for the capital city of Brazil.
Action: Wikipedia
Action Input: "Capital of Brazil"
Observation: Page: Capitals of Brazil
Summary: The current capital of Brazil, since its construction in 1960, is Brasilia. [...]
Thought: I have found the capital city of Brazil, which is Brasilia.
Now I need to find the population of Brasilia.
Action: Wikipedia
Action Input: "Population of Brasilia"
Observation: Page: Brasilia
[...]
下⼀步,智能体使⽤计算器⼯具:
Thought: I have found the population of Brasilia, but I need to calculate the square root of that population.
Action: Calculator
Action Input: Square root of the population of Brasilia (population: found in previous observation)
Observation: Answer: 1587.051038876822
得出最终答案:
Thought: I now know the final answer
Final Answer: The square root of the population of the capital of the country where the Olympic Games were held in 2016 is approximately 1587.
> Finished chain.
正如你所⻅,该智能体展⽰了较强的推理能⼒:在得出最终答案之前,它 完成了 4 个步骤。LangChain 框架使开发⼈员能够仅⽤⼏⾏代码就实现这种 推理能⼒。
在某些应⽤程序中,记住之前的交互是⾄关重要的,⽆论是短期记忆还是 ⻓期记忆。使⽤ LangChain ,你可以轻松地为链和智能体添加状态以管理记 忆。构建聊天机器⼈是这种能⼒最常⻅的⽤例。在 LangChain 中,你可以 使⽤ ConversationChain 很快地完成这个过程,只需⼏⾏代码即可将语 ⾔模型转换为聊天⼯具。
以下代码使⽤ text-ada-001 模型创建⼀个聊天机器⼈。这是⼀个只能执⾏基 本任务的⼩模型。然⽽,它是 GPT-3 系列中速度最快、成本最低的模型。该模型从未针对聊天任务做过微调,但我们可以看到,只需⼏⾏ LangChain 代码,即可使⽤这个简单的⽂本补全模型开始聊天:
from langchain import OpenAI, ConversationChain
chatbot_llm = OpenAI(model_name='text-ada-001')
chatbot = ConversationChain(llm=chatbot_llm , verbose=True)
chatbot.predict(input='Hello')
在以上代码的最后⼀⾏,我们执⾏了 predict(input='Hello') 。这要 求聊天机器⼈回复我们的 'Hello' 消息。模型的回答如下所⽰:
> Entering new ConversationChain chain...
Prompt after formatting:
The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it
truthfully says it does not know.
Current conversation:
Human: Hello
AI:
> Finished chain.
' Hello! How can I help you?'
由于将 ConversationChain 中的 verbose 设置为 True ,因此我们可 以查看 LangChain 使⽤的完整提⽰词。当我们执⾏ predict(input='Hello') 时, text-ada-001 模型收到的不仅仅是 'Hello' 消息,⽽是完整的提⽰词。该提⽰词位于标签 > Entering new ConversationChain chain... 和 > Finished chain 之间。
如果继续对话,我们会发现该函数在提⽰词中保留了对话的历史记录。如 果我们接着问模型是不是 AI ,那么这个问题也将被包含在提⽰词中:
> Entering new ConversationChain chain...
Prompt after formatting:
The following [...] does not know.
Current conversation:
Human: Hello
AI: Hello! How can I help you?
Human: Can I ask you a question? Are you an AI?
AI:
> Finished chain.
'\n\nYes, I am an AI.'
ConversationChain 对象使⽤提⽰⼯程技巧和记忆技巧,将进⾏⽂本补 全的 LLM 转换为聊天⼯具。
尽管 LangChain 让所有语⾔模型拥有了聊天能⼒,但这个解决 ⽅案并不像 GPT-3.5 Turbo 和 GPT-4 这样强⼤,后两者已经专门针对聊 天任务进⾏了优化。此外, OpenAI 已经宣布弃⽤ text-ada-001 模型。
将语⾔模型与你⾃⼰的⽂本数据相结合,这样做有助于将应⽤程序所⽤的 模型知识个性化。
⾸先检索信息,即获取⽤户 的查询并返回最相关的⽂档;然后将这些⽂档发送到模型的输⼊上下⽂ 中,以便它响应查询。本节展⽰使⽤ LangChain 和嵌⼊技术实现这⼀点是 多么简单。
document_loaders 是 LangChain 中的⼀个重要模块。通过这个模块,你可以 快速地将⽂本数据从不同的来源加载到应⽤程序中。⽐如,应⽤程序可以加载 CSV ⽂件、电⼦邮件、 PowerPoint ⽂档、 Evernote 笔记、 Facebook 聊 天记录、 HTML ⻚⾯、 PDF ⽂件和许多其他格式。要查看完整的加载器列 表,请查阅 LangChain ⽂档。每个加载器设置起来都⾮常简单。
如果 PDF ⽂件位于当前⼯作⽬录下,则以下代码将加载⽂件内容并按⻚进 ⾏划分。
from langchain.document_loaders import PyPDFLoader
loader = PyPDFLoader("ExplorersGuide.pdf")
pages = loader.load_and_split()
在使⽤ PDF 加载器之前,需要安装 pypdf 包。这可以通过 pip install pypdf 来完成。
进⾏信息检索时,需要嵌⼊每个加载的⻚⾯。正如我们在第 2 章中讨论的 那样,在信息检索中,嵌⼊是⽤于将⾮数值概念(如单词、标记和句⼦) 转换为数值向量的⼀种技术。这些嵌⼊使得模型能够⾼效地处理这些概念 之间的关系。借助 OpenAI 的嵌⼊端点,开发⼈员可以获取输⼊⽂本的数值 向量表⽰。此外, LangChain 提供了⼀个包装器来调⽤这些嵌⼊,如下所示。
from langchain.embeddings import OpenAIEmbeddings
embeddings = OpenAIEmbeddings()
要使⽤ OpenAIEmbeddings ,请先使⽤ pip install tiktoken 安装 tiktoken 包。
索引保存⻚⾯嵌⼊并使搜索变得容易。LangChain 以向量数据库为中⼼。有 许多向量数据库可供选择,详⻅ LangChain ⽂档。以下代码⽚段使⽤ Faiss 向量数据库,这是⼀个主要由 Facebook AI 团队开发的相似性搜索库。
from langchain.vectorstores import FAISS
db = FAISS.from_documents(pages, embeddings)
在使⽤ Faiss 向量数据库之前,需要使⽤ pip install faiss-cpu 命令安装 faiss-cpu 包。
下图展⽰了 PDF ⽂件的内容如何被转换为嵌⼊向量并存储在 Faiss 向量数 据库中。
q = "What is Link's traditional outfit color?"
db.similarity_search(q)[0]
我们得到以下内容:
Document(page_content='While Link’s traditional green tunic is certainly an iconic look, his wardrobe has expanded [...] Dress for Success',
metadata={'source': 'ExplorersGuide.pdf', 'page': 35})
这个问题的答案是, Link 的服装颜⾊是绿⾊。我们可以看到,答案就在选 定的内容中。输出显⽰,答案在 ExplorersGuide.pdf 的第 35 ⻚。请记住, Python 从 0 开始计数。因此,如果查看原始 PDF ⽂件,你会发现答案在第 36 ⻚,⽽⾮第 35 ⻚。
下图显⽰了信息检索过程如何使⽤查询的嵌⼊和向量数据库来识别与查询 最相似的⻚⾯。
你可能希望将嵌⼊整合到聊天机器⼈中,以便在回答问题时使⽤它检索到 的信息。再次强调,使⽤ LangChain ,只需⼏⾏代码即可轻松实现。我们使 ⽤ RetrievalQA ,它接受 LLM 和向量数据库作为输⼊。然后,我们像往 常⼀样向所获得的对象提问:
from langchain.chains import RetrievalQA
from langchain import OpenAI
llm = OpenAI()
chain = RetrievalQA.from_llm(llm=llm, retriever=db.as_retriever())
q = "What is Link's traditional outfit color?"
chain(q, return_only_outputs=True)
我们得到以下答案:
{'result': " Link's traditional outfit color is green."}
下图显⽰了 RetrievalQA 如何使⽤信息检索来回答⽤户的问题。正如 我们从图中看到的, “ 提供上下⽂ ” 将信息检索系统找到的⻚⾯和⽤户最初 的查询进⾏分组。然后,上下⽂被发送给 LLM 。LLM 可以利⽤上下⽂中的 附加信息正确回答⽤户的问题。
你可能会问:为什么在将信息添加到 LLM 的上下⽂中之前需要进⾏信息检 索?事实上,⽬前已有的语⾔模型⽆法处理包含数百⻚的⼤型⽂件。因 此,如果输⼊⽂件过⼤,那么我们会对其进⾏预过滤。这是信息检索过程 的任务。我们对比一下RAG的流程图,也许也可以发现一些关联了。
在不久的将来,随着输⼊上下⽂的不断增加,可能就不再需要使 ⽤信息检索技术了。
来源:古月居
本文仅做学术分享,如有侵权,请联系删文。