AI产品中的长期记忆和短期记忆是什么,你知道吗?

0 阅读11分钟

同学们好哦

AI 应用开发(特别是大模型应用) 中,经常会提到两个概念:

  • 短期记忆(Short-term Memory)
  • 长期记忆(Long-term Memory)

可以把它理解为:
大模型像一个人聊天时的记忆系统

  • 短期记忆 → 当前对话临时记住的东西
  • 长期记忆 → 可以长期保存、随时取出来的东西

下面我们展开聊聊。

短期记忆(Short-term Memory)

短期记忆 = 当前对话上下文

本质就是:

Context Window(上下文窗口)

点击查看 Context Window的详细介绍

Context Window 也就是:

历史对话 + 当前输入 + 模型输出

例如:

用户:我叫小王
AI:好的小王

用户:我刚刚说我叫什么?
AI:小王

AI 能回答,是因为:

用户:我叫小王
AI:好的小王
用户:我刚刚说我叫什么?

这些 全部被放进 Context Window

短期记忆的特点

特点说明
临时只在当前对话有效
有长度限制Context Window 限制
超出会被截断旧消息会被删除
不会长期保存新对话就没了

例如:

GPT-4o

Context Window128k tokens

如果对话太长:

最早的聊天记录会被删掉

所以 AI 会 “失忆”

Context Window 超长处理

有小伙伴问:历史会话越来越多,context window超长之后需要截断,这个截断的过程是谁处理的,工程还是模型。

答案:工程这边处理

一般来说,context window发送给模型之前,都会把最后需要发送的内容在工程内计算一下,然后结合目标模型最大可接受context window的大小来判断,需要裁剪掉多少内容。否则有些模型在context window超出的时候会直接报错。

我们以gpt-4o为例子,它的context window大小限制是128k ,分别以 javascript/python/java三个语言的真实代码看一下。

js案例

import OpenAI from "openai"
import { encoding_for_model } from "tiktoken"

const client = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY
})

// GPT-4o 的 context window
const MAX_CONTEXT = 128000

// 给输出预留 token
const MAX_OUTPUT = 4000

// tokenizer
const encoder = encoding_for_model("gpt-4o")

// 计算 token
function countTokens(messages) {
  let total = 0

  for (const msg of messages) {
    total += encoder.encode(msg.content).length
  }

  return total
}

// 裁剪历史
function trimMessages(messages) {
  while (countTokens(messages) > MAX_CONTEXT - MAX_OUTPUT) {
    // 删除最早的一条用户/assistant消息
    messages.splice(1, 1)
  }
  return messages
}

async function chat() {

  let messages = [
    { role: "system", content: "你是一个 helpful assistant" },
    { role: "user", content: "你好" },
    { role: "assistant", content: "你好!有什么可以帮你?" },
    { role: "user", content: "给我讲一下 JavaScript 的事件循环" }
  ]

  // 检测并裁剪 context
  messages = trimMessages(messages)

  const response = await client.chat.completions.create({
    model: "gpt-4o",
    messages,
    max_tokens: MAX_OUTPUT
  })

  console.log(response.choices[0].message.content)
}

chat()

python案例

from openai import OpenAI
import tiktoken

# 初始化客户端
client = OpenAI(api_key="YOUR_API_KEY_HERE")

# GPT-4o context window
MAX_CONTEXT = 128_000
MAX_OUTPUT = 4_000  # 给输出预留

# tokenizer
encoder = tiktoken.encoding_for_model("gpt-4o")

# 计算 token 数量
def count_tokens(messages):
    total = 0
    for msg in messages:
        total += len(encoder.encode(msg["content"]))
    return total

# 裁剪历史
def trim_messages(messages):
    while count_tokens(messages) > MAX_CONTEXT - MAX_OUTPUT:
        # 删除最早的用户/assistant消息(保留 system prompt)
        messages.pop(1)
    return messages

# 主聊天函数
def chat():
    messages = [
        {"role": "system", "content": "你是一个 helpful assistant"},
        {"role": "user", "content": "你好"},
        {"role": "assistant", "content": "你好!有什么可以帮你?"},
        {"role": "user", "content": "给我讲一下 JavaScript 的事件循环"}
    ]

    # 检测并裁剪 context
    messages = trim_messages(messages)

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        max_tokens=MAX_OUTPUT
    )

    print(response.choices[0].message["content"])

