一架梯子,一头程序猿,仰望星空!
LangChain教程(JS版本) > 内容正文

Langchain快速入门


快速入门

LangChain 是一个基于语言模型开发应用程序的框架。它能够实现以下功能:

  • 数据感知:将语言模型与其他数据源连接起来
  • 主动性:允许语言模型与其环境进行交互

LangChain 的主要核心价值是:

  1. 组件化:针对使用语言模型的抽象进行开发,配备了每种抽象的一系列实现。无论你是否使用其余的 LangChain 框架,组件都是模块化且易于使用的。
  2. 现成的链路:由一组组件构成的结构化组合,用于完成特定的高级任务。

现成的链路使得快速上手变得容易。对于更复杂的应用程序和细微的使用场景,组件使得定制现有链路或构建新链路变得简单。

安装

要安装 LangChain,请执行以下命令:

npm install -S langchain

yarn add langchain

pnpm add langchain

更多详细信息,请参阅我们的安装指南。

环境设置

使用 LangChain 通常需要与一个或多个模型提供商、数据存储、API 等进行整合。在本示例中,我们将使用 OpenAI 的模型 API。

要访问其 API,您需要一个 API 密钥。您可以通过创建帐户并前往这里获取。一旦我们获得了密钥,我们就可以通过运行以下命令将其设置为环境变量:

export OPENAI_API_KEY="..."

如果您不想设置环境变量,可以直接通过 openAIApiKey 参数将密钥传递给初始化 OpenAI LLM 类:

import { OpenAI } from "langchain/llms/openai";

const llm = new OpenAI({
  openAIApiKey: "YOUR_KEY_HERE",
});

构建应用程序

现在我们可以开始构建我们的语言模型应用程序了。LangChain 提供了许多模块,用于构建语言模型应用程序。模块可以在简单应用程序中作为独立模块使用,并可以在更复杂的用例中进行组合使用。

语言模型(LLMs)

从语言模型获取预测结果

LangChain 的基本构建块是 LLM(Language Model),它接收文本并生成更多的文本。

举个例子,假设我们正在构建一个根据公司描述生成公司名称的应用程序。为了实现这个目标,我们需要初始化一个 OpenAI 模型封装器。在这种情况下,由于我们希望输出结果更加随机,我们将使用一个较高的 temperature 值进行模型的初始化设置。

import { OpenAI } from "langchain/llms/openai";

const llm = new OpenAI({
  temperature: 0.9,
});

现在我们可以传入文本并获取预测结果了!

const result = await llm.predict("What would be a good company name for a company that makes colorful socks?");
// "Feetful of Fun"

聊天模型

聊天模型是一种语言模型的变种。虽然聊天模型在底层使用了语言模型,但它们暴露的接口有些不同:它们不是提供一个“输入文本,输出文本”的API,而是使用“聊天消息”作为输入和输出。

通过向聊天模型传递一个或多个消息,可以获取聊天补全。响应将是一个消息。目前在LangChain中支持的消息类型有AIMessageHumanMessageSystemMessageFunctionMessageChatMessageChatMessage接受一个任意的角色参数。大多数情况下,您只需要处理 HumanMessageAIMessageSystemMessage

import { ChatOpenAI } from "langchain/chat_models/openai";
import { HumanMessage, ChatMessage, SystemMessage } from "langchain/schema";

const chat = new ChatOpenAI({
  temperature: 0
});

const result = await chat.predictMessages([
  new HumanMessage("将这句话从英语翻译成法语。我喜欢编程。")
]);

/*
  AIMessage {
    content: "J'adore la programmation."
  }
*/

了解聊天模型与普通语言模型(LLM)的区别是有用的,但有时简单地将它们视为相同的也很方便。LangChain通过提供一个与普通语言模型相同的接口,让这一点变得容易。可以通过predict接口来使用这个接口与聊天模型交互。

const result = await chat.predict("将这句话从英语翻译成法语。我喜欢编程。")
// "J'adore la programmation."

提示模板

大多数LLM应用程序不会直接将用户输入传递给LLM。通常,它们会将用户输入添加到一个更大的文本片段中,称为提示模板,该模板对具体任务提供了额外的上下文信息。

在前面的示例中,我们传递给模型的文本包含生成公司名称的指令。对于我们的应用程序来说,如果用户只需提供公司/产品的描述,而不必担心给模型指令,那就太好了。

LLMs

有了提示模板,这很容易实现!在这种情况下,我们的模板非常简单:

import { PromptTemplate } from "langchain/prompts";

const prompt = PromptTemplate.fromTemplate("一个制造{product}的公司的好名字是什么?");

const formattedPrompt = await prompt.format({
  product: "多彩袜子"
});
"一个制造多彩袜子的公司的好名字是什么?"

聊天模型

与LLM类似,您可以使用MessagePromptTemplate使用模板。您可以从一个或多个MessagePromptTemplate构建ChatPromptTemplate。您可以使用ChatPromptTemplateformat_messages方法生成格式化的消息。

