AI智能体开发技术框架:从ReAct循环到多智能体协作的落地实践

发布时间:2026/10/22 5:04:17
AI智能体开发技术框架:从ReAct循环到多智能体协作的落地实践
我做了两年多智能体方向的项目从最初只会调大模型接口做闲聊到后来做了好几个能自己查数据、调工具、自动写报告的生产级Agent中间踩的坑比写的代码还多。现在有挺多朋友问我AI智能体到底该怎么开始有没有一套通用的技术框架我的回答是框架确实有但它不是银弹你要先搞清楚框架到底帮你解决了什么再动手选型否则很容易把简单的事情搞复杂。这篇文章我想用自己做项目的方式聊一下AI智能体的开发技术框架。不会去堆概念而是聊四个实在问题框架解决什么、核心模块怎么拆、从零搭一套可落地的智能体要经历什么以及多智能体和常见坑怎么处理。不管是刚入门的开发者还是已经有个Demo想往生产环境推的团队应该都能找到能直接用上的东西。1. 框架到底在解决什么问题1.1 从“写死流程”到“让模型自己决策”传统程序员的思维是“顺序执行”用户点了什么我就跑对应的函数一切由代码决定。但做智能体之后核心逻辑变成了“当前这一步该做什么由模型来决策”。这两个思维差距非常大。比如做一个“根据用户问题自动查数据库并生成报表”的功能。写死流程的话你需要枚举用户可能问的所有问题每一种写一套SQL模板这基本是死路因为用户的问题表达千奇百怪。换成智能体思维之后你只给模型提供两件事一是数据库工具封装好查询函数二是明确的系统指令。模型自己决定要不要查库、查哪些表、怎么根据结果组织回答。这个过程听起来很爽但代价是工程复杂度上来了。如果没有框架你会发现自己的代码越来越乱Prompt拼在哪都说不清工具调用的返回怎么塞回对话历史失败重试怎么办多轮对话的记忆放哪里这些问题一旦多了你就迫切需要一层抽象也就是所谓的“开发技术框架”。1.2 通用骨架感知、推理、行动、记忆我用了好几个开源编排库和平台之后发现不管它们界面多花哨核心抽象基本都能归纳成四大块感知层接收用户输入、工具返回结果、环境事件。推理层大模型根据当前状态决定下一步要做什么。行动层执行模型选择的工具调用或返回最终回答。记忆层保存短期对话上下文和长期知识供后续决策使用。这个骨架特别像一个“实习生工作流”感知是他听到你的需求推理是他想先做什么行动是他去查资料还是发消息记忆是他记得上次做到哪了。框架最大的作用就是把这四块之间的黏合逻辑固定下来让你不用每次重造轮子。我当时第一次尝试不用框架直接基于原生API写主流程。前两轮对话还好到第五轮上下文拼接已经开始混乱工具调用结果经常覆盖掉用户原意。后来老老实实按这套骨架重构代码瞬间就清晰了。所以我对智能体框架的态度是不是非用不可但你迟早会需要它。1.3 框架的价值边界什么时候不该用不过也要给提个醒不是所有场景都值得上框架。如果你的需求非常固定比如就是一个“输入关键词、返回固定格式结果”的接口直接用大模型API加几行代码就够了上框架反而多一层抽象调试更困难。我判断是否需要框架一般看三个条件任务是否有多步、不确定的流程是否需要动态调用多种工具是否需要多轮记忆和状态管理。三者中满足两个以上我才建议引入完整的框架。否则轻量实现完全够用。框架是放大器不是发动机你的业务逻辑本身不行换了什么框架都没用。2. 核心模块拆解与实现思路2.1 模型接入层接口统一比什么都重要无论你选哪家的大模型服务第一步都应该做一层模型接入抽象。别直接把厂商SDK散落到业务代码里否则以后想替换模型、做A/B测试、接私有化部署改动量会大到让你崩溃。一个最简单的接入接口长这样class AgentLLM: def chat( self, messages, toolsNone, temperature0.2, max_tokensNone, ) - LLMResult: 返回文本内容或结构化工具调用 raise NotImplementedError这里面有两个关键点第一messages必须统一成标准格式一般就是role加content如果走工具调用再加tool_calls。不同厂商的消息格式虽然看着像但字段名和嵌套方式总有点差别这层统一能消掉九成兼容性问题。第二返回值要统一。有的模型返回纯文本有的返回结构化工具调用。你需要在接入层把它们转成同一种LLMResult业务层永远只跟这个类型打交道后面换模型就很轻松。我在真实项目里经常要同时接两到三家的模型一个做通用对话一个做便宜的抽取任务。没有这层抽象之前每次切换都像重新写一遍应用。现在改配置就搞定体验差别非常大。2.2 工具注册与函数调用把大模型的“手脚”接好智能体之所以比普通聊天机器人“能干活”核心在于工具调用。模型不是真的会操作你的系统它只是根据你的功能描述输出一个“我想调用这个函数参数是这些”的结构化结果真正执行还是你代码里的事。所以工具层设计好坏直接决定智能体的可用性。我给工具注册加描述信息时一般遵循这个模式tool( namesearch_work_order, description根据工单ID或用户ID查询工单状态, parameters{ type: object, properties: { order_id: {type: string, description: 工单编号}, user_id: {type: string, description: 用户ID二选一必填} }, required: [order_id] } ) def search_work_order(order_id: str, user_id: str None): ...这里有个细节很容易被忽视模型的工具描述写得越具体选错工具的概率就越低。尤其是两个功能相近的工具一定要在描述里写清楚各自适合什么场景甚至可以写“如果你不知道工单ID请先调用另一个查询接口”。还有一个经验工具数量不是越多越好。初版曾一口气挂了二十多个工具模型经常晕头转向选错或参数填错。后来我把工具收敛到七个分类明确效果立刻稳定下来。宁可让模型多跑一步去做拆解也不要让它面对一长串鱼龙混杂的工具列表。2.3 规划与反思ReAct就够用别急着上花活很多文章讲“规划”模块讲得玄乎什么任务分解、子目标生成、反思机制。实际上落地最稳的还是最朴素的ReAct循环思考一下、调用一个工具、观察结果、再思考。这套流程足够覆盖绝大多数工具调用型Agent。ReAct循环的伪代码长这样for step in range(max_iterations): result llm.chat(messages, tools) if result.finish_reason tool_call: observation execute_tool(result.tool_call) messages.append({role: tool, content: observation}) else: return result.content你可以看到这个循环既简单又致命地依赖两个东西一是模型的工具描述二是每次工具返回的观察结果。观察结果必须结构化最好直接是JSON或简短文本别把整个HTML页面塞回去模型会被大量噪音干扰。反思机制我建议加但别每步都反思。我的做法是连续两次工具调用结果没有推进任务才触发一次“回顾当前目标、判断是否偏离、调整计划”的提示。平时每步都反思既慢又费token实际提升非常有限。2.4 记忆系统不要把所有历史都塞给模型记忆是智能体开发里最容易做崩的一块。刚开始我犯过的错是把多轮对话的全部内容一股脑放进上下文结果对话超过十轮token成本翻了好几倍模型反而更迷糊了。合理的记忆设计至少要分两层短期记忆当前任务会话内最近几轮关键信息。要设窗口比如保留最近五轮有效内容更早的做压缩摘要。长期记忆跨会话的持久信息比如用户的偏好、已经完成的任务记录。一般用向量检索的方式把历史记录切块、做嵌入、存到向量库用户新发起对话时先检索相关片段放进上下文。我在一个运维助手项目里试过这个方案每次对话结束把本轮的结论生成一个摘要存入长期记忆再次见面时先向量检索“这个用户上次处理到哪了”相关问题再开始生成。效果非常明显用户不再需要重复描述背景。这里要特别提醒记忆本质上也是“可信度存疑”的信息来源。如果检索到的记忆片段跟当前用户明确表达冲突记忆一定让位于当前输入。不能很自信地用旧信息替用户做主。3. 从零搭一个能跑通的Agent完整实操步骤3.1 第一件事先把需求和工具边界圈出来很多人做智能体上来就问“用什么技术栈”我会先问你到底要做成什么样做个“万能助手”基本做不成但“帮我处理工单、定时发报表、查知识库”就很好落地。我习惯先用一张表把自己的边界列得清清楚楚环节内容目标用户内部运营同学非技术人员核心任务查工单、查知识库、生成周报可用工具工单查询、文档检索、日报生成、消息通知禁止行为删除数据、修改配置、发送外部消息成功标准用户说一句话能在30秒内拿到可用结果这张表看起来很简单但它是整个框架设计的地基。工具边界定了后面模型调用的工具列表就定了禁止行为定了权限控制的开关也定了。我见过太多团队把智能体做成“什么都能聊”然后所有工具都开放上线第一天就出事。3.2 第一版单智能体加结构化输出跑通主链路边界定了之后不要急着做多智能体也不要一开始就加记忆。第一步永远是跑通最小闭环用户输入模型决定调用工具工具返回模型生成答案。我当时搭的最小结构只有四个文件一个模型接入类、一个工具注册表、一个主循环、一个命令行入口。主循环里甚至不需要数据库工具结果直接返回字符串。这一步的核心目的是验证工具描述和模型决策是否配合良好。跑通之后要立刻做的事情是“录测试用例”。挑二十个真实用户会问的句子比如“看一下订单12345的状态”、“帮我找一下报销流程是什么”、“上周的生产事故报告在哪”。每个用例记录模型是否正确调用工具、参数是否对、最终回答是否准确。不要用感觉判断好坏后面优化全靠这二十个用例来对比。3.3 第二版加入记忆和人工确认主链路稳定后再开始加东西。我的顺序是先加短期记忆保证多轮对话里用户不用重复说再加长期记忆识别老用户最后加一个关键的安全机制人工确认。人工确认的实现并不复杂加一个叫request_confirmation的工具就行。凡是模型打算执行高权限操作比如发外部消息、改配置、删数据都先让模型调用这个工具把操作意图写成可读文本发给前端确认用户点了同意才继续。这里有个坑一定要记住不能只靠模型“判断敏感操作”。因为模型有可能把某个敏感工具的参数填错或者根本识别不出这是敏感操作。正确做法是在工具定义里直接声明权限级别框架在执行层检查如果该工具标记为高权限无论模型是否请求确认都强制走人工审批。双重保险缺一不可。3.4 测试与收敛控制好期望值智能体和传统软件最大的不同是它做不到百分之百稳定。同样的输入换一个说法结果可能完全不同。所以在收敛阶段我的核心动作是“尽量让结果可预期”。具体做法有三个temperature往低调。工具调用类任务直接设到0或接近0减少随机性。所有工具参数尽量用枚举值约束。比如状态筛选只允许传“待处理、处理中、已完成”而不是让模型自由发挥。给模型一个“回答不了”的出口。允许它直接说“我没有找到相关信息”而不是硬编一个结果。做完这些我的二十个用例通过率一般能从最初的六成提升到八成五。剩下一成五不是继续调Prompt就能解决的需要你接受智能体是一个“有边界能力”的系统不是神话。4. 多智能体协作什么时候用、怎么设计4.1 单智能体和多智能体选择标准没那么玄聊完单智能体很多人会问是不是要做多智能体才显得高级我的回答是能单就不要多。单智能体的问题在于如果任务太复杂一个Agent要同时掌握太多工具决策会变慢、变不稳定。但多智能体的问题更大通信协调成本、状态同步、错误传播难度是指数级增长。我认为多智能体真正合理的场景是这三个工具和职责天然分属不同领域比如一个管数据分析、一个管对外沟通任务可以并行拆分多个子任务互不依赖每个子Agent的决策模型足够简单不需要大量上下文。如果你的项目只在单一领域里做工具调用老老实实单Agent就好。我见过有人为了展示技术硬把一个查询助手拆成五个Agent互相聊天结果响应变慢错误率反而更高。4.2 三种协作模式管道、编排、市场如果确实需要多智能体协作模式千万别随意设计。我从实践中总结出三种相对好用的基础模式管道模式一个Agent的输出直接作为下一个Agent的输入适合固定流程简单但前后环节相互阻塞。编排模式有一个总控Agent负责拆解任务、分发给各个执行Agent、汇总结果。这是最稳的多智能体玩法前提是总控Agent的指令足够清晰。市场模式多个Agent通过共享消息池自行协商谁来接任务灵活但极难控制不建议生产环境用。我推荐从编排模式入手。它最接近人的管理方式老板拆活员工干活老板验收。其他模式可以在编排跑通之后再做扩展。我把三种模式放在一起对比过编排模式在可调试性上优势最明显因为每一步都有明确的责任人。4.3 通信协议与消息结构设计要点多智能体最容易被忽略的是消息结构。如果Agent之间传递的是大段自由文本下游Agent解析时一定会出问题。我的建议是消息尽量结构化核心字段如下字段说明message_id全局唯一便于追踪sender发送方Agent名称receiver接收方Agent名称或广播标记task_id所属任务的唯一标识message_type请求、响应、状态更新、错误通知payload结构化数据JSON格式created_at时间戳便于排序和排查这个协议定好之后所有Agent之间的通信都走同一套接口。排查问题时只要看消息日志就能还原整个协作链路。我特别强调task_id必须有没有它多轮协作一旦并发起来你连哪条消息属于哪个任务都分不清。5. 常见问题与排查实录5.1 模型陷入死循环反复调用同一个工具这是智能体上线后最常遇到的问题。表现是Agent一直在调工具、看结果、再调工具就是不给出最终回答。根因通常是两种情况一是工具返回的结果没有让它得出结论二是系统指令没告诉它“何时可以结束”。我的排查顺序是先把工具返回的观察结果打印出来看是不是被截断或内容为空。检查系统提示里是否明确写了“获得答案后直接回复用户不要继续调用工具”。设置max_iterations硬上限比如八次超过就强制结束并返回当前得到的信息。这个上限是非常必要的兜底。没有它一次循环最多可能浪费上百次模型调用成本直接炸掉。我在所有生产Agent里都会加这个参数它不算最优方案但一定能让系统处于可控状态。5.2 上下文爆炸对话越长越慢越贵智能体跑一段时间后很多团队会发现token消耗居高不下回答还变慢。多半是上下文里塞了太多历史记录和工具结果。工具调用的中间结果尤其占地方一次查询可能返回几千甚至上万字。解决思路是分层压缩工具结果只保留“对后续决策有用的关键信息”可以在工具函数内部做摘要而不是把原始输出全部返回。对话窗口启用滑动窗口机制只保留最近N轮。早期对话定期汇总成一段摘要需要时再通过长期记忆检索出来。我见过一个项目把每次工具查询的原始结果都留在上下文里三十轮对话之后单次请求已经接近模型输入上限。做了摘要改造后同样场景的token数量降到原来的四分之一回答速度也明显变快。5.3 工具调用失败之后错误处理一团糟工具调用失败非常常见比如接口超时、数据库连接断开、参数格式不对。新手容易把异常直接抛出去导致Agent直接回复“系统错误”或者崩溃。正确的做法是把异常信息变成一条观察结果返回给模型让模型决定是重试、换一种参数、还是告诉用户失败原因。比如工具执行失败search_user_order 错误信息数据库连接超时 请根据这个信息决定下一步不要直接报错。这样处理后模型至少能生成一句人话比如“您现在查询的接口暂时不可用建议稍后再试”。同时要注意重试次数要有上限否则接口持续故障时Agent会反复调用同一工具浪费资源。通常重试一次就够了连续失败就结束任务并上报。5.4 权限控制与敏感操作确认最后一个问题也是最容易出安全事故的。智能体一旦接了发送消息、写数据库、执行脚本这类工具权限控制就必须跟框架主体一起设计不能后补。我的落地方案是三层工具级别每个工具声明一个权限属性比如“只读”“可写”“高权限”。流程级别高权限工具执行前强制调用人工确认接口等待用户显式同意。账号级别智能体运行账号使用最小权限原则只给它业务所需数据库表和接口的访问权不给全库权限。很多人觉得反正模型不会恶意操作结果模型被Prompt注入后按照用户话术里的指令去执行了危险动作。人工确认和账号鉴权才是真正的最后防线。技术上看这两件事做得越早后面越省心。我最后再分享一个体会AI智能体开发框架的选型和设计本质上是在“模型的自由度”和“工程的可控性”之间找平衡。太自由系统就变成不可控的黑盒太死板又浪费了大模型的泛化能力。真正成熟的项目往往不是用了多炫的技术而是把模型循环、工具边界和权限控制这些基础环节打磨到位了。你可以从最小闭环开始一步一步把框架搭厚这条路比一开始就追求大而全要稳得多。