自然语言处理从入门到应用——LangChain:链(Chains)-[基础知识]

分类目录:《自然语言处理从入门到应用》总目录


在本文中,我们将学习如何在LangChain中创建简单的链式连接并添加组件以及运行它。链式连接允许我们将多个组件组合在一起,创建一个统一的应用程序。例如,我们可以创建一个链式连接,接收用户输入,使用PromptTemplate对其进行格式化,然后将格式化后的响应传递给LLM。我们可以通过将多个链式连接组合在一起或将链式连接与其他组件组合来构建更复杂的链式连接。

快速入门:使用LLMChain

LLMChain是一个简单的链式连接,它接收一个prompt模板,使用用户输入对其进行格式化,并返回LLM的响应。要使用LLMChain,首先创建一个prompt模板。

from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI

llm = OpenAI(temperature=0.9)
prompt = PromptTemplate(
    input_variables=["product"],
    template="What is a good name for a company that makes {product}?",
)

现在,我们可以创建一个非常简单的链式连接,它将接收用户输入,使用它来格式化prompt,并将其发送到LLM。

from langchain.chains import LLMChain
chain = LLMChain(llm=llm, prompt=prompt)

# 仅指定输入变量运行链式连接。
print(chain.run("colorful socks"))

输出:

Colorful Toes Co.

如果有多个变量,我们可以使用字典一次输入它们。

prompt = PromptTemplate(
    input_variables=["company", "product"],
    template="What is a good name for {company} that makes {product}?",
)
chain = LLMChain(llm=llm, prompt=prompt)
print(chain.run({
    'company': "ABC Startup",
    'product': "colorful socks"
    }))

输出:

Socktopia Colourful Creations.

我们也可以在LLMChain中使用聊天模型:

from langchain.chat_models import ChatOpenAI
from langchain.prompts.chat import (
    ChatPromptTemplate,
    HumanMessagePromptTemplate,
)

human_message_prompt = HumanMessagePromptTemplate(
        prompt=PromptTemplate(
            template="What is a good name for a company that makes {product}?",
            input_variables=["product"],
        )
    )
    
chat_prompt_template = ChatPromptTemplate.from_messages([human_message_prompt])
chat = ChatOpenAI(temperature=0.9)
chain = LLMChain(llm=chat, prompt=chat_prompt_template)
print(chain.run("colorful socks"))

输出:

Rainbow Socks Co.

调用链式连接的不同方式

所有继承自Chain的类都提供了几种运行链式连接逻辑的方式。其中最直接的一种方式是使用 __call__

chat = ChatOpenAI(temperature=0)
prompt_template = "Tell me a {adjective} joke"
llm_chain = LLMChain(
    llm=chat,
    prompt=PromptTemplate.from_template(prompt_template)
)

llm_chain(inputs={"adjective":"corny"})

输出:

{'adjective': 'corny',
 'text': 'Why did the tomato turn red? Because it saw the salad dressing!'}

默认情况下,__call__ 方法会返回输入和输出的键值对。我们可以通过将return_only_outputs设置为True来配置它仅返回输出的键值对。

llm_chain("corny", return_only_outputs=True)
{'text': 'Why did the tomato turn red? Because it saw the salad dressing!'}

如果Chain只输出一个输出键(即其output_keys中只有一个元素),则可以使用run方法。需要注意的是,run方法输出一个字符串而不是字典。

# llm_chain only has one output key, so we can use run
llm_chain.output_keys

输出:

['text']

输入:

llm_chain.run({"adjective":"corny"})

输出:

'Why did the tomato turn red? Because it saw the salad dressing!'

在只有一个输入键的情况下,我们可以直接输入字符串,无需指定输入映射。

# These two are equivalent
llm_chain.run({"adjective":"corny"})
llm_chain.run("corny")

# These two are also equivalent
llm_chain("corny")
llm_chain({"adjective":"corny"})

输出:

{'adjective': 'corny',
 'text': 'Why did the tomato turn red? Because it saw the salad dressing!'}

我们可以通过Chain对象的run方法将其作为Agent中的Tool进行简单集成。

为链式连接添加记忆

Chain支持将BaseMemory对象作为其memory参数,从而使Chain对象能够在多次调用之间保留数据。换句话说,memory参数使Chain成为一个有状态的对象。

from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory

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

conversation.run("Answer briefly. What are the first 3 colors of a rainbow?")
# -> The first three colors of a rainbow are red, orange, and yellow.
conversation.run("And the next 4?")
# -> The next four colors of a rainbow are green, blue, indigo, and violet.

输出:

'The next four colors of a rainbow are green, blue, indigo, and violet.'

