尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

ReAct模式实战指南:从原理到代码,构建能思考会行动的AI智能体

ReAct模式实战指南:从原理到代码,构建能思考会行动的AI智能体 1. 项目概述从“工具调用”到“自主思考”的范式跃迁如果你最近在折腾大语言模型应用尤其是想让它帮你完成一些稍微复杂点的任务比如查查天气然后决定要不要带伞或者分析一份财报数据再生成投资建议那你大概率已经遇到了一个核心瓶颈模型怎么才能“有逻辑地”去执行一系列动作它不能只是被动地回答“今天天气如何”而是需要主动地“思考”“用户问我要不要带伞所以我得先知道天气。好我去调用天气API。哦下雨概率80%那我建议带伞并且提醒用户下午有雨。” 这个“思考-行动-观察-再思考”的循环就是ReAct工作模式的核心。它让AI Agent从一个简单的问答机变成了一个能规划、能执行、能纠错的“智能体”。我最初接触这个概念时觉得它像给模型装上了一套“外置大脑”。传统的提示工程Prompt Engineering更像是给模型一本详细的说明书告诉它第一步做什么、第二步做什么。但ReAct不同它赋予模型的是元认知能力——让模型自己决定下一步该做什么并在执行后根据结果调整策略。这不仅仅是技术上的优化更是一种工作范式的根本性转变。从“我告诉你怎么做”变成了“你自己想想该怎么做”。在实际项目中无论是构建一个能自动处理客服工单的Agent还是一个能联网搜索、分析并撰写报告的研究助手ReAct都是实现其“智能”的基石框架。接下来我就结合多次实战踩坑的经验为你彻底拆解ReAct模式并提供一个从零到一、可直接复现的实战指南。2. ReAct模式的核心原理与设计哲学2.1 什么是ReAct拆解“思考-行动”循环ReAct 全称是Reasoning Acting。这个术语最早出自一篇著名的学术论文《ReAct: Synergizing Reasoning and Acting in Language Models》。它的设计灵感来源于人类解决问题的方式我们很少能一步到位得到答案而是会先思考Reason然后采取行动Act观察行动结果Observe再基于结果进行下一轮思考如此循环。在AI Agent的语境下这三个步骤被形式化为思考Thought: Agent分析当前的任务、已有的信息包括历史记录和上一步的观察结果并推理出下一步应该执行哪个动作Action。这是Agent的“内省”过程。行动Action: Agent根据思考的结论调用一个外部工具Tool或执行一个具体操作。例如调用搜索引擎API、查询数据库、运行一段代码等。行动通常会有一个明确的输入。观察Observation: Agent接收行动执行后返回的结果。这个结果可能是一段文本、一组数据、一个状态码甚至是错误信息。这个观察结果会成为下一轮“思考”的输入。这个循环会一直持续直到Agent认为任务已经完成例如生成了最终答案或者达到了预设的步骤限制。2.2 为什么ReAct如此重要对比传统提示工程的优劣在没有ReAct之前我们通常使用思维链Chain-of-Thought, CoT提示来让模型进行推理。CoT确实提升了模型的推理能力但它有一个致命缺陷推理是封闭的。模型的“思考”完全基于其训练时学到的知识无法获取实时、动态的外部信息。它可能会编造一个不存在的API响应或者给出一个过时的股票价格。ReAct通过引入“行动”环节完美地解决了这个问题动态信息获取Agent可以通过工具与真实世界交互获取最新的、模型训练数据中不存在的信息。可验证性与纠错每一步行动的结果都是可观察的。如果结果不符合预期比如API返回错误Agent可以在下一轮思考中识别这个错误并尝试其他策略比如重试、换一个工具或向用户求助。任务分解与规划复杂任务被自动分解为一系列子任务。例如“帮我策划一个周末旅行”会被分解为“查询目的地天气”、“查找热门景点”、“对比酒店价格”等一系列行动。透明度与可解释性整个“思考-行动-观察”的轨迹Trace被完整记录了下来。这就像一份审计日志让我们可以清晰地看到Agent的决策过程便于调试和优化。简单来说CoT让模型“想得更清楚”而ReAct让模型“做得更正确”。后者是实现实用化AI Agent的必由之路。2.3 ReAct模式的关键组件与架构设计要实现一个ReAct工作流的Agent我们需要设计和整合以下几个核心组件智能体核心LLM Core通常是一个大语言模型如GPT-4、Claude 3、或开源的Llama 3、Qwen等。它的核心职责是进行“思考”即根据当前对话历史和观察生成包含下一步“行动”的文本。模型需要被精心提示Prompt以遵循ReAct的格式输出。工具集Tools这是Agent的“手脚”。每个工具都是一个具有明确定义功能的函数例如search_web(query: str) - str: 执行网络搜索。get_weather(city: str) - str: 获取城市天气。calculator(expression: str) - str: 执行数学计算。read_file(path: str) - str: 读取本地文件。 工具的定义必须清晰包括名称、描述、参数格式这样LLM才能知道在什么情况下调用哪个工具。解析器Parser负责解析LLM输出的文本。LLM的输出是一段自然语言我们需要从中精确地提取出“行动”的名称和参数。通常我们会要求LLM以特定格式如Action: 工具名\nAction Input: 参数输出然后用正则表达式或专用解析库来提取。执行器Executor负责调用解析出的工具并获取“观察”结果。执行器需要处理工具调用可能出现的异常如网络超时、参数错误并将结果格式化为字符串反馈给LLM进行下一轮思考。记忆与状态管理Memory State负责维护整个对话和任务执行的历史即所有的Thought-Action-Observation序列。这是LLM进行下一轮思考的上下文。如何高效地管理长上下文避免无关历史干扰核心决策是一个重要的工程问题。停止条件Stopping Condition定义Agent何时结束循环。最常见的是当LLM的输出中包含如Final Answer:这样的特定标记时。此外还需要设置最大迭代次数防止陷入死循环。将这些组件串联起来就构成了一个典型的ReAct Agent运行架构Prompt初始化任务 - LLM生成Thought和Action - Parser解析Action - Executor执行Tool - 更新Memory - 判断是否停止 - 下一轮循环。3. 从零搭建一个ReAct智能体实战步骤详解理论讲得再多不如亲手搭一个。下面我将以构建一个“旅行规划助手”Agent为例带你走通全流程。我们将使用Python和流行的LangChain框架来简化开发但原理是通用的。3.1 环境准备与工具定义首先安装核心依赖。我们选择LangChain是因为它提供了高度封装的ReAct实现让我们能更专注于逻辑而非底层循环。pip install langchain langchain-openai langchain-community假设我们为旅行助手定义了三个核心工具搜索工具获取景点、美食等实时信息。天气工具查询目的地未来几天的天气。计算工具进行简单的预算计算。在LangChain中工具可以用tool装饰器轻松定义。from langchain.tools import tool from langchain_openai import ChatOpenAI import requests import json # 工具1: 模拟网络搜索实际项目中可接入SerpAPI等 tool def search_web(query: str) - str: 执行一次网络搜索获取关于旅行目的地、景点、美食等的实时信息。 # 这里为演示我们模拟返回固定结果。真实情况应调用搜索引擎API。 mock_data { 上海迪士尼: 上海迪士尼乐园是中国内地首座迪士尼主题乐园拥有七大主题园区。门票平日价约399元周末及节假日约599元。, 外滩: 外滩是上海的历史文化街区以52幢风格迥异的古典复兴大楼群闻名是观赏黄浦江景和陆家嘴天际线的绝佳地点。免费开放。, 豫园: 豫园是位于上海老城厢的江南古典园林始建于明代。园内亭台楼阁、假山水榭布局精巧。门票约40元。 } for key, value in mock_data.items(): if key in query: return f搜索 {query} 的结果{value} return f未找到关于 {query} 的详细信息。 # 工具2: 获取天气模拟 tool def get_weather(city: str, date: str today) - str: 获取指定城市在特定日期的天气预报。date可以是today, tomorrow或具体的日期字符串。 weather_mock { 上海: {today: 晴转多云气温15-22°C东南风2-3级。, tomorrow: 多云气温16-24°C微风。}, 北京: {today: 晴气温5-18°C西北风3-4级。, tomorrow: 晴气温7-20°C微风。} } city_data weather_mock.get(city, {}) forecast city_data.get(date, 暂无该日期的天气预报信息。) return f{city}{date}的天气{forecast} # 工具3: 简单计算器 tool def calculator(expression: str) - str: 执行一个数学计算表达式并返回结果。例如300 * 2 500 try: # 警告实际使用中直接eval有安全风险此处仅作演示。 # 生产环境应使用更安全的计算库如numexpr或ast.literal_eval处理简单算术。 result eval(expression) return f计算结果{expression} {result} except Exception as e: return f计算表达式 {expression} 时出错{e} # 将工具包装成列表 tools [search_web, get_weather, calculator]注意上面的工具实现是高度简化的模拟。在生产环境中search_web应接入可靠的搜索引擎API如SerpAPI、Google Custom Searchget_weather应接入气象服务API而calculator应避免使用eval改用安全的数学表达式解析库。这里为了演示的清晰和可运行性使用了模拟数据。3.2 构建ReAct智能体与提示工程接下来我们需要初始化LLM并利用LangChain的create_react_agent函数来构建Agent。这个函数的核心是为LLM准备一个特殊的“系统提示词”System Prompt这个提示词会指导LLM按照ReAct的格式进行输出。from langchain import hub from langchain.agents import create_react_agent, AgentExecutor # 1. 初始化LLM。这里使用OpenAI的GPT-3.5-turbo你需要设置自己的OPENAI_API_KEY。 # 你也可以替换为其他LangChain支持的模型如ChatAnthropicClaude、ChatGroqLlama等。 llm ChatOpenAI(modelgpt-3.5-turbo, temperature0) # 2. 获取ReAct提示模板。LangChain Hub上维护了一个标准的ReAct提示词。 # 这个提示词详细规定了LLM的输出格式例如以“Thought:”、“Action:”、“Action Input:”为前缀。 prompt hub.pull(hwchase17/react) # 3. 创建ReAct Agent。它将LLM、工具和提示词绑定在一起。 agent create_react_agent(llm, tools, prompt) # 4. 创建代理执行器Agent Executor。它负责运行循环解析LLM输出 - 执行工具 - 返回观察 - 继续。 agent_executor AgentExecutor(agentagent, toolstools, verboseTrue, handle_parsing_errorsTrue, max_iterations5)关键点解析temperature0设置为0可以使模型的输出更确定、更稳定这对于需要精确解析“Action”的Agent任务非常重要。verboseTrue开启后执行器会打印出每一步的“Thought”、“Action”、“Observation”方便我们调试和观察Agent的思考过程。handle_parsing_errorsTrue当LLM的输出不符合预期格式无法解析出Action时这个选项可以让执行器尝试修复或给出友好错误而不是直接崩溃。max_iterations5设置安全阀防止Agent在某些问题上陷入无限循环。根据任务复杂度调整。3.3 运行与调试观察智能体的思考轨迹现在让我们运行这个旅行规划助手并向它提出一个稍微复杂的请求。# 向Agent提问 question 我计划周末去上海玩两天预算大概1500元。请帮我看看有什么推荐景点并考虑一下天气因素。 result agent_executor.invoke({input: question}) print(\n--- 最终答案 ---) print(result[output])当verboseTrue时你会在控制台看到类似下面的输出。这正是ReAct模式的精髓所在让我们能窥见AI的“思考”过程 Entering new AgentExecutor chain... Thought: 用户想规划一个上海周末游预算1500元。我需要考虑景点推荐和天气。首先我应该搜索上海周末值得去的景点。 Action: search_web Action Input: 上海周末推荐景点 Observation: 搜索 上海周末推荐景点 的结果上海迪士尼乐园是中国内地首座迪士尼主题乐园拥有七大主题园区。门票平日价约399元周末及节假日约599元。外滩是上海的历史文化街区以52幢风格迥异的古典复兴大楼群闻名是观赏黄浦江景和陆家嘴天际线的绝佳地点。免费开放。豫园是位于上海老城厢的江南古典园林始建于明代。园内亭台楼阁、假山水榭布局精巧。门票约40元。 Thought: 我得到了几个景点迪士尼、外滩、豫园。迪士尼门票较贵周末约599元外滩免费豫园便宜40元。用户预算1500元需要玩两天所以得考虑住宿、交通和餐饮。天气也很重要需要查询上海周末的天气来决定穿什么和是否适合户外活动。 Action: get_weather Action Input: {city: 上海, date: tomorrow} Observation: 上海tomorrow的天气多云气温16-24°C微风。 Thought: 明天天气不错多云温度适宜。那么后天呢用户说是周末玩两天。 Action: get_weather Action Input: {city: 上海, date: today} # 注意这里模型可能对“后天”的日期处理有误它错误地查询了“today”。实际项目中需要更智能的日期解析工具。 Observation: 上海today的天气晴转多云气温15-22°C东南风2-3级。 Thought: 看起来周末两天天气都挺好。现在来规划行程和预算。假设第一天去迪士尼599元第二天上午去豫园40元下午去外滩免费。需要估算住宿和餐饮。让我计算一下大致花费。 Action: calculator Action Input: 599 40 200*2 150*2 # 景点门票 两晚住宿假设200/晚 两天餐饮假设150/天 Observation: 计算结果599 40 200*2 150*2 1339 Thought: 总花费大约1339元在1500元预算内。我可以给出建议了。 Final Answer: 根据您的1500元预算和上海周末的天气情况为您规划一个两日游方案 **第一天周六天气多云16-24°C** * **上午/全天上海迪士尼乐园**。周末门票约599元。天气舒适适合户外游乐。建议早点出发。 * **晚上** 选择迪士尼附近或市区的经济型酒店约200元/晚。 **第二天周日天气晴转多云15-22°C** * **上午豫园**。体验江南古典园林门票约40元。 * **下午外滩**。欣赏历史建筑群和陆家嘴天际线免费。天气晴朗非常适合散步和拍照。 * **晚上** 返回住宿约200元。 **预算估算** * 门票迪士尼599 豫园40 639元 * 住宿200元/晚 * 2晚 400元 * 餐饮150元/天 * 2天 300元 * **总计约1339元**在您的1500元预算内。 **温馨提示** 以上为大致估算实际费用可能因具体选择浮动。周末迪士尼人流较多建议提前购票。根据天气穿着轻便衣物并备一件外套即可。通过这个详细的输出我们可以清晰地看到Agent的完整推理链思考1识别任务核心景点、天气、预算决定先搜索景点。行动1调用search_web工具。观察1获得景点信息。思考2根据景点信息意识到需要天气和预算规划决定先查天气。行动2调用get_weather工具这里出现了一次对日期理解的小偏差查询了“明天”和“今天”而非“后天”。观察2/3获得天气信息。思考3综合信息开始进行预算计算。行动3调用calculator工具。观察4获得计算结果。思考4判断信息已齐全可以生成最终答案。这个轨迹不仅证明了ReAct的有效性也为我们后续的调试和优化提供了宝贵的依据。4. 实战中的核心挑战与优化策略搭建一个能跑的ReAct Agent只是第一步。要让它在生产环境中稳定、可靠、高效地工作会遇到一系列挑战。下面是我在多个项目中总结出的核心问题和解决方案。4.1 工具设计的艺术如何让LLM“用好”工具工具是Agent的手脚设计不当会导致Agent无法有效工作。挑战1工具描述模糊。如果工具的描述description太简略LLM可能无法准确理解何时该调用它。优化策略为每个工具编写清晰、具体的描述最好包含使用场景示例。例如get_weather的描述可以写成“获取指定城市未来三天的天气预报。输入应为包含‘city’城市名如‘北京’和‘date’可选默认为‘today’可以是‘tomorrow’或‘2024-05-20’格式的JSON字符串或自然语言。”挑战2工具过多导致混淆。当工具数量超过10个时LLM可能难以准确选择。优化策略工具分类将功能相近的工具分组在提示词中说明类别。动态工具选择并非每次都将所有工具暴露给Agent。可以根据用户问题的意图先通过一个分类器另一个LLM调用或规则筛选出最相关的3-5个工具再进行ReAct循环。使用更强大的模型GPT-4在工具选择上的准确性通常远高于GPT-3.5。挑战3工具输出格式混乱。工具返回的观察结果如果过于冗长或包含无关信息会干扰LLM的后续思考。优化策略对工具的返回结果进行“后处理”。提取关键信息过滤掉广告、错误代码等噪音并以简洁、结构化的文本格式返回给LLM。4.2 解析与错误处理构建鲁棒的执行循环LLM的输出是非结构化的自然语言解析失败是家常便饭。挑战1输出格式偏离。LLM可能不严格按照“Action: tool_name\nAction Input: args”的格式输出可能会添加额外解释。解决方案强化提示Prompt Reinforcement在系统提示词中多次强调输出格式并使用“你必须严格按照以下格式输出”等强约束语句。在few-shot示例中提供完美的格式样板。使用更鲁棒的解析器除了简单的正则表达式可以使用基于语法如自定义的Pydantic模型的解析器或者利用LLM本身进行二次解析输出解析。LangChain的OutputFixingParser和RetryOutputParser就是干这个的它们能在解析失败时自动尝试让LLM修正自己的输出。挑战2工具执行异常。工具调用可能因为网络、参数错误等原因失败。解决方案在执行器层进行完善的异常捕获。当工具调用失败时不要直接抛出错误导致Agent崩溃而是将友好的错误信息如“网络请求超时请稍后再试”或“参数‘city’不能为空”作为“Observation”返回给LLM。LLM在下一轮思考中可能会尝试重试或调整参数。4.3 记忆与上下文管理应对长对话与复杂任务ReAct的每一步都会在对话历史中追加Thought、Action、Observation上下文长度会快速增长。挑战上下文窗口限制与信息冗余。当任务步骤很多时可能会超过LLM的上下文长度。同时早期的、不相关的步骤会干扰后续决策。优化策略摘要式记忆Summarization Memory定期例如每5步或当上下文达到一定长度时用一个单独的LLM调用对之前的对话历史进行摘要然后用摘要替换掉冗长的原始历史再继续后续步骤。这能显著节省token。向量存储记忆VectorStore Memory将每一步的Observation等关键信息存入向量数据库如Chroma、Pinecone。当Agent需要回忆某个信息时通过语义搜索从向量库中检索最相关的片段而不是把所有历史都塞进上下文。这非常适合需要长期记忆和知识回溯的Agent。对话窗口记忆ConversationBufferWindowMemory只保留最近K轮比如最近10轮的对话历史丢弃更早的。这对于短期、聚焦的任务很有效。4.4 停止策略与防死循环为智能体装上安全阀Agent可能会在某些问题上陷入无意义的循环或者迟迟不输出最终答案。挑战无限循环与无效动作。例如Agent可能反复查询同一个天气而无法推进。解决方案实施多层停止策略。最大迭代次数Max Iterations这是最基本的防线如我们之前设置的max_iterations5。早期停止Early Stopping监控Agent的行为。如果连续多次Action相同或相似且Observation没有带来新的信息可以主动中断循环并让Agent总结当前已知信息给出一个“尽力而为”的答案。超时控制Timeout为整个Agent运行或单个工具调用设置时间限制。5. 高级模式与框架选型指南基础的ReAct循环已经能解决很多问题但对于更复杂的场景我们需要更高级的模式或直接选用成熟的框架。5.1 规划-执行-反思Plan-and-Execute模式这是ReAct的一种进阶模式。在真正的“思考-行动”循环开始前先让LLM做一个高层级的任务分解规划。用户请求 “帮我写一份关于新能源汽车行业的研究报告并做成PPT。”规划阶段LLM先输出一个高层计划。计划 1. 搜索并收集近三年中国新能源汽车的销量数据、政策动态、主要厂商信息。 2. 分析行业发展趋势、技术瓶颈如电池和市场机遇。 3. 整理关键数据和观点设计PPT大纲。 4. 根据大纲分章节撰写报告内容。 5. 将报告内容转换为PPT幻灯片格式。执行阶段Agent再根据这个计划逐步调用工具搜索、数据分析、文档生成等去完成每一个子任务。这种模式让Agent在面对宏大、模糊的任务时能有更清晰的“路线图”避免在细节中迷失方向。LangChain的PlanAndExecute执行器就实现了这一模式。5.2 主流Agent开发框架对比除了LangChain市面上还有其他优秀的Agent框架各有侧重。框架名称核心特点适用场景学习曲线LangChain生态丰富组件化。提供了大量现成的工具、记忆、链Chain和代理Agent模板。社区活跃文档详细。快速原型开发构建复杂的、包含多种组件的AI应用。适合大多数从研究到生产的场景。中等。概念较多Model, Prompt, Chain, Agent, Memory, Tool需要时间理解其设计哲学。LlamaIndex数据感知Data-Aware。专精于让LLM与私有数据、结构化数据交互。其Agent功能更侧重于基于文档的问答和数据分析。构建企业知识库问答、文档分析、基于私有数据的智能助手。当你的Agent核心是“理解你的数据”时它是绝佳选择。中等。如果你主要处理文档和数据它的抽象很直观。AutoGen多智能体对话。由微软推出核心是让多个拥有不同角色和能力的Agent通过对话协作来解决复杂任务。需要模拟不同角色如程序员、测试员、产品经理协作完成软件开发的场景或任何需要多角色、多轮复杂协商的任务。较陡。需要理解其对话编程范式但功能非常强大。Semantic Kernel微软系插件化。由微软推出与.NET生态结合紧密。强调“插件”Plugins的概念规划能力是其亮点。面向企业级、尤其是已有大量.NET/C#资产的项目。希望深度集成到微软技术栈如Azure, Copilot中。中等。对于.NET开发者更友好。选型建议新手入门或全栈项目首选LangChain。它的通用性最强社区支持最好遇到问题容易找到解决方案。核心是处理公司内部文档/数据重点考察LlamaIndex。需要模拟团队协作或复杂对话流程深入研究AutoGen。技术栈以微软生态为主考虑Semantic Kernel。5.3 性能优化与成本控制Agent应用可能会频繁调用LLM和外部API成本和延迟是需要严肃考虑的问题。优化策略1缓存Caching。对LLM的相同提示词调用结果进行缓存。例如使用LangChain的InMemoryCache或SQLiteCache。对于工具调用如果结果不要求绝对实时如某些百科知识也可以实施缓存。优化策略2小模型协同。并非每一步都需要最强的GPT-4。可以用GPT-3.5-turbo或更小的开源模型如Qwen-7B来处理简单的工具选择、格式解析等任务只在关键推理步骤使用大模型。这种“大小模型混合”的策略能显著降低成本。优化策略3异步与流式处理。如果Agent的多个步骤之间没有强依赖可以考虑异步执行。对于需要长时间运行的任务向用户提供流式Streaming的中间思考过程可以极大提升用户体验。6. 避坑指南与最佳实践结合我过去一年多的Agent开发经验以下是一些“血泪教训”总结出的最佳实践从简单开始逐步复杂化不要一开始就设计一个拥有20个工具的万能Agent。从一个明确的任务如“查询天气并建议穿衣”和2-3个核心工具开始。验证ReAct循环能跑通后再逐步添加工具和复杂度。精心设计工具的“人机接口”把工具想象成给LLM使用的API。它的名称要直观如calculate_budget优于tool_3描述要像产品说明书一样准确参数要简单明了。好的工具设计能极大降低提示工程的难度。实施全面的日志记录务必记录下每一次Agent运行的完整轨迹Trace包括每一轮的Thought、Action、Observation。这是你调试Agent、理解其失败原因、优化提示词的最宝贵资料。可以考虑使用像LangSmith这样的可视化平台来监控和分析。为不确定性设计LLM是概率模型输出具有不确定性。你的Agent系统必须能处理这种不确定性。这意味着要有完善的错误处理、重试机制和降级方案例如当Agent连续失败时转接到人工客服或提供一个简化的备选方案。安全与合规前置Agent能自主调用工具这带来了新的风险。工具权限控制严格限制每个工具能访问的数据和能执行的操作。例如一个处理用户邮件的Agent不应该有删除所有邮件的权限。输入输出过滤对用户输入和工具返回的内容进行安全检查防止提示词注入Prompt Injection或返回有害内容。人工审核环节对于高风险操作如发送邮件、执行支付设计“人工确认”环节让Agent在执行前先征求用户或管理员的明确同意。ReAct模式为AI Agent注入了真正的“行动力”使其从理论走向实践。它不再是一个停留在对话界面的聊天机器人而是一个可以主动调研、分析、执行并完成复杂工作流的智能助手。掌握ReAct你就拿到了构建下一代AI应用的关键钥匙。
返回列表