对话缓存储存BufferMemory
会话缓冲存储(BufferMemory
)可以存储所有历史对话内容,使语言模型能记住之前的上下文。
// 创建一个新的 OpenAI 模型实例,使用 GPT-3.5 Turbo 模型
const model = new OpenAI({
modelName: "gpt-3.5-turbo",
openAIApiKey: process.env.VUE_APP_OPENAI_API_KEY, // 使用环境变量中的 API 密钥
});
// 创建一个内存实例,用于存储对话信息
const memory = new BufferMemory();
// 创建一个对话链实例,将模型和内存传入
const chain = new ConversationChain({ llm: model, memory: memory });
// 发起第一个对话请求,输入 "Hi! I'm Cyrus."
const res1 = await chain.call({ input: "Hi! I'm Cyrus." });
console.log({ res1 }); // Hello, Cyrus! It's nice to meet you. How can I assist you today?
// 发起第二个对话请求,输入 "What's my name?"
const res2 = await chain.call({ input: "What's my name?" });
console.log({ res2 }); // Your name is Cyrus.
在聊天模型中使用缓存区内存
// 创建一个新的 ChatOpenAI 实例,使用 GPT-3.5 Turbo 模型
const chat = new ChatOpenAI({
openAIApiKey: process.env.VUE_APP_OPENAI_API_KEY, // 使用环境变量中的 API 密钥
modelName: "gpt-3.5-turbo",
temperature: 0, // 温度参数,控制生成文本的随机程度
});
// 创建一个聊天提示模板,指定对话的结构
const chatPrompt = ChatPromptTemplate.fromPromptMessages([
// 系统消息,描述对话的背景和 AI 的行为
SystemMessagePromptTemplate.fromTemplate(
"The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know."
),
// 历史消息占位符,用于填充实际的对话历史
new MessagesPlaceholder("history"),
// 用户消息模板,将用户输入填充到对话中
HumanMessagePromptTemplate.fromTemplate("{input}"),
]);
// 创建一个对话链实例,将内存、提示模板和 ChatOpenAI 实例传入
const chain = new ConversationChain({
memory: new BufferMemory({ returnMessages: true, memoryKey: "history" }), // 使用 BufferMemory 存储对话历史
prompt: chatPrompt, // 使用预定义的聊天提示模板
llm: chat, // 使用 ChatOpenAI 实例作为语言模型
});
对话窗口存储BufferWindowMemory
对话窗口存储(BufferWindowMemory
)只存储最新的几轮对话,可以防止存储过多内容。
// 创建一个新的 OpenAI 模型实例,使用 GPT-3.5 Turbo 模型
const model = new OpenAI({
modelName: "gpt-3.5-turbo",
openAIApiKey: process.env.VUE_APP_OPENAI_API_KEY, // 使用环境变量中的 API 密钥
temperature: 0, // 温度参数,控制生成文本的随机程度
});
// 创建一个 BufferWindowMemory 实例,指定窗口大小为 1
const memory = new BufferWindowMemory({ k: 1 });
// 创建一个对话链实例,将模型和内存传入
const chain = new ConversationChain({ llm: model, memory: memory });
// 发起第一个对话请求
const res1 = await chain.call({ input: "Hi! I'm Jim." });
console.log({ res1 }); // 打印模型的回复
// 发起第二个对话请求
const res2 = await chain.call({ input: "What's my name?" });
console.log({ res2 }); // 打印模型的回复
// 查看当前存储的内容,只会显示最后一轮对话。
console.log(await memory.loadMemoryVariables());
// {history: "Human: What's my name?\nAI: Your name is Jim."}
对话摘要存储ConversationSummaryMemory
使用一种稍微复杂一些的内存类型—— ConversationSummaryMemory
。这种类型的记忆创建了随时间推移的对话摘要。这对于随着时间的推移压缩谈话中的信息非常有用。会话摘要内存在会话发生时对其进行汇总,并将当前的会话摘要存储在内存中。然后,可以使用这个内存将迄今为止的会话摘要注入到提示/链中。这种内存对于较长的会话非常有用,在这种情况下,在提示中逐字保存过去的消息历史记录将占用太多的标记。
const memory = new ConversationSummaryMemory({
memoryKey: "chat_history",
llm: new OpenAI({
openAIApiKey: process.env.VUE_APP_OPENAI_API_KEY,
modelName: "gpt-3.5-turbo",
temperature: 0
}),
});
const model = new OpenAI({
openAIApiKey: process.env.VUE_APP_OPENAI_API_KEY,
modelName: "gpt-3.5-turbo",
temperature: 0.9
});
const prompt =
PromptTemplate.fromTemplate(`以下是人类和人工智能之间的友好对话。人工智能很健谈,并从其上下文中提供了许多具体细节。如果人工智能不知道问题的答案,它会如实地说它不知道。
当前对话:
{chat_history}
Human: {input}
AI:`);
const chain = new LLMChain({ llm: model, prompt, memory });
const res1 = await chain.call({ input: "你好,我是小吴。" });
console.log({ res1, memory: await memory.loadMemoryVariables({}) });
/*
{
"res1": {
"text": "你好小吴!很高兴认识你。有什么我可以帮助你的吗?"
},
"memory": {
"chat_history": "The human greets the AI in Chinese and introduces themselves as Xiao Wu. The AI responds in Chinese, saying it's nice to meet Xiao Wu and asks how it can help."
}
}
*/
const res2 = await chain.call({ input: "我的名字是?" });
console.log({ res2, memory: await memory.loadMemoryVariables({}) });
/*
{
"res2": {
"text": "你的名字是小武。"
},
"memory": {
"chat_history": "The human greets the AI in Chinese and introduces themselves as Xiao Wu. The AI responds in Chinese, saying it's nice to meet Xiao Wu and asks how it can help. The human asks what their name is in Chinese. The AI responds that their name is Xiao Wu."
}
}
*/
ConversationSummaryBufferMemory
结合了 BufferMemory
和 ConversationSummaryMemory
背后的思想。它在内存中保留了一个最近交互的缓冲区,而不是完全刷新旧的交互,它将它们编译成摘要并同时使用两者。但是,与前面的实现不同,它使用令牌长度而不是交互的数量来确定何时刷新交互。
// 创建一个 ConversationSummaryBufferMemory 实例,用于存储对话摘要
const memory = new ConversationSummaryBufferMemory({
llm: new OpenAI({
modelName: "text-davinci-003",
temperature: 0,
openAIApiKey: process.env.VUE_APP_OPENAI_API_KEY // 使用环境变量中的 API 密钥
}),
maxTokenLimit: 10, // 设置最大令牌数限制
});
// 保存对话上下文
await memory.saveContext({ input: "嗨" }, { output: "怎么样" });
await memory.saveContext({ input: "没什么,你呢" }, { output: "没什么" });
// 加载内存变量并打印
const history = await memory.loadMemoryVariables({});
console.log({ history });
// 创建一个新的 ConversationSummaryBufferMemory 实例,用于在聊天提示中存储对话摘要
const chatPromptMemory = new ConversationSummaryBufferMemory({
llm: new ChatOpenAI({
modelName: "gpt-3.5-turbo",
temperature: 0,
openAIApiKey: process.env.VUE_APP_OPENAI_API_KEY // 使用环境变量中的 API 密钥
}),
maxTokenLimit: 10,
returnMessages: true, // 返回消息列表
});
// 保存聊天上下文
await chatPromptMemory.saveContext({ input: "嗨" }, { output: "怎么样" });
await chatPromptMemory.saveContext(
{ input: "没什么,你呢" },
{ output: "没什么" }
);
// 获取消息列表和之前的摘要,预测新的摘要
const messages = await chatPromptMemory.chatHistory.getMessages();
const previous_summary = "";
const predictSummary = await chatPromptMemory.predictNewSummary(
messages,
previous_summary
);
console.log(JSON.stringify(predictSummary));
// 创建一个 ChatPromptTemplate 实例,指定聊天提示的结构
const chatPrompt = ChatPromptTemplate.fromPromptMessages([
SystemMessagePromptTemplate.fromTemplate(
"以下是一个友好的人机对话。AI是健谈的,会从上下文提供许多具体细节。如果AI不知道问题的答案,它会诚实地回答不知道。"
),
new MessagesPlaceholder("history"),
HumanMessagePromptTemplate.fromTemplate("{input}"),
]);
// 创建一个新的 ChatOpenAI 模型实例,设置温度参数和 API 密钥
const model = new ChatOpenAI({
temperature: 0.9,
verbose: true,
openAIApiKey: process.env.VUE_APP_OPENAI_API_KEY // 使用环境变量中的 API 密钥
});
// 创建一个 ConversationChain 实例,将模型、内存和聊天提示传入
const chain = new ConversationChain({
llm: model,
memory: chatPromptMemory,
prompt: chatPrompt,
});
// 发起聊天预测请求,输入 "嗨,最近怎么样?"
const res1 = await chain.predict({ input: "嗨,最近怎么样?" });
console.log({ res1 }); // 嗨!最近我过得很好,谢谢关心。我一直在继续学习和进步。有什么新鲜事吗?
// 发起聊天预测请求,输入 "我在写一些文档!"
const res2 = await chain.predict({
input: "我在写一些文档!",
});
console.log({ res2 }); // 哇,写文档啊!听起来很有趣。你是在写什么类型的文档呢?是工作相关的还是个人兴趣的呢?
// 发起聊天预测请求,输入 "你听说过LangChain吗?"
const res3 = await chain.predict({
input: "你听说过LangChain吗?",
});
console.log({ res3 }); // 很抱歉,我还没有听说过LangChain。可以告诉我更多关于LangChain的信息吗?它是什么呢?
// 发起聊天预测请求,输入 "那不是正确的,虽然很多人把它弄混了!"
const res4 = await chain.predict({
input:
"那不是正确的,虽然很多人把它弄混了!",
});
console.log({ res4 }); // 非常抱歉,我可能误解了您的问题。如果您能告诉我更多关于LangChain的信息,我会非常感激。这样我就可以更好地理解和回答您的问题了。
矢量存储备份内存VectorStoreRetrieverMemory
VectorStoreRetrieverMemory
在一个 VectorDB 中存储内存,并在每次调用它时查询 top-K 最“显著”的文档。
这与大多数其他 Memory 类的不同之处在于,它不显式地跟踪交互的顺序。
在本例中, docs
是以前的会话片段。这可能是有用的参考相关的信息片段,人工智能被告知在对话早些时候。
import { OpenAI } from "langchain/llms/openai";
import { VectorStoreRetrieverMemory } from "langchain/memory";
import { LLMChain } from "langchain/chains";
import { PromptTemplate } from "langchain/prompts";
import { MemoryVectorStore } from "langchain/vectorstores/memory";
import { OpenAIEmbeddings } from "langchain/embeddings/openai";
// 创建一个内存向量存储实例,使用 OpenAIEmbeddings
const vectorStore = new MemoryVectorStore(new OpenAIEmbeddings(
{
openAIApiKey: process.env.VUE_APP_OPENAI_API_KEY, // 使用环境变量中的 API 密钥
}
));
// 创建一个 VectorStoreRetrieverMemory 实例,用于检索内存向量
const memory = new VectorStoreRetrieverMemory({
vectorStoreRetriever: vectorStore.asRetriever(1), // 检索1个文档,可以根据需求调整
memoryKey: "history", // 内存变量的键名
});
// 保存上下文信息到内存
await memory.saveContext(
{ input: "我最喜欢的食物是比萨饼" },
{ output: "那太好了,我已经记住了" }
);
await memory.saveContext(
{ input: "我最喜欢的运动是足球" },
{ output: "..." }
);
await memory.saveContext({ input: "我不喜欢凯尔特人队" }, { output: "好的" });
// 使用内存检索保存的信息
console.log(
await memory.loadMemoryVariables({ prompt: "我应该看什么运动?" })
);
/**
* {
* "history": "input: 我最喜欢的运动是足球\noutput: ..."
* }
*/
// 创建一个新的 OpenAI 模型实例,设置温度参数
const model = new OpenAI({
temperature: 0.9,
verbose: true,
openAIApiKey: process.env.VUE_APP_OPENAI_API_KEY // 使用环境变量中的 API 密钥
});
// 创建一个 PromptTemplate 实例,指定对话的结构,包括上下文信息
const prompt = PromptTemplate.fromTemplate(`以下是一个友好的人机对话。AI是健谈的,会从上下文提供许多具体细节。如果AI不知道问题的答案,它会诚实地回答不知道。
前面的对话片段:
{history}
(如果不相关,您无需使用这些信息。)
当前对话:
人类: {input}
AI:`);
// 创建一个 LLMChain 实例,将模型、提示模板和内存传入
const chain = new LLMChain({ llm: model, prompt, memory });
// 发起对话请求,输入 "嗨,我叫Perry,最近怎么样?"
const res1 = await chain.call({ input: "嗨,我叫Perry,最近怎么样?" });
console.log({ res1 }); // 嗨Perry,很高兴认识你!最近过得怎么样?你有什么新发现或有趣的事情发生了吗?
// 发起对话请求,输入 "我最喜欢的运动是什么?"
const res2 = await chain.call({ input: "我最喜欢的运动是什么?" });
console.log({ res2 }); // 哦,你最喜欢的运动是足球。你喜欢踢足球吗?
// 发起对话请求,输入 "我的名字是什么?"
const res3 = await chain.call({ input: "我的名字是什么?" });
console.log({ res3 }); // 您的名字是什么?
// ...对中文好像还不是特别友好
我们可以在Network中看到当用户提问时,embeddings会返回一堆矢量坐标
检索完了之后会把文案返回回来