自治代理(Autonomous Agents)最近经历了显着的演变,自治代理指的是无需人工干预即可独立做出决策和采取行动的系统。另一方面,由于它们基于复杂的算法进行操作,因此它们的行为难以预测,这可能导致无法实现预期行为等问题。
那么,到底是什么原因导致它不能正常工作呢?原因之一是Agent本身不了解自己能做什么。
在LangChain的Agent中,基于ReAct式的思维,Agent可以采取什么行动(或者说可以使用什么工具)被提前写在提示中,并根据该提示做出决策和行动。这样,通过意识到Agent本身“预先知道它能做什么”,就可以在一定程度上控制Agent的行为。
这篇文章我们将讨论如何从查询来生成任务。
对于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件的价格
"""
那么试着执行一下。首先,设置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()
接下来我们看看实际生成任务的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
后我们来实际执行一下上面的函数。这次,我们提出的问题是,“请比较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来进行实现!