在概率论里,连续抛硬币是一组彼此独立的事件。第一次抛到反面,不会影响下一次出现正面或反面的概率——硬币本身没有"记忆"。大语言模型(LLM)的工作原理也很类似。给定一个提示词,LLM 的响应在不同 API 调用之间是无状态的,除非明确提供之前的上下文信息。换句话说,开箱即用的 LLM 就像《海底总动员》里的多莉——那条健忘的小鱼。

那么问题来了:聊天机器人和 AI 智能体是怎么跟用户进行长时间对话的?答案很简单——记忆系统。

从零开始构建 AI 记忆系统

先来看看如何用几行 Python 代码和 OpenAI SDK 从头搭建一个记忆系统。需要注意的是,这种方法并不适合用在生产环境中,但通过这个过程可以深入理解记忆机制的工作原理、局限性以及相关成本。

记忆的两种基本类型

AI 应用通常使用两种记忆类型:

短期记忆类似于计算机的 RAM,应用在单次会话期间"记住"对话内容,会话结束后就会清空。长期记忆则像硬盘驱动器,能够跨会话持久保存信息,即使应用重启也不会丢失。

无状态应用的局限性

先从构建一个没有记忆的简单聊天应用开始,看看它在处理连续对话时会遇到什么问题。这个基础应用包含两个核心组件:LLM 客户端和提示模板。

LLM 客户端使用 OpenAI API Python SDK 调用本地模型。通过 Docker Model Runner 在本地运行模型,也可以根据需要修改客户端配置来使用其他兼容的服务:

import openai

base_url = "http://model-runner.docker.internal/engines/v1"
api_key = "docker"
model = "ai/llama3.2:latest"

client = openai.OpenAI(
    base_url=base_url,
    api_key=api_key
)

提示模板遵循标准的聊天结构,能够把用户问题嵌入到提示中:

def prompt_template(question: str):
    return [
        {"role": "system", "content": "You are a helpful AI assistant."},
        {"role": "user", "content": question},
    ]

接下来用一个 while 循环把这两个组件连接起来,接收用户输入,嵌入提示模板,发送给 LLM 并返回答案:

while True:
    question = input("Question: ")
    if question == 'quit':
        break

    completion = client.chat.completions.create(
        model=model,
        messages=prompt_template(question),
        temperature=0
    )
    print(f"AI: {completion.choices[0].message.content}")

运行这个脚本后,问一个简单的问题:

Question: What is the capital of the USA?
AI: The capital of the United States of America is Washington, D.C. (short for District of Columbia).

LLM 正确回答了——华盛顿特区。但是当尝试追问关于英国首都的问题时:

Question: and UK?

模型却返回了一大段关于英国的介绍,完全没理解这是在延续之前的话题。因为每个请求都是独立处理的,模型根本无法访问之前的问题或自己之前的回答。

给应用添加短期记忆

现在给聊天应用添加短期记忆功能。实现方法很简单:把之前的对话历史附加到提示中,为 LLM 提供更完整的上下文。这样 LLM 就能判断新问题是否与之前的对话相关,并给出合适的回答。

先修改提示模板,添加一个列表来存储对话历史:

# 存储对话记忆
conversation = []

def prompt_template(question: str):
    return (
        [{"role": "system", "content": "You are a helpful AI assistant."}]
        + conversation
        + [{"role": "user", "content": question}]
    )

这样就能在发送新问题时,同时带上之前的聊天记录。然后更新聊天应用,把新的问题和 LLM 的回答都追加到对话历史中:

while True:
    question = input("Question: ")
    if question == "quit":
        break

    completion = client.chat.completions.create(
        model=model,
        messages=prompt_template(question),
        temperature=0
    )

    answer = completion.choices[0].message.content
    print(f"AI: {answer}")

    # 更新记忆
    conversation.append({"role": "user", "content": question})
    conversation.append({"role": "assistant", "content": answer})

再次运行脚本,问同样的问题:

Question: What is the capital of the USA?
AI: The capital of the United States of America is Washington, D.C. (short for District of Columbia).
Question: and UK?
AI: The capital of the United Kingdom is London.

完美!模型现在能够理解上下文,正确回答了追问。更有意思的是,当问一个完全不相关的新问题时:

