LangChain 入门:构建 LLM 支持的应用程序的初学者指南[译]
使用 Python 构建大型语言模型的 LangChain 教程
自ChatGPT发布以来,大型语言模型(LLM)变得非常受欢迎。尽管你可能没有足够的资金和计算资源在地下室中从头开始训练一个LLM,但你仍然可以使用已经预先训练好的LLM来构建一些很酷的东西,比如:
- Personal assistants 可以根据您的数据与外界互动的个人助理
- Chatbots可以与您的客户进行对话的聊天机器人
- Analysis or summarization 对您的文档或代码的分析或总结
LLMs正在改变我们构建基于人工智能的产品的方式
凭借其奇怪的API和迅速的工程能力,LLM正在改变我们构建AI驱动产品的方式。这就是为什么以“LLMOps”为名字的新开发者工具在各个地方涌现的原因。
LangChain就是这些新工具之一。
什么是LangChain?
LangChain是一个框架,旨在通过提供以下内容来帮助您更轻松地构建基于LLM的应用程序:
- 各种不同基础模型的通用接口(see Models)
- 一个框架,帮助您管理提示信息(see Prompts)
- 一个连接长期记忆(see Memory)、外部数据(see Indexes)、其他LLMs(see Chains)和其他代理人的中央界面,用于处理LLM无法处理的任务(例如计算或搜索)(参见代see Agents)
它是由 Harrison Chase 创建的开源项目(GitHub)。
由于LangChain具有许多不同的功能,一开始可能很难理解它的作用。因此,在本文中,我们将介绍LangChain目前的六个关键模块,以便让您更好地了解其功能。
先决条件
为了按照本教程进行操作,您需要安装langchain Python包并准备好所有相关的API密钥以供使用。
LangChain 安装
在安装 langchain 包之前,请确保您拥有 ≥ 3.8.1 和 <4.0 的 Python 版本。
要安装 langchain Python 包,您可以 pip 安装它。
pip install langchain
在本教程中,我们使用版本 0.0.147。 GitHub库非常活跃;因此,请确保您拥有最新版本。
完成所有设置后,导入 langchain Python 包。
import langchain
API 密钥
构建具有LLMs的应用程序需要您想要使用的一些服务的API密钥,并且一些API相关联的费用。
LLM服务提供商(必需)- 首先,您需要一个用于所选择的LLM服务提供商的API密钥。我们目前正在经历“人工智能的Linux时刻”,开发者必须在性能和成本之间做出权衡,选择使用专有或开源的基础模型作为基础。
专有模型是由拥有大型专家团队和庞大的人工智能预算的公司所拥有的闭源基础模型。它们通常比开源模型更大,因此具有更好的性能,但也具有昂贵的应用程序编程接口(API)。专有模型提供商的例子有OpenAI、co:here、AI21 Labs或Anthropic。
大多数可用的LangChain教程使用OpenAI,但值得注意的是,OpenAI API 并非免费。要获取OpenAI API密钥,您需要拥有OpenAI帐户,然后在API密钥下选择“创建新的秘密密钥”。当 然,您也可以选择Api2Gpt提供的中转服务。
import os
os.environ["OPENAI_API_BASE"] = "https://api.api2gpt.com"
os.environ["OPENAI_API_KEY"] = ... # insert your API_TOKEN here
开源模型通常比专有模型规模较小,能力较低,但它们比专有模型更具成本效益。开源模型的例子包括:
许多开源模型都作为一个社区中心组织和托管在 Hugging Face 上。要获取 Hugging Face API 密钥,您需要一个 Hugging Face 帐户,并在访问令牌下创建一个“新的令牌”。
import os
os.environ["HUGGINGFACEHUB_API_TOKEN"] = ... # insert your API_TOKEN here
您可以免费使用Hugging Face用于开源的LLMs,但是您的使用将受到性能较低且更小的LLMs的限制。
一则个人声明——让我们坦率地说一下:当然,你可以在这里尝试使用开源基础模型。我试图只用存放在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密钥的工具。
LangChain 可以做什么?
该软件包提供了通用接口,用于许多基础模型的管理,并通过代理机制作为其他组件(如提示模板、其他LLM、外部数据和其他工具)的中央接口。
在撰写本文时,LangChain(版本0.0.147)涵盖了六个模块:
- 模型(Models):从不同的LLM和嵌入模型中进行选择
- 提示(Prompts):管理LLM的输入
- 链式结构(Chains):将LLM与其他组件相结合
- 索引(Indexes):访问外部数据
- 记忆(Memory):记录以前的对话
- 代理(Agents):访问其他工具
以下部分中的代码示例是从LangChain文档复制并修改的。
模型:从不同的LLM和嵌入式模型中选择
目前,出现了许多不同的LLM。LangChain为各种模型提供集成,并为所有模型提供简化的界面。
LangChain将不同的模型区分为三种类型,它们在输入和输出上有所不同:
- LLMs以字符串作为输入(提示)并输出一个字符串(完成)。
# 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类似。它们以一组聊天消息作为输入,并返回一个聊天消息。
文本嵌入模型接受文本输入并返回一组浮点数(嵌入),这些数字是输入文本的数值表示。嵌入有助于从文本中提取信息。稍后可以使用这些信息进行各种用途,例如计算文本之间的相似性(例如电影摘要)。
python# 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)
提示词:管理 LLM 输入
LLMs的API很奇怪。尽管在自然语言中向LLMs输入提示应该是直观的,但直到你通过稍微调整提示来获得所需的输出为止,需要花费相当多的功夫。这个过程称为提示工程。
一旦您有了一个好的提示,您可能希望将其用作其他目的的模板。因此,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:
链式结构:将 LLM 与其他组件相结合
LangChain中的链式操作仅描述将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")
索引:访问外部数据
LLM的一个限制是缺乏上下文信息(例如,无法访问某些特定文件或电子邮件)。您可以通过让LLM访问特定的外部数据来解决这个问题。
为此,您首先需要使用文档加载器加载外部数据。LangChain提供了各种加载器,可以处理不同类型的文档,包括PDF文档、电子邮件、网站和YouTube视频。
我们来加载一些来自YouTube视频的外部数据。如果您想要加载一个大型文本文档并使用文本分割器对其进行拆分,可以参考官方文档。
# 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'])
等一下——你刚才被恶搞了吗?是的,是的。
记忆:记住以前的对话
对于像聊天机器人这样的应用程序来说,它们能够记住以前的对话是至关重要的。但是默认情况下,LLMs没有任何长期记忆,除非您输入聊天历史。
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来保持对话记忆,对话将看起来像上述图像中左侧的那个。
代理人: 访问其他工具
尽管功能强大,但LLM也有一些局限性:它们缺乏上下文信息(例如,无法访问训练数据中未包含的特定知识),它们可能会很快过时(例如,GPT-4是在2021年9月之前的数据上进行训练的),并且在数学方面表现不佳。
由于大型语言模型在无法独立完成的任务上可能会出现虚构情况,所以我们需要为它们提供补充工具的访问权限,如搜索引擎(例如Google搜索)、计算器(例如Python REPL或Wolfram Alpha)和查询工具(例如维基百科)。
另外,我们需要代理人根据LLM的输出来做出关于使用哪些工具来完成任务的决策。
以下是一个示例,代理首先使用维基百科查找巴拉克·奥巴马的出生日期,然后用计算器计算他在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?")
摘要
就在几个月前,我们所有人(或者至少大部分人)都对ChatGPT的能力感到印象深刻。现在,类似LangChain这样的新型开发者工具让我们能够在几小时内在笔记本电脑上构建同样令人印象深刻的原型——这真是令人激动的时代!
LangChain是一个开源的Python库,它使得任何会编写代码的人都能构建基于LLM技术的应用程序。该软件包提供了对许多基础模型的通用接口,可以进行提示管理,并通过代理为其他组件(如提示模板、其他LLM模型、外部数据和其他工具)提供集中接口 —— 在撰写本文时。
该库提供了比本文中提到的更多功能。随着目前的开发速度,本文在一个月后也可能已经过时。
在撰写本文时,我注意到该库和文档都围绕OpenAI的API展开。尽管有很多示例是使用开源的基础模型google/flan-t5-xl运行的,但我后来改用了OpenAI的API。虽然不是免费的,在本文中使用OpenAI的API实验只花费我大约1美元。