写点什么

LangChain 初学者指南

作者:俞凡
  • 2023-12-26
    上海
  • 本文字数:5985 字

    阅读完需:约 20 分钟

LLM 可以帮助我们将 AI 能力接入应用,LangChain 作为开源工具,提供了接入各种主流 LLM 的接口,从而让我们以非常低的成本构建基于 LLM 的 AI 应用。原文: Getting Started with LangChain: A Beginner’s Guide to Building LLM-Powered Applications



自从 ChatGPT 发布以来,大语言模型(LLM)得到极大普及。虽然大多数人没有足够资金和计算资源从头开始训练 LLM,但仍然可以基于预训练的 LLM 来构建一些很酷的东西,例如:



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


凭借其奇怪的 API 和提示工程,LLM 正在改变我们构建人工智能产品的方式。这就是为什么出现大量冠以"LLMOps"名义的新开发工具的原因。


其中一个新工具就是LangChain

什么是 LangChain?

LangChain 是一个帮助我们轻松构建 LLM 驱动的应用程序的框架,提供以下功能:


  • 各种不同基础模型的通用接口

  • 帮助管理提示的框架,以及

  • 连接长期内存、外部数据、其他 LLM,以及 LLM 无法处理的任务(例如,计算或搜索)的其他代理的中心化接口。


LangChain 是由Harrison Chase创建的开源项目。


因为 LangChain 有很多不同功能,所以从头开始理解其功能可能会很有挑战性。这就是为什么我们将在本文中介绍 LangChain(目前)的六个关键模块,从而帮助读者更好理解它的功能。

前提条件

要继续学习本教程,需要安装langchain Python 包并准备好使用所有相关 API 的密钥。

安装 LangChain

在安装langchain包之前,请确保 Python 版本≥3.8.1 且<4.0。


可以通过pip安装langchain包。


pip install langchain
复制代码


本文使用 0.0.147 版本,由于 LangChainb 的 GitHub 非常活跃,因此请确保安装当前版本。


完成所有设置后,导入langchain Python 包。


import langchain
复制代码
API 密钥

基于 LLM 构建应用需要使用某些服务的 API 密钥,有些 API 是收费的。


LLM 服务商(必需的) - 首先需要 LLM 服务商的 API 密钥。我们目前正在经历"人工智能的Linux时刻",开发人员必须在专有或开源基础模型之间做出选择,而这主要基于性能和成本的权衡。


LLM 服务商: 专有和开源基础模型


专有模型是由拥有大型专家团队和大量 AI 预算的公司拥有的闭源基础模型,通常比开源模型大,因此具有更好的性能,但 API 开销也更昂贵。专有模型服务商有OpenAIco:hereAI21 LabsAnthropic


大多数 LangChain 教程都使用 OpenAI,但请注意,OpenAI API(用于实验目的并不太贵)不是免费的。要获得 OpenAI API Key,需要创建 OpenAI 帐户,然后在API keys下单击"Create new secret Key"。


import osos.environ["OPENAI_API_KEY"] = ... # 设置API_TOKEN
复制代码


开源模型通常比专有模型更小,功能更少,但比专有模型更具成本效益。开源模型有:


  • BigScience 的[BLOOM]https://huggingface.co/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"] = ... # 设置API_TOKEN
复制代码


可以免费使用 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)涵盖了六个模块:


  • 模型(Models): 从不同 LLM 和嵌入模型中选择

  • 提示(Prompts): 管理 LLM 输入

  • 链接(Chains): 将 LLM 与其他组件相结合

  • 索引(Indexes): 访问外部数据

  • 存储(Memory): 记住以前的对话

  • 代理(Agents): 访问其他工具


下面几节中的代码示例是从LangChain文档中复制和修改的。

模型(Models): 从不同 LLM 和嵌入模型中选择

目前,许多不同的 LLM 正在兴起。LangChain 提供了对各种模型的集成和简化界面。


LangChain 区分了三种输入和输出不同的模型:


  • LLM 接受字符串作为输入(提示)并输出字符串(补全)。


# 专有LLM,例如OpenAI# pip install openaifrom langchain.llms import OpenAIllm = OpenAI(model_name="text-davinci-003")
# 或者使用托管在Hugging Face上的开源LLM# pip install huggingface_hubfrom langchain import HuggingFaceHubllm = HuggingFaceHub(repo_id = "google/flan-t5-xl")
# LLM以提示词作为输入并输出补全prompt = "Alice has a parrot. What animal is Alice's pet?"completion = llm(prompt)
复制代码


LLM 模型


  • 聊天模型类似于 LLM,将聊天消息列表作为输入并返回聊天消息。

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


# 专有文本嵌入模型,例如OpenAI# pip install tiktokenfrom langchain.embeddings import OpenAIEmbeddingsembeddings = OpenAIEmbeddings()
# 或者使用托管在Hugging Face上的开源文本嵌入模型# pip install sentence_transformersfrom langchain.embeddings import HuggingFaceEmbeddingsembeddings = HuggingFaceEmbeddings(model_name = "sentence-transformers/all-MiniLM-L6-v2")
# 文本嵌入模型以文本作为输入,输出浮点数列表text = "Alice has a parrot. What animal is Alice's pet?"text_embedding = embeddings.embed_query(text)
复制代码


文本嵌入模型

提示(Prompts): 管理 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")
复制代码


