LangChain库

介绍

让我们首先来了解LangChain的基本构建块——即链。

LangChain中的链是什么?

链是通过以逻辑方式连接一个或多个大型语言模型(LLMs)而获得的。(链可以由LLMs之外的实体构建,但为了简单起见,让我们暂时使用这个定义)。

OpenAI是一种LLM(提供者),你可以使用它,但还有其他提供者,如Cohere、Bloom、Huggingface等。

注意:几乎大多数这些LLM提供者都需要你请求一个API密钥才能使用它们。因此,在继续阅读本文的其余部分之前,请确保你已经这样做了。例如:

import os
os.environ["OPENAI_API_KEY"] = "..."

P.S. 将在本教程中使用OpenAI,因为有一个在一个月后到期的积分密钥,但请随时将其替换为其他LLM。无论使用哪种LLM,本文涵盖的概念都将是有用的。

链可以是简单的(即通用的)或专业化的(即实用的)。

  1. 通用的——一个单一的LLM是最简单的链。它接受输入提示和LLM的名称,然后使用LLM进行文本生成(即提示的输出)。以下是一个示例:

让我们构建一个基本的链——创建提示并获得预测

提示创建(使用PromptTemplate)在Lanchain中有点花哨,但这可能是因为根据用例的不同,可以使用多种不同的方式来创建提示(我们将在下一篇博客中介绍AIMessagePromptTemplate、HumanMessagePromptTemplate等)。现在,这是一个简单的示例:

from langchain.prompts import PromptTemplate

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

print(prompt.format(product="podcast player"))

# OUTPUT
# What is a good name for a company that makes podcast player?

