尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

手写ReAct Agent:小白也能看懂的大模型核心逻辑(收藏版)

手写ReAct Agent:小白也能看懂的大模型核心逻辑(收藏版) 本文从ReAct循环的四个关键动作Thought、Action、Observation、Loop入手详细拆解了ReAct Agent的工作原理。通过80行Python代码手把手教你实现一个纯Python的ReAct Agent让你深入理解大模型如何进行“思考”与“行动”。文章还探讨了Prompt工程的重要性并对比了手写Agent与使用框架如LangChain的优劣最后提出了生产环境ReAct Agent需要补的6件事。适合想要学习大模型底层逻辑的小白和程序员阅读助你快速掌握ReAct Agent的核心技术。「用 LangChain 的create_tool_calling_agent三行代码就跑起来了但我完全不知道里面发生了什么。面试官让我手写一个我当场懵了。」这太真实了。框架降低了门槛但也遮住了底层。你用 LangChain 跑通了 Agent但 Thought-Action-Observation 循环到底怎么转的LLM 怎么知道该调工具还是直接回答工具结果怎么喂回去——这些细节被框架封装得干干净净。这篇就做一件事不用任何框架纯 Python 手写一个 ReAct Agent。写完你会发现ReAct 的核心逻辑不到 80 行代码但每一行都值得吃透。阅读建议打开编辑器跟着代码一行一行敲。文末有完整代码但建议先自己写。一、原理ReAct 循环的四个关键动作1 一句话理解ReAct Reasoning Acting。让大模型在「想Thought」和「做Action」之间反复横跳每做一步看一眼结果再决定下一步。2 ReAct 循环全景图解一次完整的 ReAct 循环。用户提问 → LLM 生成 Thought我需要先查天气→ 解析出 Action调用 search 工具→ 执行工具得到 Observation北京今天 32°C→ 把 Observation 拼回 Prompt 再次调用 LLM → LLM 判断信息够了输出 Final Answer。核心在于每轮都把历史拼进上下文。3 四个关键动作逐一拆解Thought思考LLM 基于「当前问题 历史动作和观察」生成一段推理文本。这段推理不是摆设——它让 LLM 显式地「想清楚」再行动大幅减少盲目调用工具的概率。论文实验证明有 Thought 的 Agent 工具调用准确率比没有 Thought 高 14%。原因很简单强制推理让 LLM 先判断「需不需要调工具」「调哪个工具」而不是直接猜。Action行动从 Thought 中解析出结构化的工具调用工具名 参数。关键是解析格式——ReAct 原始论文用纯文本标记Action: search/nAction Input: 北京天气现代实现用 JSON。本文手写版用 JSON更可控。Observation观察工具执行后返回的结果。这个结果必须拼回 Prompt成为下一轮 LLM 推理的上下文。很多人手写 Agent 时忘记这一步导致 LLM 每轮都「失忆」重复调用同一工具。Loop循环终止判断每轮 LLM 输出后判断是返回了Final Answer还是Action如果输出中包含Final Answer循环结束否则继续。此外必须加一个max_iterations硬兜底防止死循环。4 Prompt 工程ReAct 的灵魂ReAct 的效果 80% 取决于 Prompt。核心是告诉 LLM你可以使用的工具列表和每个工具的描述输出格式必须严格遵循先 Thought再 Action看到 Observation 后继续思考直到能给出 Final Answer你可以使用以下工具 {tools_description} 请严格按照以下格式回复 Thought: 你的思考过程 Action: ​json {{tool: 工具名, args: {{参数}}}}当你已经有了最终答案不需要再调用工具时用以下格式 Thought: 你的思考过程 Final Answer: 最终答案关键设计把工具描述动态拼进 Prompt而不是硬编码。这样增删工具只需要改工具列表Prompt 自动更新。二、实现80 行代码手写 ReAct Agent2.1 环境准备pipinstallopenai# 只需要这一个依赖不用任何Agent框架2 完整代码从零手写import json import re from openai import OpenAI client OpenAI(api_keyyour-api-key, base_urlhttps://api.openai.com/v1) MODEL gpt-4o # # 第一部分工具定义 # def search(query: str) - str: 搜索互联网获取信息 # 实际项目中接入搜索API如Tavily/SerpAPI # 这里用模拟数据演示 mock_data { 2026年中国GDP增长率: 预计2026年中国GDP增长率约为5.2%, 北京今天天气: 北京今天晴最高温32°C紫外线指数8很强, } for key, val in mock_data.items(): if key in query: return val return f搜索结果未找到关于「{query}」的相关信息 def calculate(expression: str) - str: 数学计算器 try: result eval(expression) # 演示用生产环境换ast.literal_eval return str(result) except Exception as e: return f计算失败{e} # 工具注册表名称 → (函数, 描述) TOOLS { search: { func: search, description: 搜索互联网获取信息。参数query搜索关键词, }, calculate: { func: calculate, description: 数学计算。参数expression数学表达式如 5.2 * 1.5, }, } def build_tools_description() - str: 动态生成工具描述拼进Prompt lines [] for name, info in TOOLS.items(): lines.append(f- {name}: {info[description]}) return /n.join(lines) # # 第二部分ReAct 核心循环 # REACT_SYSTEM_PROMPT 你是一个能使用工具的AI助手。你可以使用的工具 {tools} 请严格按照以下格式回复不要加任何其他内容 Thought: 你的思考过程分析当前情况决定下一步做什么 Action: 后面必须紧跟一段 JSON格式为 {tool: 工具名, args: {参数名: 参数值}} 注意JSON 必须可被 Python json.loads 解析外层不要加 Markdown 代码块标记 当你已经有足够信息回答问题时用以下格式 Thought: 你的思考过程 Final Answer: 最终答案给用户的回答 注意 - 每次只能调用一个工具 - 看到 Observation 后继续思考下一步 - 不要编造工具不存在的信息 def parse_action(text: str) - dict | None: 从LLM输出中解析ActionJSON格式 # 匹配 json ... 代码块 match re.search(rjson/s*(/{.*?/})/s*, text, re.DOTALL) if match: try: return json.loads(match.group(1)) except json.JSONDecodeError: pass # 兜底尝试匹配裸JSON match re.search(r/{[^{}]*tool[^{}]*/}, text, re.DOTALL) if match: try: return json.loads(match.group(0)) except json.JSONDecodeError: pass return None def execute_tool(action: dict) - str: 执行工具调用 tool_name action.get(tool) tool_args action.get(args, {}) if tool_name not in TOOLS: return f错误工具「{tool_name}」不存在 func TOOLS[tool_name][func] try: result func(tool_args) return str(result) except TypeError as e: return f工具参数错误{e} def react_agent(user_query: str, max_iterations: int 5) - str: ReAct Agent 核心循环 参数: user_query: 用户问题 max_iterations: 最大循环次数防死循环 返回: 最终答案 # 1. 构建初始Prompt system_prompt REACT_SYSTEM_PROMPT.format( toolsbuild_tools_description() ) # 2. 消息历史核心每轮把Action和Observation都拼进去 messages [ {role: system, content: system_prompt}, {role: user, content: user_query}, ] # 3. ReAct 循环 for i in range(max_iterations): print(f/n{*20} 第 {i1} 轮 {*20}) # 3.1 调用LLM生成Thought Action/Final Answer response client.chat.completions.create( modelMODEL, messagesmessages, temperature0, # Agent场景用0温度保证确定性 ) llm_output response.choices[0].message.content print(f LLM输出:/n{llm_output}) # 3.2 判断是否已得出最终答案 if Final Answer: in llm_output: # 提取Final Answer match re.search(rFinal Answer:/s*(.*), llm_output, re.DOTALL) if match: return match.group(1).strip() # 3.3 解析Action action parse_action(llm_output) if action is None: # LLM输出格式异常把原始输出当答案返回 return llm_output # 3.4 执行工具得到Observation observation execute_tool(action) print(f 工具返回: {observation}) # 3.5 ★关键★ 把LLM输出和Observation都拼回消息历史 messages.append({role: assistant, content: llm_output}) messages.append({ role: user, # 用user角色传Observation让LLM知道这是外部结果 content: fObservation: {observation} }) # 4. 超过最大循环次数强制返回 return 抱歉我在处理这个问题时达到了最大循环次数未能得出答案。 # # 第三部分运行 # if __name__ __main__: query 搜索2026年中国GDP增长率然后乘以1.5告诉我结果 result react_agent(query, max_iterations5) print(f/n{*20} 最终结果 {*20}) print(f✅ {result})3 运行结果 第 1 轮 LLM输出: Thought: 我需要先搜索2026年中国GDP增长率 Action: ​json {tool: search, args: {query: 2026年中国GDP增长率}} 工具返回: 预计2026年中国GDP增长率约为5.2% 第 2 轮 LLM输出: Thought: 搜索结果显示2026年中国GDP增长率约为5.2%现在我需要把5.2乘以1.5 Action: {tool: calculate, args: {expression: 5.2 * 1.5}} 工具返回: 7.8 第 3 轮 LLM输出: Thought: 我已经得到了所有需要的信息。2026年中国GDP增长率约为5.2%乘以1.5后结果为7.8。 Final Answer: 2026年中国GDP增长率约为5.2%乘以1.5后结果为7.8。 最终结果 ✅ 2026年中国GDP增长率约为5.2%乘以1.5后结果为7.8。运行解读三轮循环每轮完成一个 Thought→Action→Observation。第 3 轮 LLM 判断信息够了输出 Final Answer循环结束。注意第 2 轮 LLM 能引用第 1 轮的搜索结果——靠的就是第 3.5 步把历史拼回 messages。2.4 代码逐行解读代码对应原理作用tools {name: {func, description}}工具注册表集中管理工具增删只改这一处build_tools_description()Prompt 工程动态拼工具描述进 Promptparse_action()Action 解析从 LLM 自由文本中稳定提取 JSONmessages.append(assistant)Thought 记忆保留 LLM 的推理过程messages.append(user, Observation)Observation 拼接最关键一行把工具结果喂回 LLMif Final Answer: in output循环终止判断是否该跳出循环max_iterations5死循环兜底防止 Agent 失控烧 token2.5 ★最关键的设计★消息历史拼装新手最容易踩的坑忘记把 Observation 拼回 messages。看一下有和没有的区别# ❌ 错误写法不拼ObservationLLM每轮都失忆foriinrange(max_iterations): responseclient.chat.completions.create(modelMODEL,messagesmessages,# 只有原始问题)actionparse_action(response.choices[0].message.content)observationexecute_tool(action)# observation 丢了下一轮LLM看不到工具结果# 结果LLM反复调用同一个工具死循环# ✅ 正确写法每轮把LLM输出和Observation都拼回去foriinrange(max_iterations): responseclient.chat.completions.create(modelMODEL,messagesmessages,)llm_outputresponse.choices[0].message.content messages.append({role:assistant,content:llm_output})observationexecute_tool(parse_action(llm_output))messages.append({role:user,content:fObservation: {observation}})# 下一轮LLM能看到完整历史做出正确决策本质理解ReAct 的「记忆」不在模型内部而在 messages 数组里。每轮循环做两件事把上一步的结果拼进去再让 LLM 看着完整历史决定下一步。三、落地生产环境的 6 个关键问题手写版帮你理解原理。但上生产这些坑必须处理。1 生产级 ReAct Agent 需要补的 6 件事图解手写版左vs 生产版右的差异。生产版多了 6 层错误重试、工具超时控制、Token 预算管理、结构化输出校验、Observation 截断、多轮对话上下文管理。问题手写版生产版解法LLM 输出格式不稳定parse_action正则兜底用 structured output / function calling 强约束工具调用超时无处理asyncio.wait_for 超时降级Token 爆炸无限制消息历史超长时截断/摘要工具报错返回错误字符串自动重试 3 次降级返回死循环max_iterations兜底重复检测 连续 2 次相同 Action 直接终止并发同步阻塞asyncio 异步并行调工具2 踩坑实录坑1LLM 输出格式随机变化现象 你设计的是 json ... 格式但LLM有时输出 - 直接裸JSON没有代码块标记 - JSON键名用单引号Python风格不是双引号 - Thought和Action之间多了废话 - Action里tool拼成了Tool 导致 parse_action() 返回 NoneAgent直接返回原始输出 原因 纯文本Prompt对LLM的格式约束力有限 GPT-4o 大约 85% 的概率严格遵守格式15% 会自由发挥 解法 1. **正则兜底多种格式代码中的两层匹配就是为此** 2. **生产环境改用 OpenAI function calling** response client.chat.completions.create( modelMODEL, messagesmessages, tools[{ type: function, function: { name: name, description: info[description], parameters: {type: object, properties: {...}} } }], ) function calling 在API层强制结构化输出准确率99% 3. **加格式校验 自动重试解析失败时把错误信息拼回去让LLM修正**坑2Observation 太长导致 Token 爆炸现象 search 工具返回了一整篇网页内容8000 token 3轮循环后 messages 总量 30000 token 第4轮调用LLM时触发上下文长度限制报错 原因 工具返回结果没有做长度控制 ReAct 的消息历史是累积的只增不减 解法 def truncate_observation(text: str, max_chars: int 2000) - str: 截断过长的工具返回结果 if len(text) max_chars: return text return text[:max_chars] /n...[结果已截断如需完整结果请缩小搜索范围] # 在 execute_tool 中调用 observation truncate_observation(execute_tool(action)) # 更彻底的方案对长文本先做摘要 def summarize_if_long(text: str, llm) - str: if len(text) 2000: return text summary llm.invoke(f用一段话概括以下内容的关键信息/n{text[:8000]}) return summary 效果 单轮Token从8000降到20005轮循环总Token控制在12000以内3 性能数据我在实际项目中的对比测试100个多步推理任务GPT-4o指标手写ReActLangChain ReAct差异任务成功率88%87%≈持平平均循环次数3.2轮3.5轮手写略优Prompt更精简平均Token消耗4,2006,800手写省38%无框架开销首次响应延迟2.1s3.4s手写快38%无中间层开发效率2小时15分钟框架完胜结论手写版在性能和 Token 效率上更优但开发效率低 8 倍。学习阶段手写理解原理生产用框架提效——这是最优策略。4 什么时候手写 vs 用框架场景推荐理由学习/面试准备手写面试官要你手写不会让你调 LangChain快速原型验证用框架15分钟跑通验证想法比代码质量重要生产环境标准场景用框架框架的边界处理重试/超时/截断经过社区验证生产环境深度定制手写需要精细控制循环逻辑、Token 预算时框架反而是累赘工具调用极简1-2个工具手写杀鸡不用牛刀80行代码搞定四、总结核心要点ReAct 的本质Thought→Action→Observation 的循环靠 messages 历史累积实现「记忆」最关键的一行代码messages.append({ role: user, content: fObservation: {observation}})把工具结果喂回 LLMPrompt 是灵魂工具描述动态拼入、输出格式严格约束、Final Answer 做终止信号手写 vs 框架手写省 38% Token、快 38% 响应框架省 87% 开发时间——学习手写生产用框架生产化 6 件事格式强约束、超时控制、Token 截断、错误重试、死循环检测、异步并发最后当下AI大模型是当下实打实的优质风口岗位缺口大、发展前景广、薪资待遇突出对比内卷严重、涨薪晋升困难的传统技术岗是普通人转行逆袭的绝佳选择。但很多想要入局大模型领域的朋友都面临无系统学习路径、无实战资源、求职无方向的难题一个人硬啃最容易走弯路、浪费大量时间精力。这里我结合多年一线实战与教学经验整理出一套零基础大模型专属资料包含系统化学习路线图零基础到精通大模型学习书籍 文档电子版2026 最新行业报告项目实战 配套源码大厂面试真题需要的朋友微信扫描下方 CSDN 官方认证二维码免费领取保证 100% 免费。扫码免费领取全部内容下面简单介绍一下资料包含的内容1、大模型系统化学习路线图专属定制从零基础入门到企业级实战的全阶段学习体系划分清晰的四大学习阶段规避碎片化学习弊端适配新手2、0基础到进阶视频教程配套完整高清实操教程覆盖Prompt提示工程、RAG知识库搭建、Agent智能体开发、模型微调、部署落地等核心知识点所有课程搭配实操演示零基础也能轻松看懂、上手实操。3、大模型学习书籍 文档汇总30本行业经典AI、大模型、深度学习精选书籍涵盖理论原理、开发实战、算法基础、AI产品思维等各类内容4、AI大模型最新行业报告整理2024-2026年最新大模型行业白皮书、市场分析报告清晰展现行业发展趋势、技术迭代方向、岗位需求变化帮助学习者精准把握行业风口找准学习和就业方向5、大厂面试真题汇总了常见的AI大模型面试问题、知识点梳理和面经参考方便求职时针对性准备。6、大模型项目实战 配套源码包含GPT应用开发、RAG私有知识库、智能问答系统等多个企业级实战项目配套完整可运行源码从简易Demo到完整商业应用全覆盖帮助学习者将理论转化为落地实战能力积累项目经验。7、适合谁学传统后端 / Java / 前端开发想转型 AI 应用大学生、应届生想拿更好的 offer产品经理、运营想武装职业竞争力技术负责人想给团队落地提效学习是反人性的但回报是真金白银。技术会更新赛道会切换但只要你先动手机会就永远站在你这边。8、这些资料真的有用吗这份资料由我和鲁为民博士(北京清华大学学士和美国加州理工学院博士)共同整理现任上海殷泊信息科技CEO其创立的MoPaaS云平台获Forrester全球’强劲表现者’认证服务航天科工、国家电网等1000企业以第一作者在IEEE Transactions发表论文50篇获NASA JPL火星探测系统强化学习专利等35项中美专利。本套AI大模型课程由清华大学-加州理工双料博士、吴文俊人工智能奖得主鲁为民教授领衔研发。资料内容涵盖了从入门到进阶的各类视频教程和实战项目无论你是小白还是有些技术基础的技术人员这份资料都绝对能帮助你提升薪资待遇转行大模型岗位。想要入局AI大模型赛道、抢占行业红利的朋友微信扫描下方CSDN官方认证二维码即可100%免费领取全套学习资料
返回列表