AI记忆组件
默认情况下,链和代理是无状态的,这意味着它们独立地处理每个传入的查询(就像底层的LLM和聊天模型本身一样)。在一些应用中,比如聊天机器人,记住先前的交互信息(包括短期和长期的)是非常重要的。Memory(内存)类正是为此而设计的。
LangChain以两种形式提供内存组件。首先,LangChain提供了帮助管理和操作之前的聊天消息的辅助工具。这些工具被设计成可以模块化和有用,无论如何使用它们。其次,LangChain提供了将这些工具集成到链中的简便方法。
入门
在用户与语言模型的交互过程中,内存涉及到在整个过程中保留状态的概念。用户与语言模型的交互被捕捉在ChatMessages的概念中,因此这归结为从一系列聊天消息中摄取、捕获、转换和提取知识。有很多不同的方式来做到这一点,每种方式都作为其独立的内存类型存在。
通常情况下,对于每种类型的内存,有两种方法来理解和使用。一种是独立的函数,用于从一系列消息中提取信息,另一种是在链中使用这种类型的内存的方式。
内存可以返回多个信息片段(例如,最近的N条消息和所有以前消息的摘要)。返回的信息可以是字符串或消息列表。
我们将介绍内存的最简单形式:”缓冲区”内存,它只涉及保留所有先前消息的缓冲区。我们将展示如何在这里使用模块化工具函数,然后展示如何在链中使用它(既返回字符串,也返回消息列表)。
ChatMessageHistory
支持大多数(如果不是全部)内存模块的核心实用类之一是 ChatMessageHistory
类。这是一个超轻量级的包装器,提供了保存人类消息、AI消息以及获取所有消息的便捷方法。
通过对该类进行子类化,您可以使用不同的存储解决方案,例如Redis,以保持持久的聊天消息记录。
import { ChatMessageHistory } from "langchain/memory";
const history = new ChatMessageHistory();
await history.addUserMessage("Hi!");
await history.addAIChatMessage("What's up?");
const messages = await history.getMessages();
console.log(messages);
/*
[
HumanMessage {
content: 'Hi!',
},
AIMessage {
content: "What's up?",
}
]
*/
您还可以通过创建并传入ChatHistory对象来将消息加载到内存实例中。这样可以轻松地从过去的对话中获取状态。除了上述技术外,您还可以这样做:
import { BufferMemory, ChatMessageHistory } from "langchain/memory";
import { HumanChatMessage, AIChatMessage } from "langchain/schema";
const pastMessages = [
new HumanMessage("My name's Jonas"),
new AIMessage("Nice to meet you, Jonas!"),
];
const memory = new BufferMemory({
chatHistory: new ChatMessageHistory(pastMessages),
});
BufferMemory
现在我们来展示如何在链中使用这个简单的概念。我们首先展示BufferMemory
,它是一个封装ChatMessageHistory的类,用于提取消息并将其存储在输入变量中。
import { OpenAI } from "langchain/llms/openai";
import { BufferMemory } from "langchain/memory";
import { ConversationChain } from "langchain/chains";
const model = new OpenAI({});
const memory = new BufferMemory();
// This chain is preconfigured with a default prompt
const chain = new ConversationChain({ llm: model, memory: memory });
const res1 = await chain.call({ input: "Hi! I'm Jim." });
console.log({ res1 });
{response: " Hi Jim! It's nice to meet you. My name is AI. What would you like to talk about?"}
const res2 = await chain.call({ input: "What's my name?" });
console.log({ res2 });
{response: ' You said your name is Jim. Is there anything else you would like to talk about?'}
还有很多不同类型的内存,查看我们的示例以了解更多!
创建自己的内存类
BaseMemory接口有两个方法:
export type InputValues = Record;
export type OutputValues = Record;
interface BaseMemory {
loadMemoryVariables(values: InputValues): Promise;
saveContext(
inputValues: InputValues,
outputValues: OutputValues
): Promise;
}
要实现自己的内存类,有两种选择:
继承BaseChatMemory
类
这是实现自己的内存类最简单的方法。你可以继承BaseChatMemory
类,它会负责通过将输入和输出保存为聊天消息来处理saveContext
方法,并且只需实现loadMemoryVariables
方法。这个方法负责返回与当前输入值相关的内存变量。
abstract class BaseChatMemory extends BaseMemory {
chatHistory: ChatMessageHistory;
abstract loadMemoryVariables(values: InputValues): Promise;
}
继承BaseMemory
类
如果你想实现一个更自定义的内存类,可以继承BaseMemory
类并实现loadMemoryVariables
和saveContext
方法。saveContext
方法负责将输入和输出值存储在内存中,loadMemoryVariables
方法负责返回与当前输入值相关的内存变量。
abstract class BaseMemory {
abstract loadMemoryVariables(values: InputValues): Promise;
abstract saveContext(
inputValues: InputValues,
outputValues: OutputValues
): Promise;
}