if __name__ == "__main__":
    chat()

java案例

<!-- Maven 依赖示例 -->
<dependencies>
    <!-- OpenAI 官方 Java SDK -->
    <dependency>
        <groupId>com.openai</groupId>
        <artifactId>openai</artifactId>
        <version>1.1.0</version>
    </dependency>

    <!-- tiktoken-java 用于 token 计算 -->
    <dependency>
        <groupId>com.github.acheong08</groupId>
        <artifactId>tiktoken-java</artifactId>
        <version>1.0.5</version>
    </dependency>
</dependencies>

from openai import OpenAI
import tiktoken

# 初始化客户端
client = OpenAI(api_key="YOUR_API_KEY_HERE")

# GPT-4o context window
MAX_CONTEXT = 128_000
MAX_OUTPUT = 4_000  # 给输出预留

# tokenizer
encoder = tiktoken.encoding_for_model("gpt-4o")

# 计算 token 数量
def count_tokens(messages):
    total = 0
    for msg in messages:
        total += len(encoder.encode(msg["content"]))
    return total

# 裁剪历史
def trim_messages(messages):
    while count_tokens(messages) > MAX_CONTEXT - MAX_OUTPUT:
        # 删除最早的用户/assistant消息(保留 system prompt)
        messages.pop(1)
    return messages

# 主聊天函数
def chat():
    messages = [
        {"role": "system", "content": "你是一个 helpful assistant"},
        {"role": "user", "content": "你好"},
        {"role": "assistant", "content": "你好!有什么可以帮你?"},
        {"role": "user", "content": "给我讲一下 JavaScript 的事件循环"}
    ]

    # 检测并裁剪 context
    messages = trim_messages(messages)

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        max_tokens=MAX_OUTPUT
    )

    print(response.choices[0].message["content"])

if __name__ == "__main__":
    chat()

长期记忆(Long-term Memory)

长期记忆 === AI 可以长期存储的数据

例如:

用户偏好
历史资料
知识库
用户画像

这些数据通常会存到:

数据库
向量数据库
知识库

当用户提问时:

用户提问
系统检索相关记忆
把记忆塞进 Prompt
再给模型

流程:

用户问题
   ↓
检索长期记忆
   ↓
拼进 Prompt
   ↓
发送给大模型
   ↓
生成回答

这其实就是:

RAG(Retrieval Augmented Generation)

举个完整例子

  • 用户第一次和 AI 聊天时,告诉 AI 自己的偏好:

    • “我喜欢美式咖啡”
    • “我在学 JavaScript”
  • 系统把这些信息存入 长期记忆(向量数据库)

  • 下次用户提问时(此时可能已经切换了session):

    • 系统先 检索相关长期记忆,这一步属于向量搜索的范围(Embedding),点击查看详细解析
    • 把相关内容加入 Context Window
    • 发送给模型

还是以js/python/java为代码实例,大家参考一下

js

import OpenAI from "openai";
import { encoding_for_model } from "tiktoken";
import { PineconeClient } from "@pinecone-database/pinecone";

// 初始化 GPT 客户端
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

// 初始化向量数据库(长期记忆)
const pinecone = new PineconeClient();
await pinecone.init({ apiKey: process.env.PINECONE_API_KEY, environment: "us-west1-gcp" });
const index = pinecone.Index("user-memory");

// GPT-4o context window
const MAX_CONTEXT = 128000;
const MAX_OUTPUT = 4000;
const encoder = encoding_for_model("gpt-4o");

// 计算 token 数量
function countTokens(messages) {
  let total = 0;
  for (const msg of messages) {
    total += encoder.encode(msg.content).length;
  }
  return total;
}

// 裁剪短期记忆
function trimMessages(messages) {
  while (countTokens(messages) > MAX_CONTEXT - MAX_OUTPUT) {
    messages.splice(1, 1); // 删除最旧消息
  }
  return messages;
}