因为这是生成消息列表,所以与仅生成字符串的普通提示模板相比,它会稍微复杂一些。请查看有关提示的详细指南,了解此处可用的更多选项。

import {
  ChatPromptTemplate,
  SystemMessagePromptTemplate,
  HumanMessagePromptTemplate
} from "langchain/prompts";

const template = "您是一个帮助助手,可以将{input_language}翻译成{output_language}。";
const systemMessagePrompt = SystemMessagePromptTemplate.fromTemplate(template);
const humanTemplate = "{text}";
const humanMessagePrompt = HumanMessagePromptTemplate.fromTemplate(humanTemplate);

const chatPrompt = ChatPromptTemplate.fromPromptMessages([systemMessagePrompt, humanMessagePrompt]);

const formattedPrompt = await chatPrompt.formatMessages({
  input_language: "英语",
  output_language: "法语",
  text: "我喜欢编程。"
});
/*
  [
    SystemMessage {
      content: '您是一个帮助助手,可以将英语翻译成法语。'
    },
    HumanMessage {
      content: '我喜欢编程。'
    }
  ]
*/

既然我们已经有了一个模型和一个提示模板,我们就想要将两者结合起来。链(Chains)为我们提供了一种将多个基元(如模型、提示和其他链)链接在一起的方式。

LLMs

最简单和最常见的链条类型是LLMChain,它首先将输入传递给PromptTemplate,然后再传递给LLM。我们可以使用现有的模型和prompt模板构建一个LLM链条。

使用LLM链条,我们可以用下面的代码来替换原来的代码:

import { OpenAI } from "langchain/llms/openai";
import { LLMChain } from "langchain/chains";
import { PromptTemplate } from "langchain/prompts";

const llm = new OpenAI({});
const prompt = PromptTemplate.fromTemplate("一个制造{product}的好公司名字是什么?");

const chain = new LLMChain({
  llm,
  prompt
});

// Run是带有一个输入和一个输出的prompt的链条的便捷方法。
const result = await chain.run("丰富多彩的袜子");

结果是:

"充满乐趣的脚"

这就是我们的第一个链条!理解这个简单链条是为了更好地处理更复杂的链条而打下的良好基础。

聊天模型

LLMChain也可以与聊天模型一起使用:

import { ChatOpenAI } from "langchain/chat_models/openai";
import { LLMChain } from "langchain/chains";
import {
  ChatPromptTemplate,
  SystemMessagePromptTemplate,
  HumanMessagePromptTemplate
} from "langchain/prompts";

const template = "你是一个有帮助的助手,将{input_language}翻译成{output_language}。";
const systemMessagePrompt = SystemMessagePromptTemplate.fromTemplate(template);
const humanTemplate = "{text}";
const humanMessagePrompt = HumanMessagePromptTemplate.fromTemplate(humanTemplate);

const chatPrompt = ChatPromptTemplate.fromPromptMessages([systemMessagePrompt, humanMessagePrompt]);

const chat = new ChatOpenAI({
  temperature: 0,
});

const chain = new LLMChain({
  llm: chat,
  prompt: chatPrompt,
});

const result = await chain.call({
  input_language: "英语",
  output_language: "法语",
  text: "我喜欢编程",
});

结果是:

// { text: "J'adore programmer" }

代理(Agents)

我们之前的链条是运行预定的一系列步骤。为了处理复杂的工作流程,我们需要根据输入动态选择动作。

代理正是用来实现这个功能的:它们使用一个语言模型来决定要采取的动作和顺序。代理可以访问工具,并且它们可以重复选择工具、运行工具和观察输出,直到得出最终答案。

要加载一个代理,你需要选择以下内容:

  • LLM/聊天模型:为代理提供动力的语言模型。
  • 工具(Tools):执行特定任务的函数。这可以是各种功能,比如:谷歌搜索、数据库查询、Python REPL和其他链条等。有关预定义工具和其规格的列表,请参阅Tools文档。
  • 代理名称:一个字符串,用来引用支持的代理类。代理类在很大程度上由语言模型用来确定采取哪个动作来参数化。因为这篇笔记只涵盖使用标准支持代理的最简单、最高级别的API的用法。如果你想实现自定义代理,请参阅这里。有关支持的代理及其规格的列表,请参阅这里。

在本例中,我们将使用SerpAPI来查询搜索引擎。

你需要设置SERPAPI_API_KEY环境变量。

LLMs(语言模型)

import { initializeAgentExecutorWithOptions } from "langchain/agents";
import { OpenAI } from "langchain/llms/openai";
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(),
];

const executor = await initializeAgentExecutorWithOptions(tools, model, {
  agentType: "zero-shot-react-description",
  verbose: true,
});

const input = "What was the high temperature in SF yesterday in Fahrenheit? What is that number raised to the .023 power?";

const result = await executor.call({
  input,
});
> 进入新的AgentExecutor链...

