快速入门,使用聊天模型
聊天模型是语言模型的一种变体。
虽然聊天模型在内部使用语言模型,但它们公开的接口略有不同。
它们不是公开“文本输入,文本输出”的 API,而是公开一个接口,其中“聊天消息”是输入和输出。
聊天模型 API 相当新,因此我们仍在确定正确的抽象。
安装和设置
要开始使用聊天模型,请按照安装说明安装 LangChain。
入门指南
本节介绍如何开始使用聊天模型。该接口基于消息而不是原始文本。
import { ChatOpenAI } from "langchain/chat_models/openai";
import { HumanChatMessage, SystemChatMessage } from "langchain/schema";
const chat = new ChatOpenAI({ temperature: 0 });
在这里,我们使用存储在环境变量OPENAI_API_KEY
或AZURE_OPENAI_API_KEY
中的 API 密钥创建聊天模型。在本节中,我们将调用此聊天模型。
ⓘ 注意,如果您正在使用 Azure OpenAI,请确保还设置了环境变量
AZURE_OPENAI_API_INSTANCE_NAME
、AZURE_OPENAI_API_DEPLOYMENT_NAME
和AZURE_OPENAI_API_VERSION
。
聊天模型:输入消息,输出消息
您可以通过向聊天模型传递一个或多个消息来获取聊天完成。响应也将是一条消息。目前在 LangChain 中支持的消息类型有 AIChatMessage
、HumanChatMessage
、SystemChatMessage
和通用的 ChatMessage
– ChatMessage 接受一个任意的角色参数,这里我们不会使用。大多数情况下,您只需要处理 HumanChatMessage
、AIChatMessage
和 SystemChatMessage
。
const response = await chat.call([
new HumanChatMessage(
"Translate this sentence from English to French. I love programming."
),
]);
console.log(response);
AIChatMessage { text: "J'aime programmer." }
多条消息
OpenAI 的基于聊天的模型(目前为 gpt-3.5-turbo
和 gpt-4
,在 Azure OpenAI 的情况下为 gpt-4-32k
)支持多条消息作为输入。有关更多信息,请参见此处。以下是向聊天模型发送系统和用户消息的示例:
ⓘ 注意,如果您正在使用 Azure OpenAI,请确保将部署名称更改为您选择的模型的部署名称。
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(responseB);
AIChatMessage { text: "J'aime programmer." }
多个完成
您可以更进一步,使用 generate 为多组消息生成完成。这将返回一个带有额外消息参数的 LLMResult。
const responseC = 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(responseC);
{
generations: [
[
{
text: "J'aime programmer.",
message: AIChatMessage { text: "J'aime programmer." },
}
],
[
{
text: "J'aime l'intelligence artificielle.",
message: AIChatMessage { text: "J'aime l'intelligence artificielle." }
}
]
]
}
聊天提示模板:管理聊天模型的提示
您可以使用 MessagePromptTemplate
使用模板。您可以从一个或多个 MessagePromptTemplates
构建一个 ChatPromptTemplate
。您可以使用 ChatPromptTemplate
的 formatPromptValue
– 这将返回一个 PromptValue
,您可以将其转换为字符串或 Message 对象,具体取决于您是否想将格式化值用作 llm 或聊天模型的输入。
继续上一个示例:
import {
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
ChatPromptTemplate,
} from "langchain/prompts";
首先,我们创建一个可重用的模板:
const translationPrompt = ChatPromptTemplate.fromPromptMessages([
SystemMessagePromptTemplate.fromTemplate(
"You are a helpful assistant that translates {input_language} to {output_language}."
),
HumanMessagePromptTemplate.fromTemplate("{text}"),
]);
然后,我们可以使用该模板生成响应:
const responseA = await chat.generatePrompt([
await translationPrompt.formatPromptValue({
input_language: "English",
output_language: "French",
text: "I love programming.",
}),
]);
console.log(responseA);
{
generations: [
[
{
text: "J'aime programmer.",
message: AIChatMessage { text: "J'aime programmer." }
}
]
]
}
模型 + 提示 = LLMChain
这种要求完成格式化提示的模式非常常见,因此我们引入了下一个拼图:LLMChain
const chain = new LLMChain({
prompt: translationPrompt,
llm: chat,
});
然后,您可以调用该链:
const responseB = await chain.call({
input_language: "English",
output_language: "French",
text: "I love programming.",
});
console.log(responseB);
{ text: "J'aime programmer." }
代理:根据用户输入动态运行链
最后,我们介绍工具和代理,它们通过其他功能(例如搜索或计算器)扩展模型。
工具是一个函数,它接受一个字符串(例如搜索查询)并返回一个字符串(例如搜索结果)。它们还有一个名称和描述,这些名称和描述由聊天模型用于识别应调用哪个工具。
class Tool {
name: string;
description: string;
call(arg: string): Promise<string>;
}
代理是一个无状态的包装器,它包装了代理提示链(例如 MRKL),并负责将工具格式化到提示中,以及解析从聊天模型获取的响应。
interface AgentStep {
action: AgentAction;
observation: string;
}
interface AgentAction {
tool: string; // Tool.name
toolInput: string; // Tool.call argument
}
interface AgentFinish {
returnValues: object;
}
class Agent {
plan(steps: AgentStep[], inputs: object): Promise<AgentAction | AgentFinish>;
}
为了使代理更加强大,我们需要使它们迭代,即多次调用模型,直到它们到达最终答案。这就是 AgentExecutor 的工作。
class AgentExecutor {
// a simplified implementation
run(inputs: object) {
const steps = [];
while (true) {
const step = await this.agent.plan(steps, inputs);
if (step instanceof AgentFinish) {
return step.returnValues;
}
steps.push(step);
}
}
}
最后,我们可以使用 AgentExecutor 来运行代理:
// 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(new ChatOpenAI(), tools);
// Create an executor, which calls to the agent until an answer is found
const executor = AgentExecutor.fromAgentAndTools({ agent, tools });
const responseG = await executor.run(
"How many people live in canada as of 2023?"
);
console.log(responseG);
38,626,704.
内存:将状态添加到链和代理
您还可以使用链来存储状态。这对于例如聊天机器人非常有用,您希望跟踪对话历史记录。MessagesPlaceholder 是一个特殊的提示模板,将在每次调用中用传递的消息替换。
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,
});
链将在内部累积发送到模型的消息和接收到的消息。然后它将在下一次调用时将消息注入提示中。因此,您可以多次调用链,它会记住以前的消息:
const responseH = await chain.call({
input: "hi from London, how are you doing today",
});
console.log(responseH);
{
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?"
}
const responseI = await chain.call({
input: "Do you know where I am?",
});
console.log(responseI);
{
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."
}
流式
您还可以使用流式 API,以便在生成单词时将其流式传回。这对于例如聊天机器人非常有用,您希望在生成时向用户显示正在生成的内容。注意:在启用流式传输时,OpenAI 在撰写本文时不支持 tokenUsage
报告。
import { ChatOpenAI } from "langchain/chat_models/openai";
import { HumanChatMessage } from "langchain/schema";
const chat = new ChatOpenAI({
streaming: true,
callbacks: [
{
handleLLMNewToken(token: string) {
process.stdout.write(token);
},
},
],
});
await chat.call([
new HumanChatMessage("Write me a song about sparkling water."),
]);
/*
Verse 1:
Bubbles rise, crisp and clear
Refreshing taste that brings us cheer
Sparkling water, so light and pure
Quenches our thirst, it's always secure
Chorus:
Sparkling water, oh how we love
Its fizzy bubbles and grace above
It's the perfect drink, anytime, anyplace
Refreshing as it gives us a taste
Verse 2:
From morning brunch to evening feast
It's the perfect drink for a treat
A sip of it brings a smile so bright
Our thirst is quenched in just one sip so light
...
*/