AI Agent技术架构详解:从规划层到编排层的完整实现 最近经常有人问我AI Agent到底该怎么搭才不算“玩具”。概念图看了不少真到自己动手写一个能跑的Agent还是容易一头雾水。我过去半年一直在做Agent方向的落地项目从最早的单轮工具调用到后来跑多步骤任务分解、记忆检索、多Agent协作踩了不少坑。这篇文章把AI Agent的核心技术架构拆开来讲尽量绕开花哨名词讲清楚每一层到底负责什么、怎么实现、有哪些边界条件。正在做Agent开发或者准备选型的同学应该能从里面拿到一些能直接用的东西而不是只收获一堆新名词。1. 先厘清Agent到底是什么再谈架构1.1 Agent不是“模型加提示词”那么简单很多人会把“调用大模型API”和“Agent”画等号这是最常见的误解。单次调用模型本质是“输入一段文本输出一段文本”模型不会主动决定下一步做什么。而Agent是一个闭环系统模型只是决策引擎系统还要有任务拆解、外部工具调用、结果反馈、状态记忆和自我修正。这么说吧普通API调用像是“问路”你问一句模型答一句答错了你也不知道。Agent更像“开车上路”有导航规划路线有方向盘调整方向有仪表盘显示状态遇到堵车还会绕路。模型只负责“判断下一步打多少方向”但整个车能开到哪里取决于架构把判断、执行、反馈、记忆这几个环节串得多顺畅。所以讨论Agent技术架构时先要跳出“提示词技巧”的层面把注意力放在“循环”上。Agent的本质是一个循环系统模型根据当前状态决定下一步动作系统执行动作并更新状态再把更新后的结果交给模型继续判断直到目标完成或达到终止条件。1.2 架构拆解的整体视角核心五层我习惯把Agent架构拆成五个层次理解起来比较顺手规划层负责任务分解、制定执行步骤、决定下一步动作是Agent的“大脑”。记忆层负责保存对话历史、领域知识、操作结果分为短期上下文和长期存储。工具层把外部能力封装成可调用的接口包括API、代码解释器、数据库、浏览器等。执行与反馈层真正调用工具、等待结果、把执行结果结构化成模型能继续理解的内容。编排与调度层维护整个循环的状态机控制循环什么时候开始、什么时候暂停、什么时候结束负责多Agent之间的协作。五层之间不是堆叠关系而是互相配合。规划层需要记忆层提供上下文规划结果要通过工具层变成行动执行结果又要通过反馈层流回记忆层整个循环由编排层驱动。后面几节会逐一展开每一层的核心设计以及我在实际项目里碰到的问题。2. 规划层Agent的决策中枢2.1 任务分解与ReAct范式规划层要解决的核心问题是“下一步该做什么”。最简单有效的范式是ReAct也就是Reason与Act交替进行。模型不是直接输出最终答案而是先输出一段思考过程再输出一个具体动作然后观察动作结果再继续思考。这个过程把推理过程显式地写在上下文里比直接让模型“一步到位”要稳定得多。我在实际项目里明显感受到一旦任务稍微复杂比如“总结这批文档并生成周报”直接让模型一次输出完整结果经常丢三落四。而改成ReAct循环后模型会先“扫描文档目录”再“逐篇阅读”最后“汇总生成周报”每一步都有中间产物出了问题也知道是哪一步断的。规划层还需要任务分解能力。复杂目标会被拆成子任务树比如“做一个市场分析报告”拆成“收集数据”“分析趋势”“撰写报告”三个子任务每个子任务再细化成可执行的操作。拆得越细每一步模型需要做的判断越简单成功率越高代价是token消耗和循环轮数都在增加。所以要控制拆解粒度不要让一个简单任务被拆成几百个碎步骤。2.2 规划器的实现细节与常见陷阱实现规划器有两种路线。一种是用提示词让模型隐式规划每条消息都让模型输出“下一步动作”灵活但不可控。另一种是显式规划先让模型输出完整计划再逐步执行并标记计划状态类似Plan-Track-Revise。我推荐复杂场景用显式规划原因很简单可观测性更好计划挂在状态列表里哪一步完成了、哪一步失败了一眼就能看到。规划层常见的坑有几个。第一模型输出的计划与实际执行不一致比如计划写“先查数据”实际执行却直接去写报告。解决办法是在每次循环里让模型先输出一个计划步骤ID系统校验它是否在未完成的计划列表里不在就打回。第二规划过长导致上下文被计划占满没有空间装真正的执行结果。解决办法是对计划做精简只保留当前步骤和后续几步摘要不保留完整的千字计划。第三执行失败后模型不知道回溯总是按原计划继续越走越偏。所以规划层必须允许修订计划发现当前步骤连续失败两次就要暂停并重新生成后续计划。3. 记忆层让Agent不“失忆”3.1 短期记忆与上下文窗口管理Agent的短期记忆基本就是当前对话上下文。但大模型上下文窗口是有限的Agent跑几十轮之后历史消息很容易撑爆窗口。这里不能简单“删掉前面的消息”否则模型会丢失关键信息。我常用的做法是三级管理保留最近几轮完整消息保证对话连贯性。对更早的历史做摘要把长对话压缩成一段“截至目前的关键结论”。与当前任务无关的细节直接丢弃不占空间。具体操作时摘要不是一次性把所有历史塞给模型让它总结而是在每一轮结束后增量更新摘要。比如新完成一步就把这一轮的goal、action、result浓缩成一句话追加到摘要里。这样短期记忆的维护成本很低上下文也不会无限制膨胀。3.2 长期记忆与检索增强的取舍长期记忆解决的是“跨会话”和“跨任务”的知识复用。最常见的实现是把历史任务的关键信息写入向量库需要时做相似度检索。但这里有个容易被忽视的问题检索返回的是片段不是完整事实片段如果不准确反而会把模型带偏。我把长期记忆分成三类来管。一类是用户偏好和配置比如“用户喜欢简短回复”“周报模板用那个固定的”这类数据用结构化存储检索时直接精确读取不走向量。一类是任务结果沉淀比如上次任务生成的报告摘要这类数据适合向量检索但检索时一定要带上来源和可信度标签。还有一类是临时笔记比如模型中途发现的线索这类数据优先级最低检索时甚至可以忽略。长期记忆最大的坑是“记忆污染”。检索出来的内容跟当前任务只是表面相关模型却当成可靠事实写进答案最后产出垃圾。我的解决办法是给记忆条目打标签包括时间、来源任务、可信度评分检索后先让模型判断“这段记忆是否与当前问题冲突”冲突就用当前输入作为最高优先级必要时把记忆内容降级为“参考线索”而不是“事实依据”。4. 工具层Agent的手和脚如何接上世界4.1 工具注册、工具描述与函数调用Agent不可能只在脑子里转真正干活要调用工具。工具层不是简单把API地址发给模型而要做一套完整的注册机制。每个工具要声明名称、功能描述、输入参数规范、输出格式、权限级别、超时时间。模型看到的是这些工具的结构化描述而不是底层代码。目前主流的实现方式是函数调用Function Calling。模型收到用户问题和工具列表后输出一个结构化的调用意图比如“调用天气查询接口参数城市等于北京”。系统解析这个结构找到对应的工具执行后再把结果返回给模型继续处理。这里有一个关键细节工具描述写不好模型就选不对工具。不要只写“get_data”要写清楚“get_data根据日期范围获取销售明细数据返回字段包括日期、金额、订单数参数start_date和end_date是必填”。我见过太多次模型选中错误工具不是模型笨而是工具描述写得太模糊让模型靠猜。描述里加上参数格式示例和典型使用场景选择准确率会明显提升。4.2 工具选择策略与安全边界当工具数量超过20个时让模型每次在所有工具里选一个非常容易选错。我的经验是需要做个前置路由。可以按业务域分成几组比如数据类工具组、内容生成工具组、系统操作工具组先让模型判断当前任务属于哪一组再在组内选具体工具。分组之后每组工具数量控制在5到7个模型选择压力小很多。安全边界是工具层不能妥协的部分。凡是涉及发送消息、删除数据、修改线上配置、扣费这类敏感操作一定要加人工审批环节。系统不能直接让Agent调用这些工具而是生成一个待审批事件推送给用户用户确认后才执行。这里要注意审批不是只拦一次而是每次敏感操作都要拦。有些Agent第一轮通过了审批后续轮次模型又试图自动调用相同工具如果系统放行风险极高。工具调用还要考虑异常处理。网络超时、返回格式不合法、权限不足这几种情况都要反馈给模型但反馈信息要简洁。我在反馈时不会把一长串JSON错误堆给模型而是转成一句话“工具调用失败目标接口返回403可能没有权限建议更换查询方式”。模型拿到这个反馈就能做出有效调整而不是看着一堆日志发呆。5. 行动与反馈层从决策到闭环5.1 执行器的分类与观测回传规划层决定“做什么”工具层提供“能做什么”真正动手的是执行层。执行器可以是API客户端也可以是代码解释器、浏览器自动化脚本、数据库查询器。不同执行器有不同的适配重点。API客户端要做参数校验和响应解析代码解释器要注意运行时隔离不能让Agent生成的代码直接跑在宿主机上数据库查询器要限制查询超时和返回行数防止一次查询拖垮数据库。执行结果回传给模型时不能简单把原始返回内容丢回去。要做两层加工第一层提取核心结果把长文本摘要成模型最关心的信息第二层标注执行状态包括成功、失败、超时、部分成功。模型拿到“查询成功共返回3条数据第一条月份1月金额10万”这种结构化内容比拿一屏幕原始JSON要可靠得多。我踩过一个坑工具返回了大量数据比如查询了一张1000行的表直接把全部数据塞进上下文不仅token爆炸模型还会迷失在细节里抓不住重点。后来我改成“自动摘要按需下钻”的策略默认只返回统计信息和前几条示范数据模型如果需要更多细节再调用专门的“分页查询”工具继续取数。这样既省token又保持可控。5.2 反思与自我修正机制Agent不能一路莽到底必须有反思机制。反思的本质是让模型在每次动作完成后评估“这个动作有没有达成预期目标”如果没有分析原因并调整下一步计划。常见做法是self-refine也就是让模型扮演执行者和批评者两个角色。我通常在循环里加入一个轻量反思步骤每进行2到3步就生成一条反思摘要判断当前进度是否合理。比如任务要求“找出最近一个月销售下滑的原因”Agent第一轮查了总销售额数据发现下滑20%第二轮执行者是“直接生成结论”这时候反思应该发现还没有拆解渠道和品类数据直接下结论太草率应该补充查询。有了这一步Agent的质量立刻上一个台阶。反思也要防走火入魔。模型在失败后反复自我修正有时候会绕进死胡同同一个错误改来改去消耗大量token就是不换方向。所以反思步数必须设上限建议同一目标尝试3次仍无进展就触发人工求助或者切换另一种完全不同的工具组合。记住反思的目的是止损不是让Agent在错误路上越走越远。6. 编排与调度多步骤流程的黏合剂6.1 单Agent循环与状态机设计整个Agent的运行核心是编排层维护的循环。最简单的实现是while循环只要任务未完成且步骤数小于上限就执行“让模型生成下一步决定-调用工具-回传结果”。但生产环境不能写这么简陋的循环要设计成状态机。我的状态机至少有这几个状态IDLE空闲、PLANNING规划中、RUNNING执行中、WAITING_INPUT等待用户输入、TOOL_CALL工具调用中、END结束。每个状态定义清晰的进入条件和退出条件。比如状态是TOOL_CALL时系统必须要在超时时间内收到工具返回否则进入异常分支把超时信息反馈给模型重新决策。状态机的优势在于可控可以随时暂停、恢复、打断还能记录每一步的状态变迁日志排查问题非常方便。状态机还需要支持事件驱动不一定是模型每走一步都同步等结果。有些耗时操作比如“上传文档并解析”可以先把任务挂起等回调事件再继续。这样Agent不会傻等一个长时间任务整体吞吐量高很多。我们在实际项目里用事件总线传递“工具完成”“用户回复”“审批通过”这类事件Agent根据事件状态唤醒对应会话。6.2 多Agent协作与人工介入点复杂任务往往不靠一个Agent从头做到尾而是多个Agent分工协作。多Agent架构主要有几种模式。一种是管道模式上游Agent产出结果下游Agent继续加工比如“数据分析Agent”把数据整理好“报告Agent”再负责写作。一种是主从模式一个主控Agent负责任务拆解和调度把子任务分给不同专家Agent再汇总结果。还有一种是群聊模式多个Agent在共享消息通道里讨论适合头脑风暴类任务但容易发散收敛成本高。多Agent协作最要紧的是消息规范。所有Agent之间的通信必须走结构化消息至少包含消息类型、发送方、接收方、内容、关联任务ID。不能用卡通对话式文本随意传递否则下游Agent无法稳定解析。我见过一个跨Agent项目上游Agent输出“我把结果放这里了”下游Agent完全不知道“这里”在哪。人工介入点是编排层必须预留的。关键决策前后、敏感工具调用前、连续失败恢复后都要设计暂停点。人工介入不是弹个提示框就完了要把当前上下文、候选方案、决策背景完整展示给用户让用户能快速理解并做出选择。一个好的介入设计能救回大量原本注定失败的Agent任务。7. 极简Agent循环的实操实现7.1 代码骨架一个可运行的规划-工具-反思循环理论讲再多不如动手跑一个最小实现。下面我用Python写一个不依赖特定框架的极简Agent循环核心是让模型输出“思考-动作-输入”的JSON结构系统解析后执行工具并回传结果。这里使用抽象的llm.chat接口你可以对接任意大模型服务。import json import re from typing import Any, Callable # 工具注册表名称 - 处理函数 TOOL_REGISTRY: dict[str, Callable[..., str]] {} def register_tool(name: str): def decorator(func: Callable[..., str]): TOOL_REGISTRY[name] func return func return decorator # 一个极简工具示例查当前时间戳 register_tool(get_current_time) def get_current_time() - str: import datetime return datetime.datetime.now().isoformat() def build_system_message() - str: tools_desc \n.join( f- {name}: {getattr(func, __doc__, 无描述)} for name, func in TOOL_REGISTRY.items() ) return ( 你是AI Agent。你必须按以下格式输出\n {thought: 你的思考, action: 工具名, action_input: 参数} \n 或者当任务完成时输出\n {thought: 总结, finish: 最终答案} \n\n 可用的工具\n tools_desc ) def run_agent( user_goal: str, llm: Any, messages: list[dict] | None None, max_steps: int 8, ) - str: if messages is None: messages [{role: system, content: build_system_message()}] messages.append({role: user, content: user_goal}) for step in range(max_steps): response llm.chat(messagesmessages, temperature0.2) content response.strip() # 尝试解析模型输出 try: data json.loads(content) except json.JSONDecodeError: messages.append({ role: user, content: 你的输出不是合法JSON请重新严格按格式输出。 }) continue # 判断是否结束 if finish in data: messages.append({role: assistant, content: content}) return data[finish] action data.get(action) action_input data.get(action_input, ) thought data.get(thought, ) if action not in TOOL_REGISTRY: messages.append({ role: user, content: f工具 {action} 不存在可选工具是{list(TOOL_REGISTRY.keys())} }) continue # 执行工具并捕获异常 try: observation TOOL_REGISTRY[action](action_input) except Exception as exc: observation f工具执行失败{exc} messages.append({role: assistant, content: content}) messages.append({ role: user, content: f行动结果{observation}\n请继续思考下一步。 }) return 达到最大步骤数任务未完成。 # 使用示例伪代码 # llm YourLLMClient() # answer run_agent(现在几点帮我查一下, llm)这段代码看起来很简单但它包含了一个Agent循环的全部关键元素系统提示词给出动作规范、工具注册表暴露外部能力、解析与校验防止模型乱来、执行结果回传形成闭环、最大步数控制止损。7.2 运行要点与关键参数调节实际跑这个循环你会发现几个问题立刻浮现。第一模型输出的JSON经常不标准有时候会把完整格式包在Markdown代码块里所以解析时要做容错处理去掉多余的标记甚至用正则找到第一个{到最后一个}。第二temperature不能设太高我一般设置在0.2以下否则模型会输出花哨但不稳定的计划。第三动作参数是字符串工具函数需要自己解析成typed参数这里可以补充一个参数Schema校验模块防止模型传错格式。还有两个运营级参数。一个是max_steps它决定了单个任务最多循环多少轮我建议首次调试设成5因为大部分简单任务5步内能完成如果超过了更可能是规划层或工具层出了问题而不是模型能力不够。另一个是上下文长度预算每轮循环都会增加两条消息所以循环轮数越多上下文越大要在循环里做消息压缩。上面代码没有展示压缩逻辑实际部署时我建议在步骤数超过6后把早期消息折叠成摘要否则很快撞上模型窗口上限。跑通这个最小循环之后可以逐步加功能加工具描述、加反思步骤、加状态机、加多Agent消息协议。我最初也是从这种骨架开始一点点把生产级的公共模块搭起来的。没有这个骨架直接套用重型框架出了问题你根本不知道该看哪一层。8. 生产环境里的高频问题与排查思路8.1 高频问题速查表实际生产环境中Agent跑起来之后的坑远多于写Demo时的坑。我整理了一张速查表覆盖我遇到过的高频问题问题现象可能原因排查思路Agent循环不停token费用飙升缺少终止条件或模型总在重复动作检查max_steps、任务完成判断逻辑同一动作连续出现两次时主动打断上下文长度超限报错循环轮数太多或工具返回大段数据增加消息摘要限制工具返回行数设置按步骤压缩上下文的策略模型调用错误的工具工具描述含糊或工具数量过多重写工具描述加入典型场景示例拆分工具分组先路由再选择工具调用一直失败参数格式不匹配、权限问题、网络超时记录失败原因并回传模型增加参数校验层对超时工具做重试和降级Agent说完成了但结果不对缺少验证器模型产生幻觉增加目标验证节点用程序判断产物是否满足条件必要时人机确认多Agent之间消息理解错误消息格式不规范、缺少任务ID统一消息协议强制带任务上下文通信内容只用结构化字段问题被模型绕回原路反思机制设计不当增加“连续失败N次则切换方案”规则引入外部观察者介入8.2 我惯用的排查套路与观测建议排查Agent问题我第一件事永远是看trace。所以从第一天起就不要裸奔每个Agent任务要输出结构化日志里面至少包含全局唯一的trace_id、当前步骤号、模型输入的上下文长度、模型输出的动作、工具名、工具入参、工具返回摘要、耗时和成本。没有这些信息Agent出了问题就跟查一个没有日志的服务一样痛苦。其次是复现能力。Agent不是纯确定性程序模型输出的概率性导致同一个任务每次结果都不同。我在本地会准备一组固定的测试用例覆盖正常场景、边界场景、失败场景每次修改架构后把整组用例跑一遍记录每一条的通过率和平均步数。通过率变化最能反映架构改动是好是坏。最后我强烈建议在架构里埋一个“外部评估器”。不要只依赖模型自己判断任务是否成功尤其是生成类任务比如“写一份方案”模型自己说“写完了”不等于方案符合要求。外部评估器可以用规则检查必含要素也可以调用一个更便宜但维度不同的模型来打分。评估结果反馈到循环里比纯靠模型自信要可靠得多。根据我个人经验Agent架构做得再复杂真正决定能否落地的其实是“边界控制”。控制循环轮数、控制上下文长度、控制工具权限、控制失败重试次数这些看起来不性感的细节恰恰是生产级Agent和Demo Agent的分水岭。如果你刚开始搭Agent别急着上多复杂的设计先跑通一个带完整日志、带步数上限、带人工介入的最小闭环然后再一层层加规划、记忆、反思和多Agent协作。这个顺序稳定可靠少走弯路。