// 把长期记忆存入向量数据库
async function storeLongTermMemory(userId, text) {
  // 1. 获取 embedding
  const embeddingResponse = await client.embeddings.create({
    model: "text-embedding-3-large",
    input: text
  });
  const vector = embeddingResponse.data[0].embedding;

  // 2. 存入向量数据库
  await index.upsert({
    upsertRequest: {
      vectors: [
        {
          id: `${userId}-${Date.now()}`,
          values: vector,
          metadata: { text }
        }
      ]
    }
  });
}

// 查询长期记忆(RAG)
async function retrieveLongTermMemory(userId, query, topK = 5) {
  const embeddingResponse = await client.embeddings.create({
    model: "text-embedding-3-large",
    input: query
  });
  const vector = embeddingResponse.data[0].embedding;

  const searchResponse = await index.query({
    queryRequest: {
      vector,
      topK,
      includeMetadata: true,
      filter: { userId }
    }
  });

  return searchResponse.matches.map(m => m.metadata.text);
}

// 主对话流程
async function chat(userId, userMessage) {
  // 1. 检索相关长期记忆
  const longTermMemory = await retrieveLongTermMemory(userId, userMessage);

  // 2. 构建短期记忆
  let messages = [
    { role: "system", content: "你是一个 helpful assistant" }
  ];

  // 把长期记忆加入短期记忆
  if (longTermMemory.length > 0) {
    messages.push({
      role: "system",
      content: `用户的长期记忆信息:\n${longTermMemory.join("\n")}`
    });
  }

  // 当前用户消息
  messages.push({ role: "user", content: userMessage });

  // 3. 裁剪 context window
  messages = trimMessages(messages);

  // 4. 生成回答
  const response = await client.chat.completions.create({
    model: "gpt-4o",
    messages,
    max_tokens: MAX_OUTPUT
  });

  const answer = response.choices[0].message.content;
  console.log("AI:", answer);

  // 5. 存储新的长期记忆(可选)
  await storeLongTermMemory(userId, userMessage);
}

// --- 使用示例 ---
const userId = "user123";

// 第一次对话,存长期记忆
await storeLongTermMemory(userId, "我喜欢美式咖啡");
await storeLongTermMemory(userId, "我正在学习 JavaScript");

// 用户发问
await chat(userId, "给我推荐一款咖啡?");
await chat(userId, "帮我讲一下 JavaScript 的事件循环");

python

# pip install openai tiktoken pinecone-client
from openai import OpenAI
import tiktoken
import pinecone
import os

# 初始化 OpenAI
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

# 初始化 Pinecone
pinecone.init(api_key=os.getenv("PINECONE_API_KEY"), environment="us-west1-gcp")
index = pinecone.Index("user-memory")

# GPT-4o context window
MAX_CONTEXT = 128_000
MAX_OUTPUT = 4_000
encoder = tiktoken.encoding_for_model("gpt-4o")

# 计算 token
def count_tokens(messages):
    total = 0
    for msg in messages:
        total += len(encoder.encode(msg["content"]))
    return total

# 裁剪短期记忆
def trim_messages(messages):
    while count_tokens(messages) > MAX_CONTEXT - MAX_OUTPUT:
        messages.pop(1)  # 删除最早消息
    return messages

# 存储长期记忆
def store_long_term_memory(user_id, text):
    embedding_response = client.embeddings.create(
        model="text-embedding-3-large",
        input=text
    )
    vector = embedding_response.data[0].embedding
    index.upsert(
        vectors=[{
            "id": f"{user_id}-{int(os.times().system)}",
            "values": vector,
            "metadata": {"text": text, "userId": user_id}
        }]
    )

# 检索长期记忆
def retrieve_long_term_memory(user_id, query, top_k=5):
    embedding_response = client.embeddings.create(
        model="text-embedding-3-large",
        input=query
    )
    vector = embedding_response.data[0].embedding
    search_response = index.query(
        vector=vector,
        top_k=top_k,
        include_metadata=True,
        filter={"userId": user_id}
    )
    return [match['metadata']['text'] for match in search_response['matches']]

# 主聊天流程
def chat(user_id, user_message):
    long_term_memory = retrieve_long_term_memory(user_id, user_message)
    messages = [{"role": "system", "content": "你是一个 helpful assistant"}]

    if long_term_memory:
        messages.append({
            "role": "system",
            "content": f"用户的长期记忆信息:\n{chr(10).join(long_term_memory)}"
        })

    messages.append({"role": "user", "content": user_message})
    messages = trim_messages(messages)

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        max_tokens=MAX_OUTPUT
    )
    answer = response.choices[0].message["content"]
    print("AI:", answer)

    # 可选:把新信息存入长期记忆
    store_long_term_memory(user_id, user_message)


# --- 使用示例 ---
user_id = "user123"
store_long_term_memory(user_id, "我喜欢美式咖啡")
store_long_term_memory(user_id, "我正在学习 JavaScript")

chat(user_id, "给我推荐一款咖啡?")
chat(user_id, "帮我讲一下 JavaScript 的事件循环")

java

import com.theokanning.openai.OpenAiService;
import com.theokanning.openai.completion.chat.*;
import com.github.acheong08.tiktoken.Tiktoken;
import com.github.acheong08.tiktoken.Encoding;
import com.pinecone.PineconeClient; // 假设你用 Pinecone Java SDK

import java.util.ArrayList;
import java.util.List;

public class LongTermMemoryChat {

    private static final int MAX_CONTEXT = 128_000;
    private static final int MAX_OUTPUT = 4_000;

    public static void main(String[] args) {
        OpenAiService client = new OpenAiService(System.getenv("OPENAI_API_KEY"));

        // 初始化 tokenizer
        Encoding encoder = Tiktoken.encodingForModel("gpt-4o");

        // 初始化 Pinecone (长期记忆)
        PineconeClient pinecone = new PineconeClient(System.getenv("PINECONE_API_KEY"));
        var index = pinecone.Index("user-memory");

        String userId = "user123";

        // 存储长期记忆
        storeLongTermMemory(client, index, userId, "我喜欢美式咖啡");
        storeLongTermMemory(client, index, userId, "我正在学习 JavaScript");

        // 对话
        chat(client, encoder, index, userId, "给我推荐一款咖啡?");
        chat(client, encoder, index, userId, "帮我讲一下 JavaScript 的事件循环");
    }

    // 存储长期记忆
    public static void storeLongTermMemory(OpenAiService client, Object index, String userId, String text) {
        var embeddingResponse = client.createEmbeddings(
                OpenAiService.EmbeddingsRequest.builder()
                        .model("text-embedding-3-large")
                        .input(text)
                        .build()
        );
        var vector = embeddingResponse.getData().get(0).getEmbedding();
        // upsert 向量到 index
        // index.upsert(...)   // 这里具体调用看你使用的 SDK
    }

    // 检索长期记忆
    public static List<String> retrieveLongTermMemory(OpenAiService client, Object index, String userId, String query, int topK) {
        var embeddingResponse = client.createEmbeddings(
                OpenAiService.EmbeddingsRequest.builder()
                        .model("text-embedding-3-large")
                        .input(query)
                        .build()
        );
        var vector = embeddingResponse.getData().get(0).getEmbedding();
        // 搜索向量库
        List<String> results = new ArrayList<>();
        // 假设搜索返回 metadata.text
        // results.add(...);
        return results;
    }

    // 裁剪短期记忆
    public static List<ChatMessage> trimMessages(List<ChatMessage> messages, Encoding encoder) {
        while (countTokens(messages, encoder) > MAX_CONTEXT - MAX_OUTPUT) {
            messages.remove(1);
        }
        return messages;
    }

    public static int countTokens(List<ChatMessage> messages, Encoding encoder) {
        int total = 0;
        for (ChatMessage msg : messages) {
            total += encoder.encode(msg.getContent()).size();
        }
        return total;
    }

