从一次点餐说起 周末你想去吃个饭,打开微信问朋友:”帮我推荐一家餐厅呗。”
你的朋友大概不会直接甩一个店名给你。他会先想:你喜欢什么口味?川菜还是日料?预算多少?离你家远不远?现在几点了,附近还在营业的有什么?
思考一圈之后,他打开大众点评搜了一下,发现附近有几家评分不错的川菜馆,但有一家离你家太远了。他再想想,你上次说最近在减肥,于是排除了那家以大盘菜出名的。
最后他说:”去那家’蜀香小馆’吧,走路十分钟,评分4.8,分量不大适合你。”
这个过程其实就是一个ReAct 的缩影:想一想→做一做→看看结果→再想想→再做做→直到得到满意的答案 。
今天我们就来聊聊,AI Agent 是怎么像你朋友一样”边想边做”的。
什么是ReAct? ReAct 这个名字来自论文《ReAct: Synergizing Reasoning and Acting in Language Models》,它是两个单词的组合:
Re asoning(推理)—— LLM 天生就会的事,分析、思考、推理
Act ing(行动)—— 调用工具、查询数据、执行操作
传统的 LLM 只能”想”——你问它一个问题,它根据训练数据生成一段回答。但它不能”做”,它不知道今天北京的天气是几度,因为它没有访问实时数据的能力。
ReAct 的核心思想很简单:让 LLM 在推理的同时,可以调用外部工具,然后根据工具返回的结果继续推理,如此循环,直到得出最终答案。
换句话说,ReAct 赋予了 LLM “手和脚”——它不仅能思考,还能行动。
和传统 Chain 的区别 如果你用过 LangChain,你一定知道 Chain 的概念。Chain 是线性的:输入 → 处理 → 输出,一条路走到底。
1 2 传统 Chain: 用户问题 → LLM思考 → 回答
但现实世界的问题往往没那么简单。比如:
“帮我查一下北京今天的最高气温,然后算一下如果每天省下3度电,一周能省多少?”
这个问题需要两步:先查天气,再计算。普通 Chain 做不到,因为它只会一口气生成回答,很可能”瞎编”一个温度数字。
ReAct 的做法不同,它是一个循环 :
1 2 ReAct 流程: 用户问题 → LLM思考 → 决定调用工具 → 获取结果 → LLM再思考 → 再调用工具 → ... → 最终回答
区别一目了然:Chain 是一条直线,ReAct 是一个圆圈,可以转很多圈。
ReAct 的工作流程 ReAct 的执行循环可以用四个词概括:
1. Think(思考) LLM 分析当前的情况,决定下一步该做什么。它可能会想:”用户问我北京的天气,我需要调用天气查询工具。”
2. Act(行动) LLM 调用一个外部工具,比如搜索 API、数据库查询、计算器等。
3. Observe(观察) LLM 收到工具返回的结果,比如”北京今天最高气温32℃”。
4. 判断是否需要继续 如果已经有了足够的信息,就直接生成最终答案。如果还不够,回到第1步继续。
用一个更直观的流程图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 ┌─────────────────────────────────┐ │ 用户提问 │ └──────────┬──────────────────────┘ ▼ ┌─────────────────────────────────┐ │ Think:我需要先查北京天气 │ └──────────┬──────────────────────┘ ▼ ┌─────────────────────────────────┐ │ Act:调用天气工具查北京 │ └──────────┬──────────────────────┘ ▼ ┌─────────────────────────────────┐ │ Observe:返回 32℃ │ └──────────┬──────────────────────┘ ▼ ┌─────────────────────────────────┐ │ Think:现在我需要计算一周省电 │ └──────────┬──────────────────────┘ ▼ ┌─────────────────────────────────┐ │ Act:调用计算器 3×7=21 │ └──────────┬──────────────────────┘ ▼ ┌─────────────────────────────────┐ │ Observe:结果是21度电 │ └──────────┬──────────────────────┘ ▼ ┌─────────────────────────────────┐ │ 最终回答:北京今天32℃, │ │ 每天省3度电一周能省21度 │ └─────────────────────────────────┘
代码实战:用 LangChain 实现 ReAct Agent 光说不练假把式,我们来写一个真实的例子。场景很简单:一个能查天气、做计算的 AI 助手。
安装依赖 1 pip install langchain langchain-community langchain-openai duckduckgo-search
完整代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 import osfrom langchain_openai import ChatOpenAIfrom langchain.agents import AgentExecutor, create_react_agentfrom langchain_core.tools import toolfrom langchain_core.prompts import PromptTemplateos.environ["OPENAI_API_KEY" ] = "your-api-key-here" @tool def get_weather (city: str ) -> str : """查询指定城市的当前天气信息。输入城市名称,返回天气描述。""" weather_data = { "北京" : "晴天,最高气温32℃,最低气温22℃,东南风3级" , "上海" : "多云,最高气温28℃,最低气温20℃,微风" , "深圳" : "阵雨,最高气温30℃,最低气温25℃,南风2级" , } return weather_data.get(city, f"未找到{city} 的天气信息" ) @tool def calculator (expression: str ) -> str : """计算数学表达式。输入一个数学表达式字符串,返回计算结果。""" try : result = eval (expression) return str (result) except Exception as e: return f"计算出错:{str (e)} " llm = ChatOpenAI(model="gpt-4" , temperature=0 ) 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 = [get_weather, calculator] agent = create_react_agent(llm, tools, react_prompt) agent_executor = AgentExecutor( agent=agent, tools=tools, verbose=True , max_iterations=10 ) if __name__ == "__main__" : print ("=" * 50 ) result = agent_executor.invoke({"input" : "北京今天天气怎么样?" }) print (f"最终回答:{result['output' ]} " ) print ("=" * 50 ) result = agent_executor.invoke({ "input" : "北京今天最高气温是多少?如果每天省下3度电,一周能省多少度?" }) print (f"最终回答:{result['output' ]} " )
运行效果 当你运行上面的代码,你会看到 Agent 的思考过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 > Entering new AgentExecutor chain... Thought: 用户问了两个问题,我需要先查北京的天气,获取最高气温 Action: get_weather Action Input: 北京 Observation: 晴天,最高气温32℃,最低气温22℃,东南风3级 Thought: 我现在知道北京最高气温是32℃,接下来需要计算每天省3度电一周能省多少 Action: calculator Action Input: 3 * 7 Observation: 21 Thought: I now know the final answer Final Answer: 北京今天最高气温是32℃。如果每天省下3度电,一周能省21度电。 > Finished chain. 最终回答:北京今天最高气温是32℃。如果每天省下3度电,一周能省21度电。
看到了吗?Agent 先思考 需要查天气,然后行动 调用了天气工具,观察 结果后继续思考 需要做计算,再行动 调用计算器,最终得出完整答案。
这就是 ReAct 的魅力——它不是一次性把答案吐出来,而是一步一步地解决问题。
什么时候该用 ReAct? 不是所有场景都需要 ReAct,用对了才高效:
适合用 ReAct 的场景:
需要多步推理 的问题(比如”先查A,再根据A算B”)
需要调用外部工具 的场景(查数据库、调API、搜索网页)
问题比较复杂,一次推理搞不定的任务
需要根据中间结果动态调整 策略的场景
不需要 ReAct 的场景:
简单的问答、翻译、总结,直接调 LLM 就行
答案就在输入里,不需要外部数据
对延迟要求极高的实时场景(ReAct 多轮交互会增加延迟)
一个简单的判断标准:如果你的问题能一步到位,就用普通 Chain;如果需要”想一想、做一做、再想想”,那就该上 ReAct。
写在最后 ReAct 不是什么高深莫测的技术,它的核心思想就是模仿人类解决问题的方式:边想边做,根据反馈调整策略。
这其实和你平时的工作方式很像——你写代码的时候,不是一次写完就跑通了,而是写着写着发现不对,改一改,跑一下看看,再改改,直到程序正确运行。
ReAct 之所以重要,是因为它是 AI Agent 的基础思维模式 。你后面会看到的各种 Agent 框架、各种复杂的 Agent 架构,底层几乎都离不开 ReAct 这个核心思想。
理解了 ReAct,你就理解了 AI Agent 为什么能”做事”,而不只是”说话”。
下一次你让 AI 助手帮你完成一个复杂任务的时候,不妨想想:它此刻可能正在 Think → Act → Observe 的循环中,一步一步帮你找到答案。
参考论文 :Yao, S. et al. “ReAct: Synergizing Reasoning and Acting in Language Models” (ICLR 2023)
本文代码 :基于 LangChain 0.2+ 版本,完整示例可在 GitHub 上找到。