LangChain实战:ZeroShot_ReAct Agent 从零搭建,无需训练也能灵活调用工具
在大模型应用开发中,"让AI自主判断、灵活调用工具"是实现智能化的关键一步。而ZeroShot_ReAct Agent作为LangChain中最易用、最基础的智能代理方案,无需提前训练样本,仅通过工具描述就能让大模型自主决策调用逻辑,完美解决了"固定流程调用工具"的死板问题。
今天就结合实战案例,聊聊ZeroShot_ReAct的核心特点、工作逻辑,以及如何快速搭建一个能自主获取时间、执行数学计算的智能Agent,全程无冗余代码,聚焦原理与实现思路,新手也能轻松理解。
一、先搞懂:ZeroShot_ReAct 到底是什么?
首先要明确两个核心概念的结合------ZeroShot(零样本)与ReAct(推理+行动),二者结合才构成了这个Agent的强大能力:
1. ReAct:让AI像人一样"思考+行动"
ReAct是一种大模型推理框架,核心逻辑源于人类解决问题的习惯:先思考(Thought),再行动(Action),根据行动结果(Observation)再调整思考,循环往复直到得出答案。这种框架打破了"大模型只做文本生成"的局限,让AI具备了"主动调用外部工具"的能力,而不是单纯依赖自身知识库回答问题。
比如面对"现在几点了"这个问题,AI不会凭空猜测,而是会思考"我需要获取当前时间,这需要调用专门的工具",然后执行调用操作,拿到结果后再整理成最终答案------这就是ReAct的核心价值:让推理与行动协同,解决大模型"不会实时交互、不会计算"的痛点。
2. ZeroShot:无需训练,即插即用
ZeroShot(零样本)则解决了"使用门槛"的问题。传统Agent可能需要提前准备大量训练样本,告诉AI"什么场景用什么工具",而ZeroShot_ReAct Agent完全不需要------它仅通过工具的描述信息,就能自主判断"当前问题是否需要调用工具、调用哪个工具、如何传递参数"。
简单来说,你只需要告诉Agent"有一个工具能获取当前时间,无需参数",它就能在遇到"查询时间"的问题时,自动调用这个工具;遇到"数学计算"的问题时,自动匹配计算工具------这就是它最便捷的地方:无需训练,配置好工具和提示词,就能直接使用。
ZeroShot_ReAct 核心优势总结
- 零样本适配:无需训练样本,仅通过工具描述即可实现工具调用决策,降低开发成本;
- 推理透明:全程遵循"思考-行动-观察"的流程,可清晰追溯AI的决策逻辑,便于调试;
- 灵活扩展:新增工具时,只需添加工具描述和实现逻辑,无需修改Agent核心代码;
- 兼容性强:可适配各类兼容OpenAI API的大模型,无论是在线模型还是本地部署的模型(如Qwen、DeepSeek等)都能无缝对接。
二、实战拆解:ZeroShot_ReAct Agent 实现步骤
结合本次实战案例,我们搭建的Agent能实现两个核心功能:获取当前系统时间、执行数学表达式计算。整个实现过程分为4个核心步骤,逻辑清晰,可直接复用思路扩展更多工具。
步骤1:配置大模型(LLM)------ Agent的"大脑"
大模型是ZeroShot_ReAct Agent的核心,负责"思考决策":判断是否需要调用工具、调用哪个工具、如何处理工具返回结果。本次实战选用了本地部署的Qwen3.5模型,通过兼容OpenAI API的方式接入LangChain。
核心配置思路:只需指定模型的API密钥、部署地址、模型名称,以及温度(temperature)和最大令牌数(max_tokens)------温度越低,AI的决策越稳定,避免随机猜测;最大令牌数则限制单次输出的长度,防止冗余。
这里的关键的是:只要模型兼容OpenAI API,无论你用的是在线模型(如GPT、DeepSeek)还是本地部署的模型(如Ollama部署的Qwen、Llama),都能直接替换使用,无需修改后续核心逻辑。
步骤2:定义工具------ Agent的"手脚"
工具是Agent与外部交互的载体,也是ZeroShot_ReAct实现"行动"的核心。每个工具都需要明确三个关键信息:工具名称、工具功能(函数实现)、工具描述------这三个信息,尤其是工具描述,直接决定了AI能否正确判断何时调用该工具。
本次实战定义了两个工具,思路可直接复用:
- 时间工具:负责获取当前系统时间,无需输入参数,工具描述需明确"无需参数",避免AI传递多余信息;
- 计算工具:负责执行数学表达式计算,支持加减乘除和括号,工具描述需明确支持的表达式类型,让AI知道该工具能解决什么问题、需要传递什么格式的输入。
这里有一个细节:工具的描述必须简洁、准确,避免模糊表述。因为ZeroShot_ReAct Agent正是通过解析工具描述,来判断"当前问题是否需要调用该工具"------描述越清晰,AI的决策越准确,减少调用错误。同时,工具的函数实现需考虑安全性,比如计算工具需限制可执行的函数,避免恶意代码注入。
步骤3:自定义ReAct提示模板------ Agent的"行为准则"
提示模板(Prompt)是ZeroShot_ReAct Agent的"规则手册",核心作用是告诉AI"如何思考、如何输出、如何调用工具"。因为大模型本身并不知道"ReAct流程",也不知道"如何规范调用工具",需要通过提示模板来约束其行为。
本次实战的提示模板,重点做了两个核心约束(也是ZeroShot_ReAct能正常工作的关键):
- 格式约束:明确规定"需要调用工具"和"无需调用工具"的输出格式,比如调用工具时必须按照"思考-行动-输入"的三行格式输出,不能添加任何多余文字,确保Agent能正确解析AI的输出;
- 工具约束:明确告知AI可用的工具名称和工具功能,并且强调"工具名称必须完全匹配,区分大小写",避免AI因名称错误导致调用失败。
此外,提示模板中还预留了"历史执行记录"的位置,用于存储AI的思考、行动和观察记录,让AI能根据上一步的结果调整下一步的决策------这正是ReAct框架"循环推理"的核心实现。
步骤4:创建Agent和执行器------ 让Agent"动起来"
有了"大脑"(大模型)、"手脚"(工具)和"行为准则"(提示模板),就可以将三者组装成完整的ZeroShot_ReAct Agent,再通过执行器(AgentExecutor)来运行任务。
核心思路:使用LangChain提供的create_react_agent方法,将大模型、工具、提示模板整合,生成Agent;再通过AgentExecutor来控制Agent的执行流程,比如设置最大迭代次数(防止死循环)、开启详细日志(便于调试)、自动处理解析错误(提升稳定性)。
执行器的作用相当于"管家",负责调度Agent的思考和行动,确保整个流程有序进行:接收用户问题 → Agent思考决策 → 调用工具(如有) → 处理工具返回结果 → 输出最终答案。
三、关键细节与避坑指南
在搭建ZeroShot_ReAct Agent的过程中,有几个细节直接影响Agent的稳定性和准确性,新手很容易踩坑,这里重点提醒:
- 工具描述要精准:避免模糊表述,比如"计算工具"不能只写"能计算",要明确支持的运算类型、输入格式,否则AI可能无法判断何时调用;
- 格式约束要严格:AI的输出格式必须和提示模板中规定的一致,否则执行器无法解析,会导致调用失败------这也是为什么提示模板中要强调"不要添加任何额外文字";
- 大模型选择要适配:建议选择推理能力较强的模型,比如Qwen3.5、DeepSeek等,避免因模型推理能力不足,导致无法正确判断是否需要调用工具;
- 安全性要考虑:如果工具涉及外部调用或代码执行(如计算工具),需做好安全防护,比如限制可执行的函数、过滤危险输入,避免恶意攻击。
四、总结与扩展方向
本次实战搭建的ZeroShot_ReAct Agent,虽然功能简单,但已经覆盖了核心实现逻辑------它的本质就是"通过提示模板约束大模型,让大模型根据工具描述,自主完成'思考-行动-观察'的循环,实现零样本工具调用"。
对比传统的工具调用方式,ZeroShot_ReAct的优势在于"灵活、低成本":无需训练样本,新增工具时只需添加工具描述和实现逻辑,就能快速适配新的需求;而ReAct框架则让AI的决策过程更加透明,便于调试和优化,这也是其在企业智能决策、自动化流程等场景中广泛应用的原因之一。
后续扩展方向也很明确:
- 扩展工具:新增天气查询、知识库检索、文件读取等工具,实现更复杂的任务;
- 优化提示模板:调整思考逻辑的描述,提升AI的决策准确性;
- 对接更多模型:尝试接入不同的大模型,对比其在ZeroShot_ReAct场景下的表现;
- 增加记忆功能:结合LangChain的记忆组件,让Agent能记住历史对话,实现多轮交互下的工具调用。
ZeroShot_ReAct Agent是LangChain Agent体系中最基础也最实用的方案,掌握它的实现思路,能为后续搭建更复杂的智能Agent(如多Agent协同、带记忆的Agent)打下坚实基础。
如果觉得本文对你有帮助,欢迎点赞、收藏,后续会持续分享LangChain实战技巧,一起玩转大模型应用开发~
代码实现:
import os
from dotenv import load_dotenv
from langchain.agents import AgentExecutor, create_react_agent
from langchain_core.tools import Tool
from langchain_openai import ChatOpenAI
from langchain_core.prompts import PromptTemplate # ← 用于自定义 prompt
# 加载环境变量
load_dotenv()
# ========================
# 1. 配置 LLM(Ollama 兼容 OpenAI API)
# ========================
DEEPSEEK_API_KEY = "123" # 替换为实际的 API Key
llm = ChatOpenAI(
api_key=DEEPSEEK_API_KEY,
base_url="http://192.168.0.100:8085/v1",
model="qwen3.5-27b-awq",
temperature=0.3,
max_tokens=1024,
)
# ========================
# 2. 定义工具
# ========================
def get_current_time(*args, **kwargs):
from datetime import datetime
current_time = datetime.now().strftime("%Y年%m月%d日 %H:%M:%S")
return f"当前时间:{current_time}"
def calculate_math_expression(expression: str):
try:
# 构建安全的白名单内置函数
safe_funcs = {}
for func_name in ("abs", "round", "min", "max", "pow"):
if hasattr(__builtins__, func_name):
safe_funcs[func_name] = getattr(__builtins__, func_name)
# 执行安全计算
result = eval(expression, {"__builtins__": {}}, safe_funcs)
return f"数学表达式计算结果:{expression} = {result}"
except Exception as e:
return f"计算失败,错误信息:{str(e)}"
tools = [
Tool(
name="GetCurrentTime",
func=get_current_time,
description="获取当前系统时间,无需任何输入参数"
),
Tool(
name="CalculateMathExpression",
func=calculate_math_expression,
description="计算一个数学表达式,例如 '100 * (25 + 15) / 4 - 80',仅支持 + - * / 和括号"
)
]
# ========================
# 3. 自定义 ReAct 提示模板(中文 + 严格格式约束)
# ========================
react_prompt_template = """你是一个智能助手,必须严格遵守以下交互协议:
## 规则
1. 如果需要使用工具,请**严格按照以下三行格式输出**,不要添加任何额外文字、标点、说明或自然语言:
Thought: 我需要使用工具来解决问题。
Action: 工具名称
Action Input: 工具输入内容
2. 如果不需要工具,直接输出:
Thought: 我可以直接回答。
Final Answer: 你的最终答案
## 可用工具
{tools}
## 合法工具名称(必须完全匹配,区分大小写):
{tool_names}
## 用户问题
{input}
## 历史执行记录(如有)
{agent_scratchpad}
"""
# 创建 PromptTemplate,确保包含所有必要变量
prompt = PromptTemplate(
input_variables=["tools", "tool_names", "input", "agent_scratchpad"],
template=react_prompt_template
)
# ========================
# 4. 创建 Agent 和执行器
# ========================
agent = create_react_agent(
llm=llm,
tools=tools,
prompt=prompt
)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
handle_parsing_errors=True, # 自动处理解析错误并重试
max_iterations=5, # 防止死循环
)
# ========================
# 5. 执行任务
# ========================
if __name__ == "__main__":
print("===== 任务1:获取当前时间 =====")
agent_executor.invoke({"input": "请告诉我现在的时间是多少?"})
print("\n" + "=" * 50 + "\n")
print("===== 任务2:数学计算 =====")
agent_executor.invoke({"input": "请帮我计算 100 * (25 + 15) / 4 - 80 的结果是多少?"})
结果输出:
===== 任务1:获取当前时间 =====
> Entering new AgentExecutor chain...
写。
</think>
Thought: 我需要使用工具来解决问题。
Action: GetCurrentTime
Action Input:当前时间:2026年04月07日 16:49:28案。
</think>
Thought: 我可以直接回答。
Final Answer: 当前时间是2026年04月07日 16:49:28。
> Finished chain.
==================================================
===== 任务2:数学计算 =====
> Entering new AgentExecutor chain...
0'
</think>
Thought: 我需要使用工具来解决问题。
Action: CalculateMathExpression
Action Input: 100 * (25 + 15) / 4 - 80数学表达式计算结果:100 * (25 + 15) / 4 - 80 = 920.0题。
</think>
Thought: 我可以直接回答。
Final Answer: 100 * (25 + 15) / 4 - 80 的计算结果是 920.0。
> Finished chain.
更多学习资料尽在 老虎网盘资源