注意:如果你需要多个输入变量,例如:input_variables=["product", "audience"],对于一个模板,例如“What is a good name for a company that makes {product} for {audience}”,你需要执行print(prompt.format(product="podcast player", audience="children”)来获取更新后的提示。

一旦你构建了提示,我们可以使用它调用所需的LLM。为此,我们创建一个LLMChain实例(在我们的情况下,我们使用OpenAI的大型语言模型text-davinci-003)。要获取预测(即AI生成的文本),我们使用运行函数和产品的名称。

from langchain.llms import OpenAI
from langchain.chains import LLMChain

llm = OpenAI(
          model_name="text-davinci-003"# default model
          temperature=0.9#temperature dictates how whacky the output should be
llmchain = LLMChain(llm=llm, prompt=prompt)
llmchain.run("podcast player")

# OUTPUT
# PodConneXion

如果你有多个输入变量,那么你将无法使用run。相反,你将不得不将所有变量作为字典传递。例如,llmchain({"product": "podcast player", "audience": "children"}).

注意1:根据OpenAI的说法,davinci文本生成模型的费用是其聊天对应模型即gpt-3.5-turbo的10倍,所以我试图从一个文本模型切换到一个聊天模型(即从OpenAI到ChatOpenAI)结果几乎是相同的。

注意2:你可能会看到一些使用OpenAIChat而不是ChatOpenAI的教程。前者已被弃用,将不再得到支持,我们应该使用ChatOpenAI。

from langchain.chat_models import ChatOpenAI

chatopenai = ChatOpenAI(
                model_name="gpt-3.5-turbo")
llmchain_chat = LLMChain(llm=chatopenai, prompt=prompt)
llmchain_chat.run("podcast player")

# OUTPUT
# PodcastStream

这结束了我们关于简单链的部分。需要注意的是,我们很少将通用链用作独立的链。更常见的情况是它们被用作实用链的构建模块(正如我们将在接下来看到的)。

2.实用链 — 这些是专门的链,由许多语言模型组成,用于解决特定任务。

例如,LangChain支持一些端到端链(如用于摘要、问答等的AnalyzeDocumentChain)以及一些特定的链(如用于创建、查询和保存图形的GraphQnAChain)。在本教程中,我们将深入了解一种特定的链,名为PalChain。

PAL代表“程序辅助语言模型”。PALChain能够阅读以自然语言描述的复杂数学问题,并生成程序(用于解决数学问题的中间推理步骤),但将解决步骤交由运行时(比如Python解释器)来执行。

为了确认这一点确实如此,我们可以检查这里基本代码中的_call()。在底层,我们可以看到这个链:

  • 首先使用一个通用的LLMChain来理解我们传递给它的查询并获得预测。因此,这个链在初始化时需要传递一个LLM(我们将使用与之前相同的OpenAI LLM)。

  • 其次,它使用Python REPL来执行LLM输出的函数/程序。

附言:检查LangChain中任何链的base.py中的_call()是一个很好的实践,以了解底层工作原理。

from langchain.chains import PALChain
palchain = PALChain.from_math_prompt(llm=llm, verbose=True)
palchain.run("If my age is half of my dad's age and he is going to be 60 next year, what is my current age?")

# OUTPUT
# > Entering new PALChain chain...
# def solution():
#    """If my age is half of my dad's age and he is going to be 60 next year, what is my current age?"""
#    dad_age_next_year = 60
#    dad_age_now = dad_age_next_year - 1
#    my_age_now = dad_age_now / 2
#    result = my_age_now
#    return result
#
# > Finished chain.
# '29.5'

注1:如果不需要查看中间步骤,则可以将verbose设置为False。

现在你们中的一些人可能想知道——但提示呢?我们当然没有像我们构建的通用llmchain那样通过一个。事实上,它是在使用.from_math_prompt()时自动加载的。你可以使用palchain.compt.template检查默认提示,也可以直接在此处检查提示文件。

print(palchain.prompt.template)

# OUTPUT
# 'Q: Olivia has $23. She bought five bagels for $3 each. How much money does she have left?\n\n# solution in Python:\n\n\ndef solution():\n    """Olivia has $23. She bought five bagels for $3 each. How much money does she have left?"""\n    money_initial = 23\n    bagels = 5\n    bagel_cost = 3\n    money_spent = bagels * bagel_cost\n    money_left = money_initial - money_spent\n    result = money_left\n    return result\n\n\n\n\n\nQ: Michael had 58 golf balls. On tuesday, he lost 23 golf balls. On wednesday, he lost 2 more. How many golf balls did he have at the end of wednesday?\n\n# solution in Python:\n\n\ndef solution():\n    """Michael had 58 golf balls. On tuesday, he lost 23 golf balls. On wednesday, he lost 2 more. How many golf balls did he have at the end of wednesday?"""\n    golf_balls_initial = 58\n    golf_balls_lost_tuesday = 23\n    golf_balls_lost_wednesday = 2\n    golf_balls_left = golf_balls_initial - golf_balls_lost_tuesday - golf_balls_lost_wednesday\n    result = golf_balls_left\n    return result\n\n\n\n\n\nQ: There were nine computers in the server room. Five more computers were installed each day, from monday to thursday. How many computers are now in the server room?\n\n# solution in Python:\n\n\ndef solution():\n    """There were nine computers in the server room. Five more computers were installed each day, from monday to thursday. How many computers are now in the server room?"""\n    computers_initial = 9\n    computers_per_day = 5\n    num_days = 4  # 4 days between monday and thursday\n    computers_added = computers_per_day * num_days\n    computers_total = computers_initial + computers_added\n    result = computers_total\n    return result\n\n\n\n\n\nQ: Shawn has five toys. For Christmas, he got two toys each from his mom and dad. How many toys does he have now?\n\n# solution in Python:\n\n\ndef solution():\n    """Shawn has five toys. For Christmas, he got two toys each from his mom and dad. How many toys does he have now?"""\n    toys_initial = 5\n    mom_toys = 2\n    dad_toys = 2\n    total_received = mom_toys + dad_toys\n    total_toys = toys_initial + total_received\n    result = total_toys\n    return result\n\n\n\n\n\nQ: Jason had 20 lollipops. He gave Denny some lollipops. Now Jason has 12 lollipops. How many lollipops did Jason give to Denny?\n\n# solution in Python:\n\n\ndef solution():\n    """Jason had 20 lollipops. He gave Denny some lollipops. Now Jason has 12 lollipops. How many lollipops did Jason give to Denny?"""\n    jason_lollipops_initial = 20\n    jason_lollipops_after = 12\n    denny_lollipops = jason_lollipops_initial - jason_lollipops_after\n    result = denny_lollipops\n    return result\n\n\n\n\n\nQ: Leah had 32 chocolates and her sister had 42. If they ate 35, how many pieces do they have left in total?\n\n# solution in Python:\n\n\ndef solution():\n    """Leah had 32 chocolates and her sister had 42. If they ate 35, how many pieces do they have left in total?"""\n    leah_chocolates = 32\n    sister_chocolates = 42\n    total_chocolates = leah_chocolates + sister_chocolates\n    chocolates_eaten = 35\n    chocolates_left = total_chocolates - chocolates_eaten\n    result = chocolates_left\n    return result\n\n\n\n\n\nQ: If there are 3 cars in the parking lot and 2 more cars arrive, how many cars are in the parking lot?\n\n# solution in Python:\n\n\ndef solution():\n    """If there are 3 cars in the parking lot and 2 more cars arrive, how many cars are in the parking lot?"""\n    cars_initial = 3\n    cars_arrived = 2\n    total_cars = cars_initial + cars_arrived\n    result = total_cars\n    return result\n\n\n\n\n\nQ: There are 15 trees in the grove. Grove workers will plant trees in the grove today. After they are done, there will be 21 trees. How many trees did the grove workers plant today?\n\n# solution in Python:\n\n\ndef solution():\n    """There are 15 trees in the grove. Grove workers will plant trees in the grove today. After they are done, there will be 21 trees. How many trees did the grove workers plant today?"""\n    trees_initial = 15\n    trees_after = 21\n    trees_added = trees_after - trees_initial\n    result = trees_added\n    return result\n\n\n\n\n\nQ: {question}\n\n# solution in Python:\n\n\n'

注意:大多数实用链会在库的一部分中预定义它们的提示(在这里检查它们)。有时,这些提示相当详细(即:包含许多标记),因此在成本和LLM的响应质量之间肯定存在权衡。

有没有一些不需要LLMs和提示的链?

尽管PalChain需要LLMs(以及相应的提示)来解析用户以自然语言编写的问题,但LangChain中有一些链不需要。这些主要是用于预处理提示的转换链,例如去除额外的空格,然后将其输入到LLM中。你可以在这里看到另一个示例。

我们可以开始创建链吗?

当然,可以!我们已经拥有了所有需要的基本构建模块,可以开始逻辑地链接LLMs,使其中一个的输入可以传递给下一个。为此,我们将使用SimpleSequentialChain。

文档中有一些很好的示例,例如你可以在这里看到如何组合两个链,其中chain#1用于清理提示(删除额外的空格,缩短提示等),chain#2用于使用这个干净的提示调用LLM。这里还有另一个示例,其中chain#1用于生成一部戏剧的摘要,而chain#2用于根据这个摘要撰写评论。

尽管这些是优秀的示例,但我想集中讨论其他内容。如果你还记得,我之前提到链可以由除LLMs之外的实体组成。更具体地说,我对将代理和LLMs链接在一起感兴趣。但首先,什么是代理?

使用代理动态调用LLMs

这会更容易解释代理是做什么与它是什么。

假设我们想知道明天的天气预报。如果使用简单的ChatGPT API并给出提示“Show me the weather for tomorrow in London”,它不会知道答案,因为它没有访问实时数据。

如果我们能够安排这样一种情况,即利用LLM来理解我们的自然语言查询(即提示),然后代表我们调用天气API以获取所需的数据,这将非常有用,这正是代理所做的事情(当然还有其他事情)。

代理可以访问LLM和一套工具,例如Google搜索、Python REPL、数学计算器、天气API等。

LangChain支持许多代理,但坦率地说,我在教程和YouTube视频中遇到的最常见的代理是zero-shot-react-description。该代理使用ReAct(Reason + Act)框架,根据输入查询的内容从工具列表中选择最适用的工具。

附注:这里有一篇深入探讨ReAct框架的好文章。

让我们使用initialize_agent来初始化一个代理,然后传递给它所需的工具和LLM。这里提供了一长串可供代理用来与外部世界进行交互的工具。在我们的示例中,我们使用与上面相同的数学解决工具,称为pal-math。这个工具在初始化时需要一个LLM,所以我们传递给它与之前相同的OpenAI LLM实例。

from langchain.agents import initialize_agent
from langchain.agents import AgentType
from langchain.agents import load_tools


llm = OpenAI(temperature=0)
tools = load_tools(["pal-math"], llm=llm)


agent = initialize_agent(tools,
                         llm,
                         agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
                         verbose=True)

让我们在与上面相同的示例上进行测试:

agent.run("If my age is half of my dad's age and he is going to be 60 next year, what is my current age?")

# OUTPUT
# > Entering new AgentExecutor chain...
# I need to figure out my dad's current age and then divide it by two.
# Action: PAL-MATH
# Action Input: What is my dad's current age if he is going to be 60 next year?
# Observation: 59
# Thought: I now know my dad's current age, so I can divide it by two to get my age.
# Action: Divide 59 by 2
# Action Input: 59/2
# Observation: Divide 59 by 2 is not a valid tool, try another one.
# Thought: I can use PAL-MATH to divide 59 by 2.
# Action: PAL-MATH
# Action Input: Divide 59 by 2
# Observation: 29.5
# Thought: I now know the final answer.
# Final Answer: My current age is 29.5 years old.

# > Finished chain.
# 'My current age is 29.5 years old.'

注意1:在每个步骤中,你会注意到代理会执行三种操作之一——它会观察、思考或采取行动。这主要是由于ReAct框架和代理正在使用的关联提示。

print(agent.agent.llm_chain.prompt.template)
# OUTPUT
# Answer the following questions as best you can. You have access to the following tools:
# PAL-MATH: A language model that is really good at solving complex word math problems. Input should be a fully worded hard word math problem.

# Use the following format:

# Question: the input question you must answer
# Thought: you should always think about what to do
# Action: the action to take, should be one of [PAL-MATH]
# Action Input: the input to the action
# Observation: the result of the action
# ... (this Thought/Action/Action Input/Observation can repeat N times)
# Thought: I now know the final answer
# Final Answer: the final answer to the original input question
# Begin!
# Question: {input}
# Thought:{agent_scratchpad}

注意2:你可能会想知道让代理执行与LLM可以执行相同的操作的意义在哪里。有些应用程序不仅需要预先确定的LLMs/其他工具的一系列调用,还可能需要依赖用户输入的未知链。在这些类型的链中,有一个“代理”,该代理可以访问一套工具。

为了好玩,我尝试了使输入问题更复杂的示例(使用Demi Moore的年龄作为Dad实际年龄的占位符)。

agent.run("My age is half of my dad's age. Next year he is going to be same age as Demi Moore. What is my current age?")

不幸的是,答案有点偏离,因为特工没有使用黛米·摩尔的最新年龄(因为开放人工智能模型在2020年之前都是根据数据训练的)。这可以通过包括另一个工具来轻松修复--

tools = load_tools([“pal-math”, "serpapi"], llm=llm).serpapi

对于回答有关时事的问题很有用。

注意:添加你认为可能与用户查询相关的尽可能多的工具是很重要的。使用单个工具的问题是,代理不断尝试使用相同的工具,即使它与特定的观察/操作步骤不是最相关的。

下面是你可以使用的另一个工具示例——podcastapi。你需要获得自己的API密钥并将其插入下面的代码中。

tools = load_tools(["podcast-api"], llm=llm, listen_api_key="...")
agent = initialize_agent(tools,
                         llm,
                         agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
                         verbose=True)

agent.run("Show me episodes for money saving tips.")



# OUTPUT
# > Entering new AgentExecutor chain...
# I should search for podcasts or episodes related to money saving
# Action: Podcast API
# Action Input: Money saving tips
# Observation:  The API call returned 3 podcasts related to money saving tips: The Money Nerds, The Rachel Cruze Show, and The Martin Lewis Podcast. These podcasts offer valuable money saving tips and advice to help people take control of their finances and create a life they love.
# Thought: I now have some options to choose from 
# Final Answer: The Money Nerds, The Rachel Cruze Show, and The Martin Lewis Podcast are great podcast options for money saving tips.

# > Finished chain.

# 'The Money Nerds, The Rachel Cruze Show, and The Martin Lewis Podcast are great podcast options for money saving tips.'

注1:使用此API时存在已知错误,你可能会看到openai.error.InvalidRequestError:此模型的最大上下文长度为4097个令牌,但你请求了XXX个令牌(提示中为XX;完成时为XX)。请减少提示;或完成长度。当API返回的响应可能太大时,就会发生这种情况。为了解决这个问题,文档建议减少搜索结果的返回,

注2:在摆弄这个工具时,我注意到了一些不一致的地方。第一次响应并不总是完整的,例如,以下是两次连续运行的输入和响应:

输入:“提高法语水平的播客”

回应1:“学习法语最好的播客是评论得分最高的播客。”

回复2:“学习法语最好的播客是“FrenchPod101”。

在后台,该工具首先使用LLMChain根据我们的输入指令构建API URL(https://listen-api.listennotes.com/api/v2/search?q=french&type=podcast&page_size=3)以及进行API调用。在收到响应后,它使用另一个LLMChain来总结响应,以获得原始问题的答案。你可以在这里查看两个LLMchain的提示,它们更详细地描述了流程。

我们倾向于猜测上面看到的不一致的结果是由摘要步骤产生的,因为我们已经通过Postman单独调试和测试了API URL(由LLMChain#1创建),并收到了正确的响应。为了进一步证实我的疑虑,我还强调将摘要链测试为一个独立的链,其中包含一个空的API URL,希望它会抛出错误,但得到的回复是“发现了投资播客,共包含3个结果。”🤷‍♀ 很好奇,看看别人用这个工具是否运气好!

用例2:组合链,打造适合年龄的礼品生成器

让我们充分利用我们对代理和顺序链的知识,创建我们自己的顺序链。我们将结合:

链#1——我们刚刚创建的代理,可以解决数学中的年龄问题。

链#2——一种LLM,它衡量一个人的年龄,并为他们提供合适的礼物。

# Chain1 - solve math problem, get the age
chain_one = agent

# Chain2 - suggest age-appropriate gift
template = """You are a gift recommender. Given a person's age,\n
 it is your job to suggest an appropriate gift for them.



Person Age:
{age}
Suggest gift:"""

prompt_template = PromptTemplate(input_variables=["age"], template=template)
chain_two = LLMChain(llm=llm, prompt=prompt_template) 

既然我们已经准备好了两个链,我们就可以使用SimpleSequentialChain来组合它们。

from langchain.chains import SimpleSequentialChain

overall_chain = SimpleSequentialChain(
                  chains=[chain_one, chain_two],
                  verbose=True)

有几点需要注意:

我们不需要显式地传递SimpleSequentialChain的input_variables和output_variables,因为基本假设是来自链1的输出作为输入传递给链2。

最后,我们可以使用与以前相同的数学问题来运行它:

question = "If my age is half of my dad's age and he is going to be 60 next year, what is my current age?"
overall_chain.run(question)

# OUTPUT
# > Entering new SimpleSequentialChain chain...


# > Entering new AgentExecutor chain...
# I need to figure out my dad's current age and then divide it by two.
# Action: PAL-MATH
# Action Input: What is my dad's current age if he is going to be 60 next year?
# Observation: 59
# Thought: I now know my dad's current age, so I can divide it by two to get my age.
# Action: Divide 59 by 2
# Action Input: 59/2
# Observation: Divide 59 by 2 is not a valid tool, try another one.
# Thought: I need to use PAL-MATH to divide 59 by 2.
# Action: PAL-MATH
# Action Input: Divide 59 by 2
# Observation: 29.5
# Thought: I now know the final answer.
# Final Answer: My current age is 29.5 years old.

# > Finished chain.
# My current age is 29.5 years old.

# Given your age, a great gift would be something that you can use and enjoy now like a nice bottle of wine, a luxury watch, a cookbook, or a gift card to a favorite store or restaurant. Or, you could get something that will last for years like a nice piece of jewelry or a quality leather wallet.

# > Finished chain.
# '\nGiven your age, a great gift would be something that you can use and enjoy now like a nice bottle of wine, a luxury watch, a cookbook, or a gift card to a favorite store or restaurant. Or, you could get something that will last for years like a nice piece of jewelry or a quality leather wallet

有时,除了从第一个链收的内容外,你可能还需要将一些额外的上下文传递给第二个链。例如,我想根据第一条链退回的人的年龄为礼物设定预算。我们可以使用SimpleMemory来做到这一点。

首先,让我们更新chain_two的提示,并在input_variables中向其传递第二个名为budget的变量。

template = """You are a gift recommender. Given a person's age,\n
 it is your job to suggest an appropriate gift for them. If age is under 10,\n
 the gift should cost no more than {budget} otherwise it should cost atleast 10 times {budget}.

Person Age:
{output}
Suggest gift:"""

prompt_template = PromptTemplate(input_variables=["output""budget"], template=template)
chain_two = LLMChain(llm=llm, prompt=prompt_template)

如果你比较我们在SimpleSequentialChain中使用的模板与上面的模板,你会注意到我还更新了第一个输入的变量名称,从age → output。这是一个关键步骤,否则在链验证时会引发错误 - 缺少所需的输入键:{age},只有{input, output, budget}。

这是因为链中的第一个实体(即代理)的输出将成为链中的第二个实体(即chain_two)的输入,因此变量名称必须匹配。在检查代理的输出键时,我们看到输出变量被称为output,因此进行了更新。

print(agent.agent.llm_chain.output_keys)

# OUTPUT
["output"]

接下来,让我们更新我们正在创建的链的类型。我们不能再使用SimpleSequentialChain,因为它仅适用于具有单一输入和单一输出的情况。由于chain_two现在具有两个input_variables,所以我们需要使用SequentialChain,该链专门用于处理多个输入和输出。

overall_chain = SequentialChain(
                input_variables=["input"],
                memory=SimpleMemory(memories={"budget""100 GBP"}),
                chains=[agent, chain_two],
                verbose=True)

需要注意的几点:

与SimpleSequentialChain不同,SequentialChain的input_variables参数是强制性的。它是一个包含链中的第一个实体(在我们的情况下是代理)期望的输入变量名称的列表。

现在有些人可能会想知道如何知道代理将使用的输入提示中的确切名称。我们显然没有为此代理编写提示(就像我们为chain_two编写的那样)!通过检查代理的llm_chain提示模板,找到这些信息实际上非常简单。

print(agent.agent.llm_chain.prompt.template)

# OUTPUT
#Answer the following questions as best you can. You have access to the following tools:

#PAL-MATH: A language model that is really good at solving complex word math problems. Input should be a fully worded hard word math problem.

#Use the following format:

#Question: the input question you must answer
#Thought: you should always think about what to do
#Action: the action to take, should be one of [PAL-MATH]
#Action Input: the input to the action
#Observation: the result of the action
#... (this Thought/Action/Action Input/Observation can repeat N times)
#Thought: I now know the final answer
#Final Answer: the final answer to the original input question

#Begin!

#Question: {input}
#Thought:{agent_scratchpad}

正如你可以在提示的末尾看到的那样,最终用户提出的问题被存储在名为input的输入变量中。如果由于某种原因你必须在提示中操纵此名称,请确保在创建SequentialChain时也更新input_variables。

最后,你可以在与之前相同的提示下运行新的链。你将注意到,根据我们更新后的提示中的更高预算,最终的输出中包含了一些建议豪华礼物,如周末度假。

print(agent.agent.llm_chain.prompt.input_variables)

# OUTPUT
# ['input', 'agent_scratchpad']

SimpleMemory是一种存储上下文或其他信息的简单方法,这些信息在提示之间永远不会改变。它在初始化时需要一个参数——内存。你可以以dict形式将元素传递给它。例如,SimpleMemory(内存={“budget”:“100GBP”})。

最后,让我们使用与以前相同的提示来运行新链。你会注意到,根据我们更新的提示中较高的预算,最终输出有一些奢侈礼物建议,如周末度假。

overall_chain.run("If my age is half of my dad's age and he is going to be 60 next year, what is my current age?")

# OUTPUT
#> Entering new SequentialChain chain...


#> Entering new AgentExecutor chain...
# I need to figure out my dad's current age and then divide it by two.
#Action: PAL-MATH
#Action Input: What is my dad's current age if he is going to be 60 next year?
#Observation: 59
#Thought: I now know my dad's current age, so I can divide it by two to get my age.
#Action: Divide 59 by 2
#Action Input: 59/2
#Observation: Divide 59 by 2 is not a valid tool, try another one.
#Thought: I can use PAL-MATH to divide 59 by 2.
#Action: PAL-MATH
#Action Input: Divide 59 by 2
#Observation: 29.5
#Thought: I now know the final answer.
#Final Answer: My current age is 29.5 years old.

#> Finished chain.

# For someone of your age, a good gift would be something that is both practical and meaningful. Consider something like a nice watch, a piece of jewelry, a nice leather bag, or a gift card to a favorite store or restaurant.\nIf you have a larger budget, you could consider something like a weekend getaway, a spa package, or a special experience.'}

#> Finished chain.
For someone of your age, a good gift would be something that is both practical and meaningful. Consider something like a nice watch, a piece of jewelry, a nice leather bag, or a gift card to a favorite store or restaurant.\nIf you have a larger budget, you could consider something like a weekend getaway, a spa package, or a special experience.'}

结论

希望通过本文分享的内容能让你更加放心地深入研究这个库。本文只是触及到了表面,还有很多内容可以探讨。例如,如何在你自己的数据集上构建QnA聊天机器人,以及如何优化这些聊天机器人的内存,以便你可以选择/总结对话以发送到提示中,而不是将所有以前的聊天历史都作为提示的一部分发送。

✄-----------------------------------------------

看到这里,说明你喜欢这篇文章,请点击「在看」或顺手「转发」「点赞」。

欢迎微信搜索「panchuangxx」,添加小编磐小小仙微信,每日朋友圈更新一篇高质量推文(无广告),为您提供更多精彩内容。


▼     扫描二维码添加小编  ▼  ▼  

相关推荐

  • 【干货】史上最全的AIGC大模型工具集汇总(下)
  • 从B 树、B+ 树、B* 树谈到R 树
  • 如何使用Docker来渐进式提升开发及部署体验
  • 一个现代化轻量级的跨平台 Redis 桌面客户端,支持 Mac、Windows 和 Linux
  • 京东快递小程序分包优化实践
  • 前端最全的5种换肤方案总结
  • 今天面试了一个前端女生,当场想给她offer!
  • 实现 SpringBoot 程序加密,禁止 jadx 反编译
  • SpringBoot+ElasticSearch实现文档内容抽取、高亮分词、全文检索
  • Angular、React等前端框架掌门人的2024预测
  • 阿里核心业务互动频繁,业务上市计划均有变化;英伟达禁止其他硬件平台运行CUDA;微软将不支持Windows安卓子系统 |极客头条
  • 传MiniMax估值超25亿美元;淡马锡考虑投资OpenAI;谷歌搜索将过滤AI生成内容丨AIGC大事日报
  • 最强文生图模型架构曝光!28页论文详解技术细节,与Sora“师出同门”
  • 破案了!小米龙晶陶瓷:陶瓷相,玻璃芯
  • GPT4.0+Sora 永久激活 ?终身不限量使用!我上车了!!
  • 前端项目如何准确预估个人工时 ?
  • 三款国产AI模型工具大对比
  • Spring Boot中 引入 SpEL,复杂权限控制轻松搞定
  • 提升CKA考试效率:精准统计Ready状态Node节点的实用攻略
  • GPT-4 时代落幕,AI 新巨头 Claude 3 发布