从零构建智能体:基于LangChain框架实现ReAct Agent的完整指南
在当今AI应用开发浪潮中,如何让大语言模型(LLM)不仅会“思考”,还能“行动”,是构建真正智能系统的关键。LangChain框架为此提供了强大的Agent(智能体)范式,而ReAct(Reasoning + Acting)模式则是其中最经典、最有效的实现路径之一。本文将带你从零开始,深入剖析如何使用LangChain构建一个能够自主调用工具、进行多步推理的ReAct Agent,并分享实战中的核心要点与避坑指南。
一、智能体与链:从线性执行到动态决策
在深入代码之前,理解Agent与Chain(链)的本质区别至关重要。这类似于传统编程中过程式执行与基于状态的决策系统的差异。
- 链(Chain):是预定义的、线性的执行流程。如同Python或Java中一个固定的函数调用序列,一步接一步,执行完毕即结束。它适合流程明确、无需中途判断的任务。
- 智能体(Agent):则是一个动态的决策系统。它内置一个“大脑”(LLM),能够根据当前执行结果和环境反馈,自主决定下一步该做什么、调用哪个工具。这需要AgentExecutor来驱动“思考-行动-观察”的循环,直到任务完成或达到终止条件。
这种动态性使得Agent能够处理诸如“查询天气后决定是否提醒带伞”、“计算商品总价并检查库存”等需要条件判断和多步骤协作的复杂任务。它不仅适用于Python生态,其设计思想同样可以启发Go、C++等系统语言中状态机的设计,或是TypeScript前端应用中的复杂异步流程控制。
二、构建武器库:工具与工具包的精确定义
工具(Tool)是Agent与外部世界交互的手和脚。开发一个强大的Agent,很大程度上就是在设计和集成一套好用的工具。在LangChain中,将一个普通函数转化为Agent可调用的工具非常简单,核心在于@tool装饰器。
让我们看看如何定义两个基础工具:一个用于查询水果单价,另一个用于执行数学计算。以下是tools.py的核心内容:
from langchain_core.tools import tool
@tool
def calculate(expression: str) -> float:
"""执行计算并返回结果 - 使用 Python 语法,必要时请使用浮点数语法"""
return eval(expression)
@tool
def ask_fruit_unit_price(fruit: str) -> str:
"""询问水果的价格"""
fruit = fruit.strip()
if fruit.casefold() in ["apple", "苹果"]:
return "苹果单价是 10元/公斤"
if fruit.casefold() in ["banana", "香蕉"]:
return "香蕉单价是 6元/公斤"
return f"{fruit} 单价是 20元/公斤"
关键解析与最佳实践:
- 函数名即工具名:使用清晰的英文命名(如
calculate),有助于LLM准确理解工具用途。 - 文档字符串(Docstring)是灵魂:LLM完全依赖此描述来判断何时调用该工具。描述务必精确,避免歧义。例如,“执行数学表达式计算”比“计算函数”好得多。
- 参数注解必须准确:这定义了工具输入的Schema,错误的类型会导致Agent调用失败。
- ⚠️ 安全警告:示例中
calculate工具使用eval(),这在生产环境是极其危险的,会引入代码注入漏洞。真实场景应替换为ast.literal_eval、numexpr或自定义的安全表达式解析器。
将相关工具组织成工具包(Toolkit),可以方便地管理特定领域的全部能力,例如一个“电商助手工具包”可能包含查询价格、检查库存、计算运费等多个工具。[AFFILIATE_SLOT_1]
三、组装大脑:配置ReAct智能体执行器
有了工具,接下来需要创建Agent的核心——ReAct智能体执行器。这部分代码通常在agent.py中,负责集成LLM、工具并定义推理逻辑。
首先,我们需要一个精心设计的Prompt模板来引导LLM遵循ReAct模式:
prompt = PromptTemplate.from_template('''Answer the following questions as best you can. You have access to the following tools:
{tools}
Use the following format:
Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [{tool_names}]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question
Begin!
Question: {input}
Thought:{agent_scratchpad}''')
这个模板包含了几个关键占位符:{tools}(工具详细描述)、{tool_names}(工具名列表)、{input}(用户问题)和{agent_scratchpad}(历史记录)。它们共同为Agent的每一步推理提供上下文。
接下来,是创建Agent的函数:
def create_agent() -> AgentExecutor:
"""创建ReAct Agent执行器"""
dotenv.load_dotenv()
llm = ChatOpenAI(
openai_api_key=os.getenv("OPENAI_API_KEY"),
openai_api_base=os.getenv("OPENAI_API_BASE"),
model=os.getenv("AI_MODEL", "deepseek-chat"),
temperature=0.1, # 推理场景使用低temperature保证确定性
)
tools = [calculate, ask_fruit_unit_price]
agent = create_react_agent(llm=llm, tools=tools, prompt=prompt)
return AgentExecutor(
agent=agent,
tools=tools,
verbose=True # 打印详细执行过程
)
配置要点与优化建议:
- 温度(Temperature):对于需要严谨推理的Agent任务,建议设置为较低值(0-0.2)。过高的温度(如0.7)可能导致LLM“胡思乱想”,错误选择工具或生成无效内容,造成不必要的token消耗和循环。
- 模型选择:示例中使用DeepSeek API是性价比之选。若追求最高准确性和可靠性,GPT-4是更好的选择,但成本显著上升。也可根据场景尝试Claude或本地部署的模型。
- Verbose模式:调试时开启
verbose=True可以清晰看到Agent的“思考”过程,便于排查问题。生产环境应关闭以提升性能。 - 成本控制:Agent的多次循环思考会消耗大量tokens。务必设置
max_tokens上限,并考虑在本地使用小模型完成逻辑验证后再调用付费API。
四、实战演练:观察ReAct智能体的思考过程
理论结合实践,让我们通过主程序main.py来运行一个完整示例:
from agent import create_agent
if __name__ == '__main__':
# 创建Agent
agent = create_agent()
# 执行Agent
result = agent.invoke({
"input": "3公斤苹果和2公斤香蕉的总价格是多少?"
})
# 打印结果
print(result)
执行上述代码,你将看到Agent如何一步步解决“3公斤苹果和2公斤香蕉共多少钱”这个问题。其输出清晰地展示了ReAct的循环过程:
> Entering new AgentExecutor chain...
我需要计算总价格。首先,我应该找到苹果和香蕉的单价。
Thought: 我需要找到苹果的单价
Action: ask_fruit_unit_price
Action Input: 苹果
Observation: 苹果单价是 10元/公斤
Thought: 现在我需要找到香蕉的单价
Action: ask_fruit_unit_price
Action Input: 香蕉
Observation: 香蕉单价是 6元/公斤
Thought: 我已经知道了两种水果的价格。苹果是10元/公斤,香蕉是6元/公斤。现在我需要计算总成本:3公斤苹果和2公斤香蕉。
Action: calculate
Action Input: 3 * 10 + 2 * 6
Observation: 42
Thought: 我现在知道最终答案了
Final Answer: 3公斤苹果和2公斤香蕉的总价格是42元。
> Finished chain.
{'input': '3公斤苹果和2公斤香蕉的总价格是多少?', 'output': '3公斤苹果和2公斤香蕉的总价格是42元。'}
这个过程完美诠释了ReAct的核心理念:Reasoning(推理)与Acting(行动)交替进行。Agent像一个人一样,先分解问题,然后通过工具获取必要信息(查询单价),再进行计算,最终给出答案。这种模式让LLM突破了纯文本生成的限制,具备了解决现实世界问题的能力。
你可以轻松扩展更多示例,比如查询其他水果价格或进行复杂计算:
result = agent.invoke({
"input": "5公斤橙子多少钱?"
})
result = agent.invoke({
"input": "如果我买2公斤苹果和3公斤香蕉,并且有10%的折扣,我需要付多少钱?"
})
五、扩展、优化与生态整合
一个基础的ReAct Agent搭建完成后,你可以从多个维度对其进行增强,以适应更复杂的生产需求。
1. 工具生态扩展:
- 安全强化:立即替换不安全的
eval,为工具添加输入验证和异常处理。 - 能力丰富:集成网络搜索(如SerpAPI)、数据库查询、文件读写、第三方API调用等工具。LangChain社区已提供了大量现成工具。
- 领域定制:为你的垂直领域(如金融、法律、客服)开发专用工具包。
2. Agent性能优化:
- Prompt工程:微调Prompt模板,加入少样本示例(Few-shot),可以显著提升Agent在特定任务上的表现和工具调用的准确率。
- 记忆机制:为Agent添加短期或长期记忆,使其能在多轮对话中保持上下文。
- 多智能体协作:设计多个各司其职的Agent,让它们通过通信协作解决超复杂任务。这类似于在Go或C++中设计并发协作的微服务。
- 监控与可观测性:添加回调函数,记录工具调用日志、token消耗、执行时长,便于监控和成本分析。[AFFILIATE_SLOT_2]
3. 项目初始化与依赖:
开始之前,请确保环境满足要求,并安装必要依赖:
pip install langchain langchain-openai langchain-core python-dotenv
同时,在.env文件中配置你的API密钥:
OPENAI_API_KEY=your_api_key_here
OPENAI_API_BASE=https://api.deepseek.com/v1 # 或其他兼容的API端点
AI_MODEL=deepseek-chat
通过本文的逐步拆解,我们完成了从理解概念、定义工具、配置Agent到实战运行和扩展优化的全流程。使用LangChain构建ReAct Agent,本质上是为LLM装备了一套可编程的“行动准则”和“外部工具”,使其从对话机器人进化为能够自主完成任务的数字助手。无论你是Python开发者,还是正在探索Java、TypeScript中的AI应用集成,这种“思考-行动”循环的设计范式都具有极高的参考价值。现在,不妨尝试文末的挑战——为Agent添加一个汇率查询工具,让它真正走向更广阔的应用天地。
浙公网安备 33010602011771号