接下来探讨如何使用 LangChain 中的代理来增强大模型的推理和行动能力。这不仅提高了解决问题的效率,还增强了模型的可靠性和可解释性。
ReAct 框架概述
ReAct(Reasoning and Acting)框架的核心思想是结合推理(Reasoning)和行动(Acting)来完成复杂任务。通过推理,大模型分析当前环境并生成解决方案;通过行动,模型执行下一步操作,并根据结果调整推理过程。
- 推理(Reasoning): 分析当前环境,生成推理轨迹。模型可以跟踪并调整行动计划。
- 行动(Acting): 执行具体操作,如调用工具、收集信息或输出答案。
- 协同作用: 推理和行动相辅相成,使得大模型能够处理动态任务。
优势:
- 提升模型的任务完成能力,尤其是需要多步推理的场景。
- 增强模型的可解释性,每一步推理和行动都被记录。
- 支持与外部工具交互(如搜索引擎、计算器),获取实时信息。
代理(Agent)在 LangChain 中的角色
代理的作用是通过与工具集交互,协助大模型完成更复杂的任务。LangChain 中的代理通过 ReAct 框架实现了自主计划和行动的能力。
代理的三个核心组件:
- 大模型: 提供推理和决策能力。
- 工具集: 包括数据检索、计算器、搜索引擎等功能模块。
- 代理执行器(AgentExecutor): 执行代理的推理和行动流程。
代理的流程:
- 计划(Planning): 大模型生成推理轨迹并选择工具。
- 行动(Acting): 执行选定工具的操作。
- 观察(Observation): 收集工具的返回结果。
- 重复上述步骤,直到生成最终答案。
使用 LangChain 实现代理
示例 1:ZERO_SHOT_REACT_DESCRIPTION
此代理类型适合需要工具辅助的简单任务。例如,获取玫瑰的市场价格并计算加价后的售价。
实现代码:
from langchain.agents import load_tools, initialize_agent, AgentType
from langchain.llms import OpenAI
# 设置模型和工具
llm = OpenAI(temperature=0)
tools = load_tools(["serpapi", "llm-math"], llm=llm)
# 初始化代理
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
# 执行任务
agent.run("目前市场上玫瑰花的平均价格是多少?如果我在此基础上加价15%卖出,应该如何定价?")
输出解析:
-
第一轮:搜索价格
- 行动: 调用搜索工具。
- 观察: 返回玫瑰的市场价格。
-
第二轮:计算加价
- 行动: 调用计算器工具。
- 观察: 计算加价后的价格。
-
第三轮:输出结果
- 行动: 输出最终答案。
示例 2:STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION
此代理允许模型调用结构化工具集,如 PlayWright 工具包,用于复杂任务(如网页浏览)。
实现代码:
from langchain.agents.agent_toolkits import PlayWrightBrowserToolkit
from langchain.tools.playwright.utils import create_async_playwright_browser
from langchain.agents import initialize_agent, AgentType
from langchain.chat_models import ChatOpenAI
# 初始化工具包和代理
async_browser = create_async_playwright_browser()
toolkit = PlayWrightBrowserToolkit.from_browser(async_browser=async_browser)
tools = toolkit.get_tools()
llm = ChatOpenAI(temperature=0.5)
agent_chain = initialize_agent(
tools,
llm,
agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION,
verbose=True,
)
# 执行任务
import asyncio
async def main():
response = await agent_chain.arun("What are the headers on python.langchain.com?")
print(response)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
输出解析:
-
第一轮:浏览网页
- 行动: 使用
navigate_browser
工具访问网页。 - 观察: 返回网页状态码。
- 行动: 使用
-
第二轮:获取标题
- 行动: 使用
get_elements
工具提取标题。 - 观察: 返回标题内容。
- 行动: 使用
-
第三轮:输出结果
- 行动: 输出网页标题列表。
示例 3:Plan and Execute
此代理通过规划和执行的分离,处理需要更高推理能力的任务。
实现代码:
from langchain.chat_models import ChatOpenAI
from langchain_experimental.plan_and_execute import PlanAndExecute, load_agent_executor, load_chat_planner
from langchain import SerpAPIWrapper
from langchain.agents.tools import Tool
# 设置工具和模型
search = SerpAPIWrapper()
llm = ChatOpenAI(temperature=0)
tools = [
Tool(name="Search", func=search.run, description="Search current events"),
Tool(name="Calculator", func=lambda x: eval(x), description="Perform calculations")
]
# 初始化计划器和执行器
planner = load_chat_planner(llm)
executor = load_agent_executor(llm, tools, verbose=True)
agent = PlanAndExecute(planner=planner, executor=executor, verbose=True)
# 执行任务
agent.run("在纽约,100美元能买几束玫瑰?")
输出解析:
-
规划:
-
行动: 分解任务为两个子任务:
- 获取玫瑰的单价。
- 计算 100 美元可以买几束玫瑰。
-
-
执行:
- 行动 1: 使用搜索工具获取单价。
- 行动 2: 使用计算工具计算结果。
-
完成: 输出最终答案。
总结
在本讲中,我们学习了以下内容:
-
ReAct 框架: 推理与行动协同,解决复杂任务。
-
代理的核心组件: 模型、工具和执行器。
-
代理的类型和应用:
- ZERO_SHOT_REACT_DESCRIPTION: 适合简单工具交互。
- STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION: 适合复杂工具组合调用。
- Plan and Execute: 适合多步推理和执行任务。
思考题:
- 在结构化工具对话代理中,如何自定义工具集以适应特定任务?
- Plan and Execute 代理如何分解任务,确保每个子任务都能准确完成?