☰
AI Agent四层架构解析:Prompt、Tool、Context与Memory协同设计
2026/10/31 10:11:09 网站建设 项目流程

1. 从 Prompt 到 Agent:一次范式转移的底层逻辑

1.1 为什么单靠 Prompt 撑不起一个真正的 Agent

2023 年那会儿,大家做 AI 应用基本就是一条路:写一个精心雕琢的 Prompt,把用户输入塞进去,调一次模型 API,拿到结果返回。这套东西在问答、摘要、翻译这类单轮任务上确实够用,但只要任务稍微复杂一点——比如“帮我查一下这周北京的天气,如果下雨就订一张周五去上海的高铁票,并把行程加到日历里”——单次 Prompt 调用就彻底歇菜了。

原因很直接:大模型本质上是一个无状态的函数。你给它一段文本,它给你一段文本,调用结束之后它什么都不记得。它没有手去查天气,没有脚去订票,也没有脑子去判断“先查天气还是先订票”。Prompt 能做的只是“在给定上下文里生成合理的续写”,它无法主动获取新信息,也无法根据中间结果调整下一步动作。

这就是 AI Agent 要解决的核心问题。Agent 这个词在 2024 到 2025 年被炒得很热,但剥开营销外壳,它的技术内核其实就四件事:Prompt 负责决策,Tool 负责执行,Context 负责信息供给,Memory 负责状态延续。这四者缺一不可,组合起来才构成一个能“自己干活”的系统。

我见过太多团队一上来就说要做 Agent,结果做出来的东西本质上还是一个套了循环的 Prompt 调用,跑两轮就崩。问题往往不在模型能力,而在于他们没有想清楚这四层各自的职责边界。下面我按演进顺序,把这四层一层层拆开讲。

1.2 四层架构的职责划分与协作关系

先把整体图景说清楚。一个成熟的 Agent 系统,运行时大致是这样一条链路:

用户给一个目标 → Agent 把目标 + 历史记忆 + 可用工具列表一起塞进 Prompt → 模型输出一个决策(是直接回答,还是调用某个工具)→ 如果是调用工具,执行层去跑这个工具,拿到结果 → 结果作为新的 Context 回灌给模型 → 模型基于新信息继续决策 → 循环直到任务完成或达到终止条件。

这里面,Prompt 是大脑的思考方式,Tool 是手脚,Context 是眼睛和耳朵,Memory 是记忆。四者协作的关键在于“循环”和“状态管理”。单次调用没有循环,所以不是 Agent;循环了但不管理状态,跑几轮上下文就爆炸,也不是一个能用的 Agent。

我个人的经验是,判断一个系统是不是真 Agent,就看它有没有这三个特征:自主决策(自己决定下一步做什么)、工具使用(能对外部世界产生动作)、状态保持(跨轮次记住发生了什么)。三者缺一,就只能叫“增强版 Prompt”。

2. Prompt 层:Agent 的决策中枢怎么设计

2.1 从“写一句话”到“设计一套决策协议”

普通 Prompt 工程和 Agent Prompt 工程完全是两个量级的东西。普通场景下你写的是“你是一个翻译助手,请把下面的中文翻译成英文”,而 Agent 场景下你要写的是一套决策协议:告诉模型它有哪些工具可用、每个工具的参数是什么、什么情况下该调用哪个工具、调用失败怎么办、什么时候该停止。

这就引出了 Agent Prompt 的几个核心组成:

  • 角色与目标定义:明确 Agent 的身份和它要完成的终极目标。
  • 工具清单(Tool Schema):以结构化格式列出所有可用工具及其参数说明。
  • 决策规则:什么条件下直接回答,什么条件下调用工具,调用后如何判断结果是否可用。
  • 输出格式约束:强制模型以特定格式输出(比如 JSON),方便程序解析。
  • 终止条件:明确什么情况下任务算完成,避免无限循环。

