大模型本身是无状态的,每次调用都只看当前输入。如果要在多轮对话中维持上下文,就需要 Memory 模块来存储和管理对话历史。
LangChain.js 针对 Memory 提供了多个工具类,先来学习最常用的 ChatMessageHistory
快速上手案例:
import { ChatMessageHistory } from "@langchain/classic/stores/message/in_memory";
import { HumanMessage, AIMessage } from "@langchain/core/messages";const history = new ChatMessageHistory();await history.addMessage(new HumanMessage("你好,我叫小明"));
await history.addMessage(new AIMessage("你好,小明!有什么我可以帮助你的吗?"));const messages = await history.getMessages();
messages.forEach((msg, i) => {const role = HumanMessage.isInstance(msg)? "用户": AIMessage.isInstance(msg)? "AI": "❓ Unknown";console.log(`[${i + 1}] ${role} ➜ ${msg.content}`);
});
常用方法
文档:https://v03.api.js.langchain.com/classes/_langchain_core.chat_history.BaseChatMessageHistory.html
addMessage:添加消息addMessages:添加消息getMessages:获取所有消息clear:清除所有消息
实战案例
和大模型进行对话,大模型可以记住前面的对话内容
stream() 方法,方法签名如下:
stream(input: Input,options?: RunnableConfig
): AsyncGenerator<StreamEvent<Output>>
1. 输入参数 (input)
类型:Input
与 invoke() 方法保持一致:
-
如果是 LLM:可以传字符串、
BaseMessage、BaseMessage[]const model = new Ollama(model: "llama3"); model.stream("你好"); -
如果是 Chain / Runnable:则是该 Chain 约定的输入对象(例如
{ input: "..." }) -
如果是 Embeddings:通常是字符串或字符串数组
换句话说,input 的类型由具体的 Runnable 实例 决定。
2. 配置参数
类型:RunnableConfig(可选)
常见字段包括:
configurable:运行时传入的上下文配置(例如用户 ID、对话 ID,用于内存/持久化关联)。tags:给运行标记,用于调试、Tracing。metadata:附加元信息,方便日志或监控。callbacks:传入回调函数(如handleLLMNewToken等),可用于实时处理 token。maxConcurrency:并发控制。timeout:超时设置。
-EOF-