Langchain 教程

LangChain 是一个用于开发大规模语言模型(LLM)应用程序的框架。

LangChain 简化了 LLM 应用程序生命周期的每个阶段,让你轻松构建复杂的 Ai 应用程序。

LangChain 官方文档:https://js.langchain.com/open in new window

快速开始

一个简单的例子

import { ChatOpenAI } from "@langchain/openai"; // 导入 ChatOpenAI 类,用于与 OpenAI 模型进行交互
import { HumanMessage, SystemMessage } from "@langchain/core/messages"; // 导入 HumanMessage 和 SystemMessage 类,用于创建消息对象
import { StringOutputParser } from "@langchain/core/output_parsers"; // 导入 StringOutputParser 类,用于解析模型输出

// 创建一个新的 ChatOpenAI 实例,配置模型和 API 密钥
const model = new ChatOpenAI({
	model: "xxx", // 指定要使用的模型
	apiKey: "xxx", // 指定用于身份验证的 API 密钥
	configuration: {
		baseURL: "xxx" // 指定模型的基本 URL
	}
});

// 创建一个消息数组,其中包含系统消息和人类消息
const messages = [
	new SystemMessage("你是一个智能助理,你的名字叫小酷"), // 创建系统消息,设置助理的角色和名称
	new HumanMessage("你好,你是谁?") // 创建人类消息,模拟用户输入
];

// 调用模型的 invoke 方法,传递消息数组并等待结果
let result = await model.invoke(messages);

// 创建一个新的 StringOutputParser 实例,用于解析模型的输出
const parser = new StringOutputParser();

// 调用解析器的 invoke 方法,传递模型结果并等待解析后的结果
const res = await parser.invoke(result);

// 输出解析后的结果到控制台
console.log(result); // 输出:你好,我是小酷,我是一个智能助理

解析器

如: OutputParsers 是一个输出解析器,用于解析模型的输出

// 创建一个新的 StringOutputParser 实例,用于解析模型的输出
const parser = new StringOutputParser();

// 调用解析器的 invoke 方法,传递模型结果并等待解析后的结果
result = await parser.invoke(result);

// 输出解析后的结果到控制台
console.log(result); // 输出:你好,我是小酷,我是一个智能助理

采用 chain 链的方式

这种方式看起来更加直观,像流水线一样

// ...

// 使用管道操作将模型输出连接到解析器
const chain = model.pipe(parser);

// 调用链的 invoke 方法,传递消息数组并等待结果
const result = await chain.invoke(messages);

// 输出解析后的结果到控制台
console.log(result);

提示词模板

LangChain 提供了一种简单的方式来创建提示词模板,以便更好地控制模型的输出

// 定义系统消息模板
const systemTemplate = "你是一个智能助理,你的名字叫:{name}:";

// 创建一个聊天提示模板,从系统消息和用户消息创建
const promptTemplate = ChatPromptTemplate.fromMessages([
	["system", systemTemplate], // 系统消息模板
	["user", "{content}"] // 用户消息模板
]);

// 创建一个新的 StringOutputParser 实例,用于解析模型的输出
const parser = new StringOutputParser();

// 使用管道操作将提示模板、模型和解析器连接起来
const chain = promptTemplate.pipe(model).pipe(parser);

// 调用链的 invoke 方法,传递参数对象并等待结果
const result = await chain.invoke({ name: "小酷", content: "你好,你是谁" });

// 输出解析后的结果到控制台
console.log(result);

聊天

简单地构建一个聊天应用程序

上下文历史

有时候聊天需要关联上下文信息,LangChain 提供了一种简单的方式来处理上下文信息

// 引入所需的模块和配置文件
import { ChatOpenAI } from "@langchain/openai"; // 从langchain库中引入ChatOpenAI类
import { HumanMessage } from "@langchain/core/messages"; // 从langchain库中引入HumanMessage类
import { AIMessage } from "@langchain/core/messages"; // 从langchain库中引入AIMessage类
import config from "../config.json" assert { type: "json" }; // 导入配置文件config.json,并断言其类型为json

// 创建一个ChatOpenAI模型实例,并传入配置信息
const model = new ChatOpenAI({
	model: config.model.name, // 使用配置文件中的模型名称
	apiKey: config.model.apiKey, // 使用配置文件中的API密钥
	configuration: {
		baseURL: config.model.baseURL // 使用配置文件中的API基础URL
	}
});

