chat history
chat history指的是在用户和模型交流期间的对话记录,history中包含了在这一过程中产生的上下文信息和状态信息,这些信息可以根据对话的角色进行划分,比如system、user、AI等。
// 可以通过chatMessageHistory管理查看history
const history = new ChatMessageHistory();
await history.addMessage(new HumanMessage('What is LangChain?'));
await history.addMessage(new AIMessage('I am listening'));
const messages = await history.getMessages();
console.log(messages);
//
[
HumanMessage {
"content": "What is LangChain?",
"additional_kwargs": {},
"response_metadata": {}
},
AIMessage {
"content": "I am listening",
"additional_kwargs": {},
"response_metadata": {},
"tool_calls": [],
"invalid_tool_calls": []
}
]
通过向chain中加入history,模型的回答就可以具备上下文关联的能力。
// model: ollama
const history = new ChatMessageHistory();
const prompt = ChatPromptTemplate.fromMessages([
'system',
'You are a helpful assistant that helps users.',
new MessagesPlaceholder('history_message'),
['human', '${input}'],
]);
const chain = prompt.pipe(ollama);
// 使用RunnableWithMessageHistory,为chain添加memory能力
const chainWithHistory = new RunnableWithMessageHistory({
runnable: chain,
getMessageHistory: (sessionId) => history,
inputMessagesKey: 'input',
historyMessagesKey: 'history_message',
});
// 需要指定sessionId
const res1 = await chainWithHistory.invoke(
{
input: 'It is raining, tell me something about rain',
},
{
configurable: { sessionId: 'test' },
}
);
// res1 - I'd be happy to chat with you about rain.
// 指定同一个session
const res2 = await chainWithHistory.invoke(
{
input: 'What is the weather like?',
},
{
configurable: { sessionId: 'test' },
}
);
// res2 - It's raining outside! But don't worry,
memory
LLM模型是无状态的,每次API调用都是独立的。借助代码和历史消息,这些上下文内容可以作为一种记忆存储,加入到LLM模型的输入中,模型可以从记忆中获取反馈并适应用户的倾向性。
在langchain中可以用BufferMemory获取到存储内容。
const memory = new BufferMemory();
// 在对话chain中传入memory即可
const chain = new ConversationChain({ llm: ollama, memory, verbose: true });
const res1 = await chain.call({ input: 'It is rainging now' });
const res2 = await chain.call({ input: 'What is the weather like?' });
// 开启verbose日志,可以看到langchain设置的prompt中会将对话记录也传入进去
"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.\n\nCurrent conversation:\n\nHuman: It is rainging now\nAI:"
随着对话进行越来越多,需要传入的信息也越来越多,甚至超出模型限制的token长度,加上如果对话内容的主题过于分散,也会降低模型的注意力。解决这一问题,可以尝试以下几个思路。
- 使用另一种记忆存储形式,
ConversationBufferWindowMemory,思路是根据输入的窗口大小,只记忆固定窗口内的上下文内容,窗口外的信息会被丢掉。
// 设置窗口大小为1,每次输入只包含上一个对话的内容
const memory = new BufferWindowMemory({ k: 1 });
const chain = new ConversationChain({ llm: ollama, memory, verbose: true });
const res = await chain.call({
input: 'It is rainging now. I am planning to go outside.',
});
const res1 = await chain.call({ input: 'What is the weather like?' });
// 第一次对话中planning的内容已经没有了,所以模型并没有回答出正确结果
const res2 = await chain.call({
input: 'What I am going to do?',
});
- 记忆范围为所有的对话内容,但会将其转换为摘要进行记忆,对应使用的memory是
ConversationSummaryBufferMemory
const memory = new ConversationSummaryMemory({
memoryKey: 'summary',
llm: ollama,
});
const prompt = PromptTemplate.fromTemplate(`
Your are a assistant.
{summary}
Huname:{input}
AI:
`);
const chain = new ConversationChain({
llm: ollama,
memory,
prompt,
verbose: true,
});
const res = await chain.call({
input: 'It is rainging now. I am planning to go outside.',
});
const res1 = await chain.call({ input: 'What is the weather like?' });
// res1
"input": "What is the weather like?",
"summary": "Current summary:\nThe human wants to go outside but it's raining.\n\nNew lines of conversation remain the same:\n\nHuman: It is rainging now. I am planning to go outside.\nAI: I wouldn't recommend going outside in the rain unless you have an umbrella or waterproof gear. The rain might make your journey uncomfortable and potentially slippery. Would you like some suggestions on how to stay dry while still enjoying the outdoors?\n\nNew summary:\nThe human wants to go outside but it's raining, so the AI recommends bringing an umbrella or waterproof gear to avoid discomfort and potential slips."