使用这些基本 REST API 最佳实践构建出色的 API
大模型开发 - 一文搞懂 LangChain(五):Chains
一、Chains的本质
Chains是什么?Chains 在 LangChain 框架中的核心概念是用于将多个组件及其他 Chains 组合成更复杂功能,通过模块化与复用提高开发效率、代码可读性及可维护性。
- 模块化:提高代码复用性,降低开发复杂性。
- 可维护性:易于理解和维护,方便修改和扩展。
- 灵活性:支持不同组合方式,适应多变需求。
Chains两种类型的链:通用链和实用链。
- 通用链:这些链使用一个大语言模型(LLM)根据给定的提示生成文本。比如LLM链和简单顺序链。它们主要依赖于单一的语言模型来完成文本生成的任务。
- 实用链:这些链将多个大语言模型(LLM)一起用于特定任务。例如,检索QA链可能用于问答系统,LLM数学链用于处理数学相关的工作,加载摘要链用于生成文本的摘要,而PAL链则可能用于特定的自然语言处理任务。
通用链和实用链
Chains能干什么?
Chains的灵活性使得我们可以根据具体需求将多个链组合在一起,或者将链与其他功能组件相结合,从而构建出更复杂、更强大的应用程序。
Legacy Chains 是一系列传统的工具链,用于处理和转换数据,执行特定的任务,并在早期的技术环境中提供关键的功能支持。
- APIChain:将查询转换为API请求并执行,然后获取响应并传递给另一个语言模型(LLM)以作出响应。
- OpenAPIEndpointChain:与APIChain类似,但专为与OpenAPI端点交互而优化。
- ConversationalRetrievalChain:用于与文档进行对话。它接收问题和(可选的)先前的对话历史,然后使用LLM和检索器来获取相关文档,并作出响应。
- StuffDocumentsChain:将一系列文档格式化为提示,并将其传递给LLM。
- ReduceDocumentsChain:通过迭代减少文档来组合它们。它分批处理文档,然后将其传递给LLM,直到所有内容都适合在一个最终的LLM调用中处理。
- MapReduceDocumentsChain:首先对每个文档进行LLM调用,然后使用ReduceDocumentsChain来减少它们。
- RefineDocumentsChain:通过基于第一个文档生成初始答案,然后循环遍历其余文档来精炼答案。
- MapRerankDocumentsChain:对每个文档进行LLM调用,并要求其提供答案和置信度分数。返回置信度最高的答案。
- ElasticsearchDatabaseChain:将自然语言问题转换为ElasticSearch查询,执行它,然后总结响应。
- LLMMath:将用户问题转换为数学问题并执行它。
- LLMCheckerChain:使用第二次LLM调用来验证其初始答案。
- LLMSummarizationChecker:使用一系列LLM调用来创建摘要,以确保其准确性。
二、Chains的原理
Chains的工作流程:通过定义链构造函数来初始化链,配置所需的组件和可能的其他链,以形成具有特定功能的执行流程。
Chains流程包含以下四个核心步骤:
- Chain Constructor(链构造函数):在LangChain中,链构造函数用于初始化链,设定其组件、配置及嵌套的其他链。
- Function Calling(函数调用):这指链是否需要调用外部函数,如OpenAI服务,以执行其任务。
- Other Tools(其他工具):除LangChain核心组件外,链可能还使用其他工具如数据库、API等以增强其功能。
- When to Use(何时使用):这部分提供指导,帮助开发者确定在何种场景或需求下使用特定的LangChain链最为合适。
Chains的工作流程
Chains的架构:Chains作为LangChain的核心组件,通过串联各个逻辑单元,实现了流程控制、数据传递和状态管理,使得复杂的业务逻辑能够高效、有序地执行。
- 流程控制:Chains通过特定的顺序将逻辑单元串联起来,确保业务流程按照预定的顺序执行。每个逻辑单元在Chains中都被视为一个节点,节点之间的连接形成了完整的业务流程。
- 数据传递:在Chains中,数据在各个节点之间流动。每个节点接收前一个节点的输出作为输入,并根据业务需求进行处理,然后将结果传递给下一个节点。这种数据传递方式实现了各个逻辑单元之间的无缝衔接。
- 状态管理:Chains还具备状态管理能力,允许节点在执行过程中修改自身的状态,并根据上一次的状态进行相应的操作。这有助于处理复杂的业务逻辑,提高代码的复用性和可维护性。
三、Chains的应用
LangChain Expression Language(LCEL)是一种声明式的方式,可以轻松地组合链。LCEL 从一开始就被设计为支持将原型投入生产,无需任何代码更改,从最简单的“提示+LLM”链到最复杂的链。
Chains的基本案例:prompt + model + output parser
在此链中,用户输入传递到提示模板,然后提示模板输出传递到模型,然后模型输出传递到输出解析器。
基本案例的流程
1. 提示(Prompt):你创建了一个 ChatPromptTemplate 对象,该对象使用给定的模板字符串,并根据提供的输入(在这种情况下是主题)生成完整的提示。当你调用 prompt.invoke({“topic”: “ice cream”}) 时,它会返回一个 ChatPromptValue 对象,该对象包含要传递给模型的完整提示。
prompt value = prompt,invoke({"topic": "ice cream"])
prompt value
ChatPromptValue(messages=[HumanMessage(content='tell me a short joke about ice crean')])
prompt value,to messages )
[HumanMessage(content='tell me a short joke about ice cream')]
prompt value.to string()
Human: tell me a short joke about ice cream'
ChatPromptTemplate
2. 模型(Model):PromptValue
作为输入传递给ChatModel
,该模型处理后输出一个BaseMessage
格式的回复。
message = model invoke(prompt value)
message
AIMessage(content-"why don't ice creams ever get invited to parties?\n\nBecause they al
ChatModel
如果我们的模型是一个大语言模型(LLM),它将输出一个字符串作为结果。
from langchain openai. llms import OpenAI
llm = OpenAI(model="gpt-3.5-turbo-instruct")
llm. invoke(prompt value)
\nnRobot: Why did the ice cream truck break down? Because it had a meltdown!'
大语言模型(LLM)
3. 输出解析器(Output Parser):最后,我们将模型输出传递给output_parser
,它是一个BaseOutputParser
,可以接受字符串或BaseMessage
作为输入。其中,StrOutputParser
专门将任何输入简单转换为字符串。
output parser.invoke(messagel
"why did the ice cream go to therapy? ininBecause it had too many toppings and couldn't
输出解析器(Output Parser)
RAG Search Example:在这个例子中,我们想要运行一个检索增强的生成链,以便在回答问题时添加一些上下文。
RAG Search Example的流程
该流程通过创建一个包含上下文和问题的RunnableParallel对象,将其传递给提示组件以生成PromptValue,然后将该值输入到OpenAI的大型语言模型(LLM)中以生成ChatMessage,最后通过输出解析器将其转换为Python字符串并返回。
1. 创建RunnableParallel对象:首先,创建一个RunnableParallel
对象,它包含两个条目:一个是context
(由检索器获取的文档结果),另一个是question
(用户的原始问题)。为了传递问题,使用RunnablePassthrough
来复制这个条目。
2. 传递给提示组件:将上述步骤中创建的字典传递给提示组件。提示组件接收用户输入的问题和检索到的文档(作为上下文),然后构建一个提示并输出一个PromptValue
。
3. 模型组件评估:模型组件接收生成的提示,并将其传递给OpenAI的大型语言模型(LLM)进行评估。模型生成的输出是一个ChatMessage
对象。
4. 输出解析:最后,output_parser
组件接收一个ChatMessage
对象,并将其转换为Python字符串。这个字符串是从调用方法中返回的最终结果。
# Requires:
# pip install langchain docarray tiktoken
from langchain community.vectorstores import DocArrayInMemorySearchfromlangchain core.output parsers import StrOutputParser
langchain core.prompts import ChatPromptTemplatefrom
fromilangchain core,runnables import RunnableParallel, RunnablePassthrough
fromlangchain openaichat models import ChatOpenAIfrom langchain openai.embeddings import OpenAIEmbeddings
vectorstore = DocArrayInMemorySearch, from texts(
["harrison worked at kensho", "bears like to eat honey"].embedding 0penAIEmbeddings()
retriever = vectorstore.as retriever()
template = mAnswer the question based only on the following context;{context}
Question: {question》
prompt = ChatPromptTemplate.from template(template)model = ChatOpenAi()
output parser = StrOutputParser()
setup and retrieval = RunnableParallel(["context": retriever,"question": RunnablePassthrough()]
chain = setup and retrieval l prompt model output parser
chain.invoke("where did harrison work?")
本文章转载微信公众号@架构师带你玩转AI