2.3Example Selectors
如果您有大量的示例,您可能需要選擇包含在提示中的示例。ExampleSelector是負(fù)責(zé)執(zhí)行此操作的類(lèi)。
基本接口定義如下:
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唯一需要公開(kāi)的方法是select_examples。該方法接受輸入變量,然后返回一個(gè)示例列表。如何選擇這些示例取決于每個(gè)具體實(shí)現(xiàn)。以下是一些示例。
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根據(jù)長(zhǎng)度選擇要使用的示例
如果你有大量的示例,可以使用 ExampleSelector 來(lái)選擇一組最具信息量的示例,以幫助語(yǔ)言模型生成更好的響應(yīng)。這將幫助你生成更可能生成良好響應(yīng)的提示。
在下面的示例中,我們將使用基于輸入長(zhǎng)度選擇示例的 LengthBasedExampleSelector。當(dāng)你擔(dān)心構(gòu)建的提示會(huì)超過(guò)上下文窗口的長(zhǎng)度時(shí),這很有用。對(duì)于較長(zhǎng)的輸入,它將選擇較少的示例進(jìn)行包含,而對(duì)于較短的輸入,它將選擇更多的示例。
在這個(gè)例子中,我們將創(chuàng)建一個(gè)提示來(lái)生成單詞的反義詞。我們將使用 LengthBasedExampleSelector 來(lái)選擇示例
example_selector = LengthBasedExampleSelector(
? ? examples=examples,
? ? example_prompt=example_prompt,
? ? # 下面是格式樣例最大長(zhǎng)度.
? ? # 長(zhǎng)度是指 get_text_length 函數(shù)返回值.
? ? max_length=25,
)
# 使用`example_selector` 創(chuàng)建 `FewShotPromptTemplate`.
dynamic_prompt = FewShotPromptTemplate(
? ? # 使用 ExampleSelector 替代 examples.
? ? example_selector=example_selector,
? ? example_prompt=example_prompt,
? ? prefix="根據(jù)輸入給出中文反義詞",
? ? suffix="詞語(yǔ): {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("高尚")
輸出:
根據(jù)輸入給出中文反義詞 Word: happyAntonym: sad Word: tallAntonym: short Word: energeticAntonym: lethargic 詞語(yǔ): big反義詞:
低俗
前面是print(dynamic_prompt.format(input="big"))的輸出結(jié)果,后面是llm_chain.run("高尚")輸出結(jié)果。
相比之下,如果我們提供一個(gè)非常長(zhǎng)的輸入,LengthBasedExampleSelector將選擇較少的示例包含在提示中。因?yàn)橐WC最大長(zhǎng)度不能超過(guò)25,就犧牲了示例數(shù)量。
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))
輸出:
根據(jù)輸入給出中文反義詞?
?Word: happy
Antonym: sad?
?詞語(yǔ): big and huge and massive and large and gigantic and tall and much bigger than everything else反義詞:
2.3.2 相似度
SemanticSimilarityExampleSelector根據(jù)示例與輸入的相似度選擇示例。它通過(guò)查找嵌入與輸入的余弦相似度最大的示例來(lái)實(shí)現(xiàn)此目的。
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
詞語(yǔ): happy
反義詞: sad
Input: worried
Output:
給變量adjective賦值worried,屬于情緒類(lèi),根據(jù)相似度選擇器選擇了同樣是情緒類(lèi)示例:happy/sad。
print(similar_prompt.format(adjective="fat"))
輸出:
Give the antonym of every input
Word: tall
Antonym: short
Input: fat
Output:
給變量adjective賦值fat,屬于體型特征類(lèi),根據(jù)相似度選擇器選擇了同樣是體型特征類(lèi)示例:tall/short。還可以增加示例,如下:
similar_prompt.example_selector.add_example({"input": "enthusiastic", "output": "apathetic"})
還有其他選擇器,如ngram重疊。NGramOverlapExampleSelector根據(jù)ngram重疊得分選擇和排序示例,該得分表示示例與輸入的相似程度。 ngram重疊得分是一個(gè)介于0.0和1.0之間的浮點(diǎn)數(shù)。選擇器允許設(shè)置閾值得分。 ngram重疊得分小于或等于閾值的示例將被排除。默認(rèn)情況下,閾值設(shè)置為-1.0,因此不會(huì)排除任何示例,只會(huì)對(duì)它們進(jìn)行重新排序。將閾值設(shè)置為0.0將排除具有與輸入無(wú)ngram重疊的示例。具體參考官方文檔。
2.4輸出解析器
語(yǔ)言模型輸出文本。但是很多時(shí)候,你可能想要獲得比文本更結(jié)構(gòu)化的信息。這就是輸出解析器的作用。
輸出解析器是幫助結(jié)構(gòu)化語(yǔ)言模型響應(yīng)的類(lèi)。有兩種主要的方法,一個(gè)輸出解析器必須實(shí)現(xiàn):
get_format_instructions() -> str:一個(gè)方法,返回一個(gè)包含有關(guān)如何格式化語(yǔ)言模型輸出的字符串。
parse(str) -> Any:一個(gè)方法,接受一個(gè)字符串(假定為語(yǔ)言模型的響應(yīng))并將其解析為某個(gè)結(jié)構(gòu)。
然后是一個(gè)可選的:
parse_with_prompt(str) -> Any:一個(gè)方法,它接受一個(gè)字符串(假設(shè)是語(yǔ)言模型的響應(yīng))和一個(gè)提示(假設(shè)是生成這樣的響應(yīng)的提示),并將其解析為某種結(jié)構(gòu)。提示在此大多數(shù)情況下是為了提供信息以便OutputParser重新嘗試或以某種方式修復(fù)輸出。
2.4.1?逗號(hào)分隔列表輸出解析器
輸出內(nèi)容,用逗號(hào)分隔列表
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個(gè) {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!')