点 Redis 8 已到来——它是开源的

了解更多

介绍 ChatGPT 记忆项目

ChatGPT 记忆应对了人工智能应用中使用的大型语言模型 (LLM) 在上下文长度方面的限制。ChatGPT 包使用 Redis 作为向量数据库来缓存每个会话的历史用户交互,从而提供了一种基于当前上下文的自适应提示创建机制。

ChatGPT,由 OpenAI 创建的 AI 聊天机器人,彻底改变了智能聊天应用领域。其源自复杂的 GPT-3.5 和 GPT-4 大型语言模型 (LLM),并使用基于人类反馈的强化学习 (RLHF) 进行微调,具有类人般的响应和能力,自 2022 年 11 月推出以来风靡全球。宣传机器全力运转。

有些 ChatGPT 互动滑稽有趣,有些 用途令人担忧,并且它们引发了影响许多行业的 道德问题

然而,所有人都认为这项技术必将产生重大影响。例如,微软已经在使用这些模型来提供基于 AI 的编码助手(GitHub Copilot)以及支持其搜索引擎(Bing)。多邻国 (Duolingo) 和可汗学院 (Khan Academy) 正在利用它们来驱动新的学习体验。而 Be My Eyes 则使用这些工具提供一个 AI 助手,帮助视障人士

尽管这些语言模型取得了成功,但它们也存在技术限制。特别是,正在探索如何利用 ChatGPT 的软件开发者们发现,在持续对话中,模型能够跟踪的上下文数量存在问题。

上下文长度是语言模型可以用来理解和回应的先前对话中的信息量。一个类比是,顾问阅读的书籍数量,他们可以从中提供实用建议。即使图书馆很大,它也不是无限的。

充分利用上下文长度对于创建真正强大的基于 LLM 的应用程序至关重要。你需要巧妙地利用模型可用的上下文长度。尤其如此,因为成本、延迟和模型可靠性都会受到发送和接收到 LLM API(如 OpenAI 的 API)文本量的影响。

为了解决 ChatGPT 和 GPT-4 等 AI 模型上下文长度有限的问题,我们可以为模型附加一个外部记忆源供其使用。这可以显著提高模型的有效上下文长度,对于基于 Transformer 的 LLM 模型驱动的高级应用程序尤其重要。在此,我们分享了如何在我们的 chatgpt-memory 项目中使用 Redis 的向量数据库创建智能记忆管理方法。

为什么上下文长度很重要

让我们先深入了解为什么上下文长度很重要。

随着 GPT-4 的出现,ChatGPT 的上下文长度从 4,096 个 token 增加到 32,768 个 token。使用 OpenAI 的 ChatGPT 或 GPT-4 API 的费用是根据对话数量计算的;你可以在其定价页面找到更多详情。因此,在为了处理更长文档而使用更多 token 与为了最小化成本而使用相对较小的提示之间存在权衡。

然而,真正强大的应用程序需要大量的上下文长度。

理论上,通过在向量数据库(即 Redis 向量数据库)中缓存历史交互并与 LLM 聊天机器人集成,可以提供无限量的上下文。Langchain 是一个流行的用于构建智能 LLM 应用程序的库,它已经提供了这种记忆实现。然而,这些实现目前是基于启发式的,要么使用所有对话历史,要么只使用最后 k 条消息。

虽然这种行为可能会改变,但这种方法是非自适应的。例如,如果用户在对话中途改变了话题,然后又回到了原来的话题,简单的 ChatGPT 记忆方法可能无法从过去的互动中提供真正相关的上下文。这种情况的一个可能原因是 token 溢出。确切地说,与当前消息相关的历史互动在对话历史中位于非常靠前的位置,以至于无法将其放入输入文本中。此外,由于简单的 ChatGPT 记忆方法需要一个 k 值来遵守 ChatGPT 的输入文本限制,这样的互动更有可能落在最后 k 条消息之外。

ChatGPT 可以提供有益的个性化建议的主题范围是有限的。对于一个更有效、更多样化的对话系统来说,更广阔和多样化的主题范围是可取的。

为了解决这个问题,我们推出了 ChatGPT 记忆项目。ChatGPT 记忆使用 Redis 向量数据库存储嵌入式的用户与机器人的历史对话记录。然后,它使用嵌入空间内的向量搜索来“智能地”查找与当前用户消息相关的历史互动。这有助于聊天机器人通过将重要的先前互动整合到当前提示中来回忆这些信息。

与当前默认行为相比,这种方法更具自适应性,因为它只从整个历史中检索与当前消息相关的最后 k 条消息。我们可以向提示添加更多相关的上下文,而且永远不会耗尽 token 长度。ChatGPT 记忆提供了自适应记忆,克服了启发式缓冲区记忆类型的 token 限制。这种实现通过只将最相关的历史记录整合到提示中,隐含地优化了提示质量;从而实现了一种隐性的成本效益方法,同时保留了 ChatGPT 响应的实用性和丰富性。

ChatGPT 记忆项目的架构

ChatGPT 记忆使用 Redis 作为向量数据库,以缓存每个会话的历史用户互动。Redis 提供了基于 K-近邻 (KNN) 搜索的语义搜索,以及使用 L2、内积 (IP) 和余弦等距离度量的范围过滤。这些功能通过使用其中一种距离度量来检索语义相关的历史用户互动,从而实现自适应提示创建。

