
很多朋友问我搞大模型开发到底先学什么我的回答一直很简单先搞懂AI Agent尤其是从Prompt到Action这条完整链路。去年年底我带团队做一个企业内部的知识库问答助手最初大家的方案就是一个模型API加上一大段Prompt结果模型经常答非所问、工具调用混乱、长对话到一半就断片。后来我们把架构拆成五层——Prompt、规划、记忆、工具、行动重新梳理每层的职责和上下游关系问题才真正解决。这篇文章我就把这套五层架构完整拆开讲每层怎么设计、层与层之间怎么衔接、实际项目中踩过哪些坑尽量让准备入门或者正在做大模型应用开发的你少走几个星期的弯路。1. 先搞清楚一件事Agent和单次模型调用到底差在哪1.1 单独调用是问一句答一句Agent是交办一件事很多刚接触大模型开发的朋友会把Agent理解成一个带历史记录的聊天机器人这是最大的误区。普通模型API调用是什么样用户输入Prompt模型返回一段文本结束。即使你把多轮对话历史拼进去本质上模型还是在做针对已有文本生成下一段文本这件事。它不感知外部世界不主动采取行动答错了也不会自我纠正。Agent则完全不同。你可以把它理解成招了一个新同事你告诉他目标Prompt他会做计划Planning一边回忆相关经验Memory一边调用你给他的系统工具Tools最后真的去执行某个动作Action再把执行结果拿回来继续判断直到任务完成为止。这个过程不是一条直线而是首尾相接的闭环。我带团队开发知识库助手时最初就是把所有指令堆在一个Prompt里让模型一把梭。结果就是复杂问题它拆不清楚需要查数据库的时候它自己瞎编一个答案查完数据也不会顺着结果继续往下走。后来我们把Agent拆成五个职责层每个层只干一件事模型的表现立刻稳定了一个量级。这个五层架构并不是学术理论而是很多开源框架经过实战淘汰后沉淀下来的通用结构。1.2 五层架构的完整视图与分层依据五层架构在业内没有唯一官方标准不同团队分法略有差异但你把主流开源的Agent框架打开看剥掉各种封装底层基本都是这五层┌─────────────────────────────────────────────┐ │ 第1层 Prompt层 系统提示词 / 角色定义 / 边界约束 │ ├─────────────────────────────────────────────┤ │ 第2层 规划层 任务拆解 / ReAct循环 / 决策 │ ├─────────────────────────────────────────────┤ │ 第3层 记忆层 短期上下文管理 / 长期向量记忆 │ ├─────────────────────────────────────────────┤ │ 第4层 工具层 Function Calling / 外部API集合 │ ├─────────────────────────────────────────────┤ │ 第5层 Action层 真实动作执行 / 结果观察与反馈 │ └─────────────────────────────────────────────┘ ↑___________ 闭环反馈 ___________↓我习惯用这张叠罗汉的图把它画出来Prompt在最上面Action在最底下但数据流不是简单的从上往下单向流动。每一轮Action层执行完结果会作为观察重新回到模型上下文里影响下一轮决策这样才形成一个首尾衔接的循环。分层依据主要有两条。第一职责单一。Prompt只管怎么描述自己、边界在哪规划层只管下一步做什么记忆层只管哪些信息值得保留工具层只管能调外部什么能力Action层只管真正执行并带回结果。如果一个层承担太多职责出问题的时候你根本定位不到是哪里写错了。第二可观测、可替换。分层之后每一层都可以单独打印日志、单独测试、单独替换。比如把记忆从拼接历史消息换成向量检索Agent主流程的代码基本不用动。团队协作和后期维护的时候这两点价值非常明显。2. Prompt层Agent的岗位说明书比你想的更重要2.1 Agent的Prompt和你平时写的小作文Prompt完全不同我一直强调一个观点写Agent的Prompt更像是在写岗位说明书加程序语法而不是写一篇漂亮的小作文。普通Prompt的目标是一次性回答得好Agent的Prompt则要在一次循环里反复生效。模型每一轮都可能要做决策、要调用工具、要读取记忆、要执行动作所以系统提示词必须包含足够的控制结构什么时候该做什么、什么情况下必须停止、输出用什么格式、哪些信息绝对不能碰。很多团队把单轮对话里好用的长篇Prompt直接搬给Agent结果发现模型频繁发挥过度。原因很简单单轮Prompt面向的是回答Agent系统提示词面向的是流程。目标不同写法就完全不同。你让一个大模型背下一篇五千字的角色设定它在第一轮可能会很好地扮演但到了第十轮它可能已经完全忘了自己是客服开始跟你讨论哲学。这就不是模型不聪明而是Prompt结构没让它把注意力长期锁定在任务目标上。2.2 一个能扛住复杂任务的系统提示词应该包含哪些段落经过多个项目沉淀我总结出比较稳的Agent系统提示词大致包含六个区块。这里直接用表格列出来没有一个是可有可无的段落作用写法示例角色定义明确Agent身份和擅长领域你是XX电商平台的售后客服助手目标任务说清这个Agent存在的唯一目的你的目标是在不违规的前提下解决用户所有售后问题工作流程规定从收到输入到输出的标准路径先判断问题类型再决定是否需要查询订单或知识库约束禁区明确哪些动作绝对不能做不要编造退款金额不要承诺不存在的优惠活动输出格式定义回答的结构或工具触发方式需要实时数据时必须调用query_order之后再回复兜底方案模型不知道或做不到时怎么办如果无法确认用户身份直接结束对话并要求重新登录很多人只写角色定义和目标任务觉得这就够了结果模型在长流程里经常飘时不时忘记自己是谁。等我把工作流程和兜底方案加进去行为稳定性立刻不一样。这里有个小技巧兜底方案要写得具体不要写根据情况灵活处理这种废话模型遇到模糊情况最需要的是明确指令。2.3 Prompt层三大经典翻车现场先说第一个指令冲突。比如你让Agent扮演无所不知的资深专家又规定遇到不确定必须承认不知道这两个指令在特定场景下会打架。模型会怎么选往往为了维持专家人设硬着头皮回答。解决办法是在开发阶段把所有边界场景列成用例定期跑一遍观察行为是否一致。Prompt和代码一样需要回归测试。第二个约束失效。很多人喜欢在提示词里写一大串不要做XX、不要做XX结果发现越写越容易触发。这其实是模型对否定指令的处理机制问题。我更推荐把不要做什么改写成应该做什么。比如不要写严禁编造数据而是写所有数据必须来自工具返回结果如果工具没有返回请明确回答未查询到相关信息。正向指令比负向指令可靠得多。第三个模板渲染错误。这个在开发阶段最浪费时间。很多团队用Jinja2这类模板引擎渲染Prompt时不时冒出一句error rendering prompt with jinja template原因通常是变量缺失、循环标签没闭合、自定义过滤器不存在。这类问题的特点是报错信息很长但看不到具体行号排查起来非常痛苦。我现在的做法是给Prompt模板单独加一套单元测试至少保证每个变量都能正常渲染再跑业务逻辑。还有一类问题不得不提内容安全审核。模型服务商接口经常对输入做安全策略检查有时候一个测试越权提示词就会触发审查接口直接返回类似invalid prompt: your prompt was flagged as potentially violating our usage policy的报错。遇到这个你反复重试没有用问题多半是提示词里出现了被安全策略标记的敏感表达。这时候要调整措辞而不是换个密钥继续撞墙。3. 规划层任务拆解是Agent看起来聪明的真正原因3.1 从直接回答到先想再答如果你把复杂任务直接丢给模型让它一口气输出最终结果它通常会犯两类错误一是漏步骤二是跳跃式得出结论。规划层就是来解决这个问题的。最基础的手段是思维链Chain of Thought让模型在给出最终答案之前先把中间推理过程写出来。我在给Agent加CoT提示时有一个很实用的固定写法请先列出解决这个问题需要做的所有子步骤然后按顺序逐步完成。 每个步骤执行前先说明这一步要做什么再输出对应的动作或结果。这个写法的好处是模型每一步决策都有迹可循。最终结果不对时你能通过日志看出是第几步出了问题而不是对着一个黑盒答案猜原因。尤其当Agent接入了多个工具这一步的必要性会被无限放大因为你必须要知道是哪一个环节的决策导致最终结果偏离。3.2 ReAct工作流的落地写法规划层真正发挥威力的地方是ReAct模式也就是Reason思考加Act行动交替进行。一个标准的ReAct循环是这样的思考Thought根据当前信息判断下一步该做什么行动Action选择一个工具或动作给出参数观察Observation拿到行动后的结果回到第1步直到问题解决把ReAct写进系统提示词大概长这样执行规则 - 每一轮输出必须包含 Thought、Action、Action Input 三个字段 - Thought解释你当前对任务的理解和下一步计划 - Action选择要调用的工具名或输出 finish 表示任务结束 - Action Input工具参数必须是合法 JSON - 当任务完成时Action 必须为 finish我见过很多新手在写Agent时让模型自由发挥决定要不要调用工具结果模型经常略过工具直接编答案。ReAct的作用就是强制模型在思考和行动之间交替不给它跳过中间环节的机会。一旦它想直接给结论你会发现它缺少必要的Action字段这时候你可以在代码层直接拦截并提示它请先调用工具获取数据。3.3 模型不会拆任务怎么办兜底策略不是所有模型都有足够的推理能力把任务拆得很漂亮。尤其是一些轻量级模型你给它一个开放式问题它拆出来的子任务可能稀烂。我常用的兜底策略有三个。其一预设选项。与其让模型自己发明步骤不如在提示词里列出常见任务的固定步骤让它做选择。比如如果任务类型是查物流请依次调用query_order和query_logistics两个工具。这种方式把开放式规划降级成了选择题小模型也能稳定执行。其二用小模型做Planner、大模型做执行。在一些成本敏感的项目里我会用轻量模型负责拆步把拆出来的子任务逐个交给更大的模型或工具去执行。但这个方案有一个坑Planner拆错时错误会一路传导下去所以必须给每个子任务加一个验证节点发现中间步骤异常就回退到人工预设路径。其三直接降级。如果模型连续两轮都无法形成有效规划就放弃规划直接改以单轮Prompt调用模型回答。宁可用一个普通回答也不要让Agent陷入无限循环空转。在很多实际业务里及时给用户一个不完美答案比让用户等到一个完美但迷路的答案要好得多。4. 记忆层决定Agent是金鱼还是档案管理员4.1 短期记忆上下文窗口管理是硬功夫模型能访问的上下文窗口就是Agent的短期记忆。窗口有限内容塞太多不仅费Token还会让模型注意力涣散抓不住重点。我见过不少应用把用户每一轮说的话原封不动全部拼进上下文跑个十几轮就超窗口限制后续请求直接报错。更合理的做法是建立一个工作记忆区只保留当前任务真正需要的信息核心指令始终保留每轮都在当前目标始终保留随任务进展更新最近几轮对话保留最近3到5轮历史对话摘要用一段摘要代替原始长文工具返回结果只保留与当前步骤相关的关键字段我有个习惯每轮Agent执行完会把当前目标字段更新成最新状态。比如用户一开始问帮我查订单查完后又问顺便看下物流当前目标就从查询订单信息更新为查询订单信息并跟踪物流进度。这样模型永远知道此刻在做什么不会因为多轮对话而迷失方向。4.2 长期记忆向量检索、摘要沉淀与重要性判断长期记忆是Agent跨会话、跨任务积累知识的地方。目前最主流的做法是向量化加相似度检索把重要历史信息切块、向量化后存进向量数据库等需要时检索出最相关的片段放回上下文。这个方向已经不新鲜但细节决定效果我只讲三个关键点。第一写入要克制。不是所有历史记录都值得进入长期记忆。我通常会让模型先对一段信息做重要性评分大于某个阈值才写入向量库。不然垃圾信息会污染记忆空间后续检索把一堆无用内容召回反而干扰模型判断。第二检索要带业务过滤。纯向量相似度检索容易召回一些形似神不似的内容。更好的做法是入库时就给每条记忆打上标签比如客户ID、任务类型、时间范围检索时先按标签过滤再算相似度。比如同一个客户的历史咨询记录加上customer_id标签之后检索准确率会大幅提升。第三要有时效性概念。很多业务信息过了一周就失效了比如促销活动规则、临时工单状态。我在记忆表里会增加一个时间戳字段检索时把过期记忆过滤掉或者降低失效记忆的权重。这个细节经常被忽略但在真实业务里非常致命。4.3 记忆层常见的脏数据与信息污染问题记忆层最容易出现的隐性问题是信息污染——模型把不相关甚至错误的记忆当成依据然后一本正经地给出错误结论。我在一次工单分类项目里就踩过这个坑Agent先读取了长期记忆里的历史工单这些工单里有大量催单投诉相关的负面措辞结果后续分类时模型被这些高频词带偏动不动就把新工单也判成投诉。后来排查发现问题出在检索阶段没有加时间过滤召回了一堆几个月前的投诉记录。现在我的经验是长期记忆在写入前要做去重和冲突消解检索结果回填到上下文时要明确标注来源比如用以下内容来自历史记录仅供参考这样的前缀。这样模型就能区分刚拿到的实时数据和参考性历史记忆处理逻辑完全不同。这个细节听起来小但对结果稳定性的帮助非常明显尤其当你做的Agent要长期服务真实用户时历史记忆会被反复使用脏数据影响会被成倍放大。5. 工具层Agent的手脚从哪里来5.1 Function Calling是工具层的核心通道让大模型学会用工具目前最成熟的技术路径就是Function Calling也就是函数调用。流程不复杂你把一组工具用JSON Schema描述好和对话内容一起发给模型模型判断当前需要哪个工具返回一个结构化的调用请求你的程序负责执行这个工具再把结果回填给模型继续推理。如果把这个流程和上面的ReAct对应起来工具层其实是把Action字段翻译成真正的程序调用。模型不需要真的写代码去访问外部系统它只需要输出我想调用query_order参数是xxx剩下的由你的代码完成。这套机制的最大价值是把模型决定做什么和程序负责执行彻底分开各干各擅长的事。比如模型知道某个订单号需要加密处理但它不知道加密算法细节工具层知道。5.2 工具描述怎么写才能让模型正确拿捏工具描述写得好不好直接决定模型能不能选对工具、填对参数。我的经验是一份清晰的工具描述至少包含四部分内容工具名用动词开头让人和模型都能一眼看懂。search_order_info比db01好用一百倍。功能描述一句话说清工具是干嘛的、什么时候该用。参数说明每个参数的类型、是否必填、取值范围。使用示例给出一到两个完整调用示例模型会模仿这个格式。特别要提醒一个常见坑参数名称不要太抽象。我们之前有个工具把参数写成a、b结果模型经常把客户姓名填给a把手机号填给b后来改成customer_name、phone_number这样的语义化命名准确率一下就上来了。这个问题在初版设计时几乎注意不到只有等模型频繁填错参数你才会意识到参数名本身就在传达语义。5.3 工具层最容易翻车的三个场景场景一工具幻觉。模型明明没有某个工具却自己编了个工具名。这通常发生在工具列表过长、模型被绕晕的时候。解决思路有两个方向一方面工具描述尽量精简另一方面在解析模型返回时对工具名做白名单校验发现不存在的工具就报错并让模型重新选择。场景二参数格式错误。模型返回的参数有时并不符合JSON规范比如多了一个逗号、字符串引号没闭合。我建议所有工具调用结果都过一遍宽松解析器先尝试标准解析失败后再尝试修复常见格式错误。千万不要直接抛异常否则整个Agent循环会断掉用户体验直接变成服务不可用。场景三Action权限问题。真实系统里模型选对了工具参数也对但执行时提示没有权限。我自己就遇过类似no permission info for action: device.audio.startrecord的报错。这类问题的根因多半不在模型而在执行环境的权限配置。排查时先看工具层的权限拦截逻辑再考虑是不是模型选错了工具。如果不处理模型很可能反复尝试同一个无权限动作白白浪费好几轮请求。正确的做法是把权限错误转成普通工具返回结果反馈给模型该动作无权限请换一种方式让它进入下一条可行路径。6. Action层闭环不是调完API就结束6.1 动作执行与结果回填很多人以为Action层就是执行工具调用但真正的Action层还包括两个关键动作结果回填和循环判断。工具执行完返回结果不能直接丢给模型就完事。你要做一层结果整理只提取模型下一轮决策需要的信息把无关的噪声字段丢掉。举个例子一个查询订单的工具可能返回整张数据表的几十个字段但模型当前只需要订单状态和物流单号。那你就在Action层过滤只回填这两个字段。这样既省Token又能让模型聚焦在关键信息上。这里有个额外的收益你主动去掉无关字段也就主动避免了大JSON块把模型注意力稀释的问题。回填格式也最好统一我习惯用Observation: 这里是工具执行结果这样的前缀标注让模型清楚这不是用户新输入而是对行动的观察结果。6.2 错误恢复机制Action失败时Agent该怎么做一个成熟的Agent不应该因为某个Action失败就整条链路崩溃。我给Agent设计的是三层错误恢复策略。第一层简单重试。如果是网络抖动、接口超时这类临时性错误可以自动重试一到两次每次间隔递增。不需要让模型参与直接在代码层处理即可因为这类错误属于基础设施问题模型介入也没有意义。第二层反馈式改道。如果是业务性错误比如查无此订单参数不合法绝对不能盲目重试。正确做法是把错误信息作为Observation返回给模型让它换一种行动方案。比如查无此订单请检查用户输入的订单号是否存在如果确认无误就明确告诉用户无法查询。模型看到这个反馈后通常会自己调整策略。第三层整体降级。如果连续两三轮都失败说明模型可能陷入了死循环这时候要强制结束循环切换到降级回复模板比如很抱歉当前无法完成该操作已为你记录稍后将有同事跟进。这比让模型无限循环要有价值得多也符合真实客服场景的处理逻辑。6.3 从Prompt到Action的完整闭环动线到这里五层架构的完整链路可以串起来了用户发起请求Prompt层加载系统提示词和当前目标。规划层根据输入决定第一步动作。如果这一步需要历史信息记忆层检索相关内容并回填。工具层根据模型返回的调用请求真正执行外部API或系统操作。Action层把执行结果整理为Observation重新输入模型。这个循环会一直持续直到模型输出finish或者到达预设的最大迭代次数。我给自己负责的所有Agent项目都加了完整日志链路。每一轮都能看到模型思考了什么、调用了哪个工具、工具返回了什么、下一步决定做什么。看起来这是小事但在开发阶段和线上排查时这套日志的价值比任何优化技巧都大。很多Agent问题不是模型能力不够而是你根本看不到它中间想了什么。没有日志的Agent项目排查问题就像在黑灯瞎火的房间里找一枚掉在地上的针。7. 完整示例一个最小可用的五层Agent是怎么跑起来的7.1 场景设定与整体设计拿一个我最近做的订单查询助手举例。用户输入一个订单号Agent需要判断订单号是否格式合法查询订单基本信息如果订单状态是已发货再看要不要查物流轨迹最后把结果整理成自然语言回复。按照五层架构来设计各层职责划分如下Prompt层定义角色为订单客服助手包含订单号格式校验规则和输出规范。规划层用ReAct循环由模型自行决定先查订单还是直接回复。记忆层把用户历史咨询摘要存到向量库同一个用户再次咨询时带上历史上下文。工具层提供query_order和query_logistics两个预定义工具。Action层解析工具返回结果回填给模型循环直到输出finish。7.2 各层的具体代码我贴一个简化版的核心循环代码方便你看懂这个闭环是怎么跑起来的。import json SYSTEM_PROMPT 你是一个订单客服助手。 第一步确认用户提供了合法的订单号必须是13位数字。 第二步如需查询订单信息调用 query_order 工具。 第三步如果订单状态为已发货且用户询问物流则调用 query_logistics。 当用户问题已解决时输出 FINISH 结束。 每一轮输出必须包含 - thought: 你当前的判断 - action: 工具名或 FINISH - action_input: 工具入参JSON 格式 TOOLS [ { type: function, function: { name: query_order, description: 查询订单基本信息, parameters: { type: object, properties: { order_id: {type: string, description: 13位订单号} }, required: [order_id] } } }, { type: function, function: { name: query_logistics, description: 查询物流轨迹, parameters: { type: object, properties: { order_id: {type: string, description: 13位订单号} }, required: [order_id] } } } ] def call_model(messages, tools): # 在这里替换为实际的大模型 API 调用 pass def execute_tool(name, args): if name query_order: return {status: 已发货, logistics_no: SF123456} if name query_logistics: return {track: [已揽收, 运输中, 派送中]} return {error: unknown tool} def run_agent(user_input): messages [{role: system, content: SYSTEM_PROMPT}] messages.append({role: user, content: user_input}) for step in range(10): resp call_model(messages, TOOLS) action resp.get(action) if action FINISH: return resp.get(output) result execute_tool(resp[action], resp[action_input]) messages.append({ role: user, content: fObservation: {json.dumps(result, ensure_asciiFalse)} }) return 已达到最大步数请稍后重试这段代码当然不是生产级但骨架已经把ReAct循环、工具注册、动作执行、结果回填这几个核心环节全部囊括了。真实项目里你可以直接在这个骨架上扩展比如把call_model换成具体的OpenAI或Ollama调用把execute_tool换成真实的业务服务调用。7.3 实测效果与调优记录这个简化版跑通以后我做了几轮调优记录两个最典型的经验。第一轮模型在用户没有提供订单号时自己编了一个订单号去查。问题出在Prompt层没有明确订单号必须来自用户输入。我在系统提示词里加了一行如果用户没有提供订单号不要调用任何工具直接询问用户。问题立刻解决了。这个调整看起来很低级但就是这种边界指令决定了Agent在真实对话里靠不靠谱。第二轮模型查完订单之后没有继续查物流。原因是工具返回结果里已发货这个状态被淹没在JSON字段中模型没注意到。后来我在Action层做了一个小逻辑如果订单状态为已发货自动在Observation末尾追加一句话提示订单已发货如果用户需要物流信息可以调用query_logistics。模型看到之后后续决策正确率提高了很多。这种Action层主动注入提示的做法是我在多个项目里验证都非常有效的技巧。本质上它是把你对业务的理解编码进反馈信息里引导模型往正确的路径走。另外一个经验是不要把最大循环数设得太大。10次以内是合理区间超过20次基本说明规划层出了问题。与其让模型空转几十轮烧钱不如提前结束转入人工兜底。最后分享一点个人体会五层架构不是什么高深理论它就是一套实践之后沉淀下来的分工方式。我自己带团队时最大的感受是Agent开发的前两周八成时间不是在调模型而是在调试Prompt和工具之间的协作逻辑。你给模型再强的工具列表如果Prompt层说不清楚边界、Action层拿不到干净的结果整个闭环依旧会到处漏风。如果你只记住一句话那就记住这六个字分层、闭环、可观测。分层让问题看得见闭环让流程走得通可观测让Bug找得到。这三点做到位你的Agent项目就已经超过大多数停留在原型Demo阶段的方案了。