转载自: LangChain初学者入门指南

自从 ChatGPT 发布以来,大语言模型(LLM)变得非常受欢迎。虽然我可能没有足够的资金和计算资源从头训练一个 LLM,但我仍然可以利用预训练的 LLM 来构建一些很酷的东西,比如:

  1. 基于你的数据与外界进行交互的个人助手
  2. 针对你特定需求定制的聊天机器人
  3. 对你的文件或代码进行分析或摘要

由于它们奇怪的 API 和提示工程,LLM 正在改变我们构建 AI 驱动产品的方式。因此,新的开发者工具在 “LLMOps” 这一概念下不断涌现。

LangChain 就是这样一个新工具。

****#01****

什么是 LangChain?

LangChain 是一个框架,旨在帮助你更轻松地构建基于 LLM 的应用程序,它提供以下功能:

  • 通用接口:LangChain 提供了一个通用接口,用于访问多种不同的基础模型。
  • 提示管理:LangChain 提供了一个框架,帮助你管理提示信息。
  • 长期记忆接口:LangChain 提供了与长期记忆、外部数据、其他 LLM 以及其他代理(用于处理 LLM 无法处理的任务,如计算或搜索)的集中接口。

LangChain 是由 Harrison Chase 创建的开源项目,托管在 GitHub 仓库中。

GitHub:https://github.com/hwchase17/langchain

由于 LangChain 具有许多不同的功能,一开始可能会对其作用感到困惑。因此,本文将介绍 LangChain 的六个主要模块,以帮助你更好地了解其功能。

****#02****

先决条件

要按照本教程进行操作,你需要安装 langchain Python 包,并准备好所有相关的 API 密钥。

安装 LangChain

在安装 langchain 包之前,请确保你的 Python 版本为不低于 3.8.1 且低于 4.0。

要安装 langchain Python 包,你可以使用 pip install 命令。


pip install langchain

在本教程中,我们将使用版本号为 0.0.147 的 LangChain。由于 GitHub 存储库经常更新,因此请确保你使用的是最新版本。 设置完成后,导入 langchain Python 包。


import langchain

API 密钥 在使用 LLM 构建应用程序时,你需要获取一些服务的 API 密钥,而且其中一些 API 可能会有相关的费用。

首先,您你要获取一个 LLM 提供者的 API 密钥。目前,我们正在经历 “AI 的 Linux 时刻”,开发者必须在性能和成本之间做出选择,要么使用专有的商业 LLM 模型,要么选择开源的基础模型。

LLM 提供者:专有和开源的基础模型

专有模型是由拥有庞大专家团队和高额 AI 预算的公司拥有的闭源基础模型。它们通常比开源模型更大,因此性能更好,但也会伴随昂贵的 API 费用。专有模型的提供商包括 OpenAI、co:here、AI21 Labs 和 Anthropic。

大多数 LangChain 教程通常使用 OpenAI,但请注意,OpenAI API(用于实验目的并不昂贵,但)并非免费。要获取 OpenAI API 密钥,你需要拥有 OpenAI 账户,然后在 API 密钥下选择 “Create new secret key”。


import os  
os.environ["OPENAI\_API\_KEY"] = ... # insert your API\_TOKEN here

开源模型通常比专有模型小,功能也较为有限,但它们比专有模型更优惠。一些开源模型的示例包括:* BigScience 的 BLOOM

  • Meta AI 的 LLaMA
  • Google 的 Flan-T5
  • Eleuther AI 的 GPT-J

许多开源模型都被整理并托管在 Hugging Face 上,作为一个社区中心。要获得 Hugging Face API 密钥,你需要拥有 Hugging Face 账户,并在 “Access Tokens” 下创建一个 “New token”。


import os  

os.environ["HUGGINGFACEHUB\_API\_TOKEN"] = ... # insert your API\_TOKEN here