// 使用invoke方法调用模型,传入一系列对话消息
const result = await model.invoke([
	new HumanMessage({ content: "你好,我叫小酷" }), // 创建一个新的HumanMessage实例,表示用户的消息内容
	new AIMessage({ content: "你好,今天过得怎么样呢?" }), // 创建一个新的AIMessage实例,表示AI的回复内容
	new HumanMessage({ content: "我叫什么" }) // 创建另一个新的HumanMessage实例,表示用户的第二条消息内容
]);

// 将结果输出到控制台
console.log(result); // 打印出模型的回复结果

存储上下文

可以有多种方式来存储上下文信息,比如存储在内存

// 引入所需的模块和配置文件
import { InMemoryChatMessageHistory } from "@langchain/core/chat_history"; // 从langchain库中引入InMemoryChatMessageHistory类
import { ChatPromptTemplate } from "@langchain/core/prompts"; // 从langchain库中引入ChatPromptTemplate类
import { ChatOpenAI } from "@langchain/openai"; // 从langchain库中引入ChatOpenAI类
import { RunnableWithMessageHistory } from "@langchain/core/runnables"; // 从langchain库中引入RunnableWithMessageHistory类
import config from "../config.json" assert { type: "json" }; // 导入配置文件config.json,并断言其类型为json

// 创建一个ChatOpenAI模型实例,并传入配置信息
const model = new ChatOpenAI({
	model: config.model.name, // 使用配置文件中的模型名称
	apiKey: config.model.apiKey, // 使用配置文件中的API密钥
	configuration: {
		baseURL: config.model.baseURL // 使用配置文件中的API基础URL
	}
});

// 初始化一个空的消息历史记录对象
const messageHistories = {};

// 创建一个对话提示模板
const prompt = ChatPromptTemplate.fromMessages([
	["system", `你是一个智能助理,你的名字叫小酷`], // 系统消息,设定助手的角色和名字
	["placeholder", "{chat_history}"], // 占位符,用于插入历史对话
	["human", "{input}"] // 用户消息,占位符将被实际的用户输入替代
]);

// 将模型与提示模板链接
const chain = prompt.pipe(model);

// 创建一个带有消息历史记录功能的可运行对象
const withMessageHistory = new RunnableWithMessageHistory({
	runnable: chain, // 指定要运行的链
	getMessageHistory: async (sessionId) => {
		// 获取指定会话ID的消息历史记录
		if (messageHistories[sessionId] === undefined) {
			// 如果没有历史记录,创建一个新的
			messageHistories[sessionId] = new InMemoryChatMessageHistory();
		}
		return messageHistories[sessionId];
	},
	inputMessagesKey: "input", // 指定输入消息的键名
	historyMessagesKey: "chat_history" // 指定历史消息的键名
});

// 配置选项,指定会话ID
const option = {
	configurable: {
		sessionId: "cool" // 会话ID为"cool"
	}
};

// 调用带有消息历史记录的可运行对象,传入用户输入
const result = await withMessageHistory.invoke(
	{ input: "你好,你是谁" }, // 第一次用户输入
	option // 使用配置选项
);

// 再次调用带有消息历史记录的可运行对象,传入新的用户输入
const result1 = await withMessageHistory.invoke(
	{ input: "我刚才问什么" }, // 第二次用户输入
	option // 使用相同的配置选项
);

// 将第二次调用的结果输出到控制台
console.log(result1); // 打印出模型的回复结果

管理上下文

由于大模型的限制,你不能一次性传入太多的历史消息,会导致上下文窗口溢出,因此需要管理上下文

import { ChatOpenAI } from "@langchain/openai"; // 引入 ChatOpenAI 类,用于与 OpenAI 的聊天模型交互
import { RunnablePassthrough, RunnableSequence } from "@langchain/core/runnables"; // 引入 RunnablePassthrough 和 RunnableSequence 类,用于创建可运行的序列
import { HumanMessage, AIMessage } from "@langchain/core/messages"; // 引入 HumanMessage 和 AIMessage 类,用于创建人类和 AI 消息
import config from "../config.json" assert { type: "json" }; // 导入配置文件,包含模型名称和 API 密钥
import { ChatPromptTemplate } from "@langchain/core/prompts"; // 引入 ChatPromptTemplate 类,用于创建聊天提示模板

// 创建一个 ChatOpenAI 实例,用于与 OpenAI 模型交互
const model = new ChatOpenAI({
	model: config.model.name, // 从配置文件中获取模型名称
	apiKey: config.model.apiKey, // 从配置文件中获取 API 密钥
	configuration: {
		baseURL: config.model.baseURL // 从配置文件中获取模型的基础 URL
	}
});

