文章目录

1、提示词模板
所谓提示词Prompt
,指对模型的输入。语言模型接受一个文本作为输入,这个文本通常就指的是模板。LangChain
提供了一些类和函数,用于构建提示词模板和使用提示词模板:
- 提示词模板:参数化模型输入
- 示例选择器:动态选择要包含在提示词中的示例
1.1 什么是提示词模板
从形式上来讲,提示词模板是一个字符串。它可以接受一系列参数,生成不同的模板。一个提示词模板里包含以下内容:
- 对于语言模型的介绍
- 一组简洁的示例,帮助语言模型生成一个更好的响应
- 对语言模型的提问
下面是一个简单的示例:
// 首先导入提示词模板类PromptTemplate
import { PromptTemplate } from "langchain/prompts";
// 传入一个模板,语言模型会自动从模板中推断出输入变量
const prompt = PromptTemplate.fromTemplate(
`You are a naming consultant for new companies.
What is a good name for a company that makes {product}?`
);
// product是该模板的参数
const formattedPrompt = await prompt.format({
product: "colorful socks",
});
// 格式化模板后,会得到如下的结果。可以看到,输入的变量被自动添加到了提示词模板变量的位置
/*
You are a naming consultant for new companies.
What is a good name for a company that makes colorful socks?
*/
1.2 创建一个提示词模板
可以使用上述示例中的PromptTemplate
类,创建一个硬编码的提示词模板。提示词模板可以接受任意数量的输入变量,并且可以被格式化来生成模板。下面列举几种生成提示词模板的方法:
首先引入PromptTemplate
类:
import { PromptTemplate } from "langchain/prompts";
- 生成无参数的提示词模板
const noInputPrompt = new PromptTemplate({
inputVariables: [], // 没有参数,inputVariables为空
template: "Tell me a joke.",
});
const formattedNoInputPrompt = await noInputPrompt.format();
console.log(formattedNoInputPrompt);
// "Tell me a joke."
- 包含一个参数的提示词模板
const oneInputPrompt = new PromptTemplate({
inputVariables: ["adjective"], // 一个参数:adjective
template: "Tell me a {adjective} joke."
})
const formattedOneInputPrompt = await oneInputPrompt.format({
adjective: "funny",
});
console.log(formattedOneInputPrompt);
// "Tell me a funny joke."
- 生成包含多个参数的提示词模板
const multipleInputPrompt = new PromptTemplate({
inputVariables: ["adjective", "content"], // 多个参数
template: "Tell me a {adjective} joke about {content}.",
});
// .format参数进行格式化,并传入参数
const formattedMultipleInputPrompt = await multipleInputPrompt.format({
adjective: "funny",
content: "chickens",
});
console.log(formattedMultipleInputPrompt);
// "Tell me a funny joke about chickens."
- 使用
fromTemplate
生成提示词模板。如果你不想手动设定inputVariables
,则可以使用fromTemplate
来生成提示词模板。
// 编写模板
const template = "Tell me a {adjective} joke about {content}.";
const promptTemplate = PromptTemplate.fromTemplate(template);
console.log(promptTemplate.inputVariables); // 获取模板参数
// ['adjective', 'content']
// 格式化模板
const formattedPromptTemplate = await promptTemplate.format({
adjective: "funny",
content: "chickens",
});
console.log(formattedPromptTemplate); // 最终生成的模板
// "Tell me a funny joke about chickens."
1.3 对话提示词模板
对话模型接受的输入是一个聊天消息列表,这个消息列表通常被称为对话模型的提示词。聊天消息与原始字符串的区别是:每条消息都与一个角色相关联。例如,在OpenAI
的聊天模型中,聊天消息的角色可以是AI
,human
或system
等,LangChain
也针对这些角色分别提供了不同的提示词生成类,如AIMessagePromptTemplate
,HumanMessagePromptTemplate
,SystemMessagePromptTemplate
等。如下为LangChain
所提供的提示词模板:
import {
ChatPromptTemplate,
PromptTemplate,
SystemMessagePromptTemplate,
AIMessagePromptTemplate,
HumanMessagePromptTemplate,
} from "langchain/prompts";
在调用聊天模型时,可以使用这些类来替换PromptTemplate
生成提示词。有时候,为了使用方便,也可以将消息提示模板声明成为一个数组,如:
// 定义两个消息模板:系统模板和人工模板
const systemTemplate = "You are a helpful assistant that translates {input_language} to {output_language}.";
const humanTemplate = "{text}";
// 形成一个聊天模板
const chatPrompt = ChatPromptTemplate.fromMessages([
["system", systemTemplate],
["human", humanTemplate],
]);
// 格式化消息
const formattedChatPrompt = await chatPrompt.formatMessages({
input_language: "English",
output_language: "French",
text: "I love programming.",
});
console.log(formattedChatPrompt);
// 结果
/*
[
SystemMessage {
content: 'You are a helpful assistant that translates English to French.'
},
HumanMessage {
content: 'I love programming.'
}
]
*/
1.4 部分提示词模板举例
- 字符串形式
- 函数形式
1.5 提示词模板组合使用
这里我们介绍如何将多个模板组合使用。这对于对部分模板重复使用具有重要作用,其中,PipelinePrompt
可以将多个模板进行组合。PipelinePrompt
包括两个主要的组成部分:
- Final prompt:最后返回的提示
- Pipeline prompts:一个由提示词名称和提示词模板组成的元组,每一个提示词都将会被格式化,并且会作为具有相同名称的变量传递到未来的提示模板。
首先,从langchain/prompts
中引入PromptTemplate
和PipelinePromptTemplate
import { PromptTemplate, PipelinePromptTemplate } from "langchain/prompts";
下面,通过PromptTemplate.fromTemplate
方法,开始定义多个提示词模板。这里我们定义了四个模板,分别为:
fullPrompt
:是用于最终会返回的模板,包括三个变量{introduction}
,{example}
,{start}
,当finalPrompt
使用这个模板时,pipelinePrompts
就应该输入包括这三个变量的模板。introductionPrompt
:包含一个变量person
examplePrompt
:包含两个变量example_q
,example_a
startPrompt
:包含一个变量input
// 全部模板
const fullPrompt = PromptTemplate.fromTemplate(`{introduction}
{example}
{start}`);
const introductionPrompt = PromptTemplate.fromTemplate(
`You are impersonating {person}.`
);
const examplePrompt =
PromptTemplate.fromTemplate(`Here's an example of an interaction:
Q: {example_q}
A: {example_a}`);
const startPrompt = PromptTemplate.fromTemplate(`Now, do this for real!
Q: {input}
A:`);
最后,通过PipelinePromptTemplate
创建一个组合模板,并使用.format
方法,获得一个格式化的模板:
const composedPrompt = new PipelinePromptTemplate({
pipelinePrompts: [
{
name: "introduction",
prompt: introductionPrompt,
},
{
name: "example",
prompt: examplePrompt,
},
{
name: "start",
prompt: startPrompt,
},
],
finalPrompt: fullPrompt,
});
const formattedPrompt = await composedPrompt.format({
person: "Elon Musk",
example_q: `What's your favorite car?`,
example_a: "Telsa",
input: `What's your favorite social media site?`,
});
打印formattedPrompt
,可得到如下的结果:
console.log(formattedPrompt);
/*
You are impersonating Elon Musk.
Here's an example of an interaction:
Q: What's your favorite car?
A: Telsa
Now, do this for real!
Q: What's your favorite social media site?
A:
*/
可以看到,这是一个将三个模板组合得到的模板。将这个模板通过如下方式传入到大语言模型,即可进行问到:
const model = new OpenAI({
openAIApiKey: OPENAI_API_KEY,
temperature: 0
})
let result = await model.call(formattedPrompt)
2、示例选择器
假如你有一堆选择器,想要自动选择一种包含在提示中,就可以使用示例选择器。示例选择器的接口定义是:
class BaseExampleSelector {
addExample(example: Example): Promise<void | string>;
selectExamples(input_variables: Example): Promise<Example[]>;
}
这里暴露了两个方法:
addExample
:保存一个示例,以供下一次选择selectExamples
:它接受输入变量,返回示例方法的列表
这些示例如何保存和选择,取决于上述方法的具体实现。
2.1 通过长度选择
此示例选择器是根据长度选择要使用的示例。当您担心构建的提示会超过上下文窗口的长度时,这非常有用。对于较长的输入,它将选择较少的示例来包含,而对于较短的输入,它将选择更多的示例。
import { LengthBasedExampleSelector, PromptTemplate, FewShotPromptTemplate } from "langchain/prompts";
创建一个提示词模板,它将会被用于格式化示例。
const examplePrompt = new PromptTemplate({
inputVariables: ["input", "output"],
template: "Input: {input}\nOutput: {output}",
});
创建一个基于长度的LengthBasedExampleSelector
选择器,它将会被用于选择一个示例
const exampleSelector = await LengthBasedExampleSelector.fromExamples(
[
{ input: "happy", output: "sad" },
{ input: "tall", output: "short" },
{ input: "energetic", output: "lethargic" },
{ input: "sunny", output: "gloomy" },
{ input: "windy", output: "calm" },
],
{
examplePrompt,
maxLength: 25,
}
);
创建一个FewShotPromptTemplate
模板,它也会被用于示例选择
const dynamicPrompt = new FewShotPromptTemplate({
// We provide an ExampleSelector instead of examples.
exampleSelector,
examplePrompt,
prefix: "Give the antonym of every input",
suffix: "Input: {adjective}\nOutput:",
inputVariables: ["adjective"],
});
使用一个长度较小的输入,所以它会选择所有的示例。
console.log(await dynamicPrompt.format({ adjective: "big" }));
/*
Give the antonym of every input
Input: happy
Output: sad
Input: tall
Output: short
Input: energetic
Output: lethargic
Input: sunny
Output: gloomy
Input: windy
Output: calm
Input: big
Output:
*/
这里使用一个长度较长的输入,它只会选择其中一个示例。
const longString =
"big and huge and massive and large and gigantic and tall and much much much much much bigger than everything else";
console.log(await dynamicPrompt.format({ adjective: longString }));
/*
Give the antonym of every input
Input: happy
Output: sad
Input: big and huge and massive and large and gigantic and tall and much much much much much bigger than everything else
Output:
*/
2.2 通过相似度选择
该对象根据与输入的相似性来选择示例。它通过查找与输入具有最大余弦相似度的嵌入示例来实现这一点。
import { OpenAIEmbeddings } from "langchain/embeddings/openai";
import {
SemanticSimilarityExampleSelector,
PromptTemplate,
FewShotPromptTemplate,
} from "langchain/prompts";
import { HNSWLib } from "langchain/vectorstores/hnswlib";
// 创建一个用于示例选择的提示词模板
const examplePrompt = new PromptTemplate({
inputVariables: ["input", "output"],
template: "Input: {input}\nOutput: {output}",
});
// 创建一个基于语法相似度SemanticSimilarityExampleSelector的选择器
const exampleSelector = await SemanticSimilarityExampleSelector.fromExamples(
[
{ input: "happy", output: "sad" },
{ input: "tall", output: "short" },
{ input: "energetic", output: "lethargic" },
{ input: "sunny", output: "gloomy" },
{ input: "windy", output: "calm" },
],
new OpenAIEmbeddings(),
HNSWLib,
{ k: 1 }
);
// 创建一个FewShotPromptTemplate进行示例选择
const dynamicPrompt = new FewShotPromptTemplate({
// We provide an ExampleSelector instead of examples.
exampleSelector,
examplePrompt,
prefix: "Give the antonym of every input",
suffix: "Input: {adjective}\nOutput:",
inputVariables: ["adjective"],
});
// 使用天气相关的作为输入
console.log(await dynamicPrompt.format({ adjective: "rainy" }));
// 所以,输出也是天气相关
/*
Give the antonym of every input
Input: sunny
Output: gloomy
Input: rainy
Output:
*/
// 使用一个测量相关的输入,所以会得到例如tall/short的示例
console.log(await dynamicPrompt.format({ adjective: "large" }));
/*
Give the antonym of every input
Input: tall
Output: short
Input: large
Output:
*/