第六届字节跳动青训营第五课(ai_链_&_记忆) | 豆包MarsCode AI 刷题

120 阅读6分钟

链及其调用方法

简介

chain用来链接LangChain的各个组件和功能——模型之间彼此链接,或模型与其他组件链接。

image.png

链可以极大地简化流程,一般来说在不使用链的情况下,需要先定义模板,再将模板导入提示模板中,调用提示模板的format方法传入模板的参数,这才实现了提示模板的全部流程。之后需要创建模型,并将提示传入模型方可进行预测。

在使用链后,真正的核心代码如下所示,只需要定义模板,创建模型,创建链,输入提示词即可。

template = "{flower}的花语是?" 
llm = OpenAI(temperature=0) 
llm_chain = LLMChain(     
    llm=llm,
    prompt=PromptTemplate.from_template(template)) 
result = llm_chain("玫瑰")

调用方法

  • 直接调用

    直接在链后加上提示词,其内部是调用该对象内部实现的__call__方法。

  • run调用

    链.run(),和直接调用等价。

  • predict调用

    链.predict(key="?"),需要指明关键字参数。

  • apply调用

    链.apply(input),input中可以放数组,即多个参数。

  • generate调用

    链.generate(),和apply调用方法相似,但返回一个LLMResult对象,而不是字符串。LLMResult通常包含模型生成文本过程中的一些相关信息,例如令牌数量、模型名称等。

其他种类的链

SequentialChain

把几个LLMChain串起来,形成一个顺序链。定义了不同的模板,在调用模型预测时通过output_key将输出指定存储在参数中,并在下一个模板中引用,实现顺序链。

RouterChain

在不同场景,遇到不同类型的问题,LangChain会通过RouterChain来自动引导大语言模型选择不同的模板。

RouterChain,也叫路由链,能动态选择用于给定输入的下一个链。我们会根据用户的问题内容,首先使用路由器链确定问题更适合哪个处理模板,然后将问题发送到该处理模板进行回答。如果问题不适合任何已定义的处理模板,它会被发送到默认链。

例:MultiPromptChain会调用LLMRouterChain选择与给定问题最相关的提示,然后使用该提示回答问题。

  1. 构建处理模板:为鲜花护理和鲜花装饰分别定义两个字符串模板。
  2. 提示信息:使用一个列表来组织和存储这两个处理模板的关键信息,如模板的键、描述和实际内容。
  3. 初始化语言模型:导入并实例化语言模型。
  4. 构建目标链:根据提示信息中的每个模板构建了对应的LLMChain,并存储在一个字典中。
  5. 构建LLM路由链:这是决策的核心部分。首先,它根据提示信息构建了一个路由模板,然后使用这个模板创建了一个LLMRouterChain。
  6. 构建默认链:如果输入不适合任何已定义的处理模板,这个默认链会被触发。
  7. 构建多提示链:使用MultiPromptChain将LLM路由链、目标链和默认链组合在一起,形成一个完整的决策系统。

verbose=True:这是一个可选参数,用于控制链的执行过程是否输出详细信息。当设置为 True 时,程序会输出更多的信息,例如每个步骤的执行情况、中间结果等。这对于调试和理解程序的运行过程非常有帮助。

记忆

通过打印ConversationChain(llm=llm)的结果可以看到其输出包含两个参数:

  • {history}  是存储会话记忆的地方,也就是人类和人工智能之间对话历史的信息。
  • {input}  是新输入的地方,你可以把它看成是和ChatGPT对话时,文本框中的输入。

当有了{history}参数,以及HumanAI这两个前缀,就能够把历史对话信息存储在提示模板中,并作为新的提示内容在新一轮的对话过程中传递给模型。——这就是记忆机制的原理。

ConversationBufferMemory

在如下的代码中,是否加入memory=ConversationBufferMemory()都会有记忆功能,即使不显式提供 memory 参数,ConversationChain 也有记忆功能。显式使用 ConversationBufferMemory 会有更多的控制和灵活性,例如自定义记忆管理、共享记忆和调试扩展。

但是使用 ConversationBufferMemory后,新输入中也包含了更多的Token(所有的聊天历史记录),这意味着响应时间变慢和更高的成本。而且,当达到LLM的令牌数(上下文窗口)限制时,太长的对话无法被记住(对于text-davinci-003和gpt-3.5-turbo,每次的最大输入限制是4096个Token)。

conversation = ConversationChain(llm=llm, memory=ConversationBufferMemory())

ConversationBufferWindowMemory

ConversationBufferWindowMemory缓冲窗口记忆,它的思路就是只保存最新最近的几次人类和AI的互动。因此,它在之前的“缓冲记忆”基础上增加了一个窗口值 k。这意味着我们只保留一定数量的过去互动,然后“忘记”之前的互动。

尽管这种方法不适合记住遥远的互动,但它非常擅长限制使用的Token数量。如果只需要记住最近的互动,缓冲窗口记忆是一个很好的选择。但是,如果需要混合远期和近期的互动信息,则还有其他选择。

ConversationSummaryMemory

ConversationSummaryMemory对话总结记忆)的思路就是将对话历史进行汇总,然后再传递给 {history} 参数。这种方法旨在通过对之前的对话进行汇总来避免过度使用 Token。

  • 汇总对话:此方法不是保存整个对话历史,而是每次新的互动发生时对其进行汇总,然后将其添加到之前所有互动的“运行汇总”中。
  • 使用LLM进行汇总:该汇总功能由另一个LLM驱动,这意味着对话的汇总实际上是由AI自己进行的。
  • 适合长对话:对于长对话,此方法的优势尤为明显。虽然最初使用的 Token 数量较多,但随着对话的进展,汇总方法的增长速度会减慢。与此同时,常规的缓冲内存模型会继续线性增长。

在使用ConversationSummaryMemory时,需要添加参数memory=ConversationSummaryMemory(llm=llm),其中llm指的是将对话进行汇总的大模型,这种方法不仅仅利用了LLM来回答每轮问题,还利用LLM来对之前的对话进行总结性的陈述,以节约Token数量。总结对话的LLM,和用来回答问题的LLM,可以是同一个大模型,也可以是不同的大模型。

ConversationSummaryBufferMemory

ConversationSummaryBufferMemory,即对话总结缓冲记忆,它是一种混合记忆模型,结合了上述各种记忆机制,包括ConversationSummaryMemory 和 ConversationBufferWindowMemory的特点。这种模型旨在在对话中总结早期的互动,同时尽量保留最近互动中的原始内容。

压轴的果然是最屌的。

总体来说,ConversationSummaryBufferMemory为我们提供了大量的灵活性。它是我们迄今为止的唯一记忆类型,可以回忆起较早的互动并完整地存储最近的互动。在节省Token数量方面,ConversationSummaryBufferMemory与其他方法相比,也具有竞争力。

AIA

image.png

image.png