Question: How much is 2 times 2?
AI: 2 times 2 is 4.

LLM 能够自动切换上下文,处理新的话题。

简单方案背后的代价

虽然这个实现方法简单直接,但天下没有免费的午餐。这种方案存在几个明显的局限性:

Token 数量增长和成本爆炸

每次往提示中添加新的用户消息或 AI 回复,发送给模型的总 Token 数量都会增加。如果使用按 Token 计费的商业 LLM API,这意味着对话时间越长,成本越高。相同的历史上下文在每次请求中都会重复发送,成本随着对话长度呈线性甚至更糟糕的趋势增长。

上下文窗口的限制

LLM 都有固定的上下文窗口大小。一旦累积的对话超过这个限制,就不得不截断或删除较早的消息,可能导致重要信息丢失,模型表现也会变得不稳定或"忘记"关键事实。这就需要实现额外的逻辑,比如滑动窗口、对话摘要或选择性保留重要信息,这些都会增加系统复杂度。

缺乏语义理解

这种方法把记忆当作原始文本处理,而不是结构化知识。模型无法判断哪些信息重要,关键事实和闲聊内容混在一起,没有优先级或检索逻辑。结果就是模型可能错过重要上下文,过度关注最近但不相关的消息,产生不稳定或前后矛盾的答案。

脆弱的提示工程

虽然这个方案适合做演示或处理短对话,但在实际应用中很快就会崩溃。随着记忆直接注入提示,模型性能会面临风险:小的提示改动可能导致行为大变,错误难以调试,意外的格式问题可能让整个系统失效。这使得系统规模扩大后变得越来越难维护。

Agentic AI 系统的高级记忆需求

AI 智能体(Agent)已经成为当前的热点话题。但关于什么是 Agentic AI 系统,它们与生成式 AI 或 LLM 代理有什么不同,仍然存在很多困惑。

真实场景中的 Agentic AI

以一个营销用例为例来说明 Agentic AI 系统的功能需求。给定用户任务,智能体平台的目标是识别能够执行该任务的智能体或智能体组。

系统需要的第一个核心组件是编排层,能够将任务分解为子任务,由编排引擎协调相应智能体的执行。目前主要通过提示 LLM 来进行任务分解,这也意味着 Agentic AI 受限于 LLM 的推理能力。

比如给 GPT-4 这样的任务分解提示:

生成定制电子邮件活动以在 1 个月内实现 100 万美元销售额,可用产品及其性能指标在某个 URL。连接到 CRM 系统获取客户姓名、电子邮件地址和人口统计详情。

系统会分解为:分析产品 → 识别目标受众 → 创建定制电子邮件活动。然后智能体会监控执行过程和环境变化,自主适应调整。比如当发现无法达成销售目标时,自动添加新任务:寻找替代产品 → 利用客户数据 → 进行 A/B 测试。

对于大多数用例,还需要与企业系统集成(比如这里的 CRM)。Anthropic 最近提出的模型上下文协议(MCP)就是为了将 AI 智能体连接到外部系统,访问企业数据。

长期记忆的关键性

考虑到这类复杂任务的长期运行特性,内存管理成为 Agentic AI 系统的关键。一旦启动电子邮件活动,智能体需要监控活动长达 1 个月。这就需要在任务之间共享上下文,并长时间维持执行状态。

当前主流解决方案是使用向量数据库(Vector DB)外部存储智能体记忆,让数据项能够按需访问。

向量数据库与对话记忆管理

向量数据库专门设计用于存储向量并基于向量相似性处理查询。目前它们是存储和检索对话智能体数据(记忆)的主要媒介。

实现过程包括选择一个编码器模型,作为单独流程执行离线数据编码,将各种形式的原始数据(文本、音频、视频)转换为向量。相似的原始对话数据项会映射到编码空间中相近的向量位置。

以文本为例,需要转换为计算机能处理的数字向量,这个过程通过分词器完成。Token 可以是字节、字符、字符集、单词,甚至完整句子。目前最常见的分词器是字节对编码(BPE),使用一对相邻字节作为 Token。选择合适的 Token 粒度至关重要,因为它影响神经网络能够掌握的 Token 间关系,以及训练网络的计算复杂度。