我踩过最大的一个坑就是:早期写 Agent Prompt 时没做输出格式约束,模型有时候返回自然语言,有时候返回 JSON,解析层直接崩。后来强制用结构化输出(比如让模型输出{"action": "tool_name", "args": {...}}这种格式),稳定性立刻上了一个台阶。

2.2 工具描述写得好不好,直接决定 Agent 聪不聪明

这一点我要重点强调,因为它是被最多人忽视的环节。很多人以为 Agent 调错工具是模型笨,其实十有八九是工具描述写得烂。

模型选择工具的唯一依据就是你给它的工具描述。如果你写的是“查询天气”,模型不知道这个工具支持哪些城市、返回什么格式、需不需要日期参数。但如果你写的是“根据城市名和日期查询天气,输入参数为 city(字符串,如'北京')和 date(字符串,格式 YYYY-MM-DD),返回该日期的天气状况和温度”,模型的选择准确率会高出一大截。

我总结的工具描述三要素:

要素说明反例正例
功能边界这个工具具体做什么、不做什么“处理数据”“读取 CSV 文件并返回前 N 行”
参数规格每个参数的类型、格式、是否必填“传入参数”“file_path(字符串,必填,绝对路径)”
返回说明返回什么结构、异常时返回什么“返回结果”“成功返回 JSON 数组,失败返回 error 字段”

提示:工具数量超过 10 个之后,模型的选择准确率会明显下降。这时候要么做工具分组,要么引入一个“路由层”先判断该用哪一类工具,再在类内做细选。

2.3 Prompt 层的常见故障与排查思路

实际跑起来,Prompt 层最常出的问题有这么几类,我整理成速查表:

现象可能原因排查方向
模型不调用工具,直接瞎编答案工具描述不够明确,或决策规则没写清检查 Prompt 里是否明确“不知道时必须调用工具”
反复调用同一个工具没有把工具结果正确回灌,或终止条件缺失检查循环逻辑和结果注入位置
输出格式解析失败没有强制结构化输出加入格式约束和 few-shot 示例
上下文超长报错历史轮次无限累积引入 Context 裁剪或摘要机制
调用参数格式错误参数说明不清晰在工具描述里给出参数示例

这里特别说一下“上下文超长”这个问题。热词里出现的maximum context length is 1048576 tokens这类报错,在 Agent 场景下极其常见,因为每一轮循环都会往上下文里追加内容。解决办法后面在 Context 层会详细讲。

3. Tool 层:让 Agent 真正“下地干活”

3.1 工具的本质:把自然语言决策翻译成确定性执行

模型再聪明,它也只是一个文本生成器。它说“我要查天气”,这句话本身不会让天气发生变化。真正去查天气的,是 Tool 层的一段代码。所以 Tool 层的本质是一座桥:把模型输出的自然语言决策,翻译成确定性的、可执行的程序调用。

这个翻译过程有两个关键点。第一是参数映射:模型输出的参数是文本,工具需要的是具体类型(整数、日期、枚举),中间要做校验和转换。第二是结果封装:工具执行完的结果(可能是 JSON、可能是纯文本、可能是二进制)要转成模型能理解的文本格式再回灌。

我一般会把工具分成三类来管理:

  • 信息获取类:搜索、查数据库、读文件、调 API 拿数据。特点是只读,相对安全。
  • 动作执行类:发消息、写文件、下单、调外部服务。特点是有副作用,必须加权限控制。
  • 计算处理类:跑代码、做数学运算、格式转换。特点是确定性高,适合把模型不擅长的精确计算外包出去。

3.2 工具选型与封装的实际考量

选什么工具、怎么封装,直接决定 Agent 的能力上限。我的经验是遵循“能用代码解决的绝不交给模型”这个原则。比如日期计算、字符串处理、数值运算,这些模型经常算错的东西,全部封装成工具让模型调用,准确率立刻从 70% 拉到接近 100%。

