
扫盲什么是ReAct2022年普林斯顿大学和谷歌的研究团队提出的ReAct范式通过构建“推理-行动-观察”TAO的闭环机制首次实现了语言模型推理能力与外部环境交互能力的深度协同。ReAct Reasoning推理 Acting行动本质是一种让语言模型通过与外部工具、环境动态交互完成复杂任务的智能体架构范式。其核心目标是打破传统语言模型“输入-输出”的单向链路构建“感知-决策-执行-反馈”的智能闭环使模型从“被动应答者”升级为“主动问题解决者”。问题 你们用 ReAct 做过 Agent 吧讲讲 Thought、Action、Observation 这个循环。模型一直重复调同一个工具线上你们怎么发现怎么让它停下来动笔前我先把 ReAct 的循环骨架搭出来跑了一遍。故意让模型每轮都返回同一个查订单动作看它自己能不能停。没加护栏那版跑满 12 步上限工具被调了 12 次一个答案都没吐出来。ReAct 的面试答案多数人背到三个名词就停了面试官接着问的常常是循环怎么收。背定义接不住这一问。下面这版能直接背代码也能直接跑。二、ReAct面试题在考什么面试官先看你有没有真跑过。能说出循环跑了十步还在原地打转的人和只能背三个名词的人差别在调过线上没有。再往下是终止条件。一个 ReAct 循环停下来有两条路模型自己给出Final Answer或者外部护栏强制掐断。LangChain 的AgentExecutor里max_iterations默认 15官方文档专门写了一句设成None可能死循环。这句话就是留给追问的。三、分层答案从认知到落地最底下是认知层。ReAct 让模型把推理轨迹和动作交替写出来Thought记当前判断Action选工具工具跑完把结果作为Observation回灌进上下文模型再决定下一步。论文里这套写法接了一个 Wikipedia API靠真实返回的页面压住 CoT 常见的幻觉和错误传播。出处是 Yao 等人 2022 年 10 月挂上 arXiv 的 ReAct 论文编号 2210.036292023 年 3 月的 v3 是 ICLR 定稿版。往上是原理层。交替写轨迹的好处是每步都拿环境反馈对一遍前面想歪了后面有机会拐回来。论文在 HotpotQA 和 Fever 上验证了这点在 ALFWorld 和 WebShop 两个交互任务上只用一两个 in-context 示例绝对成功率比 imitation 和 RL 基线高出 34% 和 10%。这几个数字我照着摘要原文抄的面试报出来比说效果挺好有底气。工程层最要紧面试的差距多半在这里。循环得有硬边界我自己写会加三道护栏步数上限、重复动作检测、解析失败回灌。LangChain 给了其中两道max_iterations管步数handle_parsing_errors管格式错。重复动作检测在AgentExecutor的参数清单里没有OpenAI Agents SDK 超了max_turns抛MaxTurnsExceeded同样只数步数。同一个动作调了八遍这种事得自己补一行判断。四、追问与应答面试官常问光加步数上限够不够。不够。我那段实跑里12 步上限跑满工具调用 12 次钱照付答案一个没有。加一行重复检测第 3 步就拦下工具只调 2 次。步数上限兜住跑飞重复检测负责早点停作用不重叠。还可能问解析失败要不要直接报错。别抛异常。把解析错误整理成一句Observation回灌多数模型下一轮就改回格式。这正是handle_parsing_errors设成True干的事。我那个 demo 第一轮让模型自由发挥第二轮就归位第三步正常收尾。max_execution_time也建议配上它管墙钟时间能防挂死可重复调用每次都很快时间没到钱已经花完了。五、代码示例与执行流程下面这段纯标准库就能跑用脚本化输出模拟模型不依赖任何 API Key。三组对照各走一遍护栏。# 纯标准库用脚本化输出模拟模型不依赖任何 API KeyclassParseError(Exception):passdefparse(text):# 只认行首标记Thought 里提到工具名不会被误当 Actionmarks[lforlintext.splitlines()ifl.startswith((Action:,Final Answer:))]ifnotmarks:raiseParseError(缺少 Action 或 Final Answer 行)lastmarks[-1]return(finishiflast.startswith(Final)elseaction,last.split(:,1)[1].strip())defreact_loop(model,max_steps12,repeat_limitNone):返回 结局、步数、工具调用次数。history 每轮回灌模型。history,calls,last_action,streak[],0,None,0forstepinrange(1,max_steps1):try:kind,payloadparse(model(step,history))exceptParseErrorase:# 解析失败不中断把错误当 Observation 回灌让模型下一轮改格式history.append(fObservation: 解析失败{e})continueifkindfinish:returnfinish,step,calls# 先判重复再调工具重复的这一次不付工具钱ifrepeat_limitandpayloadlast_action:streak1ifstreakrepeat_limit:returnblocked_repeat,step,callselse:streak0last_action,callspayload,calls1history.append(fObservation:{payload}- 未找到记录)returnexhausted,max_steps,callsdefstuck(step,history):returnThought: 再查一次\nAction: search_order(A1001)defrecover(step,history):ifstep1:return我先查一下订单 A1001 的状态。ifstep2:returnThought: 按格式重来\nAction: search_order(A1001)returnThought: 给结论\nFinal Answer: 未查到该订单建议人工核对forname,model,kwin[(只有步数上限,stuck,{}),(加重复动作检测,stuck,{repeat_limit:2}),(解析失败回灌,recover,{}),]:end,steps,callsreact_loop(model,**kw)print(f{name}: 结局{end}步数{steps}工具调用{calls})实跑输出Python 3.13--只有步数上限:结局exhausted 步数12工具调用12--加重复动作检测:结局blocked_repeat 步数3工具调用2--解析失败回灌:结局finish 步数3工具调用1第一行是只设步数上限的代价。第二行把重复检测打开连续两次同一个动作就拦工具少调十次。第三行演示解析失败回灌模型第一轮输出自由发挥收到错误提示后改回格式第 3 步给出答案。parse里用startswith只认行首标记这个写法有讲究。换成in去匹配Thought里提一句工具名就会被误当成动作这类错误在线上很隐蔽。重复检测也放在调工具之前等工具跑完再判那一次已经付过钱了。六、加分项与踩坑点加分项。提一句early_stopping_method默认force只返回一句达到迭代上限的说明设成generate会让模型基于已走的步骤最后生成一次答案体验好多一次调用。再提一句 OpenAI Agents SDK 的error_handlers收max_turns能返回兜底输出官方页面没写默认 turn 数别在面试里编一个。护栏触发时记一条日志重复动作次数是很便宜的健康指标。踩坑点。第一解析别用in匹配Action行首startswith才稳。第二重复检测要放在调工具之前。第三步数上限别照抄 15复杂任务 15 步不够简单任务 15 步够烧掉一堆 token按业务配再叠一个时间上限。第四别把max_turns当成工具调用次数官方文档写了一次 run 里可能包含多次 LLM 调用。三个核心要点ReAct 循环得有硬边界靠模型自己喊停不靠谱。三道护栏直接背步数上限、重复动作检测、解析失败回灌。实测只设 12 步上限工具白调 12 次加了重复检测第 3 步就停。我正在整理一份《大模型面试高频题库与详解》做好后会在公众号开放领取。关注 A小码哥回复「AI面试题」即可第一时间获取。