跳转到主要内容

category

LangChain教程,用于在Python中使用大型语言模型构建任何东西

Two stochastic parrots sitting on a chain of large language models: LangChain

“What did the stochastic parrot say to the other?” (Image drawn by the author)

自从ChatGPT发布以来,大型语言模型(LLM)获得了很大的流行。尽管你可能没有足够的资金和计算资源在地下室从头开始训练LLM,但你仍然可以使用预先训练的LLM来构建一些很酷的东西,例如:

  • 可以根据您的数据与外界互动的个人助理
  • 为您的目的定制聊天机器人
  • 对您的文档或代码进行分析或总结

LLM正在改变我们构建人工智能产品的方式

凭借其怪异的API和快速的工程,LLM正在改变我们构建人工智能产品的方式。这就是为什么新的开发人员工具在“LLMOps”一词下无处不在。

LangChain就是其中一个新工具。

什么是LangChain?

LangChain是一个框架,旨在通过为您提供以下功能,帮助您更轻松地构建LLM驱动的应用程序:

  • 到各种不同基础模型的通用接口(参见模型),
  • 帮助您管理提示的框架(请参见提示),以及
  • 到长期内存(请参阅内存)、外部数据(请参阅索引)、其他LLM(请参阅链)以及LLM无法处理的任务(例如计算或搜索)的其他代理的中央接口(请参阅代理)。

这是一个开源项目(GitHub存储库),由Harrison Chase创建。

因为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密钥

使用LLM构建应用程序需要您想要使用的某些服务的API密钥,而某些API具有相关成本。

LLM提供程序(必需)-您首先需要要使用的LLM提供器的API密钥。我们目前正在经历“人工智能的Linux时刻”,开发人员必须在专有或开源基础模型之间做出选择,主要基于性能和成本之间的权衡。

LLM Providers: Proprietary and open-source foundation models

LLM Providers: Proprietary and open-source foundation models (Image by the author, inspired by Fiddler.ai, first published on W&B’s blog)

专有模型是由拥有大型专家团队和庞大人工智能预算的公司拥有的开源基础模型。它们通常比开源模型更大,因此具有更好的性能,但也有昂贵的API。专有模型提供商的例子有OpenAI、co-here、AI21实验室或Anthropic。

大多数可用的LangChain教程都使用OpenAI,但请注意,OpenAI API(实验并不昂贵,但它并不免费)并非免费。要获得OpenAI API密钥,您需要一个OpenAI帐户,然后在API密钥下“创建新密钥”。

import os
os.environ["OPENAI_API_KEY"] = ... # insert your API_TOKEN here

开源模型通常是比专有模型功能更低的较小模型,但它们比专有模型更具成本效益。开源模型的例子有:

许多开源模型都是在Hugging Face上组织和托管的,作为社区中心。要获得一个Hugging Face API密钥,您需要一个Hughing 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密钥的工具。

你能用LangChain做什么?

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

在撰写本文时,LangChain(版本0.0.147)涵盖了六个模块:

以下部分中的代码示例是从LangChain文档中复制和修改的。

模型:从不同的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 models take a prompt as an input and a completion as an output

LLM models (Image by the author)

  • 聊天模型与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)

Text embedding models take a text as an input and output its numerical representation as a list of floats

Text embedding models (Image by the author)

提示:管理LLM输入

LLM有奇怪的API。虽然用自然语言向LLM输入提示应该感觉很直观,但在从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:

链:将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")

Output of a SimpleSequentialChain using PromptTemplates and LLMs in LangChain

索引:访问外部数据

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()

现在您已经准备好将外部数据作为文档使用,您可以在矢量数据库VectorStore中使用文本嵌入模型(请参见模型)对其进行索引。流行的病媒数据库包括松果、黄鼠狼和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'])

Output of the RetrievalQA (Screenshot by the author)

等一下-你刚被灌了吗?是的,你做到了。

记忆:回忆以前的对话

对于聊天机器人这样的应用程序来说,它们能够记住以前的对话是至关重要的。但默认情况下,LLM没有任何长期记忆,除非你输入聊天历史。

Chat with and without conversational memory of LLM

Chat with and without conversational memory (Image by the author made with ifaketextmessage.com, inspired by Pinecone)

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月之前就对数据进行了训练),而且它们不擅长数学。

LLMs are bad at math

由于LLM可能会对自己无法完成的任务产生幻觉,我们需要让他们访问补充工具,如搜索(如谷歌搜索)、计算器(如Python REPL或Wolfram Alpha)和查找(如维基百科)。

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

请注意,一些LLM(如google/flan-t5-xl)不适合以下示例,因为它们不遵循会话反应描述模板。对我来说,这就是我在OpenAI上建立付费帐户并切换到OpenAI API的时候。

以下是一个例子,特工首先在维基百科上查找巴拉克·奥巴马的出生日期,然后用计算器计算他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?")

Output of the LLM agent (Screenshot by the author)

总结

就在几个月前,我们所有人(或至少大多数人)都对ChatGPT的能力印象深刻。现在,像LangChain这样的新开发工具使我们能够在几个小时内在笔记本电脑上构建同样令人印象深刻的原型——这是一个真正令人兴奋的时刻!

LangChain是一个开源Python库,它使任何能够编写代码的人都能够构建LLM驱动的应用程序。在编写本文时,该包为许多基础模型提供了通用接口,支持提示管理,并通过代理充当其他组件(如提示模板、其他LLM、外部数据和其他工具)的中央接口。

该库提供了比本文中提到的更多的功能。以目前的发展速度,这篇文章也可能在一个月内过时。

在撰写本文时,我注意到该库和文档以OpenAI的API为中心。尽管许多示例都适用于开源基础模型google/flan-t5-xl,但我在两者之间切换到了OpenAI API。尽管不是免费的,但在本文中尝试OpenAI API只花了我大约1美元。

喜欢这个故事吗?

免费订阅,以便在我发布新故事时收到通知。

 

文章链接