LangChain Agent :从查询来生成任务

发布日
目录

1. 简介

自治代理(Autonomous Agents)最近经历了显着的演变,自治代理指的是无需人工干预即可独立做出决策和采取行动的系统。另一方面,由于它们基于复杂的算法进行操作,因此它们的行为难以预测,这可能导致无法实现预期行为等问题。

那么,到底是什么原因导致它不能正常工作呢?原因之一是Agent本身不了解自己能做什么。

在LangChain的Agent中,基于ReAct式的思维,Agent可以采取什么行动(或者说可以使用什么工具)被提前写在提示中,并根据该提示做出决策和行动。这样,通过意识到Agent本身“预先知道它能做什么”,就可以在一定程度上控制Agent的行为。

这篇文章我们将讨论如何从查询来生成任务。

2. 根据查询生成任务

对于Agent来说,“提前知道他们能做什么”很重要。Agent本身根据 ReAct 思维过程顺序生成任务,但是除了Agent用的LLM之外,准备任务生成用的LLM对于控制Agengt的行为是非常有用的。

例如,假设您被问到这样的问题:“请比较 A 公司产品 X 和 B 公司产品 Y 的功能。 ” 如果该工具有办法研究这些产品(例如通过搜索网络或使用专用数据库),

1. 调查A公司产品X的特点

2. 调查B公司产品Y的特点

3. 比较产品 X 和产品 Y 的功能

它可以分解生成以上三个任务。然而,如果你不知道自己可以采取什么行动(或者有哪些工具可用),你可能无法在你的LLM中采取行动,比如“拜访A公司并咨询负责人”或“给A公司负责人打电话。”否则,可能会创建无法完成的任务。写一个好的提示是关键,但是如何真正写出提示呢?下面是一个Prompt例子。

TEMPLATE_CREATE_TASK_LIST = """

对于用户问题“{user_question}”,请按照以下规则生成任务列表:

1. 如果您的问题可以清楚地分解为多个独立的主题或元素,请将它们分成单独的问题。

2. 如果问题中包含“那些”、“那个”等不清楚的指示词,请参考对话记录猜测指示词的内容。

3. 如果问题已分解,请将分解后的问题作为任务列表返回。

4. 如果问题无法分解,请按任务列表形式返回问题。

对话历史:

{历史}

您可以采取四种操作来执行该任务:

1. Retrieval_A:用于回答A公司产品时使用

2. Retrieval_B:用于回答有关B公司产品的问题

3. Comparator:用于比较不同产品

4. Calculator:用于费用等数值计算

以下是一些示例:

示例 1:告诉我有关产品 X 和产品 Y 的信息。


1. 了解产品 X

2.了解产品Y


示例 2:如果您购买 1000 件,请估算产品 X 的价格。


1. 找出产品 X 每个地点的价格。

2.计算购买1000件的价格

"""


3. 执行

3.1 设置LLM和API KEY

那么试着执行一下。首先,设置API KEY和LLM。这一次,我们还将定义ConversationBufferMemory,假设您在接受前一个问题时生成任务。

import os

import openai

from langchain.memory import ConversationBufferMemory

from langchain.chat_models import ChatOpenAI

openai.api_key = os.environ['OPENAI_API_KEY']

    

llm = ChatOpenAI(

    model_name='gpt-3.5-turbo',

       temperature=0

)  

memory = ConversationBufferMemory()


3.2 生成任务

接下来我们看看实际生成任务的create_task_list。该函数使用LLM解析用户的问题并将其转化为具体的任务。最终结果是生成的任务列表。

from langchain.schema import AIMessage, HumanMessage, SystemMessage

from typing import List

import re


def create_task_list(user_question: str) -> List[str]:

    """Use LLM to decompose a question and convert into tasks.

       Args:

           user_question: The user's question.

        Returns:

           A list of tasks derived from the user's question.

    """

    content_message = TEMPLATE_CREATE_TASK_LIST.format(

        user_question=user_question, 

        history=memory.load_memory_variables({})['history'],

    )

    output = llm([HumanMessage(content=content_message)])

    all_responses = output.content.splitlines()

    task_list = []

    for line in all_responses:

        if re.match(r"^\d+\.", line):

            task = line[line.index('.')+2:].strip()

            if task != user_question:

                task_list.append(task)

    if len(task_list) == 0:

        task_list.append(user_question)

    return task_list

使用前面介绍的TEMPLATE_CREATE_TASK_LIST 模板输入到 LLM来进行处理 。使用正则表达式re.match(r“^\d+\.”,line)检查输出的每一行是否是编号列表的格式。如果适用,请将该行的文本添加到任务列表中。如果任务列表为空,则返回原始问题。

4. 尝试执行任务

后我们来实际执行一下上面的函数。这次,我们提出的问题是,“请比较A公司的产品X和B公司的产品Y的费用,生成购买1000个便宜的,100个贵的产品的报价。”

def main():

    question = "请比较A公司的产品X和B公司的产品Y的费用,生成购买1000个便宜的,100个贵的产品的报价。"

    task_list = create_task_list(question)

    print(task_list)


if __name__ == "__main__":

    main()

结果如下所示。

['Retrieval_A:查找 A 公司的产品 X',

'Retrieval_B:查找B公司的产品Y',

'Comparator:比较产品X和产品Y的价格',

'Calculator:计算购买1000个便宜产品时的报价',

'Calculator:计算购买100个贵的产品时的报价']

在任务生成的时候,LLM自己“很好地理解了能做什么”,所以很好地告诉了我们使用哪个工具做什么。这样的多个任务按代理顺序执行,但是多个任务不能用通常使用的LLMSingleActionAgent来处理。现在需要开发自己的代理,如LLMMultiActionAgent。


下一次,我们再来讲述通过把生成的任务交给所谓的Multi-action Agent来进行实现!