在 Hugging Face 上使用开源的 LLM 是免费的,但会有一些限制,例如只能使用较小、性能较低的 LLM。 让我们坦诚一点:当然,你可以在这里尝试使用开源基础模型。我尝试在本教程中仅使用 Hugging Face 上提供的免费开源模型(如 google/flan-t5-xl 和 sentence-transformers/all-MiniLM-L6-v2)。大多数示例都可以工作,但有些示例可能需要一些额外的工作才能使其正常工作。最终,我还是决定注册一个付费账户,使用 OpenAI,因为大多数 LangChain 的示例似乎都针对 OpenAI 的 API 进行了优化。总体而言,为了完成本教程的几个实验,我花费了约 1 美元。

如果你想使用特定的向量数据库,如 Pinecone、Weaviate 或 Milvus,你需要注册并获取 API 密钥,并查看它们的定价信息。在本教程中,我们使用的是不需要注册即可使用的 Faiss。

根据你希望 LLM 与其交互的工具,如 OpenWeatherMap 或 SerpAPI,你可能需要注册并获取 API 密钥,并查看它们的定价信息。在本教程中,我们仅使用不需要 API 密钥的工具。

****#03****

LangChain 可以做什么?

该包提供了通用接口,可访问许多基础模型,并支持提示管理,同时作为其他组件(如提示模板、其他 LLM、外部数据和其他工具)的中央接口。

截至撰写本文时(版本 0.0.147),LangChain 涵盖了六个模块。

以下各节中的代码示例是从 LangChain 文档中复制并修改的。

Model:选择不同的 LLM 和嵌入模型

目前,出现了许多不同的 LLM。LangChain 提供了对多种模型的集成,并为它们提供了简化的接口。

LangChain 将不同类型的模型区分为三类,它们在输入和输出方面存在差异:

LLM 接受字符串作为输入(提示),并输出字符串(完成文本)。


# Proprietary LLM from e.g. OpenAI  
# pip install openai  
from langchain.llms import OpenAI  
llm = OpenAI(model\_name="text-davinci-003")  

# Alternatively, open-source LLM hosted on Hugging Face  
# pip install huggingface\_hub  
from langchain import HuggingFaceHub  
llm = HuggingFaceHub(repo\_id = "google/flan-t5-xl")  

# The LLM takes a prompt as an input and outputs a completion  
prompt = "Alice has a parrot. What animal is Alice's pet?"  
completion = llm(prompt)

LLM 模型

Chat 模型与 LLM 相似。它们接受一个聊天消息的列表作为输入,并返回一个聊天消息。

文本嵌入模型接受文本输入,并返回一个浮点数列表(嵌入),这些浮点数是输入文本的数值表示。嵌入有助于从文本中提取信息。这些信息随后可以在后续使用,例如用于计算文本之间的相似性(例如电影摘要)。


# Proprietary text embedding model from e.g. OpenAI  
# pip install tiktoken  
from langchain.embeddings import OpenAIEmbeddings  
embeddings = OpenAIEmbeddings()  

# Alternatively, open-source text embedding model hosted on Hugging Face  
# pip install sentence\_transformers  
from langchain.embeddings import HuggingFaceEmbeddings  
embeddings = HuggingFaceEmbeddings(model\_name = "sentence-transformers/all-MiniLM-L6-v2")  

# The embeddings model takes a text as an input and outputs a list of floats  
text = "Alice has a parrot. What animal is Alice's pet?"  
text\_embedding = embeddings.embed\_query(text)

文本嵌入模型

Prompt:管理 LLM 的输入

LLM 的 API 使用起来有些奇怪。虽然以自然语言输入提示给 LLM 可能会觉得直观,但要获得所需的输出却需要对提示进行相当多的调整。这个过程被称为提示工程

一旦你有了一个好的提示,你可能希望将其作为其他用途的模板。因此,LangChain 为你提供了所谓的 PromptTemplates,帮助你从多个组件构建提示。


from langchain import PromptTemplate  

template = "What is a good name for a company that makes {product}?"  

prompt = PromptTemplate(  
    input\_variables=["product"],  
    template=template,  
)  

prompt.format(product="colorful socks")

上述提示可以看作是零样本问题设置,即你希望 LLM 在训练时使用了足够相关的数据,以提供令人满意的回答。

另一个改进 LLM 输出的技巧是在提示中添加一些示例,使其成为小样本问题设置。