编码后的数据保存在向量数据库中,推理时可以使用相同的编码器模型基于向量相似性检索。聊天过程中,对话智能体通过编码查询并在向量数据库中搜索相关信息,检索到的信息用于基于存储的历史回答问题。

向量数据库的数据质量问题

向量数据库的主要问题在于数据质量。由于依赖嵌入模型的准确性,它们受限于嵌入模型的局限性。

嵌入模型(如 Sentence-BERT、OpenAI 的 text-embedding-ada-002)是为通用文本表示设计的,但不一定能捕获领域特定的细微差别。比如在金融领域,"债券"和"债务"的嵌入可能非常相似,导致检索不准确。

此外,向量数据库不擅长处理时间或因果关系。考虑这样一系列事件:“用户订阅了服务” → “用户取消了订阅” → “用户重新订阅了服务”。向量相似性可能无法区分这些事件的顺序,导致智能体基于过时信息做决定。

向量数据库也难以处理上下文更新。如果用户最初说喜欢披萨,后来改变主意偏好素食,向量数据库可能检索到旧的嵌入,导致不一致的响应。在处理稀疏或异常数据时,比如罕见的技术术语或用户特定的俚语,可能没有足够的训练数据,导致低质量嵌入和检索失败。

检索效率的挑战

检索通常基于 k-最近邻(k-NN)搜索,可能返回不相关的结果。比如查询"推荐披萨餐厅",k-NN 可能返回关于披萨食谱的文档,而不是餐厅建议。k-NN 搜索计算密集,尤其对于大型数据集,可能导致高延迟,特别是在实时应用中。另外,向量数据库缺乏可解释性,不会说明为什么检索到特定文档,这让调试检索问题变得困难。

超越向量数据库:多层次记忆体系

Agentic AI 需要管理多种类型的记忆,仅靠向量数据库是不够的:

语义记忆存储关于世界的一般知识,比如"巴黎是法国首都"。情景记忆保存个人经历,比如"用户上次访问了网站"。程序记忆记录技能和程序,比如"如何发送电子邮件"。

向量数据库足以处理语义记忆,但对于情景和程序记忆就显得力不从心,因为它们需要结构化和关系型表示。

知识图谱:语义记忆的优选方案

知识图谱(Knowledge Graph)是处理语义记忆的优秀替代方案。它们将实体和关系表示为图结构,节点代表实体,边代表关系。

比如这样的知识图谱:“用户” — “喜欢” — “披萨”,“披萨” — “是” — “食物”。

知识图谱支持超越向量相似性的推理和查询。可以查询"用户喜欢的所有食物"或"披萨的所有属性"。而且知识图谱能处理时间和因果关系,可以表示"用户在 2023 年订阅了服务",“用户在 2024 年取消了订阅”。最重要的是,知识图谱具有可解释性,能够追踪为什么检索到特定信息。

有限状态机:程序记忆的最佳选择

有限状态机(FSM)是处理程序记忆的理想方案。它们将任务表示为状态和转换序列。

比如这样的状态机:状态"开始" → “分析产品” → “识别受众” → “创建活动” → “结束”。

FSM 让智能体能够跟踪任务进度,基于当前状态做出决策。还能处理异常情况,比如"分析产品"失败时,可以转换到"错误处理"状态。FSM 的行为是可预测的,能够预判智能体在任何给定状态下的行为。

混合架构:整合多种记忆系统

最佳实践是结合向量数据库、知识图谱和有限状态机,发挥各自的优势:

向量数据库用于快速检索相关文档。知识图谱用于管理语义和情景记忆。有限状态机用于跟踪程序记忆。

智能体可以这样工作:使用向量数据库快速检索相关文档,使用知识图谱推理用户偏好相关的事实,使用 FSM 跟踪任务执行进度。

这种混合方法提供了一个全面的内存管理系统,克服了单一方法的局限性。

写在最后

简单粗暴地把对话历史塞进提示词确实能让 AI 记住聊天内容,但这招在实际项目里很快就会遇到瓶颈——Token 越堆越多,成本蹭蹭往上涨,上下文窗口也撑不住。向量数据库解决了一部分问题,但要让智能体真正聪明起来,还得配合知识图谱和状态机一起用,这样才能搭出一个既能记事儿、又会推理、还能干活的靠谱系统。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