LangChain---Agents ReAct模式:让你的AI学会行动与思考
本文介绍了如何利用LangChain构建智能代理(Agent),让大语言模型从被动问答转向主动执行任务。主要内容包括:1. Agent的核心概念:通过"思考-行动-观察"循环(ReAct模式)完成任务,Tools作为Agent的能力扩展;2. 工具定义方法:使用@tool装饰器、Tool类或预构建工具集;3. RunnableAgent实现:基于OpenAI函数调用机制,结合L
教程涉及的代码已放在Git上,地址在文章末尾
【本期目标】
-
理解 LangChain Agent 的核心理念、架构和与传统链条的区别。
-
掌握 Tools 的定义和使用,将外部功能暴露给LLM。
-
学习如何利用最新的 RunnableAgent (基于 Function Calling) 构建一个智能代理。
-
理解 Agent 的执行流程:思考 (Thought)、行动 (Action)、观察 (Observation) 循环。
-
通过实际案例,构建一个能够自主调用工具的智能助手。
引言:为什么需要Agent?从“问答”到“行动”
到目前为止,我们构建的LangChain应用主要是根据输入(用户问题、上下文)来生成输出(答案、摘要)。这种模式非常强大,但它仍然是被动的。LLM只是一个“问答机器”。
然而,现实世界中的任务往往更复杂:
-
“帮我查一下明天北京的天气怎么样?” -> 需要调用天气API。
-
“帮我计算一下256乘以48是多少?” -> 需要调用计算器。
-
“我想预订一个上海到北京的机票。” -> 需要查询航班信息,可能还需要预订接口。
这些任务不能仅仅通过语言模型生成文本来完成,它们需要“行动”——调用外部工具或执行特定功能。
LangChain Agent 的核心思想就是:
让 LLM 不仅仅生成文本,而是能够:
-
理解任务: 接收用户的请求。
-
思考(Reasoning): 分析任务,判断需要哪些步骤和工具。
-
规划(Planning): 制定一个执行计划。
-
行动(Acting): 自主选择并调用合适的外部 Tool。
-
观察(Observation): 获取工具的执行结果。
-
迭代(Iteration): 根据观察结果,继续思考、规划、行动,直到任务完成。
这就赋予了LLM“智能体”的属性,它不再是被动的生成器,而是能主动解决问题的执行者。
核心概念:Tools——Agent的“能力”
Tools 是 Agent 的“手脚”,它们是 Agent 可以调用的外部功能。在LangChain中,一个 Tool 通常就是一个包装了特定功能的Python函数。
Tools 的定义和特点:
-
名称 (name): 工具的唯一标识符(LLM会用这个名字来引用工具)。
-
描述 (description): 对工具功能的清晰、详细解释。这是给LLM看的!描述越好,LLM越能正确选择和使用工具。
-
输入模式 (args_schema / func): 工具接受的输入参数。
LangChain 提供了多种方式来创建 Tools:
-
使用 @tool 装饰器 (最推荐和简洁的方式)
-
将任何 Python 函数转化为 Tool。
-
函数名就是 tool_name。
-
函数的 docstring 就是 tool_description。
-
函数参数就是 tool_input。
-
from langchain_core.tools import tool
# 1. 定义一个简单的计算器工具
@tool
def add(a: int, b: int) -> int:
"""Adds two integers and returns the result."""
return a + b
@tool
def multiply(a: int, b: int) -> int:
"""Multiplies two integers and returns the result."""
return a * b
print("--- @tool 装饰器示例 ---")
print(f"add(2, 3) 结果: {add.invoke({'a': 2, 'b': 3})}") # 工具也可以直接invoke
print(f"multiply(4, 5) 结果: {multiply.invoke({'a': 4, 'b': 5})}")
print(f"工具名称: {add.name}")
print(f"工具描述: {add.description}\n")
-
Tool 类 (更灵活的定义方式)
-
当你需要更精细控制工具的名称、描述或输入时。
-
func:实际执行的Python函数。
-
name:工具名称。
-
description:工具描述。
-
args_schema:可选,用于更严格地定义输入参数的Pydantic模型。
-
from langchain_core.tools import Tool
from pydantic import BaseModel, Field
# 定义一个Pydantic模型来描述输入参数
class SearchInput(BaseModel):
query: str = Field(description="The search query string.")
def _run_search(query: str) -> str:
"""这是一个模拟的网页搜索函数"""
# 实际生产中这里会调用搜索引擎API
if "天气" in query:
return "北京明天晴,气温20-30度。"
elif "LangChain" in query:
return "LangChain是一个用于LLM应用开发的框架。"
else:
return "没有找到相关信息。"
search_tool = Tool(
name="web_search",
description="Search the web for information. Use this tool for general knowledge questions or current events.",
func=_run_search,
args_schema=SearchInput # 使用Pydantic模型定义输入
)
print("--- Tool 类示例 ---")
print(f"search_tool.invoke('北京明天天气') 结果: {search_tool.invoke('北京明天天气')}\n")
-
预构建的 Toolkits (常用工具集合)
-
LangChain 提供了很多开箱即用的 Toolkits,例如:
-
WikipediaToolkit:查询维基百科。
-
PythonREPLTool:执行Python代码。
-
ArxivQueryRun:查询Arxiv论文。
-
-
这些工具通常需要安装额外的库。
-
from langchain_community.tools import WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapper
# 初始化维基百科工具
wiki_tool = WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper(lang="zh",top_k_results=1))
print("--- 预构建工具示例 (Wikipedia) ---")
try:
wiki_result = wiki_tool.invoke("马斯克")
print(f"马斯克维基百科 (部分): {wiki_result[:200]}...\n")
except Exception as e:
print(f"Wikipedia工具调用失败,可能需要安装 'wikipedia' 库或网络问题: {e}\n")
# pip install wikipedia
小结:Tools 是 Agent 能够执行的动作。清晰的 name 和 description 对LLM正确使用工具至关重要。
第一部分:RunnableAgent——LCEL时代的智能体构建
LangChain 构建 Agent 的最推荐方式是利用 RunnableAgent。它与 OpenAI 的 Function Calling (函数调用) 能力紧密结合,并能很好地融入LCEL链条。
Function Calling (函数调用) 机制:
-
这是LLM的一个强大能力:它不仅能生成文本,还能生成符合你定义函数(或工具)的JSON对象。
-
LLM会根据你提供的工具描述和用户输入,判断是否需要调用工具,以及调用哪个工具、使用哪些参数。
-
LLM不会真正执行工具,它只是告诉你“我需要调用这个工具,参数是这些”。实际执行由你的代码完成。
RunnableAgent 的工作流程:
-
用户输入: Agent 接收到用户的问题。
-
LLM思考与工具选择: Agent 将用户输入和所有可用的 Tools 的描述提供给一个支持 Function Calling 的 LLM。LLM生成一个“下一步”的响应:
-
直接回答用户(如果不需要工具)。
-
生成一个**工具调用(Tool Call)**的请求(包含工具名和参数)。
-
-
工具执行: 如果LLM请求调用工具,Agent 会找到对应的工具,并执行它,获取结果(Observation)。
-
循环迭代: Agent 将工具执行结果连同之前的对话历史和思考过程,再次反馈给LLM。LLM根据新的信息继续思考,可能再次调用工具,直到它认为任务完成并能给出最终答案。
【实践:构建一个简单的计算器Agent】
from dotenv import load_dotenv
import os
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessage, AIMessage, ToolMessage
from langchain_core.tools import tool # 用于@tool装饰器
from langchain.agents import AgentExecutor # 核心的Agent执行器
from langchain.agents.format_scratchpad import format_to_openai_function_messages # 格式化中间步骤
from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser # 解析LLM输出
from langchain_core.runnables import RunnablePassthrough
load_dotenv()
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
# 定义工具 (复用上面定义的 add 和 multiply)
@tool
def add(a: int, b: int) -> int:
"""Adds two integers and returns the result."""
return a + b
@tool
def multiply(a: int, b: int) -> int:
"""Multiplies two integers and returns the result."""
return a * b
tools = [add, multiply] # 将工具列表传入
# 1. 定义 Agent 的提示模板
# MessagesPlaceholder("agent_scratchpad") 是关键,它会插入LLM的思考过程和工具执行结果
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个数学助手,可以使用工具进行加法和乘法运算。"),
MessagesPlaceholder(variable_name="chat_history"), # 可以选择性加入聊天历史
("user", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad"), # LLM的思考过程和工具输出会填充这里
])
# 2. 将LLM绑定到工具 (这是 OpenAI Function Calling 的核心)
# LLM 会自动知道如何使用这些工具,并在需要时生成工具调用请求
llm_with_tools = llm.bind_tools(tools)
# 3. 构建 Agent 核心逻辑 (LCEL 链)
# 这一步是关键!它定义了 Agent 的思考循环
agent_runnable = RunnablePassthrough.assign(
agent_scratchpad=lambda x: format_to_openai_function_messages(x["intermediate_steps"])
) | prompt | llm_with_tools | OpenAIFunctionsAgentOutputParser()
# 4. 创建 AgentExecutor
# AgentExecutor 是实际运行 Agent 的组件,它会处理 LLM 的响应 (是文本还是工具调用),
# 如果是工具调用,它会执行工具并把结果反馈给 LLM,直到任务完成。
agent_executor = AgentExecutor(agent=agent_runnable, tools=tools, verbose=True) # verbose=True 会打印详细的思考过程
print("--- 简单的计算器 Agent 示例 ---")
print("Agent 正在运行中...")
# 调用 Agent
response_calc1 = agent_executor.invoke({"input": "256乘以48是多少?", "chat_history": []})
print(f"问题: 256乘以48是多少?")
print(f"Agent 回答: {response_calc1['output']}\n")
response_calc2 = agent_executor.invoke({"input": "200加300再乘以2是多少?", "chat_history": []})
print(f"问题: 200加300再乘以2是多少?")
print(f"Agent 回答: {response_calc2['output']}\n")
response_no_tool = agent_executor.invoke({"input": "你好,能帮我做点什么?", "chat_history": []})
print(f"问题: 你好,能帮我做点什么?")
print(f"Agent 回答: {response_no_tool['output']}\n") # 不需要工具,直接回答
代码解析:
-
@tool装饰器:方便地定义了 add 和 multiply 两个工具。
-
llm.bind_tools(tools):这是利用 OpenAI Function Calling 的核心。它告诉LLM它有哪些可用的工具以及它们的描述。LLM会根据你的输入,在内部决定是否需要“调用”这些工具。
-
MessagesPlaceholder(variable_name="agent_scratchpad"):这是 Agent 循环的关键。每一次LLM的思考(比如决定调用哪个工具)和工具的输出(ToolMessage)都会被格式化后,通过这个占位符传入LLM的下一次调用,形成一个持续的“思考-行动-观察”循环。
-
format_to_openai_function_messages():一个工具函数,负责将 intermediate_steps(即 Agent 过去的所有思考和工具调用/输出)转化为LLM能够理解的 Message 列表。
-
OpenAIFunctionsAgentOutputParser():解析LLM的输出。如果LLM决定调用工具,它会解析出工具名和参数;如果LLM给出最终答案,它会解析出答案。
-
-
AgentExecutor:这是运行 Agent 的最终组件。它接收我们构建的 agent_runnable (即核心的 Agent 逻辑链) 和 tools 列表。它负责协调整个“思考-行动-观察”循环,直到任务完成或达到最大迭代次数。
-
verbose=True:这是调试 Agent 最重要的参数!它会打印出 Agent 内部的每一步思考、工具调用和观察结果,让你清楚地看到 Agent 的决策过程。
小结:RunnableAgent 结合 OpenAI Function Calling,是构建Agent的最现代、最强大的方式。它让LLM能够智能地选择和执行外部工具,从而完成更复杂的任务。
第二部分:Agent的思维过程:ReAct模式
上面 verbose=True 打印出的日志,就是 Agent 内部“思考-行动-观察”循环的体现,这通常被称为 ReAct (Reasoning and Acting) 模式。
-
Thought(思考):LLM会分析用户的问题和现有的信息,思考下一步应该做什么。它会解释为什么选择某个工具,或者为什么直接给出答案。
-
Action(行动):如果LLM认为需要工具,它会指定要调用的工具名称和参数。
-
Observation (观察): AgentExecutor 会执行这个工具,并将工具的输出(结果)作为 Observation。
-
循环:Observation 会被添加到 agent_scratchpad 中,再次作为输入传给LLM,LLM根据新的 Observation 继续进行 Thought,直到得出最终答案。
这个循环直到LLM认为不再需要工具,而是可以直接生成最终的 Answer 时才会停止。
第三部分:Agent的局限性与挑战
虽然Agent非常强大,但它们并非完美无缺,在实际应用中你可能会遇到以下挑战:
-
Token消耗: 每次迭代都需要将历史思考过程和工具输出传给LLM,这会显著增加Token消耗和成本。
-
延迟: 多次LLM调用和工具执行会增加整体响应时间。
-
幻觉与错误决策: LLM可能错误地理解工具的描述,或者在规划步骤时出现逻辑错误,导致工具调用失败或无限循环。
-
工具设计: 工具的名称和描述质量至关重要。模糊或不准确的描述会导致LLM难以正确选择和使用工具。
-
鲁棒性: 对于复杂的、多步骤的任务,Agent 仍然可能出现错误或无法完成任务。
解决策略:
-
清晰的工具描述: 确保工具名称简洁,描述准确且包含使用场景示例。
-
细粒度工具: 尽量将复杂功能拆分成多个简单、原子化的工具。
-
Agent 评测与调试: 使用 LangSmith 详细追踪 Agent 运行轨迹,分析失败原因。
-
错误处理与重试: 在工具执行和AgentExecutor中加入错误处理机制。
-
LangGraph:对于更复杂、需要精确控制流程和状态的Agent,LangGraph 是更强大的选择。
本期小结
本期教程中
-
理解了 LangChain Agent 的核心理念,即如何让LLM从“问答”迈向“行动”。
-
掌握了 Tools 的定义和使用,将外部功能暴露给LLM。
-
学会了如何利用最新的 RunnableAgent 和 OpenAI Function Calling 机制构建一个智能代理。
-
理解了 Agent 内部的“思考-行动-观察”循环 (ReAct模式)。
-
初步了解了 Agent 可能面临的挑战及应对策略。
Agent 极大地扩展了LLM的应用边界,让AI应用具备了解决复杂现实世界问题的能力。在下一期教程中,我们将把目光重新聚焦于RAG,但会是更高阶的RAG——构建你的第一个生产级RAG应用,将前面学到的数据处理、检索、记忆和Agent思想整合起来,搭建一个更强大的知识问答系统!敬请期待!
AI大模型从0到精通全套学习大礼包
我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
只要你是真心想学AI大模型,我这份资料就可以无偿共享给你学习。大模型行业确实也需要更多的有志之士加入进来,我也真心希望帮助大家学好这门技术,如果日后有什么学习上的问题,欢迎找我交流,有技术上面的问题,我是很愿意去帮助大家的!
如果你也想通过学大模型技术去帮助就业和转行,可以点扫描下方👇👇
大模型重磅福利:入门进阶全套104G学习资源包免费分享!
01.从入门到精通的全套视频教程
包含提示词工程、RAG、Agent等技术点
02.AI大模型学习路线图(还有视频解说)
全过程AI大模型学习路线
03.学习电子书籍和技术文档
市面上的大模型书籍确实太多了,这些是我精选出来的
04.大模型面试题目详解
05.这些资料真的有用吗?
这份资料由我和鲁为民博士共同整理,鲁为民博士先后获得了北京清华大学学士和美国加州理工学院博士学位,在包括IEEE Transactions等学术期刊和诸多国际会议上发表了超过50篇学术论文、取得了多项美国和中国发明专利,同时还斩获了吴文俊人工智能科学技术奖。目前我正在和鲁博士共同进行人工智能的研究。
所有的视频由智泊AI老师录制,且资料与智泊AI共享,相互补充。这份学习大礼包应该算是现在最全面的大模型学习资料了。
资料内容涵盖了从入门到进阶的各类视频教程和实战项目,无论你是小白还是有些技术基础的,这份资料都绝对能帮助你提升薪资待遇,转行大模型岗位。
智泊AI始终秉持着“让每个人平等享受到优质教育资源”的育人理念,通过动态追踪大模型开发、数据标注伦理等前沿技术趋势,构建起"前沿课程+智能实训+精准就业"的高效培养体系。
课堂上不光教理论,还带着学员做了十多个真实项目。学员要亲自上手搞数据清洗、模型调优这些硬核操作,把课本知识变成真本事!
如果说你是以下人群中的其中一类,都可以来智泊AI学习人工智能,找到高薪工作,一次小小的“投资”换来的是终身受益!
应届毕业生:无工作经验但想要系统学习AI大模型技术,期待通过实战项目掌握核心技术。
零基础转型:非技术背景但关注AI应用场景,计划通过低代码工具实现“AI+行业”跨界。
业务赋能 突破瓶颈:传统开发者(Java/前端等)学习Transformer架构与LangChain框架,向AI全栈工程师转型。
👉获取方式:
😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓
更多推荐
所有评论(0)