大模型智能体简易流程:从ReAct原理到手写Agent Demo 📅 发布时间:2026/9/14 16:30:20 👁 浏览次数: “大模型智能体”和“agent”这两个词几乎把我的信息流淹没了。不少朋友跑来问AI Agent到底是什么它和平时聊天的ChatGPT有什么本质区别我能不能自己动手搭一个说实话这名字起得确实唬人但拆开之后核心逻辑并不复杂。今天我就把“大模型智能体agent简易流程”这根硬骨头完整地啃一遍以一个老开发的角度说说我理解的agent是什么、工作流程怎么走、怎么手写一个最简Demo以及那些文档里不会写的坑。这篇内容特别适合刚接触agent、想做agent开发或大模型应用开发的朋友读完你会觉得这东西没有想象中那么玄乎。1. 为什么需要Agent从“会聊天”到“能办事”1.1 大模型不等于智能体先想一个问题你让ChatGPT“查一下明天杭州的天气”它真的能查吗答案是不能。大模型本质上是语言模型知识停留在训练数据截止的那一天也没有能力去访问实时数据库或调用真实工具。它给出的“杭州明天有雨”只是根据训练数据里的语言模式推测出来的一段话并不是真正查了气象系统。这就是大模型和智能体之间最核心的分界线前者只会“说”后者会“做”。那agent是怎么实现“做”的用一句话概括大模型 感知 工具 记忆 规划循环。大模型在其中充当大脑中枢相当于一个坐在驾驶位上有判断力但手脚被绑住的司机工具就是解开束缚的手脚比如搜索引擎、天气API、计算器、数据库查询接口感知负责读取外部状态记忆负责保存历史信息和经验规划负责把大任务拆成小步骤。整套系统不断循环直到任务闭环。1.2 Agent的核心组成与工作流程自制一个简易agent最关心的就是流程。朴素地讲它的运作可以归纳为四步循环接收任务用户说“帮我查一下某公司最新融资消息并用一句话总结”。模型思考规划模型内部推理——这事需要联网搜索、需要查新闻、需要总结于是决定调用搜索工具。执行工具调用程序把模型“想调用搜索”的意图转成真实的函数执行拿到返回值。观察与再思考把工具返回的结果喂给模型模型判断信息是否够用。不够就继续调用其他工具够了就生成最终答案。这四步就是业界常说的ReAct循环Reason推理 Act行动。理解了这个循环agent开发的基础盘就到手了。后面所有的agent框架、流程编排、多智能体协同本质都是在“循环”外面加了一层更智能的管道。所以我一直建议新手先别看复杂架构先把这层循环啃下来后面再看任何框架都会觉得眼熟。2. 简易Agent的四要素拆解2.1 大模型大脑负责推理与决策模型选型是整个agent的地基。如果模型本身的推理能力不行工具编排做得再顺agent也会变成“脑血栓指挥官”。我实际体验下来做agent至少需要一个具备基础工具调用能力的模型。OpenAI的GPT-4o系列、Anthropic的Claude系列确实成熟但属于云端服务如果你更倾向本地或开源方案可以重点考虑Qwen通义千问系列、GLM系列、Llama系列里支持function calling的版本。实测中Qwen2.5系列的工具调用格式稳定性不错适合新手起步。这里有个关键认知不是你随便拿一个开源模型就能兼容所有agent框架。模型必须与工具调用协议对齐也就是说模型必须知道“什么情况下该输出一个结构化动作而不是直接输出自然语言”。选模型时优先看它是否官方支持tool_calling其次是上下文长度再其次是响应速度。上下文长度决定agent能记住多少轮交互速度则直接决定用户等不等得起。2.2 工具手脚让Agent能操作外部世界工具是agent真正产生价值的来源。简易流程里工具本质就是一个个普通Python函数但需要在旁边附一份“说明书”让模型读懂这个函数叫什么、接收什么参数、什么场景下使用。这份说明书通常是JSON Schema结构。举个例子做天气查询工具说明书会写清楚函数名get_weather参数city是字符串类型作用是查询某城市实时天气。开发中一定要注意工具不是越多越好。我见过不少初学者一口气塞给模型十几个工具结果模型陷入选择困难要么选错要么干脆胡编结果。我自己的习惯是先给三到五个必要工具把每个工具的描述写得口语化、边界清晰确保模型“读得懂说明书”。另外工具内部还要加异常处理因为工具一旦返回一堆裸报错模型很容易被带偏产生更多幻觉。2.3 记忆短期上下文与长期知识记忆可以分成两段。短期记忆就是多轮对话的上下文窗口保存在messages列表里长期记忆则是把重要信息抽出来存进向量数据库或普通数据库等下次需要时再检索注入。简易agent一般只做短期记忆也就是把用户说过的话、模型已生成的内容都拼到messages里继续传给模型。这种方式实现简单但后面会遇到上下文爆炸的问题我会在第4章详细讲。如果想做长期记忆最简单的方案是将对话历史切片用embedding模型转成向量存入轻量级向量库比如Chroma、Milvus、pgvector收到新问题时先做向量检索把最相关的旧信息取出来拼进提示词。这里不需要一上来就搞复杂架构一个带embedding检索的Python脚本就能覆盖大部分场景。2.4 规划与循环ReAct工作模式刚才提到ReAct实际工程里大部分简易agent用的都是这种“循环式”规划而不是一次性让模型把子任务全拆完再逐步执行。循环式的好处在于灵活模型每一步都能根据最新结果动态调整不怕中间环节出问题。缺点也同样明显轮数一多耗时和成本都会上升。所以成熟框架里通常会设置最大循环次数比如最多5步超过就强制输出当前结论。打个比方ReAct就像你让助理去办一件事你下达总指示用户问题助理自己判断该先问谁、去哪里查最后回来汇总。每次得到新答复后他都会停下来想一想“信息够了没”不够就继续跑够了就收工汇报。你要在代码层维护好的就是这套“请示-汇报”的闭环同时设定兜底规则防止助理在街上瞎转圈。3. 从零手写一个简易Agent流程实操3.1 环境准备与模型选择我建议新手直接走“本地模型 OpenAI兼容接口”路线起步。这样既能理解agent原理又不会被复杂框架干扰。最稳妥的本地部署工具是Ollama它能用一条命令拉取Qwen2.5、Llama3等模型并且提供OpenAI兼容的HTTP接口。如果你的环境可以直连云端服务直接用OpenAI或Anthropic接口也可以后面代码基本通用。先装好Ollama然后执行ollama pull qwen2.5:7b ollama serve服务启动后本地接口地址就是 http://localhost:11434/v1 。这里不是非要跑7B显存不足可以换 qwen2.5:3b 甚至 1.5b只是效果会随模型规模打折。动手阶段先把流程跑通最重要。还需要准备Python环境建议3.10以上安装openai这个库因为Ollama的兼容接口可以直接用OpenAI SDKpip install openai环境准备好后先做一个最简单的连通性测试确认能正常拿到模型回复。这一步经常被忽略但它能帮你快速区分“模型问题”和“代码问题”。3.2 让模型学会“调用工具”Function Calling接入工具调用的核心是“给模型一份工具说明书”。我用一个查天气工具和一个计算器工具做演示。第一步定义工具JSON并向大模型声明import json from openai import OpenAI client OpenAI( base_urlhttp://localhost:11434/v1, api_keyollama ) tools [ { type: function, function: { name: get_weather, description: 查询指定城市的天气情况当用户询问天气问题时使用, parameters: { type: object, properties: { city: {type: string, description: 城市名比如北京、上海} }, required: [city] } } }, { type: function, function: { name: calculate, description: 进行数学计算比如加减乘除、幂运算等, parameters: { type: object, properties: { expression: {type: string, description: 数学表达式如 (3 5) * 2} }, required: [expression] } } } ] def get_weather(city): # 实际项目中这里接入天气API weather_map {北京: 晴22度, 上海: 多云25度, 广州: 阵雨28度} return weather_map.get(city, f{city}的天气数据暂未接入) def calculate(expression): # 简易计算器仅作演示生产环境绝对不要用eval allowed set(0123456789-*/(). ) if not set(expression).issubset(allowed): return 表达式包含非法字符 return str(eval(expression))为什么用JSON Schema因为模型不是真正去执行工具而是根据描述生成一个带参数结构的“调用意图”。真正执行函数的是你程序里的Python函数。这个设计把“模型决策”和“程序执行”解耦了既清晰又安全。如果你的某个工具执行成本很高你甚至可以在这层加权限控制决定是否真正放行。3.3 跑通ReAct循环思考-行动-观察-总结接下来写主循环。以一次用户提问为例完整流程是把用户问题放进messages带着tools列表发给模型模型返回tool_calls说明它想调用工具程序解析调用名和参数执行对应函数再把结果以tool角色消息追加回messages然后让模型基于观察结果继续推理直到它不再请求调用工具而是直接输出最终回答。def run_agent(user_input, max_steps5): messages [{role: user, content: user_input}] for step in range(max_steps): resp client.chat.completions.create( modelqwen2.5:7b, messagesmessages, toolstools ) msg resp.choices[0].message # 模型没有要求调用工具说明可以给出最终答案 if not msg.tool_calls: return msg.content # 模型要求调用工具先把这条消息完整加入上下文 messages.append(msg) # 逐条执行模型想要调用的工具 for tc in msg.tool_calls: fn_name tc.function.name try: args json.loads(tc.function.arguments) if tc.function.arguments else {} except json.JSONDecodeError: args {} if fn_name get_weather: result get_weather(**args) elif fn_name calculate: result calculate(**args) else: result 未知工具 messages.append({ role: tool, tool_call_id: tc.id, content: json.dumps(result, ensure_asciiFalse) }) return 达到最大步数请基于现有信息给出最终回答。 print(run_agent(北京天气怎么样顺便帮我算一下 (3 5) * 2 等于多少。))这段代码虽然简短但把agent核心循环已经讲清楚了。我提醒几个容易踩的细节第一max_steps必须限制否则模型可能反复请求工具导致死循环第二工具执行结果追加到messages时role必须是tool且tool_call_id要跟模型的调用id一一对应否则部分严格协议的模型会报错第三json.loads解析参数时一定要加异常兜底因为模型偶尔会返回格式不标准的内容。如果模型不支持tools参数可以退一步在系统提示词里要求模型输出固定JSON格式的“调用指令”程序再做正则解析和执行兼容性会好很多。3.4 实验效果与观察跑上面的例子时模型会先看到“北京天气怎么样”于是输出一个tool_call调用get_weathercity参数大概率是“北京”拿到天气结果后再看第二句“顺便帮我算一下...”它又会调用calculate表达式参数通常是“(35)*2”最后模型综合工具结果生成一句回答类似“北京今天晴22度(35)*216”。整个过程在本地7B模型上可能耗时10到30秒比直接问答慢不少这很正常因为多了一轮以上的工具调用和上下文传递。如果模型一次收到两个问题它可能一次发起多个tool_call也可能按顺序一个一个来这取决于模型训练行为。如果发现模型不调用工具而是直接编答案通常有三个方向排查模型规模太小、工具描述不够清楚、系统提示词里没有强调“不确定必须调用工具”。三个方向挨个试基本能找到原因。4. 真实场景中的常见问题与排查技巧4.1 工具调用格式崩了怎么办工具调用最常见的翻车现场是模型返回的tool_calls参数解析失败或者干脆不返回tool_call。我实际遇到三种情况。第一种模型支持tools协议但偶尔返回空的function.arguments导致json.loads直接崩溃。处理方式是解析前做防御空值给个默认空字典解析失败则记录原始文本。代码可以参考3.3节里的try方式。第二种模型本身不支持tools但你又想在老模型上搭agent。这种就不要再硬套工具协议了改用文本约束在系统提示词里要求模型“需要调用工具时只输出JSON例如{tool: get_weather, args: {city: 北京}}”然后你在代码里用正则提取JSON并执行。这种方式虽然不如原生tool_call稳定但兼容性好很多旧项目仍在使用。第三种工具函数内部抛异常。很多初学者工具方法里不写try一崩整个agent循环就断了。正确做法是让工具尽量返回结构化错误信息比如“查询失败城市名不能为空”。模型拿到这样的文本才知道如何修正下一轮动作而不是面对一堆陌生的异常堆栈。4.2 Agent卡死循环怎么破死循环是agent最让人头疼的问题。常见表现是模型反复调用同一个工具参数还一样但永远不进入总结阶段。我一度遇到过模型在天气查询上连续循环八次的情况每次都查同一个城市成本浪费不说用户也等疯了。破解思路分三个层次第一层代码层加max_steps限制强制退出这是必要兜底。第二层在system提示词里写明“如果工具结果已经能满足用户需求请直接回答不要重复调用工具”。第三层在每轮循环里做“重复调用检测”如果连续两次调用同一个工具和参数就跳过执行直接让模型基于现有信息生成回答。更进阶一点可以给每轮工具调用记录一个累计成本超过预设阈值就提前终止。这个逻辑适合对费用敏感的生产项目。4.3 上下文爆炸与记忆失效简易agent把所有历史记录都塞进messages跑上几轮之后上下文会明显膨胀。速度变慢、费用变高模型反而抓不住重点。我也遇到过工具返回一大段数据下一轮模型已经忘记初始任务是什么的情况这就是上下文被无关信息稀释了。处理上下文爆炸我常用的手段有四个截断历史只保留最近N轮对话更早的丢弃或做摘要。摘要压缩每过几轮让模型把已有对话总结成一段摘要替换原始长文本。精简工具输出工具只返回关键字段比如查天气只返回“北京晴22度”不要带着大段说明文字。长短期记忆分离把重要事实抽到外部存储每次按需检索注入。新手做小项目优先做“截断”和“精简输出”性价比最高。4.4 开源模型工具调用能力不足的平替方案如果你直接用本地小模型做复杂agent效果确实可能不如GPT-4o或Claude这是客观能力差距。但很多业务其实不需要那么强的通用推理。比如只做天气查询、只做文档检索这类垂直场景完全可以把“自主决策”简化为“规则或意图识别”再用大模型抽取关键参数。这不算退步反而是工程上的务实选择。如果一定要保留完整ReAct循环那建议选择官方支持function calling的中大规模模型比如通义千问Qwen2.5-7B及以上、智谱GLM-4系列别指望1B、3B小模型能稳定规划。小模型当“实体提取器”挺好用当“自主决策规划器”就容易翻车。以下是常见问题速查表现象常见原因排查方向模型不调用工具模型太小 / tools描述不清换大模型、精简工具描述、加system约束工具返回后模型仍胡编工具结果拼入messages方式不对检查roletool与tool_call_id是否严格对应工具参数错误模型没理解参数含义description写清楚最好给出示例多轮循环不收敛缺少终止条件加max_steps和重复调用检测响应越来越慢上下文膨胀截断历史 / 摘要压缩 / 精简输出5. 从简易Agent到工程化进阶路线建议5.1 给Agent加上长期记忆简易agent跑通后如果要继续深入我建议第一站做长期记忆。推荐一个极简落地路径先装Chroma这类轻量向量库用embedding模型把用户指令或重要信息转成向量每次新会话开始时先检索最相似的几条历史记录拼到上下文中这样用户第二次来agent还能记得之前的约定。这个方案代码量不大但对体验提升非常明显。长期记忆还可以再拆分事实型记忆存用户信息、偏好程序型记忆存已经固化的技能流程。对简易agent来说先把事实型记忆做好就够了。程序型往往要走向知识库工程复杂度会突然拉高没必要一上来就搞。5.2 多Agent与协作框架单agent处理复杂任务力不从心时很多人会想到多agent协作一个写代码一个做测试一个汇总结果彼此通过消息传递协作。但我说句大实话多agent不是银弹。维护多个agent的提示词、记忆同步和行为一致性成本成倍增长。新手如果一上来就搭“AI团队”通常会被各种意外交互搞到崩溃。框架方面LangGraph适合对流程控制要求高的场景CrewAI上手更轻快MetaGPT偏向模拟软件开发团队。选框架前先问自己我的业务是需要agent自主规划还是已经有清晰固定流程别为了用框架而用框架。手动搭多个agent时核心仍然是那个ReAct循环只不过多了一个负责分发任务和汇总结果的“主控分支”。5.3 学习路线与实战建议最后聊聊学习路线。很多刚入门的朋友总问大模型agent开发应该先学什么。我的建议是三板斧。第一板斧是提示词工程尤其是把函数描述、系统提示词写清楚这比想象中重要得多。第二板斧是编程基础熟练JSON处理和HTTP接口调用因为agent世界里到处都是结构化和API交互。第三板斧是动手复现照着本文Demo敲一遍然后把工具替换成自己业务里的接口比如查库存、写文档、发邮件。推荐的练习顺序把本文Demo改成三个新工具跑通完整调用链路。给agent加入短期截断和简单摘要逻辑。用一个真实API替换模拟函数比如天气、新闻或数据库查询。学习LangGraph把一个固定业务流编排成一张带分支的图。针对自己的业务场景定义五个以内高价值工具让agent完成一个端到端任务。这套路径从零到能落地一个可用agent通常需要两到四周。别一上来就啃论文先把工程手感练出来后面再看理论会发现很多概念都能对上号。说实话我从第一次跑通ReAct循环到真正理解agent的能力边界中间花了不少时间。回头看不难但确实踩了很多坑。最深的体会是不要高估模型的自主能力也不要低估工具描述的重要性。很多时候agent表现“傻”不是模型不行是说明书没写清楚。现在我再写agent都会先把每个工具的描述像写产品需求一样列清楚再谈后面的事。这个习惯建议你也养成很多莫名其妙的坑都能提前躲开。