"""包含少量示例的提示模板。"""
from __future__ import annotations
from pathlib import Path
from typing import Any, Dict, List, Literal, Optional, Union
from langchain_core.example_selectors import BaseExampleSelector
from langchain_core.messages import BaseMessage, get_buffer_string
from langchain_core.prompts.chat import (
BaseChatPromptTemplate,
BaseMessagePromptTemplate,
)
from langchain_core.prompts.prompt import PromptTemplate
from langchain_core.prompts.string import (
DEFAULT_FORMATTER_MAPPING,
StringPromptTemplate,
check_valid_template,
get_template_variables,
)
from langchain_core.pydantic_v1 import BaseModel, Extra, Field, root_validator
class _FewShotPromptTemplateMixin(BaseModel):
"""包含少量示例的提示模板。"""
examples: Optional[List[dict]] = None
"""需要格式化到提示符中的示例。
应提供这个或者example_selector中的一个。"""
example_selector: Optional[BaseExampleSelector] = None
"""选择要格式化为提示符的示例的ExampleSelector。
应提供此项或示例。"""
class Config:
"""这个pydantic对象的配置。"""
extra = Extra.forbid
arbitrary_types_allowed = True
@root_validator(pre=True)
def check_examples_and_selector(cls, values: Dict) -> Dict:
"""检查是否提供了一个且仅一个 examples/example_selector。"""
examples = values.get("examples", None)
example_selector = values.get("example_selector", None)
if examples and example_selector:
raise ValueError(
"Only one of 'examples' and 'example_selector' should be provided"
)
if examples is None and example_selector is None:
raise ValueError(
"One of 'examples' and 'example_selector' should be provided"
)
return values
def _get_examples(self, **kwargs: Any) -> List[dict]:
"""获取用于格式化提示的示例。
参数:
**kwargs: 要传递给示例选择器的关键字参数。
返回:
示例列表。
"""
if self.examples is not None:
return self.examples
elif self.example_selector is not None:
return self.example_selector.select_examples(kwargs)
else:
raise ValueError(
"One of 'examples' and 'example_selector' should be provided"
)
async def _aget_examples(self, **kwargs: Any) -> List[dict]:
"""获取用于格式化提示的示例。
参数:
**kwargs: 要传递给示例选择器的关键字参数。
返回:
示例列表。
"""
if self.examples is not None:
return self.examples
elif self.example_selector is not None:
return await self.example_selector.aselect_examples(kwargs)
else:
raise ValueError(
"One of 'examples' and 'example_selector' should be provided"
)
[docs]class FewShotPromptTemplate(_FewShotPromptTemplateMixin, StringPromptTemplate):
"""包含少量示例的提示模板。"""
[docs] @classmethod
def is_lc_serializable(cls) -> bool:
"""返回类是否可序列化。"""
return False
validate_template: bool = False
"""是否尝试验证模板。"""
input_variables: List[str]
"""提示模板期望的变量名称列表。"""
example_prompt: PromptTemplate
"""用于格式化单个示例的PromptTemplate。"""
suffix: str
"""一个用于放置示例后的提示模板字符串。"""
example_separator: str = "\n\n"
"""用于连接前缀、示例和后缀的字符串分隔符。"""
prefix: str = ""
"""一个放在示例之前的提示模板字符串。"""
template_format: Literal["f-string", "jinja2"] = "f-string"
"""提示模板的格式。选项包括:'f-string','jinja2'。"""
@root_validator()
def template_is_valid(cls, values: Dict) -> Dict:
"""检查前缀、后缀和输入变量是否一致。"""
if values["validate_template"]:
check_valid_template(
values["prefix"] + values["suffix"],
values["template_format"],
values["input_variables"] + list(values["partial_variables"]),
)
elif values.get("template_format"):
values["input_variables"] = [
var
for var in get_template_variables(
values["prefix"] + values["suffix"], values["template_format"]
)
if var not in values["partial_variables"]
]
return values
class Config:
"""这个pydantic对象的配置。"""
extra = Extra.forbid
arbitrary_types_allowed = True
@property
def _prompt_type(self) -> str:
"""返回提示类型键。"""
return "few_shot"
[docs] def save(self, file_path: Union[Path, str]) -> None:
if self.example_selector:
raise ValueError("Saving an example selector is not currently supported")
return super().save(file_path)
[docs]class FewShotChatMessagePromptTemplate(
BaseChatPromptTemplate, _FewShotPromptTemplateMixin
):
"""聊天提示模板,支持少量示例。
此提示模板生成的高级结构是消息列表,包括前缀消息、示例消息和后缀消息。
该结构使得创建具有中间示例的对话成为可能,例如:
系统:您是一个乐于助人的AI助手
人类:2+2等于多少?
AI:4
人类:2+3等于多少?
AI:5
人类:4+4等于多少?
此提示模板可用于生成固定的示例列表,也可以根据输入动态选择示例。
示例:
带有固定示例列表的提示模板(与上述示例对话匹配):
.. code-block:: python
from langchain_core.prompts import (
FewShotChatMessagePromptTemplate,
ChatPromptTemplate
)
examples = [
{"input": "2+2", "output": "4"},
{"input": "2+3", "output": "5"},
]
example_prompt = ChatPromptTemplate.from_messages(
[('human', '{input}'), ('ai', '{output}')]
)
few_shot_prompt = FewShotChatMessagePromptTemplate(
examples=examples,
# 这是用于格式化每个单独示例的提示模板。
example_prompt=example_prompt,
)
final_prompt = ChatPromptTemplate.from_messages(
[
('system', 'You are a helpful AI Assistant'),
few_shot_prompt,
('human', '{input}'),
]
)
final_prompt.format(input="4+4等于多少?")
带有动态选择示例的提示模板:
.. code-block:: python
from langchain_core.prompts import SemanticSimilarityExampleSelector
from langchain_core.embeddings import OpenAIEmbeddings
from langchain_core.vectorstores import Chroma
examples = [
{"input": "2+2", "output": "4"},
{"input": "2+3", "output": "5"},
{"input": "2+4", "output": "6"},
# ...
]
to_vectorize = [
" ".join(example.values())
for example in examples
]
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_texts(
to_vectorize, embeddings, metadatas=examples
)
example_selector = SemanticSimilarityExampleSelector(
vectorstore=vectorstore
)
from langchain_core import SystemMessage
from langchain_core.prompts import HumanMessagePromptTemplate
from langchain_core.prompts.few_shot import FewShotChatMessagePromptTemplate
few_shot_prompt = FewShotChatMessagePromptTemplate(
# 将传递给示例选择器的变量。
input_variables=["input"],
example_selector=example_selector,
# 定义每个示例的格式。
# 在这种情况下,每个示例将变为2条消息:
# 1条人类消息和1条AI消息
example_prompt=(
HumanMessagePromptTemplate.from_template("{input}")
+ AIMessagePromptTemplate.from_template("{output}")
),
)
# 定义整体提示。
final_prompt = (
SystemMessagePromptTemplate.from_template(
"You are a helpful AI Assistant"
)
+ few_shot_prompt
+ HumanMessagePromptTemplate.from_template("{input}")
)
# 显示提示
print(final_prompt.format_messages(input="3+3等于多少?")) # noqa: T201
# 在LLM中使用
from langchain_core.chat_models import ChatAnthropic
chain = final_prompt | ChatAnthropic(model="claude-3-haiku-20240307")
chain.invoke({"input": "3+3等于多少?"})
"""
[docs] @classmethod
def is_lc_serializable(cls) -> bool:
"""返回类是否可序列化。"""
return False
input_variables: List[str] = Field(default_factory=list)
"""用于传递给示例选择器的提示模板将使用的变量名称列表。"""
example_prompt: Union[BaseMessagePromptTemplate, BaseChatPromptTemplate]
"""每个示例的格式化类。"""
class Config:
"""这个pydantic对象的配置。"""
extra = Extra.forbid
arbitrary_types_allowed = True
[docs] def pretty_repr(self, html: bool = False) -> str:
raise NotImplementedError()