只要用过AI Agent,大概都遇到过这样的尴尬场景:你十分钟前刚告诉它自己不吃辣、喜欢硬一点的床垫、项目里用的是Python 3.11,结果聊着聊着,它居然给你推荐起了川菜,或者写出了一段Python 3.9的代码。这时候你难免有点恼火——它是把我说的话都忘了吗?真相其实是:它不是"忘记"了,而是它压根就没"记住"过。这句话乍一听有点反常识,但恰恰是理解Agent底层运作逻辑的起点。
一、大模型本身是没有状态的
所谓"无状态",意思是大模型(LLM)每被调用一次,都是一次完全独立、从零开始的运算过程。它既不记得你上一句问了什么,也不知道你究竟是谁。
对写过代码的人来说,这个概念并不陌生:大模型本质上就是一个纯函数——相同的输入会得到大致相同的输出,但函数本身并不会因为被调用过就留下任何痕迹。它没有全局变量,没有会话状态,更没有持久化存储这一说。
那ChatGPT为什么看起来能进行连贯的多轮对话呢?因为这种连贯感,其实是外部系统在背后帮它撑起来的。每一轮对话发生时,系统都会把之前全部的对话内容重新拼接一遍,连同新的提问一起,作为完整的输入再次喂给模型。对模型来说,它每次接收到的都是一整段文字,它要做的,只是基于这段文字往下续写而已——它不是在"回忆",而是在阅读一篇不断变长的文章,然后接着写下去。
这就引出一个根本性的问题:既然模型自身不具备状态,那Agent的"状态"究竟是从哪儿来的?
答案是:状态其实是由Agent外围的架构系统在维护的。Agent框架负责管理对话历史、追踪任务进度、保存工具调用的结果,并在每次唤起模型之前,把这些相关信息整理打包后一并送进去。说白了,模型只负责"当下这一刻"的思考,而搭建出"当下全貌"的工作,全靠Agent框架在背后完成。
二、上下文窗口:一块容量有限的空间
弄明白"无状态"之后,接下来要理解的概念是上下文窗口(Context Window)。
大模型能接收的输入是有长度上限的。早期GPT-3.5大约只能处理4K token,到了GPT-4扩展到了128K,Claude支持到200K,Gemini号称能达到百万级别。但不管这个数字看起来多大,终究是有边界的。也就是说,你不可能把所有历史信息无限制地堆进去——随着对话越聊越长、任务越来越复杂,迟早会遇到装不下的那一天。 由此就衍生出一个工程难题,叫做上下文管理:在这块有限的空间里,到底该放进去什么、舍弃什么、又该怎么摆放。
业内比较常见的应对思路大致有这几种:
裁剪式策略,也就是只保留最近几轮对话内容,更早的历史直接舍弃。这种做法实现简单,但有可能丢掉一些关键信息。
压缩摘要策略,让模型把较早的对话内容浓缩成一段摘要,放在上下文最前面。这样能省下不少token空间,但压缩过程中信息损失几乎无法避免。
滑动窗口结合关键信息固定,把系统指令、用户画像、任务目标这些重要内容固定放在开头位置,中间部分则采用滑动窗口的方式动态更新。这是目前比较成熟的Agent产品普遍采用的方案。
检索增强(也就是常说的RAG),不再把所有信息一股脑塞进上下文,而是在真正需要的时候,通过向量检索的方式从外部知识库中实时调取相关内容片段。
不管采用哪种思路,本质上做的都是同一件事——在有限的空间里,对信息进行取舍和合理编排。
三、记忆:比上下文更长久的存在
很多人容易把"上下文"和"记忆"这两个概念混为一谈,但其实它们处在完全不同的层次上。
上下文指的是模型在单次调用中能够看到的全部信息,它是短暂的、临时性的——一旦这次调用结束,上下文也就随之消失了。而记忆指的是能够跨越多次调用、甚至跨越不同会话持续存在的信息,它是持久性的,被保存在Agent框架之外的存储系统当中。
打个比方可能更好理解:上下文有点像我们的工作记忆,也就是此刻正在处理的信息,容量有限,注意力一转移就很容易丢失;而记忆则更像是长期记忆,存放在大脑某个角落,需要的时候才被重新提取出来。
在Agent系统当中,记忆通常被划分为三种类型:
短期记忆,指的是当前这次会话中的对话历史。它在会话进行期间始终可用,但也会随着上下文管理策略被裁剪或者压缩。
长期记忆,指的是能够跨会话持久保存下来的信息。比如你提到过自己不吃辣,这个偏好就会被提取出来存进数据库,等到下一次开启新对话时还能被重新调用。
工作记忆,指的是Agent在执行复杂任务过程中产生的中间状态。比如它正在替你做一项调研,已经查阅完三个网站、还剩两个没看完——这个执行进度,就属于工作记忆的范畴。
记忆和上下文之间的关系可以这样理解:记忆相当于上下文的"补给仓库"。记忆本身并不会直接影响模型最终输出的结果,它必须先被检索召回,再被放进上下文当中,模型才能看到并加以利用。
把信息存进长期记忆只是第一步,真正关键的是,要在恰当的时机,把恰当的记忆内容精准检索出来,放进上下文里。这一环节做得好不好,直接决定了Agent在用户眼中看起来有多"聪明"。
四、归根结底,一切都是Prompt
对大模型来说,不管你背后的架构搭建得多复杂、记忆系统设计得多精巧、上下文管理做得多高级,最终摆在它面前的,其实就是一段文字而已,而这段文字就是Prompt。
Agent架构所做的一切努力,归根结底都是在回答同一个问题:如何拼凑出一段最恰当的Prompt,让模型在这一次调用中给出最优质的回应?
一个典型的Agent Prompt,大致是按照这样的结构拼接而成的:最前面是系统指令,用来定义Agent的角色定位、能力边界和行为规范;接着是用户画像与偏好,这部分是从长期记忆中检索出来的用户相关信息;然后是当前任务目标的描述;再往后是从知识库中检索到的相关参考资料;之后是Agent可以调用的工具说明;再加上经过裁剪或压缩处理的历史对话内容;最后是用户刚刚发出的新一轮输入。
这每一个组成部分,分别来自不同的源头——有的来自系统配置,有的来自记忆模块,有的来自检索系统,有的来自上下文管理器——但它们最终都会汇聚成一段完整统一的Prompt,被送进那个本身没有任何状态的大模型当中。
而Agent所谓的"魔法",其实就藏在这里:它并不是让大模型本身变得更强大,而是想方设法,让大模型在每一次被调用时,都能看到当下最恰当、最合适的那一份信息。