封装工具时有几个实操要点:

  1. 单一职责:一个工具只做一件事。不要搞一个“万能工具”接收各种参数做不同的事,那样模型根本学不会怎么用。
  2. 幂等设计:尤其是动作执行类工具,要考虑重复调用的情况。比如“发消息”这个工具,如果 Agent 因为重试调了两次,用户就收到两条消息,体验很差。
  3. 超时与重试:外部 API 调用必须设超时,失败要有明确的错误返回,让模型知道“这次失败了,可以换个方式再试”。
  4. 错误信息友好化:工具报错时返回给模型的不能是堆栈信息,而应该是“查询失败,原因:城市名不存在,请检查输入”这种模型能理解并据此调整的文本。

注意:动作执行类工具一定要加“确认机制”或“权限白名单”。我见过 Agent 因为理解偏差,把测试环境的删除操作跑到了生产库上,这种事故一旦发生就是灾难性的。

3.3 工具调用失败的典型场景与处理

工具调用失败是常态,不是异常。网络抖动、API 限流、参数错误、权限不足,各种情况都会遇到。关键是 Agent 要能优雅地处理失败,而不是一失败就整个流程崩掉。

我处理失败的标准套路是三层:

  • 第一层:工具内部重试。对于网络类瞬时故障,工具内部自动重试 2-3 次,对模型透明。
  • 第二层:错误信息回灌。重试仍失败,把清晰的错误信息返回给模型,让模型决定是换个工具、换个参数,还是直接告诉用户“这个操作暂时做不了”。
  • 第三层:熔断降级。某个工具连续失败多次,暂时把它从可用列表里摘掉,避免模型反复撞墙。

这套机制跑下来,Agent 的鲁棒性会有质的提升。很多看起来“模型不行”的问题,其实是失败处理没做好。

4. Context 层:Agent 的“工作台”怎么管

4.1 Context 不是越长越好,而是要“刚刚好”

Context 是 Agent 运行时最稀缺的资源。模型的上下文窗口再大(现在动辄 100 万 token),也架不住 Agent 循环几十轮往里塞东西。而且上下文越长,模型的注意力越分散,关键信息越容易被淹没,响应也越慢、越贵。

所以 Context 管理的核心目标不是“塞更多”,而是“在正确的时刻,把正确的信息,以正确的形式,放到模型面前”。这跟人干活是一个道理:你桌上堆满文件反而找不到东西,只放当前要处理的那几份,效率最高。

Context 里通常包含这几类信息:

  • 系统 Prompt:角色、规则、工具清单,相对固定。
  • 对话历史:用户说了什么、Agent 回了什么。
  • 工具调用记录:调了哪些工具、参数是什么、返回了什么。
  • 当前任务状态:任务进行到哪一步了、还差什么。

4.2 上下文膨胀的三种治理手段

当上下文开始膨胀,我一般按这个顺序处理:

第一种:滑动窗口裁剪。最简单粗暴,只保留最近 N 轮对话。缺点是可能丢掉早期的重要信息。适合任务步骤之间相对独立的场景。

第二种:摘要压缩。把早期的对话历史用模型压缩成一段摘要,保留关键结论,丢掉过程细节。这个方式效果好,但要多花一次模型调用。我的经验是每积累 5-8 轮就压缩一次,压缩后的摘要控制在 200 字以内。

第三种:结构化状态外置。这是最优雅的方式:不把历史全塞进上下文,而是维护一个结构化的“任务状态对象”,只把当前状态注入 Prompt。比如一个订票 Agent,状态对象就是{出发地, 目的地, 日期, 是否已查票, 是否已下单},每轮只把这个对象序列化后放进去,上下文永远很短。

实际项目里我通常是三种混用:状态外置为主,摘要压缩为辅,滑动窗口兜底。

4.3 上下文注入顺序对模型表现的影响

这是一个很微妙但很实用的点:同样的信息,放在上下文的不同位置,模型的使用效果不一样。

我的实测经验是,模型对上下文开头和结尾的信息最敏感,中间部分容易被忽略(这就是所谓的“lost in the middle”现象)。所以注入顺序应该是:

  1. 系统 Prompt 和核心规则放最前面。
  2. 当前任务状态和最近一轮的工具结果放最后面(紧挨着模型要生成的位置)。
  3. 历史摘要和次要信息放中间。

