引言
大模型能够通过中间的推理步骤,实现对复杂问题的推理,获得更好的结果,解决更难、更具挑战的任务。但是仅仅有这些并不能解决大模型的固有问题:无法自动更新知识、导致出现幻觉(这里的幻觉差不多就是会根据你提供的信息,进行胡编乱造)。也就是说,大模型只有那些它训练过的知识,以及上下文提供给它的信息。如果你给的问题并不在它的认知范围内,它就会出现幻觉。例如:
为了解决这类问题,可以让大模型先检查提示中信息的真实性,如果真,就继续输出;如果不真,则进行修正。如果这些知识超出它认知范围,可以去调用外部工具去搜索,检查信息的真实性。
代理
这种大模型进行自主判断、自行调用工具、自行决定下一步行动的行为,就是代理。
在LangChain中使用代理,我们只需要理解下面三个元素。
- 大模型:提供逻辑的引擎,负责生成预测和处理输入。
- 与之交互的外部工具:可能包括数据清洗工具、搜索引擎、应用程序等。
- 控制交互的代理:调用适当的外部工具,并管理整个交互过程的流程。
当我们面对一个复杂问题的时候,我们会考虑选择什么样的工具去解决这个问题,最后得到一个结果。
但是这个过程如果没有引导,对于大模型来说并不简单,比如:
- 什么时候开始在本地知识库中搜索(这个比较简单,毕竟是第一个步骤,可以预设)?
- 怎么确定本地知识库的检索已经完成,可以开始下一步?
- 调用哪一种外部搜索工具(比如Google引擎)?
- 如何确定外部搜索工具返回了想要找的内容?
- 如何确定信息真实性的检索已经全部完成,可以开始下一步?
那么,LangChain中的代理是怎样自主计划、自行判断,并执行行动的呢?
ReAct框架
ReAct框架主要由三个关键概念组成:Thought(思考)、Act(行动)和Obs(观察)。
- Thought(思考) :由LLM模型生成,是LLM产生行为和依据的基础。它代表了模型在面对特定任务时的逻辑推理过程,是决策的前提。
- Act(行动) :指LLM判断本次需要执行的具体行为。这通常涉及选择合适的工具或API,并生成所需的参数,以实现目标行动。
- Obs(观察) :LLM框架对于外界输入的获取,类似于LLM的“五官”,将外界的反馈信息同步给LLM模型,协助模型进一步做分析或决策。
如果再对这三个过程进行简化的话,就会变成推理-行动,也就是Reasoning-Acting框架。
ReAct框架会提示 LLMs 为任务生成推理轨迹和操作,这使得代理能系统地执行动态推理来创建、维护和调整操作计划,同时还支持与外部环境(例如Google搜索、Wikipedia)的交互,以将额外信息合并到推理中。
通过代理实现ReAct框架
下面做一个示例:
目标是找到玫瑰的当前市场价格,然后计算出加价15%后的新价格。
在开始之前,有一个准备工作,就是你需要在 serpapi.com 注册一个账号,并且拿到你的 SERPAPI_API_KEY,这个就是我们要为大模型提供的 Google 搜索工具。
下载需要的包
pip install google-search-results
示例代码:
# 设置OpenAI和SERPAPI的API密钥
import os
os.environ["OPENAI_API_KEY"] = 'Your OpenAI API Key'
os.environ["SERPAPI_API_KEY"] = 'Your SerpAPI API Key'
# 加载所需的库
from langchain.agents import load_tools
from langchain.agents import initialize_agent
from langchain.agents import AgentType
from langchain.llms import OpenAI
# 初始化大模型
llm = OpenAI(temperature=0)
# 设置工具
tools = load_tools(["serpapi", "llm-math"], llm=llm)
# 初始化Agent
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
agent.run("目前市场上玫瑰花的平均价格是多少?如果我在此基础上加价15%卖出,应该如何定价?")
输出:
> Entering new chain...
I need to find the current market price of roses and then calculate the new price with a 15% markup.
Action: Search
Action Input: "Average price of roses"
Observation: According to the study, the average price for a dozen roses in the United States is $80.16. The Empire State hovers closer to that number than its neighbors, with a bouquet setting back your average New Yorker $78.33.
Thought: I need to calculate the new price with a 15% markup.
Action: Calculator
Action Input: 80.16 * 1.15
Observation: Answer: 92.18399999999998
Thought: I now know the final answer.
Final Answer: The new price with a 15% markup would be $92.18.
> Finished chain.
可以看到,ZERO_SHOT_REACT_DESCRIPTION类型的智能代理在LangChain中,自动形成了一个完善的思考与行动链条,而且给出了正确的答案。
代理的关键组件
- 代理(Agent):这个类决定下一步执行什么操作。它由一个语言模型和一个提示(prompt)驱动。提示可能包含代理的性格(也就是给它分配角色,让它以特定方式进行响应)、任务的背景(用于给它提供更多任务类型的上下文)以及用于激发更好推理能力的提示策略(例如ReAct)。LangChain中包含很多种不同类型的代理。
- 工具(Tools):工具是代理调用的函数。这里有两个重要的考虑因素:一是让代理能访问到正确的工具,二是以最有帮助的方式描述这些工具。如果你没有给代理提供正确的工具,它将无法完成任务。如果你没有正确地描述工具,代理将不知道如何使用它们。LangChain提供了一系列的工具,同时你也可以定义自己的工具。
- 工具包(Toolkits):工具包是一组用于完成特定目标的彼此相关的工具,每个工具包中包含多个工具。比如LangChain的Office365工具包中就包含连接Outlook、读取邮件列表、发送邮件等一系列工具。当然LangChain中还有很多其他工具包供你使用。
- 代理执行器(AgentExecutor):代理执行器是代理的运行环境,它调用代理并执行代理选择的操作。执行器也负责处理多种复杂情况,包括处理代理选择了不存在的工具的情况、处理工具出错的情况、处理代理产生的无法解析成工具调用的输出的情况,以及在代理决策和工具调用进行观察和日志记录。
总的来说,代理就是一种用语言模型做出决策、调用工具来执行具体操作的系统。通过设定代理的性格、背景以及工具的描述,你可以定制代理的行为,使其能够根据输入的文本做出理解和推理,从而实现自动化的任务处理。而 代理执行器(AgentExecutor) 就是上述机制得以实现的引擎。
结构化工具
简单点说,就是调用包含一系列复杂工具的“结构化工具箱”中的多个工具,完成批次相关的任务集合。
结构化工具的示例包括:
- 文件管理工具集:支持所有文件系统操作,如写入、搜索、移动、复制、列目录和查找。
- Web 浏览器工具集:官方的 PlayWright 浏览器工具包,允许代理访问网站、点击、提交表单和查询数据。
什么是 Playwright
Playwright是一个开源的自动化框架,它可以让你模拟真实用户操作网页,帮助开发者和测试者自动化网页交互和测试。 下面,我们要通过Playwright浏览器工具来访问一个测试网页。
在这之前,先用 pip install playwright 安装Playwright工具。
不过,如果只用pip安装Playwright工具安装包,就使用它,还不行,会得到下面的信息。
因此我们还需要通过 playwright install 命令来安装三种常用的浏览器工具。
代码:
from playwright.sync_api import sync_playwright
def run():
# 使用Playwright上下文管理器
with sync_playwright() as p:
# 使用Chromium,但你也可以选择firefox或webkit
browser = p.chromium.launch()
# 创建一个新的页面
page = browser.new_page()
# 导航到指定的URL
page.goto('https://langchain.com/')
# 获取并打印页面标题
title = page.title()
print(f"Page title is: {title}")
# 关闭浏览器
browser.close()
if __name__ == "__main__":
run()
输出:
Page title is: LangChain
Self-Ask with Search 代理
Self-Ask with Search代理是一种利用追问和中间答案策略帮助大型语言模型处理多步推理问题的工具。它通过提出问题并利用搜索结果来找到答案,特别适合解决那些需要额外信息才能解答的问题。
工作原理: 这种代理将大问题切分成小问题,逐步解答。它首先识别出需要解决的子问题,然后使用搜索工具进行搜索,找到相关答案,并基于这些答案提出进一步的问题,直到找到最终答案。
实例代码:
from langchain import OpenAI, SerpAPIWrapper
from langchain.agents import initialize_agent, Tool
from langchain.agents import AgentType
llm = OpenAI(temperature=0)
search = SerpAPIWrapper()
tools = [
Tool(
name="Intermediate Answer",
func=search.run,
description="useful for when you need to ask with search",
)
]
self_ask_with_search = initialize_agent(
tools, llm, agent=AgentType.SELF_ASK_WITH_SEARCH, verbose=True
)
self_ask_with_search.run(
"使用玫瑰作为国花的国家的首都是哪里?"
)
输出:
好了,就学到这里吧。