思路: 首先我需要查找温度, 然后使用计算器将其提升到0.023的幂.
操作: 搜索
操作输入: "昨天旧金山的高温"
观察结果: 旧金山昨天的温度。昨天最高温度:57°F(下午1:56)昨天最低温度:49°F(上午1:56)昨天平均温度...

思路: 现在我有了温度值,所以我可以使用计算器将其提高到0.023的幂。
操作: 计算器
操作输入: 57^.023
观察结果: 答案:1.0974509573251117

思路: 我现在知道了最终答案
最终答案: 1.0974509573251117.

> 完成链条.
// { output: "1.0974509573251117" }

聊天模型

代理程序也可以与聊天模型一起使用。有几种使用场景,但如果使用OpenAI和具备函数功能的模型,您可以将openai-functions作为代理程序类型。

import { initializeAgentExecutorWithOptions } from "langchain/agents";
import { ChatOpenAI } from "langchain/chat_models/openai";
import { SerpAPI } from "langchain/tools";
import { Calculator } from "langchain/tools/calculator";

const executor = await initializeAgentExecutorWithOptions(
  [new Calculator(), new SerpAPI()],
  new ChatOpenAI({ modelName: "gpt-4-0613", temperature: 0 }),
  {
    agentType: "openai-functions",
    verbose: true,
  }
);

const result = await executor.run("New York的温度是多少?");
/*
  {
    "output": "纽约当前的温度是89°F,但体感温度为92°F。请注意,由于高温可能导致脱水或中暑,请小心。"
  }
*/

内存​

迄今为止,我们所看到的链条和代理程序都是无状态的,但对于许多应用程序来说,参考过去的交互是必要的。例如,聊天机器人需要在过去信息的上下文中理解新消息。

内存模块为您提供了一种维护应用程序状态的方式。基本的内存接口很简单:它允许您根据最新的运行输入和输出来更新状态,并允许您使用存储的状态修改(或上下文化)下一个输入。

内置的内存系统有很多种。其中最简单的是缓冲区内存,它只需将最近的几个输入/输出添加到当前输入的前面-我们将在下面的示例中使用这种方式。

LLMs

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,
  verbose: true,
});
const res1 = await chain.call({ input: "Hi! I'm Jim." });

这里是底层发生的事情

> 进入新的链...
格式化后的提示信息:
以下是一个友好对话,一个人和一个AI之间的对话。 AI健谈,提供来自其上下文的许多具体细节。 如果AI不知道问题的答案,它会坦率地说它不知道。

当前对话:

人类:嗨!你好!
AI:

> 链接完成。

>> '你好!你今天好吗?'

现在我们再次运行链式调用

const res2 = await chain.call({ input: "我的名字是什么?" });

我们将看到传递给模型的完整提示信息包含了我们第一次交互的输入和输出,以及我们最新的输入

> 进入新的链...
格式化后的提示信息:
以下是一个友好对话,一个人和一个AI之间的对话。 AI健谈,提供来自其上下文的许多具体细节。 如果AI不知道问题的答案,它会坦率地说它不知道。

当前对话:

人类:嗨!你好!
AI: 你好!你今天好吗?
人类:我过得很好!只是和一个AI聊天。
AI:

> 链接完成。

>> "你的名字是Jim。"

Chat模型

您可以在使用Chat模型初始化的链式调用和代理中使用Memory。它与LLMs的Memory之间的主要区别在于,我们可以将它们保留为其自己独特的内存对象,而不是试图将所有先前的消息压缩成一个字符串。

import { ConversationChain } from "langchain/chains";
import { ChatOpenAI } from "langchain/chat_models/openai";
import {
  ChatPromptTemplate,
  HumanMessagePromptTemplate,
  SystemMessagePromptTemplate,
  MessagesPlaceholder,
} from "langchain/prompts";
import { BufferMemory } from "langchain/memory";

const chat = new ChatOpenAI({ temperature: 0 });

const chatPrompt = ChatPromptTemplate.fromPromptMessages([
  SystemMessagePromptTemplate.fromTemplate(
    "以下是一个友好对话,一个人和一个AI之间的对话。 AI健谈,提供来自其上下文的许多具体细节。 如果AI不知道问题的答案,它会坦率地说它不知道。"
  ),
  new MessagesPlaceholder("history"),
  HumanMessagePromptTemplate.fromTemplate("{input}"),
]);

// 将当前对话直接作为消息返回,并将其插入上面提示中的MessagesPlaceholder中。
const memory = new BufferMemory({
  returnMessages: true,
  memoryKey: "history"
});

const chain = new ConversationChain({
  memory,
  prompt: chatPrompt,
  llm: chat,
  verbose: true,
});

const res = await chain.call({
  input: "我的名字是Jim。",
});
你好Jim!很高兴认识你。今天我能帮你什么忙吗?
const res2 = await chain.call({
  input: "我的名字是什么?",
});
你的名字是Jim。你在我们对话的开始提到了它。Jim,有什么具体的问题或讨论吗?


关联主题