Source code for langchain_core.prompts.chat

"""聊天提示模板。"""

from __future__ import annotations

from abc import ABC, abstractmethod
from pathlib import Path
from typing import (
    Any,
    Dict,
    List,
    Literal,
    Optional,
    Sequence,
    Set,
    Tuple,
    Type,
    TypedDict,
    TypeVar,
    Union,
    cast,
    overload,
)

from langchain_core._api import deprecated
from langchain_core.load import Serializable
from langchain_core.messages import (
    AIMessage,
    AnyMessage,
    BaseMessage,
    ChatMessage,
    HumanMessage,
    SystemMessage,
    convert_to_messages,
)
from langchain_core.messages.base import get_msg_title_repr
from langchain_core.prompt_values import ChatPromptValue, ImageURL, PromptValue
from langchain_core.prompts.base import BasePromptTemplate
from langchain_core.prompts.image import ImagePromptTemplate
from langchain_core.prompts.prompt import PromptTemplate
from langchain_core.prompts.string import StringPromptTemplate, get_template_variables
from langchain_core.pydantic_v1 import Field, root_validator
from langchain_core.utils import get_colored_text
from langchain_core.utils.interactive_env import is_interactive_env


[docs]class BaseMessagePromptTemplate(Serializable, ABC): """消息提示模板的基类。"""
[docs] @classmethod def is_lc_serializable(cls) -> bool: """返回类是否可序列化。""" return True
[docs] @classmethod def get_lc_namespace(cls) -> List[str]: """获取langchain对象的命名空间。""" return ["langchain", "prompts", "chat"]
[docs] @abstractmethod def format_messages(self, **kwargs: Any) -> List[BaseMessage]: """格式化kwargs中的消息。应返回一个BaseMessages列表。 参数: **kwargs:用于格式化的关键字参数。 返回: BaseMessages列表。 """
[docs] async def aformat_messages(self, **kwargs: Any) -> List[BaseMessage]: """格式化kwargs中的消息。应返回一个BaseMessages列表。 参数: **kwargs:用于格式化的关键字参数。 返回: BaseMessages列表。 """ return self.format_messages(**kwargs)
@property @abstractmethod def input_variables(self) -> List[str]: """这个提示模板的输入变量。 返回: 输入变量的列表。 """
[docs] def pretty_repr(self, html: bool = False) -> str: """可读性强的表示。""" raise NotImplementedError
[docs] def pretty_print(self) -> None: print(self.pretty_repr(html=is_interactive_env())) # noqa: T201
def __add__(self, other: Any) -> ChatPromptTemplate: """合并两个提示模板。 参数: other: 另一个提示模板。 返回: 合并后的提示模板。 """ prompt = ChatPromptTemplate(messages=[self]) # type: ignore[call-arg] return prompt + other
[docs]class MessagesPlaceholder(BaseMessagePromptTemplate): """提示模板,假设变量已经是消息列表。 一个占位符,可用于传递消息列表。 直接使用: .. code-block:: python from langchain_core.prompts import MessagesPlaceholder prompt = MessagesPlaceholder("history") prompt.format_messages() # raises KeyError prompt = MessagesPlaceholder("history", optional=True) prompt.format_messages() # returns empty list [] prompt.format_messages( history=[ ("system", "You are an AI assistant."), ("human", "Hello!"), ] ) # -> [ # SystemMessage(content="You are an AI assistant."), # HumanMessage(content="Hello!"), # ] 构建具有聊天历史的提示: .. code-block:: python from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder prompt = ChatPromptTemplate.from_messages( [ ("system", "You are a helpful assistant."), MessagesPlaceholder("history"), ("human", "{question}") ] ) prompt.invoke( { "history": [("human", "what's 5 + 2"), ("ai", "5 + 2 is 7")], "question": "now multiply that by 4" } ) # -> ChatPromptValue(messages=[ # SystemMessage(content="You are a helpful assistant."), # HumanMessage(content="what's 5 + 2"), # AIMessage(content="5 + 2 is 7"), # HumanMessage(content="now multiply that by 4"), # ]) """ variable_name: str """用作消息的变量名称。""" optional: bool = False """如果为True,则可以无需参数调用format_messages,并返回一个空列表。如果为False,则必须传入一个名为`variable_name`的命名参数,即使其值为空列表。"""
[docs] @classmethod def get_lc_namespace(cls) -> List[str]: """获取langchain对象的命名空间。""" return ["langchain", "prompts", "chat"]
def __init__(self, variable_name: str, *, optional: bool = False, **kwargs: Any): super().__init__(variable_name=variable_name, optional=optional, **kwargs)
[docs] def format_messages(self, **kwargs: Any) -> List[BaseMessage]: """格式化kwargs中的消息。 参数: **kwargs:用于格式化的关键字参数。 返回: BaseMessage的列表。 """ value = ( kwargs.get(self.variable_name, []) if self.optional else kwargs[self.variable_name] ) if not isinstance(value, list): raise ValueError( f"variable {self.variable_name} should be a list of base messages, " f"got {value}" ) return convert_to_messages(value)
@property def input_variables(self) -> List[str]: """这个提示模板的输入变量。 返回: 输入变量名称的列表。 """ return [self.variable_name] if not self.optional else []
[docs] def pretty_repr(self, html: bool = False) -> str: var = "{" + self.variable_name + "}" if html: title = get_msg_title_repr("Messages Placeholder", bold=True) var = get_colored_text(var, "yellow") else: title = get_msg_title_repr("Messages Placeholder") return f"{title}\n\n{var}"
MessagePromptTemplateT = TypeVar( "MessagePromptTemplateT", bound="BaseStringMessagePromptTemplate" ) """Type variable for message prompt templates."""
[docs]class BaseStringMessagePromptTemplate(BaseMessagePromptTemplate, ABC): """用于使用字符串提示模板的消息提示模板的基类。""" prompt: StringPromptTemplate """字符串提示模板。""" additional_kwargs: dict = Field(default_factory=dict) """传递给提示模板的额外关键字参数。"""
[docs] @classmethod def get_lc_namespace(cls) -> List[str]: """获取langchain对象的命名空间。""" return ["langchain", "prompts", "chat"]
[docs] @classmethod def from_template( cls: Type[MessagePromptTemplateT], template: str, template_format: str = "f-string", partial_variables: Optional[Dict[str, Any]] = None, **kwargs: Any, ) -> MessagePromptTemplateT: """从字符串模板创建一个类。 参数: template: 一个模板。 template_format: 模板的格式。 partial_variables: 一个变量字典,可以用来部分填充模板。例如,如果模板是`"{variable1} {variable2}"`,而`partial_variables`是`{"variable1": "foo"}`,那么最终的提示将是`"foo {variable2}"`。 **kwargs: 传递给构造函数的关键字参数。 返回: 这个类的一个新实例。 """ prompt = PromptTemplate.from_template( template, template_format=template_format, partial_variables=partial_variables, ) return cls(prompt=prompt, **kwargs)
[docs] @classmethod def from_template_file( cls: Type[MessagePromptTemplateT], template_file: Union[str, Path], input_variables: List[str], **kwargs: Any, ) -> MessagePromptTemplateT: """从模板文件创建一个类。 参数: template_file: 模板文件的路径。字符串或路径。 input_variables: 输入变量的列表。 **kwargs: 传递给构造函数的关键字参数。 返回: 这个类的一个新实例。 """ prompt = PromptTemplate.from_file(template_file, input_variables) return cls(prompt=prompt, **kwargs)
[docs] @abstractmethod def format(self, **kwargs: Any) -> BaseMessage: """格式化提示模板。 参数: **kwargs: 用于格式化的关键字参数。 返回: 格式化后的消息。 """
[docs] async def aformat(self, **kwargs: Any) -> BaseMessage: """格式化提示模板。 参数: **kwargs: 用于格式化的关键字参数。 返回: 格式化后的消息。 """ return self.format(**kwargs)
[docs] def format_messages(self, **kwargs: Any) -> List[BaseMessage]: """格式化kwargs中的消息。 参数: **kwargs:用于格式化的关键字参数。 返回: BaseMessages的列表。 """ return [self.format(**kwargs)]
[docs] async def aformat_messages(self, **kwargs: Any) -> List[BaseMessage]: return [await self.aformat(**kwargs)]
@property def input_variables(self) -> List[str]: """这个提示模板的输入变量。 返回: 输入变量名称的列表。 """ return self.prompt.input_variables
[docs] def pretty_repr(self, html: bool = False) -> str: # TODO: Handle partials title = self.__class__.__name__.replace("MessagePromptTemplate", " Message") title = get_msg_title_repr(title, bold=html) return f"{title}\n\n{self.prompt.pretty_repr(html=html)}"
[docs]class ChatMessagePromptTemplate(BaseStringMessagePromptTemplate): """聊天消息提示模板。""" role: str """消息的作用。"""
[docs] @classmethod def get_lc_namespace(cls) -> List[str]: """获取langchain对象的命名空间。""" return ["langchain", "prompts", "chat"]
[docs] def format(self, **kwargs: Any) -> BaseMessage: """格式化提示模板。 参数: **kwargs: 用于格式化的关键字参数。 返回: 格式化后的消息。 """ text = self.prompt.format(**kwargs) return ChatMessage( content=text, role=self.role, additional_kwargs=self.additional_kwargs )
[docs] async def aformat(self, **kwargs: Any) -> BaseMessage: text = await self.prompt.aformat(**kwargs) return ChatMessage( content=text, role=self.role, additional_kwargs=self.additional_kwargs )
_StringImageMessagePromptTemplateT = TypeVar( "_StringImageMessagePromptTemplateT", bound="_StringImageMessagePromptTemplate" ) class _TextTemplateParam(TypedDict, total=False): text: Union[str, Dict] class _ImageTemplateParam(TypedDict, total=False): image_url: Union[str, Dict] class _StringImageMessagePromptTemplate(BaseMessagePromptTemplate): """人类消息提示模板。这是用户发送的消息。""" prompt: Union[ StringPromptTemplate, List[Union[StringPromptTemplate, ImagePromptTemplate]] ] """提示模板。""" additional_kwargs: dict = Field(default_factory=dict) """传递给提示模板的额外关键字参数。""" _msg_class: Type[BaseMessage] @classmethod def get_lc_namespace(cls) -> List[str]: """获取langchain对象的命名空间。""" return ["langchain", "prompts", "chat"] @classmethod def from_template( cls: Type[_StringImageMessagePromptTemplateT], template: Union[str, List[Union[str, _TextTemplateParam, _ImageTemplateParam]]], template_format: str = "f-string", **kwargs: Any, ) -> _StringImageMessagePromptTemplateT: """从字符串模板创建一个类。 参数: template: 一个模板。 template_format: 模板的格式。 **kwargs: 传递给构造函数的关键字参数。 返回: 此类的一个新实例。 """ if isinstance(template, str): prompt: Union[StringPromptTemplate, List] = PromptTemplate.from_template( template, template_format=template_format ) return cls(prompt=prompt, **kwargs) elif isinstance(template, list): prompt = [] for tmpl in template: if isinstance(tmpl, str) or isinstance(tmpl, dict) and "text" in tmpl: if isinstance(tmpl, str): text: str = tmpl else: text = cast(_TextTemplateParam, tmpl)["text"] # type: ignore[assignment] # noqa: E501 prompt.append( PromptTemplate.from_template( text, template_format=template_format ) ) elif isinstance(tmpl, dict) and "image_url" in tmpl: img_template = cast(_ImageTemplateParam, tmpl)["image_url"] if isinstance(img_template, str): vars = get_template_variables(img_template, "f-string") if vars: if len(vars) > 1: raise ValueError( "Only one format variable allowed per image" f" template.\nGot: {vars}" f"\nFrom: {tmpl}" ) input_variables = [vars[0]] else: input_variables = None img_template = {"url": img_template} img_template_obj = ImagePromptTemplate( input_variables=input_variables, template=img_template ) elif isinstance(img_template, dict): img_template = dict(img_template) if "url" in img_template: input_variables = get_template_variables( img_template["url"], "f-string" ) else: input_variables = None img_template_obj = ImagePromptTemplate( input_variables=input_variables, template=img_template ) else: raise ValueError() prompt.append(img_template_obj) else: raise ValueError() return cls(prompt=prompt, **kwargs) else: raise ValueError() @classmethod def from_template_file( cls: Type[_StringImageMessagePromptTemplateT], template_file: Union[str, Path], input_variables: List[str], **kwargs: Any, ) -> _StringImageMessagePromptTemplateT: """从模板文件创建一个类。 参数: template_file: 模板文件的路径。字符串或路径。 input_variables: 输入变量的列表。 **kwargs: 传递给构造函数的关键字参数。 返回: 这个类的一个新实例。 """ with open(str(template_file), "r") as f: template = f.read() return cls.from_template(template, input_variables=input_variables, **kwargs) def format_messages(self, **kwargs: Any) -> List[BaseMessage]: """格式化kwargs中的消息。 参数: **kwargs:用于格式化的关键字参数。 返回: BaseMessages的列表。 """ return [self.format(**kwargs)] async def aformat_messages(self, **kwargs: Any) -> List[BaseMessage]: return [await self.aformat(**kwargs)] @property def input_variables(self) -> List[str]: """这个提示模板的输入变量。 返回: 输入变量名称的列表。 """ prompts = self.prompt if isinstance(self.prompt, list) else [self.prompt] input_variables = [iv for prompt in prompts for iv in prompt.input_variables] return input_variables def format(self, **kwargs: Any) -> BaseMessage: """格式化提示模板。 参数: **kwargs: 用于格式化的关键字参数。 返回: 格式化后的消息。 """ if isinstance(self.prompt, StringPromptTemplate): text = self.prompt.format(**kwargs) return self._msg_class( content=text, additional_kwargs=self.additional_kwargs ) else: content: List = [] for prompt in self.prompt: inputs = {var: kwargs[var] for var in prompt.input_variables} if isinstance(prompt, StringPromptTemplate): formatted: Union[str, ImageURL] = prompt.format(**inputs) content.append({"type": "text", "text": formatted}) elif isinstance(prompt, ImagePromptTemplate): formatted = prompt.format(**inputs) content.append({"type": "image_url", "image_url": formatted}) return self._msg_class( content=content, additional_kwargs=self.additional_kwargs ) async def aformat(self, **kwargs: Any) -> BaseMessage: """格式化提示模板。 参数: **kwargs: 用于格式化的关键字参数。 返回: 格式化后的消息。 """ if isinstance(self.prompt, StringPromptTemplate): text = await self.prompt.aformat(**kwargs) return self._msg_class( content=text, additional_kwargs=self.additional_kwargs ) else: content: List = [] for prompt in self.prompt: inputs = {var: kwargs[var] for var in prompt.input_variables} if isinstance(prompt, StringPromptTemplate): formatted: Union[str, ImageURL] = await prompt.aformat(**inputs) content.append({"type": "text", "text": formatted}) elif isinstance(prompt, ImagePromptTemplate): formatted = await prompt.aformat(**inputs) content.append({"type": "image_url", "image_url": formatted}) return self._msg_class( content=content, additional_kwargs=self.additional_kwargs ) def pretty_repr(self, html: bool = False) -> str: # TODO: Handle partials title = self.__class__.__name__.replace("MessagePromptTemplate", " Message") title = get_msg_title_repr(title, bold=html) prompts = self.prompt if isinstance(self.prompt, list) else [self.prompt] prompt_reprs = "\n\n".join(prompt.pretty_repr(html=html) for prompt in prompts) return f"{title}\n\n{prompt_reprs}"
[docs]class HumanMessagePromptTemplate(_StringImageMessagePromptTemplate): """人类消息提示模板。这是用户发送的消息。""" _msg_class: Type[BaseMessage] = HumanMessage
[docs]class AIMessagePromptTemplate(_StringImageMessagePromptTemplate): """AI消息提示模板。这是AI发送的消息。""" _msg_class: Type[BaseMessage] = AIMessage
[docs] @classmethod def get_lc_namespace(cls) -> List[str]: """获取langchain对象的命名空间。""" return ["langchain", "prompts", "chat"]
[docs]class SystemMessagePromptTemplate(_StringImageMessagePromptTemplate): """系统消息提示模板。 这是一条不发送给用户的消息。 """ _msg_class: Type[BaseMessage] = SystemMessage
[docs] @classmethod def get_lc_namespace(cls) -> List[str]: """获取langchain对象的命名空间。""" return ["langchain", "prompts", "chat"]
[docs]class BaseChatPromptTemplate(BasePromptTemplate, ABC): """用于聊天提示模板的基类。""" @property def lc_attributes(self) -> Dict: """返回一个属性名称列表,这些属性应该包含在序列化的kwargs中。这些属性必须被构造函数接受。 """ return {"input_variables": self.input_variables}
[docs] def format(self, **kwargs: Any) -> str: """将聊天模板格式化为字符串。 参数: **kwargs:用于填充此聊天模板中所有模板消息的模板变量的关键字参数。 返回: 格式化后的字符串 """ return self.format_prompt(**kwargs).to_string()
[docs] async def aformat(self, **kwargs: Any) -> str: """将聊天模板格式化为字符串。 参数: **kwargs:用于填充此聊天模板中所有模板消息的模板变量的关键字参数。 返回: 格式化后的字符串 """ return (await self.aformat_prompt(**kwargs)).to_string()
[docs] def format_prompt(self, **kwargs: Any) -> PromptValue: """格式化提示。应返回一个PromptValue。 参数: **kwargs:用于格式化的关键字参数。 返回: PromptValue。 """ messages = self.format_messages(**kwargs) return ChatPromptValue(messages=messages)
[docs] async def aformat_prompt(self, **kwargs: Any) -> PromptValue: messages = await self.aformat_messages(**kwargs) return ChatPromptValue(messages=messages)
[docs] @abstractmethod def format_messages(self, **kwargs: Any) -> List[BaseMessage]: """将kwargs格式化为消息列表。"""
[docs] async def aformat_messages(self, **kwargs: Any) -> List[BaseMessage]: """将kwargs格式化为消息列表。""" return self.format_messages(**kwargs)
[docs] def pretty_repr(self, html: bool = False) -> str: """可读性强的表示。""" raise NotImplementedError
[docs] def pretty_print(self) -> None: print(self.pretty_repr(html=is_interactive_env())) # noqa: T201
MessageLike = Union[BaseMessagePromptTemplate, BaseMessage, BaseChatPromptTemplate] MessageLikeRepresentation = Union[ MessageLike, Tuple[ Union[str, Type], Union[str, List[dict], List[object]], ], str, ]
[docs]class ChatPromptTemplate(BaseChatPromptTemplate): """聊天模型的提示模板。 用于为聊天模型创建灵活的模板化提示。 示例: .. code-block:: python from langchain_core.prompts import ChatPromptTemplate template = ChatPromptTemplate.from_messages([ ("system", "You are a helpful AI bot. Your name is {name}."), ("human", "Hello, how are you doing?"), ("ai", "I'm doing well, thanks!"), ("human", "{user_input}"), ]) prompt_value = template.invoke( { "name": "Bob", "user_input": "What is your name?" } ) # 输出: # ChatPromptValue( # messages=[ # SystemMessage(content='You are a helpful AI bot. Your name is Bob.'), # HumanMessage(content='Hello, how are you doing?'), # AIMessage(content="I'm doing well, thanks!"), # HumanMessage(content='What is your name?') # ] #) 消息占位符: .. code-block:: python # 除了Human/AI/Tool/Function消息外, # 您还可以使用MessagesPlaceholder初始化模板, # 可以直接使用类或使用简写元组语法: template = ChatPromptTemplate.from_messages([ ("system", "You are a helpful AI bot."), # 意味着模板将在“conversation”键下接收一个可选的消息列表 ("placeholder", "{conversation}") # 等效写法: # MessagesPlaceholder(variable_name="conversation", optional=True) ]) prompt_value = template.invoke( { "conversation": [ ("human", "Hi!"), ("ai", "How can I assist you today?"), ("human", "Can you make me an ice cream sundae?"), ("ai", "No.") ] } ) # 输出: # ChatPromptValue( # messages=[ # SystemMessage(content='You are a helpful AI bot.'), # HumanMessage(content='Hi!'), # AIMessage(content='How can I assist you today?'), # HumanMessage(content='Can you make me an ice cream sundae?'), # AIMessage(content='No.'), # ] #) 单变量模板: 如果您的提示只有一个输入变量(即,1个实例的“{variable_nams}”), 并且您使用非字典对象调用模板,则提示模板将将提供的参数注入到该变量位置。 .. code-block:: python from langchain_core.prompts import ChatPromptTemplate template = ChatPromptTemplate.from_messages([ ("system", "You are a helpful AI bot. Your name is Carl."), ("human", "{user_input}"), ]) prompt_value = template.invoke("Hello, there!") # 等效于 # prompt_value = template.invoke({"user_input": "Hello, there!"}) # 输出: # ChatPromptValue( # messages=[ # SystemMessage(content='You are a helpful AI bot. Your name is Carl.'), # HumanMessage(content='Hello, there!'), # ] # ) """ # noqa: E501 input_variables: List[str] """模板消息中的输入变量列表。用于验证。""" messages: List[MessageLike] """消息列表,包括消息提示模板或消息。""" validate_template: bool = False """是否尝试验证模板。"""
[docs] @classmethod def get_lc_namespace(cls) -> List[str]: """获取langchain对象的命名空间。""" return ["langchain", "prompts", "chat"]
def __add__(self, other: Any) -> ChatPromptTemplate: """合并两个提示模板。 参数: other: 另一个提示模板。 返回: 合并后的提示模板。 """ # Allow for easy combining if isinstance(other, ChatPromptTemplate): return ChatPromptTemplate(messages=self.messages + other.messages) # type: ignore[call-arg] elif isinstance( other, (BaseMessagePromptTemplate, BaseMessage, BaseChatPromptTemplate) ): return ChatPromptTemplate(messages=self.messages + [other]) # type: ignore[call-arg] elif isinstance(other, (list, tuple)): _other = ChatPromptTemplate.from_messages(other) return ChatPromptTemplate(messages=self.messages + _other.messages) # type: ignore[call-arg] elif isinstance(other, str): prompt = HumanMessagePromptTemplate.from_template(other) return ChatPromptTemplate(messages=self.messages + [prompt]) # type: ignore[call-arg] else: raise NotImplementedError(f"Unsupported operand type for +: {type(other)}") @root_validator(pre=True) def validate_input_variables(cls, values: dict) -> dict: """验证输入变量。 如果未设置input_variables,则将其设置为消息中所有输入变量的并集。 参数: values:要验证的值。 返回: 经过验证的值。 """ messages = values["messages"] input_vars = set() input_types: Dict[str, Any] = values.get("input_types", {}) for message in messages: if isinstance(message, (BaseMessagePromptTemplate, BaseChatPromptTemplate)): input_vars.update(message.input_variables) if isinstance(message, MessagesPlaceholder): if message.variable_name not in input_types: input_types[message.variable_name] = List[AnyMessage] if "partial_variables" in values: input_vars = input_vars - set(values["partial_variables"]) if "input_variables" in values and values.get("validate_template"): if input_vars != set(values["input_variables"]): raise ValueError( "Got mismatched input_variables. " f"Expected: {input_vars}. " f"Got: {values['input_variables']}" ) else: values["input_variables"] = sorted(input_vars) values["input_types"] = input_types return values
[docs] @classmethod def from_template(cls, template: str, **kwargs: Any) -> ChatPromptTemplate: """从模板字符串创建一个聊天提示模板。 创建一个聊天模板,由假定来自人类的单个消息组成。 参数: 模板:模板字符串 **kwargs:传递给构造函数的关键字参数。 返回: 此类的一个新实例。 """ prompt_template = PromptTemplate.from_template(template, **kwargs) message = HumanMessagePromptTemplate(prompt=prompt_template) return cls.from_messages([message])
[docs] @classmethod @deprecated("0.0.1", alternative="from_messages classmethod", pending=True) def from_role_strings( cls, string_messages: List[Tuple[str, str]] ) -> ChatPromptTemplate: """从(角色,模板)元组列表中创建一个聊天提示模板。 参数: string_messages:(角色,模板)元组列表。 返回: 一个聊天提示模板。 """ return cls( # type: ignore[call-arg] messages=[ ChatMessagePromptTemplate.from_template(template, role=role) for role, template in string_messages ] )
[docs] @classmethod @deprecated("0.0.1", alternative="from_messages classmethod", pending=True) def from_strings( cls, string_messages: List[Tuple[Type[BaseMessagePromptTemplate], str]] ) -> ChatPromptTemplate: """从(角色类,模板)元组列表中创建一个聊天提示模板。 参数: string_messages:(角色类,模板)元组列表。 返回: 一个聊天提示模板。 """ return cls.from_messages(string_messages)
[docs] @classmethod def from_messages( cls, messages: Sequence[MessageLikeRepresentation], template_format: Literal["f-string", "mustache"] = "f-string", ) -> ChatPromptTemplate: """从各种消息格式创建一个聊天提示模板。 示例: 从消息模板列表实例化: .. code-block:: python template = ChatPromptTemplate.from_messages([ ("human", "你好,你好吗?"), ("ai", "我很好,谢谢!"), ("human", "听到这个很高兴。"), ]) 从混合消息格式实例化: .. code-block:: python template = ChatPromptTemplate.from_messages([ SystemMessage(content="你好"), ("human", "你好,你好吗?"), ]) 参数: messages: 消息表示的序列。 可以使用以下格式表示消息: (1) BaseMessagePromptTemplate,(2) BaseMessage,(3) 2元组 (消息类型,模板); 例如,("human", "{user_input}"), (4) 2元组 (消息类,模板),(4) 一个字符串,简写为("human", 模板); 例如,"{user_input}" 返回: 一个聊天提示模板 """ _messages = [ _convert_to_message(message, template_format) for message in messages ] # Automatically infer input variables from messages input_vars: Set[str] = set() partial_vars: Dict[str, Any] = {} for _message in _messages: if isinstance(_message, MessagesPlaceholder) and _message.optional: partial_vars[_message.variable_name] = [] elif isinstance( _message, (BaseChatPromptTemplate, BaseMessagePromptTemplate) ): input_vars.update(_message.input_variables) return cls( input_variables=sorted(input_vars), messages=_messages, partial_variables=partial_vars, )
[docs] def format_messages(self, **kwargs: Any) -> List[BaseMessage]: """将聊天模板格式化为最终消息列表。 参数: **kwargs:用于填充此聊天模板中所有模板消息中的模板变量的关键字参数。 返回: 格式化消息列表 """ kwargs = self._merge_partial_and_user_variables(**kwargs) result = [] for message_template in self.messages: if isinstance(message_template, BaseMessage): result.extend([message_template]) elif isinstance( message_template, (BaseMessagePromptTemplate, BaseChatPromptTemplate) ): message = message_template.format_messages(**kwargs) result.extend(message) else: raise ValueError(f"Unexpected input: {message_template}") return result
[docs] async def aformat_messages(self, **kwargs: Any) -> List[BaseMessage]: """将聊天模板格式化为最终消息列表。 参数: **kwargs:用于填充此聊天模板中所有模板消息中的模板变量的关键字参数。 返回: 格式化消息列表 """ kwargs = self._merge_partial_and_user_variables(**kwargs) result = [] for message_template in self.messages: if isinstance(message_template, BaseMessage): result.extend([message_template]) elif isinstance( message_template, (BaseMessagePromptTemplate, BaseChatPromptTemplate) ): message = await message_template.aformat_messages(**kwargs) result.extend(message) else: raise ValueError(f"Unexpected input: {message_template}") return result
[docs] def partial(self, **kwargs: Any) -> ChatPromptTemplate: """获取一个新的ChatPromptTemplate,其中已经填充了一些输入变量。 参数: **kwargs: 用于填充模板变量的关键字参数。应该是输入变量的子集。 返回: 一个新的ChatPromptTemplate。 示例: .. code-block:: python from langchain_core.prompts import ChatPromptTemplate template = ChatPromptTemplate.from_messages( [ ("system", "You are an AI assistant named {name}."), ("human", "Hi I'm {user}"), ("ai", "Hi there, {user}, I'm {name}."), ("human", "{input}"), ] ) template2 = template.partial(user="Lucy", name="R2D2") template2.format_messages(input="hello") """ prompt_dict = self.__dict__.copy() prompt_dict["input_variables"] = list( set(self.input_variables).difference(kwargs) ) prompt_dict["partial_variables"] = {**self.partial_variables, **kwargs} return type(self)(**prompt_dict)
[docs] def append(self, message: MessageLikeRepresentation) -> None: """将消息附加到聊天模板的末尾。 参数: message:要附加的消息的表示。 """ self.messages.append(_convert_to_message(message))
[docs] def extend(self, messages: Sequence[MessageLikeRepresentation]) -> None: """使用一系列消息扩展聊天模板。""" self.messages.extend([_convert_to_message(message) for message in messages])
@overload def __getitem__(self, index: int) -> MessageLike: ... @overload def __getitem__(self, index: slice) -> ChatPromptTemplate: ... def __getitem__( self, index: Union[int, slice] ) -> Union[MessageLike, ChatPromptTemplate]: """用于索引到聊天模板中。""" if isinstance(index, slice): start, stop, step = index.indices(len(self.messages)) messages = self.messages[start:stop:step] return ChatPromptTemplate.from_messages(messages) else: return self.messages[index] def __len__(self) -> int: """获取聊天模板的长度。""" return len(self.messages) @property def _prompt_type(self) -> str: """提示类型的名称。""" return "chat"
[docs] def save(self, file_path: Union[Path, str]) -> None: """将提示保存到文件中。 参数: file_path:文件路径。 """ raise NotImplementedError()
[docs] def pretty_repr(self, html: bool = False) -> str: # TODO: handle partials return "\n\n".join(msg.pretty_repr(html=html) for msg in self.messages)
def _create_template_from_message_type( message_type: str, template: Union[str, list], template_format: Literal["f-string", "mustache"] = "f-string", ) -> BaseMessagePromptTemplate: """从消息类型和模板字符串创建一个消息提示模板。 参数: message_type: str 消息模板的类型(例如,"human","ai"等)。 template: str 模板字符串。 返回: 适当类型的消息提示模板。 """ if message_type in ("human", "user"): message: BaseMessagePromptTemplate = HumanMessagePromptTemplate.from_template( template, template_format=template_format ) elif message_type in ("ai", "assistant"): message = AIMessagePromptTemplate.from_template( cast(str, template), template_format=template_format ) elif message_type == "system": message = SystemMessagePromptTemplate.from_template( cast(str, template), template_format=template_format ) elif message_type == "placeholder": if isinstance(template, str): if template[0] != "{" or template[-1] != "}": raise ValueError( f"Invalid placeholder template: {template}." " Expected a variable name surrounded by curly braces." ) var_name = template[1:-1] message = MessagesPlaceholder(variable_name=var_name, optional=True) elif len(template) == 2 and isinstance(template[1], bool): var_name_wrapped, is_optional = template if not isinstance(var_name_wrapped, str): raise ValueError( "Expected variable name to be a string." f" Got: {var_name_wrapped}" ) if var_name_wrapped[0] != "{" or var_name_wrapped[-1] != "}": raise ValueError( f"Invalid placeholder template: {var_name_wrapped}." " Expected a variable name surrounded by curly braces." ) var_name = var_name_wrapped[1:-1] message = MessagesPlaceholder(variable_name=var_name, optional=is_optional) else: raise ValueError( "Unexpected arguments for placeholder message type." " Expected either a single string variable name" " or a list of [variable_name: str, is_optional: bool]." f" Got: {template}" ) else: raise ValueError( f"Unexpected message type: {message_type}. Use one of 'human'," f" 'user', 'ai', 'assistant', or 'system'." ) return message def _convert_to_message( message: MessageLikeRepresentation, template_format: Literal["f-string", "mustache"] = "f-string", ) -> Union[BaseMessage, BaseMessagePromptTemplate, BaseChatPromptTemplate]: """实例化来自各种消息格式的消息。 消息格式可以是以下之一: - BaseMessagePromptTemplate - BaseMessage - 2元组(角色字符串,模板);例如,("human", "{user_input}") - 2元组(消息类,模板) - 字符串:简写为("human",模板);例如,"{user_input}" 参数: message:支持格式之一中的消息表示 返回: 消息实例或消息模板的实例 """ if isinstance(message, (BaseMessagePromptTemplate, BaseChatPromptTemplate)): _message: Union[ BaseMessage, BaseMessagePromptTemplate, BaseChatPromptTemplate ] = message elif isinstance(message, BaseMessage): _message = message elif isinstance(message, str): _message = _create_template_from_message_type( "human", message, template_format=template_format ) elif isinstance(message, tuple): if len(message) != 2: raise ValueError(f"Expected 2-tuple of (role, template), got {message}") message_type_str, template = message if isinstance(message_type_str, str): _message = _create_template_from_message_type( message_type_str, template, template_format=template_format ) else: _message = message_type_str( prompt=PromptTemplate.from_template( cast(str, template), template_format=template_format ) ) else: raise NotImplementedError(f"Unsupported message type: {type(message)}") return _message