另外,工具返回的结果如果很长(比如一个网页的全文),一定要先做截断或摘要再注入,否则一次工具调用就能把上下文撑爆。我一般会把单个工具结果限制在 2000 字以内,超长的做摘要。

5. Memory 层:让 Agent 拥有“记忆”

5.1 Memory 和 Context 的区别,很多人搞混

这两个概念经常被混为一谈,但它们的职责完全不同。Context 是“当前工作台”,Memory 是“长期档案柜”。

Context 是临时的,任务结束就清空;Memory 是持久的,跨会话、跨任务保留。Context 容量有限,必须精打细算;Memory 容量可以很大,但需要检索机制来决定“什么时候把哪段记忆调出来放进 Context”。

举个例子:一个客服 Agent,用户这次来问“我上次买的那个东西到哪了”。Context 里只有这次对话,但 Memory 里存着这个用户的历史订单和上次的沟通记录。Agent 需要从 Memory 里检索出相关信息,注入到当前 Context,才能正确回答。

5.2 记忆的三种类型与存储策略

我把 Agent 的记忆分成三类,各自有不同的存储和检索策略:

记忆类型内容存储方式检索方式
工作记忆当前任务的中间状态内存对象直接读取
情景记忆历史对话、过往任务记录向量数据库语义相似度检索
语义记忆领域知识、事实、规则知识库/向量库关键词+语义混合检索

工作记忆就是前面说的“结构化状态对象”,生命周期最短。情景记忆是“发生过什么”,用向量库存,按语义相似度召回。语义记忆是“知道什么”,通常是预置的领域知识。

热词里提到的agent 存储 working memory和tencentdb agent memory说的就是这块。实际选型上,小规模用内存 + 本地向量库就够,规模上来了再考虑专门的存储服务。

5.3 记忆检索的精度问题与优化

Memory 层最容易出问题的地方是检索精度。存进去容易,取出来准很难。用户问“上次那个事”,你得准确找到“上次”指的是哪次、哪个事。

我的优化经验有这么几条:

  • 写入时做结构化:不要存原始对话,存的时候就提取出关键信息(时间、人物、事件、结论),检索时按结构字段过滤再语义匹配,精度高很多。
  • 混合检索:纯向量检索对精确匹配(比如订单号、人名)不敏感,要结合关键词检索。我一般用“向量召回 Top 20 + 关键词过滤”的组合。
  • 加时间衰减:越近的记忆权重越高,符合人的记忆规律。
  • 定期清理:过期的、无关的记忆要清理,否则检索池被污染,精度下降。

提示:记忆污染是个隐蔽的坑。如果 Agent 把错误的信息写进了长期记忆,后续所有基于这段记忆的回答都会错,而且很难排查。所以写入记忆前最好加一道校验,或者对关键记忆做人工审核。

6. 四层协同:一个完整 Agent 的运行实录

6.1 从用户输入到任务完成的完整链路

把四层串起来看,一个完整的 Agent 运行过程是这样的(以一个“帮我整理本周工作并生成周报”的 Agent 为例):

  1. 接收目标:用户输入“帮我整理本周工作并生成周报”。
  2. 加载记忆:从 Memory 检索该用户的历史工作记录和偏好格式。
  3. 组装 Context:系统 Prompt + 工具清单 + 检索到的记忆 + 用户目标。
  4. 模型决策:模型判断需要先获取本周的工作数据,选择调用“查询工作日志”工具。
  5. 工具执行:Tool 层调用日志 API,返回本周的原始记录。
  6. 结果回灌:把日志数据注入 Context,模型基于数据生成周报草稿。
  7. 模型决策:判断草稿是否完整,是否需要调用“格式化”工具。
  8. 循环:直到模型输出最终周报,任务终止。
  9. 写入记忆:把本次生成的周报和用户反馈写入 Memory,供下次参考。