// 创建一个对话提示模板
const prompt = ChatPromptTemplate.fromMessages([
	["system", `你是一个智能助理`], // 系统消息,设定助手的角色和名字
	["placeholder", "{chat_history}"], // 占位符,用于插入历史对话
	["human", "{input}"] // 用户消息,占位符将被实际的用户输入替代
]);

// 过滤消息,只保留最近的 10 条对话记录
const filterMessages = (data) => {
	return data.chat_history.slice(-10);
};

// 创建一个可运行的序列,包括消息过滤、提示模板和模型调用
const chain = RunnableSequence.from([
	RunnablePassthrough.assign({
		chat_history: filterMessages // 过滤消息
	}),
	prompt, // 应用提示模板
	model // 调用模型
]);

// 创建一些示例消息
const messages = [
	new HumanMessage({ content: "你好!我是小酷" }), // 人类消息
	new AIMessage({ content: "你好!" }), // AI 消息
	new HumanMessage({ content: "我喜欢香草冰淇淋" }), // 人类消息
	new AIMessage({ content: "不错" }), // AI 消息
	new HumanMessage({ content: "2 + 2 等于多少" }), // 人类消息
	new AIMessage({ content: "4" }), // AI 消息
	new HumanMessage({ content: "谢谢" }), // 人类消息
	new AIMessage({ content: "没问题!" }), // AI 消息
	new HumanMessage({ content: "玩得开心吗?" }), // 人类消息
	new AIMessage({ content: "是的!" }), // AI 消息
	new HumanMessage({ content: "那太好了!" }), // 人类消息
	new AIMessage({ content: "是的,确实如此!" }) // AI 消息
];

// 调用序列,传入历史对话和新的用户输入
const result = await chain.invoke({
	chat_history: messages, // 历史对话
	input: "你叫什么名字?" // 新的用户输入
});

// 输出结果
console.log(result);

流式输出

大模型的推理需要一定的时间,不能让用户等待太久,因此需要流式输出

// 引入所需的模块和配置文件
import { InMemoryChatMessageHistory } from "@langchain/core/chat_history"; // 从langchain库中引入InMemoryChatMessageHistory类
import { ChatPromptTemplate } from "@langchain/core/prompts"; // 从langchain库中引入ChatPromptTemplate类
import { ChatOpenAI } from "@langchain/openai"; // 从langchain库中引入ChatOpenAI类
import { RunnableWithMessageHistory } from "@langchain/core/runnables"; // 从langchain库中引入RunnableWithMessageHistory类
import config from "../config.json" assert { type: "json" }; // 导入配置文件config.json,并断言其类型为json

// 创建一个ChatOpenAI模型实例,并传入配置信息
const model = new ChatOpenAI({
	model: config.model.name, // 使用配置文件中的模型名称
	apiKey: config.model.apiKey, // 使用配置文件中的API密钥
	configuration: {
		baseURL: config.model.baseURL // 使用配置文件中的API基础URL
	}
});

// 初始化一个空的消息历史记录对象
const messageHistories = {};

// 创建一个对话提示模板
const prompt = ChatPromptTemplate.fromMessages([
	["system", `你是一个智能助理,你的名字叫小酷`], // 系统消息,设定助手的角色和名字
	["placeholder", "{chat_history}"], // 占位符,用于插入历史对话
	["human", "{input}"] // 用户消息,占位符将被实际的用户输入替代
]);

// 将模型与提示模板链接
const chain = prompt.pipe(model);

// 创建一个带有消息历史记录功能的可运行对象
const withMessageHistory = new RunnableWithMessageHistory({
	runnable: chain, // 指定要运行的链
	getMessageHistory: async (sessionId) => {
		// 获取指定会话ID的消息历史记录
		if (messageHistories[sessionId] === undefined) {
			// 如果没有历史记录,创建一个新的
			messageHistories[sessionId] = new InMemoryChatMessageHistory();
		}
		return messageHistories[sessionId];
	},
	inputMessagesKey: "input", // 指定输入消息的键名
	historyMessagesKey: "chat_history" // 指定历史消息的键名
});

// 配置选项,指定会话ID
const option = {
	configurable: {
		sessionId: "cool" // 会话ID为"cool"
	}
};

// 调用带有消息历史记录的可运行对象,传入用户输入
const stream = await withMessageHistory.stream(
	{ input: "你好,你是谁" }, // 第一次用户输入
	option // 使用配置选项
);

// 流式输出
for await (const chunk of stream) {
	console.log("|", chunk.content);
}
Last Updated: