大模型——LangChain开源框架介绍
2023年可以说是AI大语言模型发展元年,随着OpenAI的ChatGPT和GPT-4的发布,点燃了人工智能大语言模型的发展浪潮,各大科技公司纷纷推出了自家的大语言模型产品,各国更是将大语言模型的发展作为人工智能技术的重要突破来推进,纷纷进行业务和技术层面的布局。然而现有预训练大模型也存在一定技术缺陷,如仅有通用知识表示,知识只截止在训练时的日期,对于新知识无从习得。而大模型的更新训练需要耗费巨量的资源和成本,对于大模型应用层面的企业或个人更是无力承担。因此在这种背景下,出现了LangChain开源框架,用于将外部数据和LLM大语言模型相结合,让LLM能够基于外部数据知识的基础上进行智能问答,这就是LangChain开源框架搭建的基于AI大模型下的AI应用开发新范式。本文重点介绍LangChain的概念、业务架构、核心模块和应用场景等基本内容,方便大家能够对LangChain有更深入的了解。
1. LangChain开源框架的概念
LangChain是一个用于开发由语言模型驱动的应用程序的框架,旨在帮助开发人员使用语言模型构建端到端的应用程序。它提供了一套工具、组件和接口,可简化创建由大型语言模型 (LLM) 和聊天模型提供支持的应用程序的过程。LangChain 可以轻松管理与语言模型的交互,将多个组件链接在一起,可连接其他数据源,即LangChain是一个可以将大语言模型和外部数据及计算相结合的开源框架,可以让大语言模型能够基于外部数据源进行数据生成。
一个强大而又有差异的应用程序不仅会通过 API 调用语言模型,也会将语言模型连接到其他数据源进行数据感知(如Pinecone),还允许语言模型能够与其环境进行交互(如访问互联网获取数据),而LangChain可以很好的完成这些任务。目前LangChain开源框架提供了Python和JavaScript包。
2. LangChain开源框架业务架构
与大模型不断涌现的业务创新路线不同,LangChain选择了一条基于大模型之上的应用开发框架创新之路,它借助大模型出色的多模态数据理解和生成能力,结合外部计算和数据源提供应用程序开发的框架,并且对代码进行开源,使得其在2023年3月随着GPT-4的发布其关注度得到了直线飙升。
LangChain定义了一套基于大模型之上的应用开发框架,倡议各大模型能够按照框架定义进行相关实现,其也在不断完善其在大模型上的支持的能力,它的更新迭代很快,新的内容在不断出现。下图描述了LangChain的业务架构,内部核心业务包括六个部分:Models、Prompts、Agents、Indexes、Chains、Memory。
LangChain的核心业务原理是首先利用Indexes索引模块针对外部数据源(如文本文档或数据库)进行文档加载、文本分割、向量化后存储到向量存储数据库VectorStore中;其次根据用户的提问在VectorStore向量存储数据库中检索和提问Promp相似的相关信息;之后将提问以及检索出的相似信息传递到LLM;最后LLM根据输入进行理解和生成数据信息,并通过Agents完成后续Action动作的处理。这样,开发者就可以轻松的在LangChain这个开发框架之上基于大模型进行特定行业、特定用途、针对特定数据源的AI应用程序的开发了。其扩展了大模型的应用领域和空间。
LangChain认为,AI应用开发必不可少的需要基于LLM大模型,LangChain通过Models提供非常便捷的接入各LLM的接口,包括GPT和GLM系列模型均可以通过LangChain的Models接口进行调用;同时简化提示难度、丰富提示灵活度也是未来AI应用开发所必须具备的能力,LangChain提供了Prompts用于给开发者提供灵活的自定义提示模板的功能;为了更好的理解人力意图,AI工具的内部执行流程应该类似管道流水线,这种流程在机器学习领域被称为Pipeline,在LangChain的定义中的被称为Chains;大语言模型对上下文的理解能力是自然语言理解的基础,AI能够记住人类的提示以及自身的操作将是升用户体验的关键,LangChain中通过Memory模块来实现这一记忆功能;并且未来AI在千行百业的落地生花离不开外部工具和数据的交互,LangChain中通过Agents模块设定代理来使用这些工具进而拓展AI工具本身的功能,通过Indexes模块提供本地文件以及外部数据的索引的功能,让AI工具能够更加方便的进行的本地文件或外部数据的管理。而LangChain功能还在不断的完善、不段的更新,未来随着LangChain的不断应用,LangChain会越来越完善,越来越强大。
3. LangChain开源框架核心模块
基于以上业务架构,LangChain内部核心业务包括六个部分:Models、Prompts、Agents、Indexes、Chains、Memory。分别描述如下:
3.1. Models 组件
Models组件:模型接入LLM的交互组件,用于和不同类型模型完成业务交互,LangChain将模型分为LLMS、Chat Model、Text Embedding三类模型,分别通过不同类与操作完成三种模型的业务交互。
大型语言模型(LLMs) 是指具备语言理解和生成能力的商用大型语言模型,以文本字符串作为输入,并返回文本字符串作为输出。LangChain中设计LLM类用于与大语言模型进行接口交互,该类旨在为LLM提供商提供标准接口,如OpenAI、Coherent、Hugging Face。
以OpenAI LLM包装器为例,其使用方法如下:
from LangChain.llms import OpenAI
llm = OpenAI(model_name = 'text-davinci-003',n=2,best_of = 2)
llm("Please introduce yourself")
llm.get_num_tokens(question)
没错,就是最基本的功能,可以直接调用它,传入一个字符串并返回一个字符串,进行文本生成,也可以统计计算所需要的token数。更广泛地,也可以使用输入列表调用它,获取比仅文本更完整的响应。如:llm.generate([“Tell me a joke”, “Tell me a poem”]*15)
Chat Model聊天模型是语言模型的一个变体,聊天模型以语言模型为基础,其内部使用语言模型,不再以文本字符串为输入和输出,而是将聊天信息列表为输入和输出,他们提供更加结构化的API。通过聊天模型可以传递一个或多个消息。LangChain目前支持四类消息类型:分别是AIMessage、HumanMessage、SystemMessage和ChatMessage 。
chat = ChatOpenAI(temperature=0)
chat([HumanMessage(content="Translate this sentence from English to French. I love programming.")])
AIMessage(content="J'aime programmer.", additional_kwargs={})
SystemMessage:系统消息是用来设定模型的一种工具,可以用于指定模型具体所处的环境和背景,如角色扮演等;
HumanMessage:人类消息就是用户信息,由人给出的信息,如提问;使用Chat Model模型就得把系统消息和人类消息放在一个列表里,然后作为Chat Model模型的输入
AIMessage:就是AI输出的消息,可以是针对问题的回答
ChatMessage:Chat消息可以接受任意角色的参数
大多数情况下,我们只需要处理HumanMessage、AIMessage和SystemMessage消息类型。此外聊天模型支持多个消息作为输入,如下系统消息和用户消息的示例
messages = [
SystemMessage(content="You are a helpful assistant that translates English to French."),
HumanMessage(content="I love programming.")
]
chat(messages)
AIMessage(content="J'aime programmer.", additional_kwargs={})
还可以使用generate来生成多组消息。
batch_messages = [
[
SystemMessage(content="You are a helpful assistant that translates English to French."),
HumanMessage(content="I love programming.")
],
[SystemMessage(content="You are a helpful assistant that translates English to French."),HumanMessage(content="I love artificial intelligence.")],
]
result = chat.generate(batch_messages)
文本嵌入模型 text-embedding-model 是将文本进行向量表示,从而可以在向量空间中对文本进行诸如语义搜索之类的操作,即在向量空间中寻找最相似的文本片段。而这些在LangChain中是通过Embedding类来实现的。
Embedding类是一个用于与文本嵌入进行交互的类。这个类旨在为提供商(有许多嵌入提供商,如OpenAI、Cohere、Hugging Face等)提供一个标准接口。LangChain中的Embedding类公开了两种方法:embed_documents和embed_query。最大的区别在于这两种方法具有不同的接口:一个适用于多个文档,而另一个适用于单个文档。除此之外,将这两个方法作为两个单独的方法的另一个原因是,某些嵌入提供商针对要搜索的文档与查询本身具有不同的嵌入方法。
3.2. Prompts提示工程
提示(Prompt)指的是模型的输入,这个输入一般很少是硬编码的,而是从使用特定的模板组件构建而成的,这个模板组件就是PromptTemplate提示模板,可以提供提示模板作为输入,模板指的是我们希望获得答案的具体格式和蓝图。LangChain 提供了预先设计好的提示模板,可以用于生成不同类型任务的提示。当预设的模板无法满足要求时,也可以使用自定义的提示模板。
在 LangChain 中,我们可以根据需要设置提示模板,并将其与主链相连接以进行输出预测。此外,LangChain 还提供了输出解析器的功能,用于进一步精炼结果。输出解析器的作用是指导模型输出的格式化方式,以及将输出解析为所需的格式。
LangChain提供了几个类和函数,使构建和处理提示变得容易。
LLM提示模板(LLM Prompt Templates)
LLM语言模型是以文本字符串为输入,这个文本字符串通常称为提示。有时是个硬编码的字符串,而绝大多数情况下这个提示是一个模板、一些例子和用户的输入的组合。
LLM提示模板是针对LLM语言模型生成提示的可重复方法,包含一个文本字符串模板,该模板能够接收用户的一些输入参数而生成提示。
LLM提示模板一般包含:对语言模型的指导,一组少量示例来帮助语言模型生成更好的响应,对语言模型的提问。
LLM提示模板的创建可以使用PromptTemplate类来完成,简单举例如下:
from LangChain import PromptTemplate
template = " Please help me to find a new name for my company that makes {product}?"
prompt = PromptTemplate(input_variables=["product"],template=template,
)
prompt.format(product="super phone")
#-> Please help me to find a new name for my company that makes super phone?
聊天提示模板(Chat Prompt Template)
Chat Models聊天模型以聊天消息列表作为输入,这个聊天消息列表通常称为提示。聊天消息和用户输入LLM语言模型的原始文本字符串有所不同,聊天消息需要依附于对应角色,如和系统、人类、AI角色相对应的SystemMessage、HumanMessage、AIMessage。聊天模型应更密切地遵循系统聊天消息的指示。
聊天提示模板的创建可以使用与聊天相关的提示模板,而非PromptTemplate,以充分发挥基础聊天模型的潜力。LangChain 提供了不同类型的 MessagePromptTemplate。其中最常用的三类 AIMessagePromptTemplate、SystemMessagePromptTemplate 和 HumanMessagePromptTemplate,分别用于创建 AI 消息、系统消息和人类消息。
SystemMessagePromptTemplate ---- 创建与系统角色相关联的消息模板
AIMessagePromptTemplate ---- 创建与AI角色相关联的消息模板
HumanMessagePromptTemplate ---- 创建与人类角色相关联的消息模板
在聊天模型支持使用任意角色发送聊天消息的情况下,也可以使用 ChatMessagePromptTemplate,允许用户指定角色名称。
示例选择器(Example Selectors)
示例选择器是指在使用大型语言模型进行生成任务时,通过设计合适的示例或提示文本,来引导模型生成期望的输出。如引导模型了解应该生成的内容和格式、帮助控制模型生成的上下文、约束或限制模型生成的内容、辅助生成对特定问题或情境的应答等。
示例选择器的功能在于通过设计合适的示例文本,引导模型生成期望的内容、控制上下文、约束输出等,从而提高生成任务的准确性和可控性。在使用大型语言模型时承担着引导、指导和约束的作用,使得模型的生成更加符合预期和要求。
如果在使用中有大量的示例,就需要选择包含在提示中的示例。LangChain中的ExampleSelector类是负责执行此任务。如下一些提示例子
#These are a lot of examples of a pretend task of creating antonyms.
examples = [{"input": "happy", "output": "sad"},{"input": "tall", "output": "short"},{"input": "energetic", "output": "lethargic"},{"input": "sunny", "output": "gloomy"},{"input": "windy", "output": "calm"},
]
通常情况下,在提示中包含示例很有用。这些示例可以是硬编码的,但如果它们是动态选择的,则效果会更有力。
输出解析器(Output Parsers)
输出解析器是指对模型生成的结果进行解析和处理的组件。它的主要功能是将模型生成的文本进行解析,提取有用的信息并进行后续处理。如对模型生成的文本进行解析、提取有用信息、识别实体、分类和过滤结果,以及对生成文本进行后处理,从而使生成结果更易于理解和使用。它在与大型语言模型交互时起到解析和处理结果的作用,增强了模型的应用和可用性。
语言模型输出文本。但是很多时候,可能想要获得比文本更结构化的信息。这就是输出解析器的作用。即输出解析器是帮助结构化语言模型响应的类,LangChain中主要提供的类是PydanticOutputParser。
3.3. Chains链
通常我们使用单独的LLM也可以解决问题,但是对于更加复杂的应用程序需要在LLM之间或与其他系统进行链接来完成任务,这个通常称为链接LLM。链允许将模型或系统间的多个组件组合起来,创建一个单一的、一致的应用程序。举例来说,我们创建一个链,该链接受用户的输入,通过PromptTemplate模板对输入进行格式化并传递到LLM语言模型。还可以将多个链组合起来,或者将链与其他系统组件组合起来,来构建更复杂的链,实现更强大的功能。LangChain为链提供了标准接口以及常见实现,与其他工具进行了大量集成,并为常见应用程序提供了端到端链。
上例中接受用户输入通过模板格式化输入后传递到语言模型就可以通过一个简单的链类来实现,如在LangChain中的LLMChain类。它是一个简单的链,可接受一个提示模板,使用用户输入对其进行格式化,并从 LLM 返回响应。当然LLMChain也可以用于聊天模型。
from LangChain.prompts import PromptTemplate
from LangChain.llms import OpenAI
from LangChain.chains import LLMChainllm = OpenAI(temperature=0.9)
prompt = PromptTemplate(
input_variables=["product"],
template=" Please help me to find a new name for my company that makes {product}?",
)
chain = LLMChain(llm=llm, prompt=prompt)
print(chain.run("super phone"))
LangChain 提供了很多现成的链接,但是有时可能需要为特定应用创建一个自定义链接。另外LangChain中还有序列链的概念,即按照预定义的顺序执行链接的链,如SimpleSequentialChain就是最简单的顺序链类型,其中每个步骤都有一个输入/输出,一个步骤的输出是下一个步骤的输入。LangChain中还有非常多关于链的高级用法。
3.4. Agents代理
通常用户的一个问题可能需要应用程序的多个逻辑处理才能完成相关任务,而且往往可能是动态的,会随着用户的输入不同而需要不同的Action,或者LLM输出的不同而执行不同的Action。因此应用程序不仅需要预先确定LLM以及其他工具调用链,而且可能还需要根据用户输入的不同而产生不同的链条。使用代理可以让LLM访问工具变的更加直接和高效,工具提供了无限的可能性,有个工具,LLM可以搜索网络、进行数学计算、运行代码等等相关功能。
LangChain中代理使用LLM来确定采取哪些行动及顺序,查看观察结果,并重复直到完成任务。LangChain 库提供了大量预置的工具,也允许修改现有工具 或创建新工具。当代理被正确使用时,它们可以非常强大。在LangChain中,通过“代理人”的概念在这些类型链条中访问一系列的工具完成任务。根据用户的输入,代理人可以决定是否调用其中任何一个工具。如下是一段简单的示例:
#加载要使用的语言模型来控制代理人
llm = OpenAI(temperature=0);
#加载一些需要使用的工具,如serpapi和llm-math,llm-math工具需要使用LLM
tools = load_tools(["serpapi", "llm-math"], llm=llm)
#使用工具、语言模型和代理人类型初始化一个代理人。
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
#控制代理执行
agent.run("Who is Vin Diesel's girlfriend? What is her current age raised to the 0.5 power?")
以上示例需要处理三个过程,首先查询Vin Diesel's girlfriend,然后在查询她的年龄,再计算指数关系。可看到代理的工作过程。
3.5. Indexes索引
Indexes索引是指构造文档的方法,以便 LLM 可以最好地与它们交互。LangChain可以将外部数据和LLM进行结合来理解和生成自然语言,其中外部数据可以是本地文档、数据库等资源,将这些数据进行分片向量化存储于向量存储数据库中,再通过用户的Prompt检索向量数据库中的相似信息传递给大语言模型进行生成和执行Action。其中这个检索向量数据库中的相似相关信息的过程中Indexex索引贯穿其中,起到了举足轻重的作用。
索引用于处理外部数据并使其准备好与语言模型交互的模式和功能,包括有文档加载器、向量存储、文本拆分器和检索器等功能。此模块包含用于处理文档的实用工具函数、不同类型的索引,以及可以在链中使用这些索引。
在链中使用索引的最常见方式是“检索”步骤。这一步是指接受用户的查询并返回最相关的文档。大多数时候,当我们谈论索引和检索时,我们谈论的是索引和检索非结构化数据(如文本文档)。LangChain 支持的索引和检索类型目前主要集中在向量数据库上
文档加载程序
文档加载程序是解决如何从各种源数据中加载文档,将语言模型与外部的文本数据结合使用是LangChain的强大之处。这样做的第一步是将数据加载到“文档”中,该模块可以使这一过程变得容易,这依赖于一个强大的工具,Unstructured Python 包,其将能够将文件(如:文本、PowerPoint、图像、HTML、PDF 等)转换为文本数据。
文本分割器
文本分割器是解决关于分割文本的功能。当处理长篇文本时,需要将文本拆分为块。 将文本拆分为小的、语义上有意义的块,开始将这些小块组合成一个较大的块,直到达到一定的大小,将该块作为自己的文本块,然后开始创建一个新的文本块,其中包含一些重叠,以保持文本块之间的上下文。尽管听起来很简单,但这里存在着很多潜在的复杂性。既要保持小的文本块,也要将语义相关的文本端保持在一起,还要能够进行上下文的关联。
LangChain支持的文本分割器是 RecursiveCharacterTextSplitter。该文本分割器需要一个字符列表。它尝试根据第一个字符分割创建块,但如果任何块太大,则移动到下一个字符,依此类推。默认情况下,它尝试分割的字符是[" ", “\n”, " ", “”]。LangChain还支持很多文本分割器,如:字符文本分割器、Hugging Face长度函数、Latex文本分割器、Python代码文本分割器等等。
向量存储(VectorStores)
向量存储是构建Indexes索引的重要组成部分之一。处理向量存储的关键部分是创建要放入其中的向量,这通常是通过embedding来创建的。LangChain为openAI实现了embedding类OpenAIEmbeddings。
检索器接口(Retrievers)
检索器接口是一种通用接口,使文档和语言模型易于组合。LangChain中公开了一个get_relevant_documents方法,该方法接受查询(字符串)并返回文档列表。
LangChain利用Indexex索引处理外部数据通过文档加载器、文本分割器的向量化处理后存储于向量存储数据库中,最后通过用户的提问调用检索器接口获得相似向量信息传递到LLM进行处理。
3.6. Memory记忆存储
Memory是在用户与语言模型的交互过程中始终保持状态的概念。体现在用户与语言模型的交互聊天消息过程,这就涉及为从一系列聊天消息中摄取、捕获、转换和提取知识。Memory在Chains/Agents调用之间维持状态,默认情况下,Chains和Agents是无状态的,这意味着它们独立地处理每个传入的查询,但在某些应用程序中,如:聊天机器人,记住以前的交互非常重要,无论是在短期的还是长期的。“Memory”这个概念就是为了实现这一点。
LangChain提供了两种方式使用记忆存储Memory组件,一种是提供了管理和操作以前的聊天消息的辅助工具来从消息序列中提取信息;另一种是在Chains中进行关联使用。Memory可以返回多条信息,如最近的 N 条消息或所有以前消息的摘要等。返回的信息可以是字符串,也可以是消息列表。
LangChain提供了从聊天记录、缓冲记忆、Chains中提取记忆信息的方法类以及接口,如ChatMessageHistory 类,一个超轻量级的包装器,提供了一些方便的方法来保存人类消息、AI消息,然后从中获取它们;再如ConversationBufferMemory类,它是 ChatMessageHistory 的一个包装器,用于提取变量中的消息等等。
4. LangChain开源框架的应用场景
与大模型不断涌现的业务创新路线不同,LangChain选择了一条基于大模型之上的应用开发框架创新之路,它借助大模型出色的多模态数据理解和生成能力,结合外部计算和数据源提供应用程序开发的框架,并且对代码进行开源,使得其在2023年3月随着GPT-4的发布其关注度得到了直线飙升。其原因是LangChain开启了基于大模型之上的应用程序开发模式的探索,LangChain是AI应用的开发工具、开发协议和开发范式。正如李开复先生的描述一样,AI进入2.0时代,所有应用都会被重写一遍。这也体现了AI的发展方向,而LangChain开源框架会极大的助力和促进这一趋势的快速落地成型,LangChain认为,未来的基于LLM的AI应用都是基于其六大核心元素Models、Prompts、Chains、Agents、Memory、Indexes的拼凑和堆叠,那么通过LangChain各元素的搭配组合会有怎样的应用场景呢?
个人助理类应用
LangChain让AI应用不仅仅能够回答问题,还可以采取行动,这开启了无数实际应用的可能性,任何涉及个人助手的事务都将会变得简单,如预定酒店、预定机票、支付税款等。
本地数据的分析和处理
LangChain可以将外部数据和LLM大模型相结合,通过针对外部数据的筛选和检索提出所要解决的问题,而且不仅有答复还可以有行动,指导解决问题完成任务。外部数据可以是本地文件、本地数据库等,这样就可以利用LangChain对本地数据进行分析、针对数据分析的结果还可以进一步的进行处理而采取行动,包括需要通过编码才能完成的工作依然胜任。具体如财务报表分析、客户关系数据处理、采购订单、物料库存管理等等。
定制化行业机器人
LLM大语言模型具有通用知识能力,通用知识领域LLM能够给出较好的答案,但是行业领域方面它的能力有有限了,而对于实时更新的业务内容更是一头雾水。而通过LangChain可以进行本地行业知识数据库接入到LLM中进行智能处理,可以借助LLM对通用知识的理解能力来解决行业领域业务知识的问题和处理,如可以快速完成行业智能客服、行业聊天机器人、更可以进行行业机器人的定制设计。
本地知识库的创建
LangChain可以完成本地知识库的搭建,能够将本地知识库快速搭建和升级成为具备自然语言理解和生成能力的领域知识库模型。可以赋能各中小企业无需通过大规模的神经网络训练和建设,就可以满足内部业务知识库模型建设。随着清华大学GLM系列开源模型的不断发展和支持能力的不断升级,使用LangChain + ChatGLM-6B来搭建本地知识库已经在各中小企业中得到了很多的实践和应用。
LangChain是一种AI应用程序的开发协议、开发框架,它基于LLM大语言模型的基础之上构建了一套AI应用程序的开发框架,其核心能力也在不断的完善和更新,且随着多模态大模型的不断涌现和升级,LangChain的应用场景会越来越丰富,创新业务也会不断涌现,期待未来LangChain会有更有优秀的表现。
5. 结语
LangChain以一种不同于大模型发展路线的创新方式选择了一条基于大模型之上的应用开发框架创新之路,通过借助大模型出色的多模态数据理解和生成能力,结合外部计算和数据源提供应用程序开发的框架,期望通过统一的功能模块的称呼和开发规范来定义基于LLM模型下的AI应用开发范式,且LangChain还提供了一系列实现这些功能的API,让基于LangChain开源框架的AI应用开发快速落地。本文重点对LangChain开源框架做了基本的业务介绍,涉及LangChain的概念、业务架构、核心元素功能以及应用场景的探索。期待对大家有所帮助。