2.3Example Selectors
如果您有大量的示例,您可能需要选择包含在提示中的示例。ExampleSelector是负责执行此操作的类。
基本接口定义如下:
class BaseExampleSelector(ABC):
"""Interface for selecting examples to include in prompts."""
@abstractmethod
def select_examples(self, input_variables: Dict[str, str]) -> List[dict]:
"""Select which examples to use based on the inputs."""
ExampleSelector唯一需要公开的方法是select_examples。该方法接受输入变量,然后返回一个示例列表。如何选择这些示例取决于每个具体实现。以下是一些示例。
from langchain.prompts.example_selector import LengthBasedExampleSelector
# These are a lot of examples of a pretend task of creating antonyms.
examples = [
{"word": "happy", "antonym": "sad"},
{"word": "tall", "antonym": "short"},
{"word": "energetic", "antonym": "lethargic"},
{"word": "sunny", "antonym": "gloomy"},
{"word": "windy", "antonym": "calm"},
]
# Next, we specify the template to format the examples we have provided.
# We use the `PromptTemplate` class for this.
example_formatter_template = """
Word: {word}
Antonym: {antonym}\n
"""
example_prompt = PromptTemplate(
input_variables=["word", "antonym"],
template=example_formatter_template,
)
2.3.1根据长度选择要使用的示例
如果你有大量的示例,可以使用 ExampleSelector 来选择一组最具信息量的示例,以帮助语言模型生成更好的响应。这将帮助你生成更可能生成良好响应的提示。
在下面的示例中,我们将使用基于输入长度选择示例的 LengthBasedExampleSelector。当你担心构建的提示会超过上下文窗口的长度时,这很有用。对于较长的输入,它将选择较少的示例进行包含,而对于较短的输入,它将选择更多的示例。
在这个例子中,我们将创建一个提示来生成单词的反义词。我们将使用 LengthBasedExampleSelector 来选择示例
example_selector = LengthBasedExampleSelector(
examples=examples,
example_prompt=example_prompt,
# 下面是格式样例最大长度.
# 长度是指 get_text_length 函数返回值.
max_length=25,
)
# 使用`example_selector` 创建 `FewShotPromptTemplate`.
dynamic_prompt = FewShotPromptTemplate(
# 使用 ExampleSelector 替代 examples.
example_selector=example_selector,
example_prompt=example_prompt,
prefix="根据输入给出中文反义词",
suffix="词语: {input}\n反义词:",
input_variables=["input"],
example_separator=" ",
)
# 使用 `format` 方法生成提示.
print(dynamic_prompt.format(input="big"))
llm_chain=LLMChain(
prompt=dynamic_prompt,
llm=llm
)
llm_chain.run("高尚")
输出:
根据输入给出中文反义词 Word: happyAntonym: sad Word: tallAntonym: short Word: energeticAntonym: lethargic 词语: big反义词:
低俗
前面是print(dynamic_prompt.format(input="big"))的输出结果,后面是llm_chain.run("高尚")输出结果。
相比之下,如果我们提供一个非常长的输入,LengthBasedExampleSelector将选择较少的示例包含在提示中。因为要保证最大长度不能超过25,就牺牲了示例数量。
long_string = "big and huge and massive and large and gigantic and tall and much bigger than everything else"
print(dynamic_prompt.format(input=long_string))
输出:
根据输入给出中文反义词
Word: happy
Antonym: sad
词语: big and huge and massive and large and gigantic and tall and much bigger than everything else反义词:
2.3.2 相似度
SemanticSimilarityExampleSelector根据示例与输入的相似度选择示例。它通过查找嵌入与输入的余弦相似度最大的示例来实现此目的。
from langchain.prompts.example_selector import SemanticSimilarityExampleSelector
from langchain.vectorstores import Chroma
example_selector = SemanticSimilarityExampleSelector.from_examples(
# This is the list of examples available to select from.
examples,
# This is the embedding class used to produce embeddings which are used to measure semantic similarity.
HuggingFaceEmbeddings(),
# This is the VectorStore class that is used to store the embeddings and do a similarity search over.
Chroma,
# This is the number of examples to produce.
k=1
)
similar_prompt = FewShotPromptTemplate(
# We provide an ExampleSelector instead of examples.
example_selector=example_selector,
example_prompt=example_prompt,
prefix="Give the antonym of every input",
suffix="Input: {adjective}\nOutput:",
input_variables=["adjective"],
)
print(similar_prompt.format(adjective="worried"))
输出:
Give the antonym of every input
词语: happy
反义词: sad
Input: worried
Output:
给变量adjective赋值worried,属于情绪类,根据相似度选择器选择了同样是情绪类示例:happy/sad。
print(similar_prompt.format(adjective="fat"))
输出:
Give the antonym of every input
Word: tall
Antonym: short
Input: fat
Output:
给变量adjective赋值fat,属于体型特征类,根据相似度选择器选择了同样是体型特征类示例:tall/short。还可以增加示例,如下:
similar_prompt.example_selector.add_example({"input": "enthusiastic", "output": "apathetic"})
还有其他选择器,如ngram重叠。NGramOverlapExampleSelector根据ngram重叠得分选择和排序示例,该得分表示示例与输入的相似程度。 ngram重叠得分是一个介于0.0和1.0之间的浮点数。选择器允许设置阈值得分。 ngram重叠得分小于或等于阈值的示例将被排除。默认情况下,阈值设置为-1.0,因此不会排除任何示例,只会对它们进行重新排序。将阈值设置为0.0将排除具有与输入无ngram重叠的示例。具体参考官方文档。
2.4输出解析器
语言模型输出文本。但是很多时候,你可能想要获得比文本更结构化的信息。这就是输出解析器的作用。
输出解析器是帮助结构化语言模型响应的类。有两种主要的方法,一个输出解析器必须实现:
get_format_instructions() -> str:一个方法,返回一个包含有关如何格式化语言模型输出的字符串。
parse(str) -> Any:一个方法,接受一个字符串(假定为语言模型的响应)并将其解析为某个结构。
然后是一个可选的:
parse_with_prompt(str) -> Any:一个方法,它接受一个字符串(假设是语言模型的响应)和一个提示(假设是生成这样的响应的提示),并将其解析为某种结构。提示在此大多数情况下是为了提供信息以便OutputParser重新尝试或以某种方式修复输出。
2.4.1 逗号分隔列表输出解析器
输出内容,用逗号分隔列表
from langchain.output_parsers import CommaSeparatedListOutputParser
from langchain.prompts import PromptTemplate
output_parser = CommaSeparatedListOutputParser()
format_instructions = output_parser.get_format_instructions()
prompt = PromptTemplate(
template="使用中文列出7个 {subject}.\n{format_instructions}",
input_variables=["subject"],
partial_variables={"format_instructions": format_instructions}
)
_input = prompt.format(subject="世界七大洲")
#llm.temperature=0.0
output = llm(_input)
output_parser.parse(output)
输出:
['世界七大洲如下:\n\n非洲大陆,亚洲大陆,北美洲,南美洲,欧洲大陆,大洋洲,南极洲。']
2.4.2 PydanticOutputParser
from langchain.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field, validator
# Define your desired data structure.
class Joke(BaseModel):
setup: str = Field(description="question to set up a joke")
punchline: str = Field(description="answer to resolve the joke")
# You can add custom validation logic easily with Pydantic.
@validator('setup')
def question_ends_with_question_mark(cls, field):
if field[-1] != '?':
raise ValueError("Badly formed question!")
return field
# Set up a parser + inject instructions into the prompt template.
parser = PydanticOutputParser(pydantic_object=Joke)
prompt = PromptTemplate(
template="Answer the user query.\n{format_instructions}\n{query}\n",
input_variables=["query"],
partial_variables={"format_instructions": parser.get_format_instructions()}
)
# And a query intented to prompt a language model to populate the data structure.
joke_query = "Tell me a joke."
_input = prompt.format_prompt(query=joke_query)
output=llm(_input.to_string())
from langchain.output_parsers import OutputFixingParser
new_parser = OutputFixingParser.from_llm(parser=parser, llm=llm)
new_parser.parse(output)
输出:
Joke(setup="What do you call a cow that can't jump over the fence?", punchline='A dairy product!')