此外,ChatGPT 记忆项目利用了 Redis 支持的向量索引算法,包括 FLAT 索引(采用暴力搜索方法)和优化的分层可导航小世界 (HNSW) 索引。Redis 支持实时的嵌入创建/更新/删除 (CRUD) 操作,以便在生产环境中管理此过程。

除了弥补启发式记忆限制的不足之外,ChatGPT 记忆还允许实时管理并发对话会话。它为每个聊天会话隔离了与用户过去与聊天机器人互动相关的历史记录。一旦 ChatGPT 助手回应了用户的查询,查询和助手的回应都会使用 OpenAI 的嵌入服务进行嵌入。然后将生成的嵌入在 Redis 索引中进行索引,以便以后检索。

后续的互动按以下方式进行

  1. 用户向 ChatGPT 机器人发送新消息。
  2. ChatGPT 记忆使用嵌入 API 对用户消息进行嵌入以获得查询向量,并查询 Redis 向量数据库以获得与语义相关的排名靠前的 k 个历史互动。
  3. ChatGPT 记忆将检索到的互动与当前用户消息一起整合到当前提示中,并将提示发送给 ChatGPT。
  4. 一旦获得 ChatGPT 的回应,当前的互动就会被向量化并缓存在 Redis 向量数据库中。

这使得用户能够获得更好、个性化的答案,因为系统有更多信息可供参考。

an illustration with arrows, a redis logo, and a human head icon dead center
ChatGPT 为基于检索的自动提示增强提供了一个强大的机制。

代码演练

在使用 ChatGPT 记忆之前,你需要克隆代码库并安装依赖项。你还需要一个 OpenAI API 密钥,以及访问基于云的 Redis 向量数据库(你可以免费试用)。

获得这些凭据后,通过在以下 bash 脚本中填入值,将它们设置为名为 OPENAI_API_KEYREDIS_HOSTREDIS_PASSWORDREDIS_PORT 的环境变量。

# OPENAI API key
EXPORT OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# Redis cloud database's credentials
EXPORT REDIS_HOST=localhost
EXPORT REDIS_PORT=1234
EXPORT REDIS_PASSWORD=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

之后,你只需编写几行代码即可开始使用 ChatGPT 记忆。

创建一个 Redis 数据存储连接实例。

from chatgpt_memory.datastore import RedisDataStoreConfig, RedisDataStore


redis_datastore_config = RedisDataStoreConfig(
    host=REDIS_HOST,
    port=REDIS_PORT,
    password=REDIS_PASSWORD,
)
redis_datastore = RedisDataStore(config=redis_datastore_config)

实例化 OpenAI 嵌入客户端,用于对对话历史进行向量化。

from chatgpt_memory.llm_client import EmbeddingConfig, EmbeddingClient

embedding_config = EmbeddingConfig(api_key=OPENAI_API_KEY)
embed_client = EmbeddingClient(config=embedding_config)

创建记忆管理器,用于根据当前上下文协调语义提示创建。

from chatgpt_memory.memory.manager import MemoryManager

memory_manager = MemoryManager(
    datastore=redis_datastore,
    embed_client=embed_client,
    topk=1
)

然后连接到 ChatGPT API。

from chatgpt_memory.llm_client import ChatGPTClient, ChatGPTConfig

chat_gpt_client = ChatGPTClient(
    config=ChatGPTConfig(api_key=OPENAI_API_KEY, verbose=True),
    memory_manager=memory_manager
)

最后,你已经准备好与 ChatGPT 客户端互动,该客户端拥有由 GPT 和 Redis 数据存储支持的无限上下文和自适应记忆。

conversation_id = None
while True:
    user_message = input("\n Please enter your message: ")
    response = chat_gpt_client.converse(
        message=user_message,
        conversation_id=conversation_id
    )
    conversation_id = response.conversation_id
    print(response.chat_gpt_answer)

互动示例

那么,它看起来是怎样的?考虑以下与 ChatGPT 对话的两个示例。它们说明了两种操作模式之间的性能差异。

没有 ChatGPT 记忆

A chatgpt conversation without memory
在这个低上下文示例中,ChatGPT 用户告诉了系统他的姓名和年龄……但即使只过了几句话,它也不记得了。

当记忆功能未激活时,ChatGPT 模型无法检索用户在之前的互动中提供的任何信息——即使是几句话之前的信息。

启用 ChatGPT 记忆

a chatgpt conversation
启用 ChatGPT 后,用户提供的信息会进入系统,以便在对话的后续部分被访问。

呈现的两个对话具有相似的消息流程。然而,未启用记忆功能的对话表明,ChatGPT 模型无法回忆起用户提供的任何信息。相比之下,当记忆功能启用时,模型记住了用户的特定细节,并提供了个性化和可定制的对话体验。

后续步骤

我们认为 ChatGPT 记忆是不断壮大的旨在改进 LLM 能力的工具生态系统中的一个有价值的补充。它为开发者构建强大且具有上下文感知能力的 AI 应用提供了一个绝佳机会。

ChatGPT 记忆的解决方案也突显了 Redis 向量数据库的本质重要性,它满足了众多 AI 用例的需求,包括但不限于 LLM。

要亲自试用 ChatGPT 记忆,请前往我们的 GitHub 仓库并按照本文中的说明操作。你可以在几分钟内启动一个实例。最后,如果你有兴趣了解更多关于如何使用 Redis 和 LangChain 等工具构建 LLM 应用的信息,请注册即将到来的 RedisDays 虚拟会议