上面的提示可以看作是一个零样本问题设置(zero-shot problem setting) ,我们希望 LLM 在足够的相关数据上进行了训练,以提供令人满意的响应。


改进 LLM 输出的另一个技巧是在提示中添加一些示例,使其成为多样本问题设置(few-shot problem setting)


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: happyAntonym: sad
Word: tallAntonym: short
Word: bigAntonym:
复制代码

链接(Chains): 将 LLM 与其他组件相结合

LangChain 中的链接简单描述了将 LLM 与其他组件组合在一起创建应用的过程。例如:


  • 结合 LLM 和提示模板(参见本节)

  • 通过将第一个 LLM 的输出作为第二个 LLM 的输入,顺序组合多个 LLM(参见本节)

  • 将 LLM 与外部数据相结合,例如用于问答(参见索引章节)

  • 将 LLM 与长期存储相结合,例如用于聊天记录(参见存储章节)


前一节创建了一个提示模板,当我们想在 LLM 中使用时,可以使用LLMChain,如下所示:


from langchain.chains import LLMChain
chain = LLMChain(llm = llm, prompt = prompt)
# 通过输入特定参数执行该链chain.run("colorful socks")
复制代码


如果我们想使用第一个 LLM 的输出作为第二个 LLM 的输入,可以使用SimpleSequentialChain:


from langchain.chains import LLMChain, SimpleSequentialChain
# 像前面的代码示例一样定义第一个链# ...
# 基于提示词模板和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)
# 结合第一和第二链overall_chain = SimpleSequentialChain(chains=[chain, chain_two], verbose=True)
# 只指定第一个链的输入并运行该链。catchphrase = overall_chain.run("colorful socks")
复制代码


在 LangChain 中使用 PromptTemplates 和 LLM 的 SimpleSequentialChain 输出

索引(Indexes): 访问外部数据

LLM 的一个限制是缺乏上下文信息(例如访问特定文档或电子邮件),可以通过允许 LLM 访问特定外部数据来解决这个问题。


为此,首先需要使用文档加载器加载外部数据。LangChain 为不同类型文档提供了各种加载器,从 pdf 和电子邮件到网站和 YouTube 视频不等。


我们从 YouTube 视频中加载一些外部数据。如果你想加载大型文本文档并使用 Text Splitter 来拆分,可以参考官方文档


# 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()
复制代码


现在已经准备好了外部数据作为documents,可以使用矢量数据库(VectorStore) 中的文本嵌入模型对其进行索引。流行的矢量数据库包括 Pinecone、Weaviate 和 Milvus。本文使用 Faiss,因为它不需要 API 密钥。


# pip install faiss-cpufrom langchain.vectorstores import FAISS
# 创建矢量数据库作为索引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 的输出


等等,你是不是被忽悠了?是的,确实是。

存储(Memory): 记住以前的对话

对于像聊天机器人这样的应用来说,能够记住以前的对话至关重要。但默认情况下 LLM 没有任何长期记忆,除非显式输入聊天记录。


聊天有没有会话记忆的比较


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来保存会话记录,那么会话将看起来像上图中左侧的对话。

代理(Agents): 访问其他工具

LLM 有强大的能力,但也有很多限制:缺乏上下文信息(例如训练数据没有覆盖的特定领域知识),信息会快速过时(例如 GPT-4 是基于 2021 年 9 月份之前的数据训练的),以及不擅长数学。



因为 LLM 可能会对自己无法完成的任务产生幻觉,所以需要使用辅助工具,例如搜索(例如,Google搜索)、计算器(例如,Python REPLWolfram Alpha)和查找(例如,Wikipedia)。


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


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


在下面的示例中,代理首先在维基百科上查找巴拉克·奥巴马的出生日期,然后用计算器计算出他在 2022 年的年龄。


# pip install wikipediafrom langchain.agents import load_toolsfrom langchain.agents import initialize_agentfrom 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 代理输出

总结

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


LangChain 是一个开源 Python 库,可以让任何会写代码的人构建 LLM 驱动的应用程序。该包为许多基础模型提供了通用接口,支持提示管理,并充当其他组件(如提示模板、其他 LLM、外部数据以及支持代理的其他工具)的中心化接口。


该库提供了比本文提到的更多特性。以目前的发展速度,这篇文章也可能会很快过时。


在撰写本文时,我注意到库和文档都围绕 OpenAI 的 API。虽然许多例子都使用开源模型 google/flan-t5-xl,但我还是切换到了 OpenAI API。尽管不是免费的,但本文中的 OpenAI API 实验只花了大约 1 美元。




你好,我是俞凡,在 Motorola 做过研发,现在在 Mavenir 做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI 等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。为了方便大家以后能第一时间看到文章,请朋友们关注公众号"DeepNoMind",并设个星标吧,如果能一键三连(转发、点赞、在看),则能给我带来更多的支持和动力,激励我持续写下去,和大家共同成长进步!

发布于: 刚刚阅读数: 5
用户头像

俞凡

关注

公众号:DeepNoMind 2017-10-18 加入

俞凡,Mavenir Systems研发总监,关注高可用架构、高性能服务、5G、人工智能、区块链、DevOps、Agile等。公众号:DeepNoMind

评论

发布
暂无评论
LangChain初学者指南_人工智能_俞凡_InfoQ写作社区