    // 主聊天流程
    public static void chat(OpenAiService client, Encoding encoder, Object index, String userId, String userMessage) {
        List<String> longTermMemory = retrieveLongTermMemory(client, index, userId, userMessage, 5);

        List<ChatMessage> messages = new ArrayList<>();
        messages.add(new ChatMessage("system", "你是一个 helpful assistant"));

        if (!longTermMemory.isEmpty()) {
            messages.add(new ChatMessage("system", "用户的长期记忆信息:\n" + String.join("\n", longTermMemory)));
        }

        messages.add(new ChatMessage("user", userMessage));
        messages = trimMessages(messages, encoder);

        ChatCompletionRequest request = ChatCompletionRequest.builder()
                .model("gpt-4o")
                .messages(messages)
                .maxTokens(MAX_OUTPUT)
                .build();

        ChatCompletionResult result = client.createChatCompletion(request);
        System.out.println("AI: " + result.getChoices().get(0).getMessage().getContent());

        // 可选:把用户新消息存入长期记忆
        storeLongTermMemory(client, index, userId, userMessage);
    }
}

AI系统的完整记忆架构

真实 AI 产品一般是这样设计:

                 用户输入
                    │
                    ▼
              ┌───────────┐
              │ 短期记忆  │
              │ Context   │
              └───────────┘
                    │
                    ▼
              ┌───────────┐
              │ 长期记忆  │
              │ Vector DB │
              └───────────┘
                    │
                    ▼
                  Prompt
                    │
                    ▼
                  大模型
                    │
                    ▼
                   回复

短期记忆 vs 长期记忆(核心区别)

短期记忆长期记忆
本质Context Window外部存储
生命周期当前对话永久
存储位置PromptDB / Vector DB
大小有限制几乎无限
用途上下文理解知识/用户记忆

总结来说:

短期记忆是模型的“脑子”,长期记忆是模型的“外挂硬盘”。

AI工程里的经典组合

真实 AI 应用基本是这三层:

短期记忆
+ 长期记忆
+ 工具调用

也就是:

Conversation Memory
RAG Memory
Tool Memory

很多 AI Agent 架构都是这样。

为什么大模型一定要有长期记忆

大模型本身是 无状态的

  • 大模型 API(如 GPT-4o、Claude)本身不会存储任何用户对话。
  • 每次请求都是 全新的计算,短期记忆只能通过 上下文传递
  • 如果没有长期记忆,模型就“每次都是新鲜人”,无法延续跨会话的知识。

举例

  • 今天用户说:我喜欢美式咖啡
  • 明天用户问:给我推荐咖啡
  • 如果没有长期记忆,模型不知道用户偏好,只能随机推荐

Context Window 有限制

  • GPT-4o context window ≈ 128k tokens
  • 对话过长或长期使用时,旧消息会被裁剪
  • 这导致 短期记忆只能保留最近几轮对话
  • 长期记忆才能保存核心信息,避免重要数据被丢掉

支撑个性化和用户体验

长期记忆让模型能做到:

  • 记住用户偏好
  • 记住历史任务和问题
  • 提供连续性和个性化回答

例如:

  • “小王喜欢喝美式咖啡” → 明天直接推荐冷萃
  • “用户之前问过 JavaScript 事件循环” → 下次能直接接着讲

支持 RAG(Retrieval-Augmented Generation)

  • 大模型知识有限(截止训练时间)
  • 用户提供的长期数据不能全部塞进 Context Window
  • 解决方案:把长期知识 存储到向量数据库或文档库
  • 查询时再检索,结合当前对话生成回答

流程:

用户问题 → 检索长期记忆 → 拼入 Prompt → 模型生成回答

这就是现代大模型系统必须做长期记忆的根本原因。

工程成本角度

  • 如果只靠短期记忆:

    • 大量信息会被丢掉
    • 每次都要重复提供上下文
    • 用户体验差
  • 长期记忆 + RAG:

    • 数据可以压缩、摘要、索引
    • 只检索相关信息
    • 节省 token 成本和计算资源

总结

  1. 短期记忆可以理解为让模型记住当前session内的历史会话
  2. 长期记忆可以理解为让模型除了当前session外,其他session里的历史对话
  3. 一般的ai产品应用会同时具备长期记忆和短期记忆
  4. 短期记忆的实现方式只需要把当前session的历史记录摘要汇总到prompt里即可
  5. 长期记忆需要通过RAG功能把相关内容向量匹配出来再汇总到prompt

最后

如果对你有用的话

f658630cdbe9f30a3120595887f617e4.png