LangChain 快速入门
LangChain 是使用语言模型开发应用的框架。通常应用不仅通过 API 调用大语言模型,同时还需要:
数据意识:将语言模型连接到其他数据源
代理性:让语言模型可以和环境交互。 以上是 LangChain 的设计原则。
组件说明
以下是根据复杂度的顺序的组件列表:
Schema: 包括整个库中使用的接口和基类。
Models: 包括各种LLMs、聊天模型和嵌入模型的整合。
Prompts: 包括提示模板和与提示有关的功能,如输出解析器和实例选择器。
Indexes: 包括处理你自己的数据的模式和功能,使其准备好与语言模型(包括文档加载器、矢量存储、文本分割器和检索器)互动。
Memory: 内存是指在链/代理的调用之间保持状态。LangChain提供了一个内存的标准接口,一个内存实现的集合,以及使用内存的链/代理的例子。
Chains: 链超越了单一的LLM调用,是一系列的调用(无论是对LLM还是不同的工具)。LangChain为链提供了一个标准接口,与其他工具进行了大量的整合,并为常见的应用提供了端到端的链。
Agents: 代理使用LLM决定采取哪种行动,并观察结果,并重复该行动直到完成任务。LangChain提供了一个标准的代理接口,提供了一些可供选择的代理,以及端到端的代理实例。
快速入门
一、安装和设置
需要 Node.js (ESM and CommonJS) - 18.x, 19.x, 20.x
可以 clone starter 仓库 https://github.com/domeccleston/langchain-ts-starter
npm install -S langchain
二、构建一个语言模型的的应用
假设我们正在构建一个根据公司产品生成公司名的应用。
首先我们导入 OpenAI 的 LLM wrapper。
import { OpenAI } from "langchain/llms/openai";
使用 OpenAI 我们需要配置 OPENAI_API_KEY,我们可以在 .env
文件中配置然后使用 dotenv
包来读取。
OPENAI_API_KEY="..."
或者通过直接在 shell 中导出环境变量。
export OPENAI_API_KEY=sk-....
也可以直接在代码中初始化。
const model = new OpenAI({
openAIApiKey: "sk-...", // 如果用上面的方法配置了,这个参数可以省略
temperature: 0.9
});
然后我们就可以使用模型的预测能力:
const res = await model.call(
"What would be a good company name a company that makes colorful socks?"
);
console.log(res);
输出:
Rainbow Toes
三、Prompt Templates:管理提示词
通常情况不会直接把用户的输入发送给LLM,而是使用用户的输入构建提示词,再发送给LLM。
比如说,上面的那个例子里,我们只需要用户输入公司的产品,然后用这个信息再构建提示词。
我们首先定义提示词模版:
import { PromptTemplate } from "langchain/prompts";
const template = "What is a good name for a company that makes {product}?";
const prompt = new PromptTemplate({
template: template,
inputVariables: ["product"],
});
然后再传入product:
const res = await prompt.format({ product: "colorful socks" });
console.log(res);
完整代码示例:
import { OpenAI } from "langchain/llms/openai";
import { PromptTemplate } from "langchain/prompts";
const model = new OpenAI({ temperature: 0.9, modelName: 'gpt-3.5-turbo' });
const template = "What is a good name for a company that makes {product}?";
const prompt = new PromptTemplate({
template: template,
inputVariables: ["product"],
});
async function main() {
const promptFormated = await prompt.format({ product: "colorful socks" });
console.log(promptFormated)
const res = await model.call(promptFormated);
console.log(res);
}
main()
输出:
What is a good name for a company that makes colorful socks?
四、Chains:在多步骤工作流中将 LLMs 和提示词结合起来
LangChain 的 Chain 是由 links 组成的,link 可以是基本的 LLMs 或者其他 chain。最核心的是由 PromptTemplate 和 LLM 组成的 LLMChain。
import { LLMChain } from "langchain/chains";
const chain = new LLMChain({ llm: model, prompt: prompt });
const res = await chain.call({ product: "colorful socks" });
console.log(res);
完整代码示例:
import { OpenAI } from "langchain/llms/openai";
import { PromptTemplate } from "langchain/prompts";
const model = new OpenAI({ temperature: 0.9, modelName: 'gpt-3.5-turbo' });
const template = "What is a good name for a company that makes {product}?";
const prompt = new PromptTemplate({
template: template,
inputVariables: ["product"],
});
const chain = new LLMChain({ llm: model, prompt: prompt });
async function main() {
const res = await chain.call({ product: "colorful socks" });
console.log(res);
}
main()
五、Agents:根据用户的输入动态地选择 Chain 运行
Agent 可以使用 LLM 来决定按哪种顺序采取哪个 aciton,一个 action 可以使用一种 tool 并观察它的输出,或者返回给用户。
下面是需要理解的概念:
Tool:完成特定任务的函数,比如在网上搜索,在数据库里查询,执行代码,或者其他的 Chain。tool 的接口接受字符串作为输入,字符串作为输出。
LLM:Agent使用的大语言模型。
Agent:使用的代理,
我们这个例子中使用 SerpAPI 来调用 Google Search API,在 .env
文件中配置环境变量:
SERPAPI_API_KEY="..."
安装 serpapi
包:
npm install -S serpapi
完整代码示例:
import { OpenAI } from "langchain/llms/openai";
import { initializeAgentExecutorWithOptions } from "langchain/agents";
import { SerpAPI } from "langchain/tools";
import { Calculator } from "langchain/tools/calculator";
const model = new OpenAI({ temperature: 0 });
const tools = [
new SerpAPI(process.env.SERPAPI_API_KEY, {
location: "Austin,Texas,United States",
hl: "en",
gl: "us",
}),
new Calculator(),
];
async function main() {
const executor = await initializeAgentExecutorWithOptions(tools, model, {
agentType: "zero-shot-react-description",
});
console.log("Loaded agent.");
const input =
"Who is Olivia Wilde's boyfriend?" +
" What is his current age raised to the 0.23 power?";
console.log(`Executing with input "${input}"...`);
const result = await executor.call({ input });
console.log(`Got output ${result.output}`);
}
main()
六、Memory:给 Chain 和 Agent 添加状态
之前的 chain 和 agent 都是无状态的。你常常希望 chain 或者 agent 有它之前交互的记忆,最简单的就是设计聊天机器人的时候,希望它记住以前的对话,这样可以根据上下文更好的对话,这是一种“短期记忆”。你还会希望chain和agent随着时间能够记住关键信息,一种“长期记忆”。
LangChain 提供了几个专门的 Chain,下面将介绍 ConversationChain。
ConversationChain 默认有一个简单的内存类型,可以记住以前所有的输入/输出,并将它们添加到传递的上下文中国呢,让我们来看看如何使用这个链。
import { OpenAI } from "langchain/llms/openai";
import { BufferMemory } from "langchain/memory";
import { ConversationChain } from "langchain/chains";
const model = new OpenAI({});
const memory = new BufferMemory();
const chain = new ConversationChain({ llm: model, memory: memory });
async function main() {
const res = await chain.call({ input: "Hi! I'm Jim." });
console.log(res);
}
main()
七、Streaming
可以通过 streaming API 来逐个获取生成的单词。
import { OpenAI } from "langchain/llms/openai";
const chat = new OpenAI({
streaming: true,
callbacks: [
{
handleLLMNewToken(token: string) {
process.stdout.write(token);
},
},
],
});
async function main() {
await chat.call("Write me a song about sparkling water.");
}
main()
八、Chat Models
Chat models 是语言模型的一个变种,虽然Chat Models也是用 LLM,但是暴露的接口有一些不一样,不是暴露 “text in, text out“ API,而是暴露一个 Chat Messages 的输入输出。
import { ChatOpenAI } from "langchain/chat_models/openai";
import { HumanChatMessage, SystemChatMessage } from "langchain/schema";
const chat = new ChatOpenAI({ temperature: 0 });
async function main() {
const response = await chat.call([
new HumanChatMessage(
"Translate this sentence from English to French. I love programming."
),
]);
console.log(response);
}
main()
输出:
AIChatMessage { text: "J'aime programmer.", name: undefined }
OpenAI基于聊天的模型(目前是gpt-3.5-turbo和gpt-4)支持多条消息作为输入。下面是一个向聊天模型发送系统和用户消息的例子:
import { ChatOpenAI } from "langchain/chat_models/openai";
import { HumanChatMessage, SystemChatMessage } from "langchain/schema";
const chat = new ChatOpenAI({ temperature: 0 });
async function main() {
const responseB = await chat.call([
new SystemChatMessage(
"You are a helpful assistant that translates English to French."
),
new HumanChatMessage("Translate: I love programming."),
]);
console.log(response);
}
main()
你可以更进一步生成多组消息的补全。这将返回一个带有额外消息参数的LLMResult。
import { ChatOpenAI } from "langchain/chat_models/openai";
import { HumanChatMessage, SystemChatMessage } from "langchain/schema";
const chat = new ChatOpenAI({ temperature: 0 });
async function main() {
const response = await chat.generate([
[
new SystemChatMessage(
"You are a helpful assistant that translates English to French."
),
new HumanChatMessage(
"Translate this sentence from English to French. I love programming."
),
],
[
new SystemChatMessage(
"You are a helpful assistant that translates English to French."
),
new HumanChatMessage(
"Translate this sentence from English to French. I love artificial intelligence."
),
],
]);
console.log(JSON.stringify(response, null, 2));
}
main()
输出:
{
"generations": [
[
{
"text": "J'aime programmer.",
"message": {
"type": "ai",
"data": {
"content": "J'aime programmer."
}
}
}
],
[
{
"text": "J'aime l'intelligence artificielle.",
"message": {
"type": "ai",
"data": {
"content": "J'aime l'intelligence artificielle."
}
}
}
]
],
"llmOutput": {
"tokenUsage": {
"completionTokens": 16,
"promptTokens": 73,
"totalTokens": 89
}
}
}
使用 Chat Prompt Templates:
import { ChatOpenAI } from "langchain/chat_models/openai";
import { HumanChatMessage, SystemChatMessage } from "langchain/schema";
import {
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
ChatPromptTemplate,
} from "langchain/prompts";
const chat = new ChatOpenAI({ temperature: 0 });
const translationPrompt = ChatPromptTemplate.fromPromptMessages([
SystemMessagePromptTemplate.fromTemplate(
"You are a helpful assistant that translates {input_language} to {output_language}."
),
HumanMessagePromptTemplate.fromTemplate("{text}"),
]);
async function main() {
const response = await chat.generatePrompt([
await translationPrompt.formatPromptValue({
input_language: "English",
output_language: "French",
text: "I love programming.",
}),
]);
console.log(JSON.stringify(response, null, 2));
}
main()
输出:
{
"generations": [
[
{
"text": "J'adore la programmation.",
"message": {
"type": "ai",
"data": {
"content": "J'adore la programmation."
}
}
}
]
],
"llmOutput": {
"tokenUsage": {
"completionTokens": 8,
"promptTokens": 28,
"totalTokens": 36
}
}
}
Model + Prompt = LLMChain:
import { ChatOpenAI } from "langchain/chat_models/openai";
import { LLMChain } from "langchain/chains";
import {
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
ChatPromptTemplate,
} from "langchain/prompts";
const chat = new ChatOpenAI({ temperature: 0 });
const translationPrompt = ChatPromptTemplate.fromPromptMessages([
SystemMessagePromptTemplate.fromTemplate(
"You are a helpful assistant that translates {input_language} to {output_language}."
),
HumanMessagePromptTemplate.fromTemplate("{text}"),
]);
const chain = new LLMChain({
prompt: translationPrompt,
llm: chat,
});
async function main() {
const response = await chain.call({
input_language: "English",
output_language: "French",
text: "I love programming.",
});
console.log(JSON.stringify(response, null, 2));
}
main()
输出:
{
"text": "J'adore la programmation."
}
使用 Agents:
import { ChatOpenAI } from "langchain/chat_models/openai";
import { SerpAPI } from "langchain/tools";
import { ChatAgent, AgentExecutor } from "langchain/agents"
const chat = new ChatOpenAI({ temperature: 0 });
// Define the list of tools the agent can use
const tools = [
new SerpAPI(process.env.SERPAPI_API_KEY, {
location: "Austin,Texas,United States",
hl: "en",
gl: "us",
}),
];
// Create the agent from the chat model and the tools
const agent = ChatAgent.fromLLMAndTools(chat, tools);
// Create an executor, which calls to the agent until an answer is found
const executor = AgentExecutor.fromAgentAndTools({ agent, tools });
async function main() {
const response = await executor.run(
"How many people live in canada as of 2023?"
);
console.log(response);
}
main()
输出:
The estimated population of Canada as of January 1, 2023 is 39,566,248.
使用 Memory 给 chain 和 agent 添加状态:
import { ChatOpenAI } from "langchain/chat_models/openai";
import { ConversationChain } from "langchain/chains";
import { BufferMemory } from "langchain/memory";
import {
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
ChatPromptTemplate,
MessagesPlaceholder
} from "langchain/prompts";
const chat = new ChatOpenAI({ temperature: 0 });
const chatPrompt = ChatPromptTemplate.fromPromptMessages([
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}"),
]);
const chain = new ConversationChain({
memory: new BufferMemory({ returnMessages: true, memoryKey: "history" }),
prompt: chatPrompt,
llm: chat,
});
async function main() {
const responseH = await chain.call({
input: "hi from London, how are you doing today",
});
console.log(responseH);
const responseI = await chain.call({
input: "Do you know where I am?",
});
console.log(responseI);
}
main()
输出:
{
response: "Hello! As an AI language model, I don't have feelings, but I'm functioning properly and ready to assist you with any questions or tasks you may have. How can I help you today?"
}
{
response: "Yes, you mentioned that you are from London. However, as an AI language model, I don't have access to your current location unless you provide me with that information."
}