from langchain import PromptTemplate, FewShotPromptTemplate  

examples = [  
    {"word": "happy", "antonym": "sad"},  
    {"word": "tall", "antonym": "short"},  
]  

example\_template = """  
Word: {word}  
Antonym: {antonym}\n  
"""  

example\_prompt = PromptTemplate(  
    input\_variables=["word", "antonym"],  
    template=example\_template,  
)  

few\_shot\_prompt = FewShotPromptTemplate(  
    examples=examples,  
    example\_prompt=example\_prompt,  
    prefix="Give the antonym of every input",  
    suffix="Word: {input}\nAntonym:",  
    input\_variables=["input"],  
    example\_separator="\n",  
)  

few\_shot\_prompt.format(input="big")

以上代码将生成一个提示模板,并根据提供的示例和输入组合成以下提示:


Give the antonym of every input  

Word: happy  
Antonym: sad  



Word: tall  
Antonym: short  


Word: big  
Antonym:  

Chain:将 LLM 与其他组件结合

在 LangChain 中,Chaining 简单地描述了将 LLM 与其他组件结合以创建应用程序的过程。一些例子包括:

  • 将 LLM 与提示模板结合。
  • 通过将第一个 LLM 的输出作为第二个 LLM 的输入,按顺序组合多个 LLM。
  • 将 LLM 与外部数据结合,例如用于问答系统。
  • 将 LLM 与长期记忆结合,例如用于聊天历史记录。

在上一节中,我们创建了一个提示模板。当我们希望将其与 LLM 一起使用时,可以使用 LLMChain 按照以下方式进行组合:


from langchain.chains import LLMChain  

chain = LLMChain(llm = llm,   
                  prompt = prompt)  

# Run the chain only specifying the input variable.  
chain.run("colorful socks")

如果我们希望将第一个 LLM 的输出作为第二个 LLM 的输入,我们可以使用 SimpleSequentialChain(简单顺序链):


from langchain.chains import LLMChain, SimpleSequentialChain  

# Define the first chain as in the previous code example  
# ...  

# Create a second chain with a prompt template and an LLM  
second\_prompt = PromptTemplate(  
    input\_variables=["company\_name"],  
    template="Write a catchphrase for the following company: {company\_name}",  
)  

chain\_two = LLMChain(llm=llm, prompt=second\_prompt)  

# Combine the first and the second chain   
overall\_chain = SimpleSequentialChain(chains=[chain, chain\_two], verbose=True)  

# Run the chain specifying only the input variable for the first chain.  
catchphrase = overall\_chain.run("colorful socks")

使用 LangChain 中的 PromptTemplates 和 LLM 输出 SimpleSequentialChain

Indexe:访问外部数据

LLM 的一个限制是它们缺乏上下文信息(例如,无法访问某些特定文档或电子邮件)。为了克服这一限制,你可以让 LLM 访问特定的外部数据。

为此,首先需要使用文档加载器加载外部数据。LangChain 提供了各种加载器,适用于不同类型的文档,包括 PDF 文件、电子邮件、网页和 YouTube 视频等。

让我们从 YouTube 视频中加载一些外部数据。如果你希望加载大型文本文档并使用文本拆分器进行分割,可以参考官方文档:

https://python.langchain.com/en/latest/modules/indexes/text_splitters.html


# pip install youtube-transcript-api  
# pip install pytube  

from langchain.document\_loaders import YoutubeLoader  

loader = YoutubeLoader.from\_youtube\_url("https://www.youtube.com/watch?v=dQw4w9WgXcQ")  
      
documents = loader.load()

现在你已经准备好将外部数据作为文档进行索引,可以使用文本嵌入模型在向量数据库中进行索引。流行的向量数据库包括 Pinecone、Weaviate 和 Milvus。在本文中,我们使用 Faiss,因为它不需要 API 密钥。


# pip install faiss-cpu  
from langchain.vectorstores import FAISS  

# create the vectorestore to use as the index  
db = FAISS.from\_documents(documents, embeddings)

现在你的文档(在这种情况下,是一个视频)已经以嵌入形式存储在向量存储中。 现在,你可以使用这些外部数据进行各种操作。让我们使用它来完成一个问题回答任务,借助信息检索器:


from langchain.chains import RetrievalQA  

retriever = db.as\_retriever()  

qa = RetrievalQA.from\_chain\_type(  
    llm=llm,   
    chain\_type="stuff",   
    retriever=retriever,   
    return\_source\_documents=True)  

query = "What am I never going to do?"  
result = qa({"query": query})  

print(result['result'])

RetrievalQA 的输出

等一下 —— 你刚刚被 “Rickroll” 了吗?没错,你被骗了。

Memory:记住先前的对话

对于聊天机器人等应用程序来说,能够记住之前的对话是至关重要的。但是在默认情况下,语言模型缺乏长期记忆能力,除非你输入聊天历史。

使用和不使用会话记忆的聊天

LangChain 通过提供几种不同的选项来处理聊天历史来解决这个问题:

  • 保留所有的对话记录
  • 保留最近的 k 个对话记录
  • 对对话进行摘要

在这个例子中,我们将使用 ConversationChain 来为这个应用程序提供对话记忆功能。


from langchain import ConversationChain  

conversation = ConversationChain(llm=llm, verbose=True)  

conversation.predict(input="Alice has a parrot.")  

conversation.predict(input="Bob has two cats.")  

conversation.predict(input="How many pets do Alice and Bob have?")

这将导致上述图片中右侧的对话形式。如果没有 ConversationChain 来保持对话记忆,对话将会像上图左侧那样。

Agent:访问其他工具

尽管 LLM 非常强大,但它们也有一些限制:它们缺乏上下文信息(例如,无法访问训练数据中未包含的特定知识),它们可能会很快过时(例如,GPT-4 是在 2021 年 9 月之前的数据上进行训练的),并且在处理数学问题时表现不佳。

LLM 数学不好

因为 LLM 在无法独立完成的任务上可能会产生虚构的答案,所以我们需要给它们提供访问辅助工具的权限,例如搜索引擎(如 Google 搜索)、计算器(如 Python REPL 或 Wolfram Alpha)和查询工具(如 Wikipedia)。

另外,我们需要代理来根据 LLM 的输出决定使用哪些工具来完成任务。

需要注意的是,一些 LLM,比如 google/flan-t5-xl,并不适用于下面的示例,因为它们不遵循 “对话 - 反应 - 描述” 模板。因此,对我而言,这是设置付费账户并切换到 OpenAI API 的一个重要因素。

以下是一个示例:代理首先通过 Wikipedia 查找巴拉克・奥巴马的出生日期,然后再用计算器计算他在 2022 年的年龄。


# pip install wikipedia  
from langchain.agents import load\_tools  
from langchain.agents import initialize\_agent  
from langchain.agents import AgentType  

tools = load\_tools(["wikipedia", "llm-math"], llm=llm)  
agent = initialize\_agent(tools,   
                         llm,   
                         agent=AgentType.ZERO\_SHOT\_REACT\_DESCRIPTION,   
                         verbose=True)  


agent.run("When was Barack Obama born? How old was he in 2022?")

LLM 代理的输出

****#04****

总结

就在几个月前,我们(至少大部分人)都对 ChatGPT 的能力感到吃惊。而现在,类似 LangChain 这样的新型开发工具使我们能够在几个小时内在自己的笔记本电脑上构建同样让人吃惊的原型 —— 这真是激动人心的时刻!

LangChain 是一个开源的 Python 库,任何懂编程的人都能够构建基于 LLM 的应用程序。该库提供了通用接口来连接多个基础模型,支持提示管理,并通过代理作为中央接口连接其他组件,如提示模板、其他 LLM、外部数据和其他工具。截止撰写本文时,该库提供了许多未在本文中提及的功能。鉴于当前的快速发展速度,本篇文章可能一个月后就会过时。

在撰写本文时,我注意到该库和文档都以 OpenAI 的 API 为中心。尽管许多示例可以使用开源基础模型 google/flan-t5-xl,但我在中途切换到了 OpenAI API。尽管 OpenAI API 并非免费,但在本文中尝试使用它的成本只有约 1 美元。