这个链路里,每一层都在各司其职。Prompt 决定“做什么”,Tool 负责“怎么做”,Context 保证“信息够用”,Memory 保证“记得住”。

6.2 并发场景下 Agent 的状态隔离

热词里有个问题问得很好:ai agent 怎么扛并发。这是从 Demo 走向生产必须跨过的坎。

单用户单任务的 Agent 好做,但一旦要同时服务成百上千个用户,问题就来了:状态怎么隔离?资源怎么分配?上下文怎么不串?

我的实践方案是每个会话一个独立的 Agent 实例,实例之间完全隔离。具体做法:

  • 会话级隔离:每个用户会话对应一个独立的 Context 和 Memory 命名空间,绝不共享。
  • 无状态服务 + 外部状态存储:Agent 服务本身做成无状态的,所有状态(Context、Memory)都存在外部存储(Redis、向量库)里,这样服务可以水平扩展。
  • 工具调用的并发控制:对外部 API 的调用要做限流和排队,避免把下游打挂。
  • 超时与资源回收:每个 Agent 实例设最大运行时长和最大循环次数,防止死循环占资源。

这套方案跑下来,单机撑几百个并发会话问题不大,再往上就靠加机器。

6.3 一个真实项目的踩坑记录

说个我实际做过的项目。当时做一个自动处理工单的 Agent,四层都搭好了,测试环境跑得很顺,一上生产就出问题。

第一个坑是上下文爆炸。工单处理过程中要读大量历史记录,几轮下来上下文就超了。后来改成“只注入当前工单相关记录 + 历史摘要”,问题解决。

第二个坑是工具重试导致重复操作。有个“关闭工单”的工具,因为网络超时触发了重试,结果工单被关了两次,触发了下游告警。后来给所有动作类工具加了幂等键,同一个操作只执行一次。

第三个坑是记忆污染。Agent 把一次错误的判断写进了长期记忆,导致后续同类工单全部处理错误。后来加了记忆写入的校验规则,关键记忆必须经过规则引擎确认才能落库。

这三个坑,每一个都不是模型能力问题,全是工程问题。所以我一直说,做 Agent,模型只是其中一环,工程能力才是决定成败的关键。

7. 演进方向与个人实践建议

7.1 从单 Agent 到多 Agent 协作

单 Agent 能处理的任务复杂度是有上限的。当任务需要多种专业能力时,多 Agent 协作就成了自然选择。比如一个“市场分析”任务,可以拆成“数据采集 Agent”“数据分析 Agent”“报告撰写 Agent”,各司其职,通过消息传递协作。

但多 Agent 不是银弹。Agent 之间的通信开销、任务拆分的合理性、结果汇总的一致性,都是新的挑战。我的建议是:能用单 Agent 加多工具解决的,就不要上多 Agent。多 Agent 适合那种职责边界非常清晰、单 Agent 上下文确实装不下的场景。

7.2 给不同阶段实践者的建议

如果你是刚入门,我的建议是从单工具单任务的 Agent 做起。先跑通“Prompt 决策 + 一个工具调用 + 结果回灌”这个最小闭环,理解循环和状态管理,再逐步加工具、加记忆。

如果你已经在做生产级 Agent,重点应该放在可观测性和稳定性上。每一次模型决策、每一次工具调用、每一次记忆读写,都要有日志。出了问题能快速定位是哪一层的问题,这比模型能力重要得多。

如果你在考虑架构选型,记住一个原则:Context 管理决定性能上限,Memory 设计决定能力上限,Tool 生态决定应用边界。三者要平衡投入,不要只盯着模型调优。

我个人在实际操作中的体会是,Agent 这个领域变化很快,但底层的那套逻辑——决策、执行、信息、状态——是稳定的。把这几层的原理吃透,不管上层框架怎么换,你都能快速上手。最后分享一个小技巧:调试 Agent 时,把每一轮的完整 Context 和模型输出都打印出来,你会发现很多问题一眼就能看出来,比盯着最终结果瞎猜高效得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询