基本上,BaseMemory定义了langchain存储记忆的接口。它允许通过load_memory_variables方法读取存储的数据,并通过save_context方法存储新数据。我们可以在《自然语言处理从入门到应用——LangChain:记忆(Memory》系列文章了解更多信息。

调试链式连接

仅从输出中调试Chain对象可能会很困难,因为大多数Chain对象涉及相当数量的输入prompt预处理和LLM输出后处理。将verbose设置为True将在运行时打印出Chain对象的一些内部状态。

conversation = ConversationChain(
    llm=chat,
    memory=ConversationBufferMemory(),
    verbose=True
)
conversation.run("What is ChatGPT?")

日志输出:

> Entering new ConversationChain chain...
Prompt after formatting:
The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.

Current conversation:

Human: What is ChatGPT?
AI:

> Finished chain.

输出:

'ChatGPT is an AI language model developed by OpenAI. It is based on the GPT-3 architecture and is capable of generating human-like responses to text prompts. ChatGPT has been trained on a massive amount of text data and can understand and respond to a wide range of topics. It is often used for chatbots, virtual assistants, and other conversational AI applications.'

使用SequentialChain将链式连接组合起来

在调用语言模型之后的下一步是对语言模型进行一系列的调用。我们可以使用顺序链式连接来实现这一点,顺序链式连接按照预定义的顺序执行其链接。具体而言,我们将使用SimpleSequentialChain。这是最简单的顺序链式连接类型,其中每个步骤都具有单个输入/输出,一个步骤的输出是下一个步骤的输入。在本文中,我们的顺序链式连接将首先为产品创建一个公司名称,我们将重用之前初始化的LLMChain来创建这个公司名称。然后再为产品创建一个口号。我们将初始化一个新的LLMChain来创建这个口号:

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)

现在我们可以将这两个LLMChain结合起来,这样我们就可以一步创建一个公司名称和一个标语。

from langchain.chains import SimpleSequentialChain
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")
print(catchphrase)

日志输出:

> Entering new SimpleSequentialChain chain...
Rainbow Socks Co.


"Put a little rainbow in your step!"

> Finished chain.

输出:

"Put a little rainbow in your step!"

使用Chain类创建自定义链式连接

LangChain提供了许多现成的链式连接,但有时我们可能希望为特定的用例创建自定义链式连接。在这个例子中,我们将创建一个自定义链式连接,它将两个LLMChain的输出连接起来。

要创建一个自定义链式连接:

  1. 创建一个Chain类的子类
  2. 填写input_keysoutput_keys属性
  3. 添加_call方法,展示如何执行链式连接

下面的示例演示了这些步骤:

from langchain.chains import LLMChain
from langchain.chains.base import Chain

from typing import Dict, List


class ConcatenateChain(Chain):
    chain_1: LLMChain
    chain_2: LLMChain

    @property
    def input_keys(self) -> List[str]:
        # Union of the input keys of the two chains.
        all_input_vars = set(self.chain_1.input_keys).union(set(self.chain_2.input_keys))
        return list(all_input_vars)

    @property
    def output_keys(self) -> List[str]:
        return ['concat_output']

    def _call(self, inputs: Dict[str, str]) -> Dict[str, str]:
        output_1 = self.chain_1.run(inputs)
        output_2 = self.chain_2.run(inputs)
        return {'concat_output': output_1 + output_2}

现在,我们可以尝试运行我们调用的链:

prompt_1 = PromptTemplate(
    input_variables=["product"],
    template="What is a good name for a company that makes {product}?",
)
chain_1 = LLMChain(llm=llm, prompt=prompt_1)

prompt_2 = PromptTemplate(
    input_variables=["product"],
    template="What is a good slogan for a company that makes {product}?",
)
chain_2 = LLMChain(llm=llm, prompt=prompt_2)

concat_chain = ConcatenateChain(chain_1=chain_1, chain_2=chain_2)
concat_output = concat_chain.run("colorful socks")
print(f"Concatenated output:\n{concat_output}")

输出:

Concatenated output:

Funky Footwear Company

"Brighten Up Your Day with Our Colorful Socks!"

参考文献:
[1] LangChain官方网站:https://www.langchain.com/
[2] LangChain ️ 中文网,跟着LangChain一起学LLM/GPT开发:https://www.langchain.com.cn/
[3] LangChain中文网 - LangChain 是一个用于开发由语言模型驱动的应用程序的框架:http://www.cnlangchain.com/

你可能感兴趣的:(自然语言处理从入门到应用,人工智能,深度学习,自然语言处理,langchain,链)