你好,我是方可乐。
一个正在深耕AI编程的30+的AI应用开发工程师。
用AI编程开发过Web应用网站,浏览器插件,微信小程序,AI智能体,RAG系统。
关注公众号&添加微信:ThinkFun666
领取【AI编程资料包】
去年6月份,我做了一个连自己都觉得疯狂的决定:裸辞,All in AI。
现在已经换赛道成功,继续在工作中探索。
今天我们来讲React,ReAct = Reasoning + Acting(推理 + 行动)。
为什么我们需要React呢?先来回顾上节课的坑。
在上一课里,我们用 Tools Agent 让 AI 可以调用工具,比如生成密码、做 Base64 编解码。
但 Tools Agent 有个明显限制:只能调用一次工具,或者我们提前写死调用顺序。
一旦任务需要多步,比如“生成密码再编码”,AI 就没法自己完成。
ReAct 就能够很好地解决这个问题。
它的特点是:
-
• AI 会先思考(我要解决什么问题?需要用哪个工具?) -
• 再行动(调用某个工具) -
• 再思考(结果够了吗?还要不要继续?) -
• 最终给出答案
最大的区别在于:
-
• Tools Agent:只会调用一次工具 -
• ReAct Agent:可以调用多次工具,直到完成目标
LangChain 如何实现 ReAct?
在 LangChain 里,用 AgentExecutor 加上 AgentType.ZERO_SHOT_REACT_DESCRIPTION 就能启用 ReAct。
核心就是它的 prompt 模板,分三部分:
prefix:开场白,告诉 AI 它是一个会思考和调用工具的助手。
你是一个会思考和行动的助手,可以灵活选择工具来帮用户解决问题。
suffix:结尾模板,必须包含两个占位符:
-
• {input}—— 用户输入 -
• {agent_scratchpad}—— AI 的“草稿本”,记录思考/行动/观察过程例如:
开始思考!记住要使用中文回答。问题: {input}思考: {agent_scratchpad}
format_instructions:格式说明,LangChain 自动生成(不用手写)。
!!!注意:
-
• {input}和{agent_scratchpad}是固定的,不能删。
老规矩,下面我们上代码,当你看完完整的代码和效果之后,就知道是怎么回事了。
新建文件12_react_call_tools.py
import os
import random
import base64
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain.agents import initialize_agent, AgentType
from langchain.tools import tool
load_dotenv()
# 初始化 LLM
llm = ChatOpenAI(
model="deepseek-chat",
base_url=os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com/v1"),
api_key=os.getenv("DEEPSEEK_API_KEY"),
temperature=0
)
# 工具1:密码生成器(沿用11课)
@tool
def generate_password(level: str) -> str:
"""根据复杂度生成密码,复杂度可选:low / medium / high"""
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
special = "!@#$%^&*()_+-=[]{}|;:,.<>?"
length = {"low": 6, "medium": 10, "high": 16}.get(level, 8)
pool = chars + special if level == "high" else chars
return "".join(random.choice(pool) for _ in range(length))
# 工具2:Base64 编码(沿用11课)
@tool
def base64_encode(text: str) -> str:
"""将输入字符串进行 Base64 编码"""
return base64.b64encode(text.encode()).decode()
# 工具3:Base64 解码(沿用11课)
@tool
def base64_decode(text: str) -> str:
"""将 Base64 字符串解码为原始字符串"""
return base64.b64decode(text.encode()).decode()
tools = [generate_password, base64_encode, base64_decode]
# 使用 initialize_agent 创建 ReAct Agent
agent_executor = initialize_agent(
tools=tools,
llm=llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True,
handle_parsing_errors=True,
agent_kwargs={
"prefix": """You are a helpful assistant that can use tools to solve problems. Always respond in Chinese.
Use the following format strictly:
Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take (generate_password, base64_encode, or base64_decode)
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 in Chinese
IMPORTANT: Always end with "Final Answer:" followed by your response. Never add extra text after giving the final answer.""",
"suffix": "Begin!\n\nQuestion: {input}\nThought: {agent_scratchpad}"
}
)
print("=== ReAct 密码助手(思考 + 行动)===\n")
while True:
user_input = input("你:")
if user_input.lower() in ["quit", "exit", "退出"]:
print("退出。")
break
result = agent_executor.invoke({"input": user_input})
print("AI:", result["output"], "\n")
正常运行后,结果如下:
这里有个挺坑的地方,就是提示词里面的格式得写对,不然就会导致格式错误一直在思考循环。
ReAct提示词结构分析
固定的核心结构(不能改)
"prefix": """[角色定义] + [格式规范]""","suffix": "Begin!\n\nQuestion: {input}\nThought: {agent_scratchpad}"
suffix部分是固定的,包含:
-
• {input}- 用户输入的占位符 -
• {agent_scratchpad}- Agent思考过程的占位符 -
• Begin!和Question:是ReAct框架的标准开始格式
可以修改的部分
A. 角色定义部分(完全可自定义)
"You are a helpful assistant that can use tools to solve problems. Always respond in Chinese."
可以改为:
-
• "You are a professional data analyst..." -
• "You are a coding expert..." -
• "You are a customer service representative..."
B. 工具名称列表(必须与实际工具匹配)
"Action: the action to take (generate_password, base64_encode, or base64_decode)"
这里的工具名称必须与你定义的工具函数名完全一致。
C. 语言要求(可选)
"Always respond in Chinese""Final Answer: the final answer to the original input question in Chinese"
对AI应用开发感兴趣的同学,欢迎加微信申请入群交流学习。
想要学习AI应用开发的同学,可以参照我的代码跑起来,举一反三,一天一个脚印的进步,我相信,会足够坚实。
接下来100天,我会记录从Java程序员到AI应用开发工程师的完整转型路:每一个困惑、每一次突破、每一个真实瞬间。
当前是30/100。
如果你也想了解AI应用开发到底是什么,如果你也在考虑转型但还在犹豫,那就跟着我的记录,一起探索。
继续折腾中,有问题随时交流 🤝
微信号:ThinkFun666
我的免费AI编程交流群,欢迎加入讨论AI编程玩法(加我微信,说明需求和来意,申请入群)
推荐阅读:
我就喜欢干这种傻事!为什么转型AI应用开发,我不建议你直接从看书开始学起?

