Agent 核心架构:思考-行动-观察循环(ReAct)
Agent 核心架构思考-行动-观察循环ReActReAct 是 Agent 最经典的工作模式思考要做什么 → 执行动作 → 观察结果 → 再思考下一步。这篇深入讲 ReAct 的原理、Prompt 模板设计、循环控制、停止条件以及实际开发中的常见问题。大家好我是黒漂技术佬。上一篇讲了 Agent 是什么这篇深入核心架构ReAct 循环。Reason Act 推理 行动。Agent 不是一次性输出答案而是像人解决问题一样先想想要干嘛动手做看看结果再决定下一步循环往复直到搞定。这篇讲 ReAct 的原理、Prompt 怎么写、循环怎么控制、怎么判断任务完成。一、ReAct 是什么来源ReAct 是 2022 年普林斯顿和 Google 提出的方法论文《ReAct: Synergizing Reasoning and Acting in Language Models》。核心思想让大模型把「推理过程」和「行动」交替输出边想边做。循环结构┌─────────────────────────────────────┐ │ Thought思考我现在要做什么 │ │ ↓ │ │ Action行动调用某个工具 │ │ ↓ │ │ Observation观察工具返回结果 │ │ ↓ │ │ 再 Thought根据结果想下一步 │ └─────────── 循环直到完成 ────────────┘每一轮输出一个 Thought Action拿到 Observation 后进入下一轮。最终输出当模型判断信息足够了就输出 Final Answer结束循环。二、完整的 ReAct 示例问题张三出生于哪一年他创办的公司上市了吗ReAct 过程问题张三出生于哪一年他创办的公司上市了吗 Thought: 我需要先知道张三是谁、创办了什么公司然后查他的出生年份和公司上市情况。 先搜索张三的基本信息。 Action: 搜索「张三 创始人 公司」 Observation: 张三1980年出生某科技公司创始人兼CEO公司名为未来科技 2015年成立主要做人工智能。 Thought: 知道了张三1980年出生创办了未来科技。接下来要查这家公司有没有上市。 Action: 搜索「未来科技 是否上市」 Observation: 未来科技于2021年在科创板上市股票代码688XXX。 Thought: 信息都齐了张三1980年出生他的公司未来科技2021年科创板上市。 可以给出最终答案了。 Final Answer: 张三出生于1980年。他创办的未来科技公司已于2021年在科创板上市。两轮思考行动就把问题解决了。三、ReAct Prompt 模板系统提示词System Prompt告诉模型怎么按 ReAct 格式输出。核心要素说明有哪些工具可用规定输出格式Thought / Action / Action Input说明循环规则什么时候输出 Final Answer一个标准模板你是一个智能助手可以使用以下工具来回答问题 工具列表 - 搜索输入关键词搜索互联网信息 - 计算器输入数学表达式计算结果 - 天气查询输入城市名获取实时天气 回答问题时严格按照以下格式输出 Thought: 你对当前问题的思考说明接下来要做什么 Action: 工具名称 Action Input: 工具的输入参数 Observation: 工具返回的结果这部分由系统填入不用你写 然后继续下一轮 Thought/Action直到信息足够 当你认为已经有足够信息回答问题时输出 Final Answer: 最终的答案 注意 1. 每次只输出一个 Action 2. 必须有 Observation 才能继续思考 3. 不确定的时候就搜索不要瞎猜 4. 信息足够就立刻给出 Final Answer不要多余步骤为什么格式要严格因为程序要解析模型的输出提取 Action 和 Action Input然后去调用工具。格式乱了解析失败整个循环就断了。实际开发中Function Calling 原生支持的模型更方便不用手写解析。但理解 ReAct 的原理很重要。四、循环控制流程程序侧的执行流程# 伪代码defagent_run(question,max_steps10):historystep0whilestepmax_steps:# 1. 把历史拼到 prompt 里调用大模型promptsystem_prompthistoryf\n问题{question}responsellm(prompt)# 2. 解析模型输出ifFinal Answer:inresponse:returnextract_answer(response)action,action_inputparse_action(response)historyresponse\n# 3. 调用工具observationcall_tool(action,action_input)historyfObservation:{observation}\nstep1return达到最大步数未能完成任务关键要素历史记录每轮的 Thought/Action/Observation 都要传给模型它要看着前面的过程继续想解析输出从模型回复里提取 Action 和参数工具调用执行实际的工具函数停止条件输出 Final Answer 或者达到最大步数五、停止条件正常停止Final Answer模型自己判断信息足够了输出 Final Answer循环结束。异常停止1. 最大步数限制防止模型死循环设一个最大轮数比如 10 步到了就强制停止。ifstepmax_steps:return执行步数超限任务未完成2. 重复 Action 检测连续调用同一个工具同样的参数说明卡住了强制停止。3. 错误累积工具连续报错说明方向不对停止并提示。4. 超时整体执行时间设上限防止某个步骤卡住太久。六、ReAct 的变种1. CoTChain of Thought只有思考没有行动。就是让模型一步步想但不调用外部工具。适合纯推理问题。问题一个苹果3块买5个多少钱 思考一个3块5个就是3×5。 计算3×515 答案15块ReAct CoT 工具调用。2. Plan-and-Execute先做完整规划再按计划执行。Plan: 1. 查A 2. 查B 3. 对比总结 执行步骤1... 执行步骤2... 执行步骤3...适合任务比较明确、步骤可以预先规划的场景。ReAct 是走一步看一步Plan-and-Execute 是先想好全部再做。3. Reflexion反思型执行完之后反思效果好不好不好就重来。执行 → 评估结果 → 反思问题 → 重新执行多了一个反思的步骤质量更高但也更慢更贵。七、Function Calling vs 手写 ReAct原生 Function Calling现在主流大模型GPT、Claude、Qwen、DeepSeek都原生支持 Function Calling / Tool Use。你给模型一份工具的 JSON Schema 描述模型直接输出要调用哪个函数、参数是什么结构化输出不用自己解析。// 工具描述{name:search,description:搜索互联网信息,parameters:{type:object,properties:{query:{type:string,description:搜索关键词}},required:[query]}}模型返回{tool_calls:[{name:search,arguments:{query:张三 出生日期}}]}对比手写 ReAct Prompt原生 Function Calling格式稳定性容易乱解析容易失败结构化输出稳定工具数量少了还行多了容易乱支持多工具兼容性所有模型都能用需要模型支持开发成本高要写解析逻辑低直接用API实际开发优先用原生 Function Calling。但理解 ReAct 的原理有助于调试和设计 Agent。八、常见问题和优化问题 1模型不按格式输出原因Prompt 约束不够强或者模型能力不够。解决系统提示词写得更详细、更严格给 1-2 个示例Few-shot用支持 Function Calling 的模型输出解析加容错匹配不到就重试问题 2死循环反复调用同一个工具原因模型判断不了信息够不够或者工具返回的结果它理解不了。解决最大步数限制重复检测连续 2-3 次同样的调用就强制停止Prompt 里强调「信息足够就给 Final Answer」工具返回结果做摘要别把太长的原文直接塞进去问题 3跳过工具直接瞎答原因模型偷懒或者没意识到需要用工具。解决Prompt 里强调「不知道的就搜索不要编造」系统提示词里加「禁止直接回答需要实时信息的问题」用更听话的模型比如 GPT-4问题 4上下文太长爆了原因轮次多了历史记录越来越长token 超了。解决工具结果做摘要只保留关键信息历史记录截断只保留最近几轮用总结代替完整历史问题 5工具调用参数错原因模型没理解工具参数的含义或者格式不对。解决工具描述写清楚每个参数的含义和格式加参数校验不对就让模型重试给调用示例九、一个最小可运行的 ReAct Agent伪代码tools{search:lambdaquery:search_web(query),calc:lambdaexpr:str(eval(expr)),}system_prompt 你可以使用以下工具 - search: 搜索输入关键词 - calc: 计算器输入数学表达式 格式 Thought: 思考 Action: 工具名 Action Input: 参数 Observation: 结果 信息足够就输出 Final Answer: 答案 defrun(query):historyfor_inrange(10):# 最多10步promptsystem_prompthistoryf\n问题{query}\nThought:respllm(prompt)ifFinal Answer:inresp:returnresp.split(Final Answer:)[-1].strip()# 解析 actionactionextract(resp,Action:)action_inputextract(resp,Action Input:)# 调用工具obstools[action](action_input)historyfThought:{resp}\nObservation:{obs}\nreturn超出步数限制实际开发不用自己写这么底层LangChain 之类的框架都封装好了。但原理就是这么回事。十、本篇小结ReAct Reason推理 Act行动思考-行动-观察循环标准格式Thought → Action → Observation循环直到 Final Answer程序侧控制循环拼历史 → 调模型 → 解析动作 → 调工具 → 拼结果 → 下一轮停止条件输出 Final Answer、达到最大步数、重复检测、超时变种CoT纯思考、Plan-and-Execute先规划再执行、Reflexion带反思实际开发优先用原生 Function Calling比手写 ReAct 稳定很多常见问题格式乱、死循环、跳过工具瞎答、上下文太长、参数错下一篇讲工具调用Function Calling 的具体用法、工具怎么定义、多工具怎么选、常见的工具类型。我是黒漂技术佬。