Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
chat.py1492 linesDownload Raw Back to prompts
1"""Chat prompt template."""2 3from __future__ import annotations4 5from abc import ABC, abstractmethod6from collections.abc import Sequence7from pathlib import Path8from typing import (9    Annotated,10    Any,11    TypedDict,12    TypeVar,13    cast,14    overload,15)16 17from pydantic import (18    Field,19    PositiveInt,20    SkipValidation,21    model_validator,22)23from typing_extensions import Self, override24 25from langchain_core._api import deprecated26from langchain_core.messages import (27    AIMessage,28    AnyMessage,29    BaseMessage,30    ChatMessage,31    HumanMessage,32    SystemMessage,33    convert_to_messages,34)35from langchain_core.messages.base import get_msg_title_repr36from langchain_core.prompt_values import ChatPromptValue, ImageURL37from langchain_core.prompts.base import BasePromptTemplate38from langchain_core.prompts.dict import DictPromptTemplate39from langchain_core.prompts.image import ImagePromptTemplate40from langchain_core.prompts.message import (41    BaseMessagePromptTemplate,42)43from langchain_core.prompts.prompt import PromptTemplate44from langchain_core.prompts.string import (45    PromptTemplateFormat,46    StringPromptTemplate,47    get_template_variables,48)49from langchain_core.utils import get_colored_text50from langchain_core.utils.interactive_env import is_interactive_env51 52 53class MessagesPlaceholder(BaseMessagePromptTemplate):54    """Prompt template that assumes variable is already list of messages.55 56    A placeholder which can be used to pass in a list of messages.57 58    !!! example "Direct usage"59 60        ```python61        from langchain_core.prompts import MessagesPlaceholder62 63        prompt = MessagesPlaceholder("history")64        prompt.format_messages()  # raises KeyError65 66        prompt = MessagesPlaceholder("history", optional=True)67        prompt.format_messages()  # returns empty list []68 69        prompt.format_messages(70            history=[71                ("system", "You are an AI assistant."),72                ("human", "Hello!"),73            ]74        )75        # -> [76        #     SystemMessage(content="You are an AI assistant."),77        #     HumanMessage(content="Hello!"),78        # ]79        ```80 81    !!! example "Building a prompt with chat history"82 83        ```python84        from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder85 86        prompt = ChatPromptTemplate.from_messages(87            [88                ("system", "You are a helpful assistant."),89                MessagesPlaceholder("history"),90                ("human", "{question}"),91            ]92        )93        prompt.invoke(94            {95                "history": [("human", "what's 5 + 2"), ("ai", "5 + 2 is 7")],96                "question": "now multiply that by 4",97            }98        )99        # -> ChatPromptValue(messages=[100        #     SystemMessage(content="You are a helpful assistant."),101        #     HumanMessage(content="what's 5 + 2"),102        #     AIMessage(content="5 + 2 is 7"),103        #     HumanMessage(content="now multiply that by 4"),104        # ])105        ```106 107    !!! example "Limiting the number of messages"108 109        ```python110        from langchain_core.prompts import MessagesPlaceholder111 112        prompt = MessagesPlaceholder("history", n_messages=1)113 114        prompt.format_messages(115            history=[116                ("system", "You are an AI assistant."),117                ("human", "Hello!"),118            ]119        )120        # -> [121        #     HumanMessage(content="Hello!"),122        # ]123        ```124    """125 126    variable_name: str127    """Name of variable to use as messages."""128 129    optional: bool = False130    """Whether `format_messages` must be provided.131 132    If `True` `format_messages` can be called with no arguments and will return an empty133    list.134 135    If `False` then a named argument with name `variable_name` must be passed in, even136    if the value is an empty list.137    """138 139    n_messages: PositiveInt | None = None140    """Maximum number of messages to include.141 142    If `None`, then will include all.143    """144 145    def __init__(146        self, variable_name: str, *, optional: bool = False, **kwargs: Any147    ) -> None:148        """Create a messages placeholder.149 150        Args:151            variable_name: Name of variable to use as messages.152            optional: Whether `format_messages` must be provided.153 154                If `True` format_messages can be called with no arguments and will155                return an empty list.156 157                If `False` then a named argument with name `variable_name` must be158                passed in, even if the value is an empty list.159        """160        # mypy can't detect the init which is defined in the parent class161        # b/c these are BaseModel classes.162        super().__init__(variable_name=variable_name, optional=optional, **kwargs)  # type: ignore[call-arg,unused-ignore]163 164    def format_messages(self, **kwargs: Any) -> list[BaseMessage]:165        """Format messages from kwargs.166 167        Args:168            **kwargs: Keyword arguments to use for formatting.169 170        Returns:171            List of `BaseMessage` objects.172 173        Raises:174            ValueError: If variable is not a list of messages.175        """176        value = (177            kwargs.get(self.variable_name, [])178            if self.optional179            else kwargs[self.variable_name]180        )181        if not isinstance(value, list):182            msg = (183                f"variable {self.variable_name} should be a list of base messages, "184                f"got {value} of type {type(value)}"185            )186            raise ValueError(msg)  # noqa: TRY004187        value = convert_to_messages(value)188        if self.n_messages:189            value = value[-self.n_messages :]190        return value191 192    @property193    def input_variables(self) -> list[str]:194        """Input variables for this prompt template.195 196        Returns:197            List of input variable names.198        """199        return [self.variable_name] if not self.optional else []200 201    @override202    def pretty_repr(self, html: bool = False) -> str:203        """Human-readable representation.204 205        Args:206            html: Whether to format as HTML.207 208        Returns:209            Human-readable representation.210        """211        var = "{" + self.variable_name + "}"212        if html:213            title = get_msg_title_repr("Messages Placeholder", bold=True)214            var = get_colored_text(var, "yellow")215        else:216            title = get_msg_title_repr("Messages Placeholder")217        return f"{title}\n\n{var}"218 219 220MessagePromptTemplateT = TypeVar(221    "MessagePromptTemplateT", bound="BaseStringMessagePromptTemplate"222)223"""Type variable for message prompt templates."""224 225 226class BaseStringMessagePromptTemplate(BaseMessagePromptTemplate, ABC):227    """Base class for message prompt templates that use a string prompt template."""228 229    prompt: StringPromptTemplate230    """String prompt template."""231 232    additional_kwargs: dict = Field(default_factory=dict)233    """Additional keyword arguments to pass to the prompt template."""234 235    @classmethod236    def from_template(237        cls,238        template: str,239        template_format: PromptTemplateFormat = "f-string",240        partial_variables: dict[str, Any] | None = None,241        **kwargs: Any,242    ) -> Self:243        """Create a class from a string template.244 245        Args:246            template: a template.247            template_format: format of the template.248            partial_variables: A dictionary of variables that can be used to partially249                fill in the template.250 251                For example, if the template is `"{variable1} {variable2}"`, and252                `partial_variables` is `{"variable1": "foo"}`, then the final prompt253                will be `"foo {variable2}"`.254 255            **kwargs: Keyword arguments to pass to the constructor.256 257        Returns:258            A new instance of this class.259        """260        prompt = PromptTemplate.from_template(261            template,262            template_format=template_format,263            partial_variables=partial_variables,264        )265        return cls(prompt=prompt, **kwargs)266 267    @classmethod268    def from_template_file(269        cls,270        template_file: str | Path,271        **kwargs: Any,272    ) -> Self:273        """Create a class from a template file.274 275        Args:276            template_file: path to a template file.277            **kwargs: Keyword arguments to pass to the constructor.278 279        Returns:280            A new instance of this class.281        """282        prompt = PromptTemplate.from_file(template_file)283        return cls(prompt=prompt, **kwargs)284 285    @abstractmethod286    def format(self, **kwargs: Any) -> BaseMessage:287        """Format the prompt template.288 289        Args:290            **kwargs: Keyword arguments to use for formatting.291 292        Returns:293            Formatted message.294        """295 296    async def aformat(self, **kwargs: Any) -> BaseMessage:297        """Async format the prompt template.298 299        Args:300            **kwargs: Keyword arguments to use for formatting.301 302        Returns:303            Formatted message.304        """305        return self.format(**kwargs)306 307    def format_messages(self, **kwargs: Any) -> list[BaseMessage]:308        """Format messages from kwargs.309 310        Args:311            **kwargs: Keyword arguments to use for formatting.312 313        Returns:314            List of `BaseMessage` objects.315        """316        return [self.format(**kwargs)]317 318    async def aformat_messages(self, **kwargs: Any) -> list[BaseMessage]:319        """Async format messages from kwargs.320 321        Args:322            **kwargs: Keyword arguments to use for formatting.323 324        Returns:325            List of `BaseMessage` objects.326        """327        return [await self.aformat(**kwargs)]328 329    @property330    def input_variables(self) -> list[str]:331        """Input variables for this prompt template.332 333        Returns:334            List of input variable names.335        """336        return self.prompt.input_variables337 338    @override339    def pretty_repr(self, html: bool = False) -> str:340        """Human-readable representation.341 342        Args:343            html: Whether to format as HTML.344 345        Returns:346            Human-readable representation.347        """348        # TODO: Handle partials349        title = self.__class__.__name__.replace("MessagePromptTemplate", " Message")350        title = get_msg_title_repr(title, bold=html)351        return f"{title}\n\n{self.prompt.pretty_repr(html=html)}"352 353 354class ChatMessagePromptTemplate(BaseStringMessagePromptTemplate):355    """Chat message prompt template."""356 357    role: str358    """Role of the message."""359 360    def format(self, **kwargs: Any) -> BaseMessage:361        """Format the prompt template.362 363        Args:364            **kwargs: Keyword arguments to use for formatting.365 366        Returns:367            Formatted message.368        """369        text = self.prompt.format(**kwargs)370        return ChatMessage(371            content=text, role=self.role, additional_kwargs=self.additional_kwargs372        )373 374    async def aformat(self, **kwargs: Any) -> BaseMessage:375        """Async format the prompt template.376 377        Args:378            **kwargs: Keyword arguments to use for formatting.379 380        Returns:381            Formatted message.382        """383        text = await self.prompt.aformat(**kwargs)384        return ChatMessage(385            content=text, role=self.role, additional_kwargs=self.additional_kwargs386        )387 388 389class _TextTemplateParam(TypedDict, total=False):390    text: str | dict391 392 393class _ImageTemplateParam(TypedDict, total=False):394    image_url: str | dict395 396 397class _StringImageMessagePromptTemplate(BaseMessagePromptTemplate):398    """Human message prompt template. This is a message sent from the user."""399 400    prompt: (401        StringPromptTemplate402        | list[StringPromptTemplate | ImagePromptTemplate | DictPromptTemplate]403    )404    """Prompt template."""405    additional_kwargs: dict = Field(default_factory=dict)406    """Additional keyword arguments to pass to the prompt template."""407 408    _msg_class: type[BaseMessage]409 410    @classmethod411    def from_template(412        cls: type[Self],413        template: str414        | list[str | _TextTemplateParam | _ImageTemplateParam | dict[str, Any]],415        template_format: PromptTemplateFormat = "f-string",416        *,417        partial_variables: dict[str, Any] | None = None,418        **kwargs: Any,419    ) -> Self:420        """Create a class from a string template.421 422        Args:423            template: a template.424            template_format: format of the template.425 426                Options are: `'f-string'`, `'mustache'`, `'jinja2'`.427            partial_variables: A dictionary of variables that can be used too partially.428 429            **kwargs: Keyword arguments to pass to the constructor.430 431        Returns:432            A new instance of this class.433 434        Raises:435            ValueError: If the template is not a string or list of strings.436        """437        if isinstance(template, str):438            prompt: StringPromptTemplate | list = PromptTemplate.from_template(439                template,440                template_format=template_format,441                partial_variables=partial_variables,442            )443            return cls(prompt=prompt, **kwargs)444        if isinstance(template, list):445            if (partial_variables is not None) and len(partial_variables) > 0:446                msg = "Partial variables are not supported for list of templates."447                raise ValueError(msg)448            prompt = []449            for tmpl in template:450                if isinstance(tmpl, str) or (451                    isinstance(tmpl, dict)452                    and "text" in tmpl453                    and set(tmpl.keys()) <= {"type", "text"}454                ):455                    if isinstance(tmpl, str):456                        text: str = tmpl457                    else:458                        text = cast("_TextTemplateParam", tmpl)["text"]  # type: ignore[assignment]459                    prompt.append(460                        PromptTemplate.from_template(461                            text, template_format=template_format462                        )463                    )464                elif (465                    isinstance(tmpl, dict)466                    and "image_url" in tmpl467                    and set(tmpl.keys())468                    <= {469                        "type",470                        "image_url",471                    }472                ):473                    img_template = cast("_ImageTemplateParam", tmpl)["image_url"]474                    input_variables = []475                    if isinstance(img_template, str):476                        variables = get_template_variables(477                            img_template, template_format478                        )479                        if variables:480                            if len(variables) > 1:481                                msg = (482                                    "Only one format variable allowed per image"483                                    f" template.\nGot: {variables}"484                                    f"\nFrom: {tmpl}"485                                )486                                raise ValueError(msg)487                            input_variables = [variables[0]]488                        img_template = {"url": img_template}489                        img_template_obj = ImagePromptTemplate(490                            input_variables=input_variables,491                            template=img_template,492                            template_format=template_format,493                        )494                    elif isinstance(img_template, dict):495                        img_template = dict(img_template)496                        for key in ["url", "path", "detail"]:497                            if key in img_template:498                                input_variables.extend(499                                    get_template_variables(500                                        img_template[key], template_format501                                    )502                                )503                        img_template_obj = ImagePromptTemplate(504                            input_variables=input_variables,505                            template=img_template,506                            template_format=template_format,507                        )508                    else:509                        msg = f"Invalid image template: {tmpl}"510                        raise ValueError(msg)511                    prompt.append(img_template_obj)512                elif isinstance(tmpl, dict):513                    if template_format == "jinja2":514                        msg = (515                            "jinja2 is unsafe and is not supported for templates "516                            "expressed as dicts. Please use 'f-string' or 'mustache' "517                            "format."518                        )519                        raise ValueError(msg)520                    data_template_obj = DictPromptTemplate(521                        template=cast("dict[str, Any]", tmpl),522                        template_format=template_format,523                    )524                    prompt.append(data_template_obj)525                else:526                    msg = f"Invalid template: {tmpl}"527                    raise ValueError(msg)528            return cls(prompt=prompt, **kwargs)529        msg = f"Invalid template: {template}"530        raise ValueError(msg)531 532    @classmethod533    def from_template_file(534        cls: type[Self],535        template_file: str | Path,536        input_variables: list[str],537        **kwargs: Any,538    ) -> Self:539        """Create a class from a template file.540 541        Args:542            template_file: path to a template file.543            input_variables: list of input variables.544            **kwargs: Keyword arguments to pass to the constructor.545 546        Returns:547            A new instance of this class.548        """549        template = Path(template_file).read_text(encoding="utf-8")550        return cls.from_template(template, input_variables=input_variables, **kwargs)551 552    def format_messages(self, **kwargs: Any) -> list[BaseMessage]:553        """Format messages from kwargs.554 555        Args:556            **kwargs: Keyword arguments to use for formatting.557 558        Returns:559            List of `BaseMessage` objects.560        """561        return [self.format(**kwargs)]562 563    async def aformat_messages(self, **kwargs: Any) -> list[BaseMessage]:564        """Async format messages from kwargs.565 566        Args:567            **kwargs: Keyword arguments to use for formatting.568 569        Returns:570            List of `BaseMessage` objects.571        """572        return [await self.aformat(**kwargs)]573 574    @property575    def input_variables(self) -> list[str]:576        """Input variables for this prompt template.577 578        Returns:579            List of input variable names.580        """581        prompts = self.prompt if isinstance(self.prompt, list) else [self.prompt]582        return [iv for prompt in prompts for iv in prompt.input_variables]583 584    def format(self, **kwargs: Any) -> BaseMessage:585        """Format the prompt template.586 587        Args:588            **kwargs: Keyword arguments to use for formatting.589 590        Returns:591            Formatted message.592        """593        if isinstance(self.prompt, StringPromptTemplate):594            text = self.prompt.format(**kwargs)595            return self._msg_class(596                content=text, additional_kwargs=self.additional_kwargs597            )598        content: list = []599        for prompt in self.prompt:600            inputs = {var: kwargs[var] for var in prompt.input_variables}601            if isinstance(prompt, StringPromptTemplate):602                formatted_text: str = prompt.format(**inputs)603                if formatted_text != "":604                    content.append({"type": "text", "text": formatted_text})605            elif isinstance(prompt, ImagePromptTemplate):606                formatted_image: ImageURL = prompt.format(**inputs)607                content.append({"type": "image_url", "image_url": formatted_image})608            elif isinstance(prompt, DictPromptTemplate):609                formatted_dict: dict[str, Any] = prompt.format(**inputs)610                content.append(formatted_dict)611        return self._msg_class(612            content=content, additional_kwargs=self.additional_kwargs613        )614 615    async def aformat(self, **kwargs: Any) -> BaseMessage:616        """Async format the prompt template.617 618        Args:619            **kwargs: Keyword arguments to use for formatting.620 621        Returns:622            Formatted message.623        """624        if isinstance(self.prompt, StringPromptTemplate):625            text = await self.prompt.aformat(**kwargs)626            return self._msg_class(627                content=text, additional_kwargs=self.additional_kwargs628            )629        content: list = []630        for prompt in self.prompt:631            inputs = {var: kwargs[var] for var in prompt.input_variables}632            if isinstance(prompt, StringPromptTemplate):633                formatted_text: str = await prompt.aformat(**inputs)634                if formatted_text != "":635                    content.append({"type": "text", "text": formatted_text})636            elif isinstance(prompt, ImagePromptTemplate):637                formatted_image: ImageURL = await prompt.aformat(**inputs)638                content.append({"type": "image_url", "image_url": formatted_image})639            elif isinstance(prompt, DictPromptTemplate):640                formatted_dict: dict[str, Any] = prompt.format(**inputs)641                content.append(formatted_dict)642        return self._msg_class(643            content=content, additional_kwargs=self.additional_kwargs644        )645 646    @override647    def pretty_repr(self, html: bool = False) -> str:648        """Human-readable representation.649 650        Args:651            html: Whether to format as HTML.652 653        Returns:654            Human-readable representation.655        """656        # TODO: Handle partials657        title = self.__class__.__name__.replace("MessagePromptTemplate", " Message")658        title = get_msg_title_repr(title, bold=html)659        prompts = self.prompt if isinstance(self.prompt, list) else [self.prompt]660        prompt_reprs = "\n\n".join(prompt.pretty_repr(html=html) for prompt in prompts)661        return f"{title}\n\n{prompt_reprs}"662 663 664class HumanMessagePromptTemplate(_StringImageMessagePromptTemplate):665    """Human message prompt template.666 667    This is a message sent from the user.668    """669 670    _msg_class: type[BaseMessage] = HumanMessage671 672 673class AIMessagePromptTemplate(_StringImageMessagePromptTemplate):674    """AI message prompt template.675 676    This is a message sent from the AI.677    """678 679    _msg_class: type[BaseMessage] = AIMessage680 681 682class SystemMessagePromptTemplate(_StringImageMessagePromptTemplate):683    """System message prompt template.684 685    This is a message that is not sent to the user.686    """687 688    _msg_class: type[BaseMessage] = SystemMessage689 690 691class BaseChatPromptTemplate(BasePromptTemplate, ABC):692    """Base class for chat prompt templates."""693 694    @property695    @override696    def lc_attributes(self) -> dict:697        return {"input_variables": self.input_variables}698 699    def format(self, **kwargs: Any) -> str:700        """Format the chat template into a string.701 702        Args:703            **kwargs: Keyword arguments to use for filling in template variables in all704                the template messages in this chat template.705 706        Returns:707            Formatted string.708        """709        return self.format_prompt(**kwargs).to_string()710 711    async def aformat(self, **kwargs: Any) -> str:712        """Async format the chat template into a string.713 714        Args:715            **kwargs: Keyword arguments to use for filling in template variables in all716                the template messages in this chat template.717 718        Returns:719            Formatted string.720        """721        return (await self.aformat_prompt(**kwargs)).to_string()722 723    def format_prompt(self, **kwargs: Any) -> ChatPromptValue:724        """Format prompt.725 726        Should return a `ChatPromptValue`.727 728        Args:729            **kwargs: Keyword arguments to use for formatting.730        """731        messages = self.format_messages(**kwargs)732        return ChatPromptValue(messages=messages)733 734    async def aformat_prompt(self, **kwargs: Any) -> ChatPromptValue:735        """Async format prompt.736 737        Should return a `ChatPromptValue`.738 739        Args:740            **kwargs: Keyword arguments to use for formatting.741        """742        messages = await self.aformat_messages(**kwargs)743        return ChatPromptValue(messages=messages)744 745    @abstractmethod746    def format_messages(self, **kwargs: Any) -> list[BaseMessage]:747        """Format kwargs into a list of messages.748 749        Returns:750            List of `BaseMessage` objects.751        """752 753    async def aformat_messages(self, **kwargs: Any) -> list[BaseMessage]:754        """Async format kwargs into a list of messages.755 756        Returns:757            List of `BaseMessage` objects.758        """759        return self.format_messages(**kwargs)760 761    def pretty_repr(762        self,763        html: bool = False,  # noqa: FBT001,FBT002764    ) -> str:765        """Human-readable representation.766 767        Args:768            html: Whether to format as HTML.769 770        Returns:771            Human-readable representation.772        """773        raise NotImplementedError774 775    def pretty_print(self) -> None:776        """Print a human-readable representation."""777        print(self.pretty_repr(html=is_interactive_env()))  # noqa: T201778 779 780MessageLike = BaseMessagePromptTemplate | BaseMessage | BaseChatPromptTemplate781 782MessageLikeRepresentation = (783    MessageLike784    | tuple[str | type, str | Sequence[dict] | Sequence[object]]785    | str786    | dict[str, Any]787)788 789 790class ChatPromptTemplate(BaseChatPromptTemplate):791    """Prompt template for chat models.792 793    Use to create flexible templated prompts for chat models.794 795    !!! example796 797        ```python798        from langchain_core.prompts import ChatPromptTemplate799 800        template = ChatPromptTemplate(801            [802                ("system", "You are a helpful AI bot. Your name is {name}."),803                ("human", "Hello, how are you doing?"),804                ("ai", "I'm doing well, thanks!"),805                ("human", "{user_input}"),806            ]807        )808 809        prompt_value = template.invoke(810            {811                "name": "Bob",812                "user_input": "What is your name?",813            }814        )815        # Output:816        # ChatPromptValue(817        #    messages=[818        #        SystemMessage(content='You are a helpful AI bot. Your name is Bob.'),819        #        HumanMessage(content='Hello, how are you doing?'),820        #        AIMessage(content="I'm doing well, thanks!"),821        #        HumanMessage(content='What is your name?')822        #    ]823        # )824        ```825 826    !!! note "Messages Placeholder"827 828        ```python829        # In addition to Human/AI/Tool/Function messages,830        # you can initialize the template with a MessagesPlaceholder831        # either using the class directly or with the shorthand tuple syntax:832 833        template = ChatPromptTemplate(834            [835                ("system", "You are a helpful AI bot."),836                # Means the template will receive an optional list of messages under837                # the "conversation" key838                ("placeholder", "{conversation}"),839                # Equivalently:840                # MessagesPlaceholder(variable_name="conversation", optional=True)841            ]842        )843 844        prompt_value = template.invoke(845            {846                "conversation": [847                    ("human", "Hi!"),848                    ("ai", "How can I assist you today?"),849                    ("human", "Can you make me an ice cream sundae?"),850                    ("ai", "No."),851                ]852            }853        )854 855        # Output:856        # ChatPromptValue(857        #    messages=[858        #        SystemMessage(content='You are a helpful AI bot.'),859        #        HumanMessage(content='Hi!'),860        #        AIMessage(content='How can I assist you today?'),861        #        HumanMessage(content='Can you make me an ice cream sundae?'),862        #        AIMessage(content='No.'),863        #    ]864        # )865        ```866 867    !!! note "Single-variable template"868 869        If your prompt has only a single input variable (i.e., one instance of870        `'{variable_nams}'`), and you invoke the template with a non-dict object, the871        prompt template will inject the provided argument into that variable location.872 873        ```python874        from langchain_core.prompts import ChatPromptTemplate875 876        template = ChatPromptTemplate(877            [878                ("system", "You are a helpful AI bot. Your name is Carl."),879                ("human", "{user_input}"),880            ]881        )882 883        prompt_value = template.invoke("Hello, there!")884        # Equivalent to885        # prompt_value = template.invoke({"user_input": "Hello, there!"})886 887        # Output:888        #  ChatPromptValue(889        #     messages=[890        #         SystemMessage(content='You are a helpful AI bot. Your name is Carl.'),891        #         HumanMessage(content='Hello, there!'),892        #     ]893        # )894        ```895    """896 897    messages: Annotated[list[MessageLike], SkipValidation()]898    """List of messages consisting of either message prompt templates or messages."""899 900    validate_template: bool = False901    """Whether or not to try validating the template."""902 903    def __init__(904        self,905        messages: Sequence[MessageLikeRepresentation],906        *,907        template_format: PromptTemplateFormat = "f-string",908        **kwargs: Any,909    ) -> None:910        """Create a chat prompt template from a variety of message formats.911 912        Args:913            messages: Sequence of message representations.914 915                A message can be represented using the following formats:916 917                1. `BaseMessagePromptTemplate`918                2. `BaseMessage`919                3. 2-tuple of `(message type, template)`; e.g.,920                    `('human', '{user_input}')`921                4. 2-tuple of `(message class, template)`922                5. A string which is shorthand for `('human', template)`; e.g.,923                    `'{user_input}'`924            template_format: Format of the template.925            **kwargs: Additional keyword arguments passed to `BasePromptTemplate`,926                including (but not limited to):927 928                - `input_variables`: A list of the names of the variables whose values929                    are required as inputs to the prompt.930                - `optional_variables`: A list of the names of the variables for931                    placeholder or `MessagePlaceholder` that are optional.932 933                    These variables are auto inferred from the prompt and user need not934                    provide them.935 936                - `partial_variables`: A dictionary of the partial variables the prompt937                    template carries.938 939                    Partial variables populate the template so that you don't need to940                    pass them in every time you call the prompt.941 942                - `validate_template`: Whether to validate the template.943                - `input_types`: A dictionary of the types of the variables the prompt944                    template expects.945 946                    If not provided, all variables are assumed to be strings.947 948        Examples:949            Instantiation from a list of message templates:950 951            ```python952            template = ChatPromptTemplate(953                [954                    ("human", "Hello, how are you?"),955                    ("ai", "I'm doing well, thanks!"),956                    ("human", "That's good to hear."),957                ]958            )959            ```960 961            Instantiation from mixed message formats:962 963            ```python964            template = ChatPromptTemplate(965                [966                    SystemMessage(content="hello"),967                    ("human", "Hello, how are you?"),968                ]969            )970            ```971        """972        messages_ = [973            _convert_to_message_template(message, template_format)974            for message in messages975        ]976 977        # Automatically infer input variables from messages978        input_vars: set[str] = set()979        optional_variables: set[str] = set()980        partial_vars: dict[str, Any] = {}981        for message in messages_:982            if isinstance(message, MessagesPlaceholder) and message.optional:983                partial_vars[message.variable_name] = []984                optional_variables.add(message.variable_name)985            elif isinstance(986                message, (BaseChatPromptTemplate, BaseMessagePromptTemplate)987            ):988                input_vars.update(message.input_variables)989 990        kwargs = {991            "input_variables": sorted(input_vars),992            "optional_variables": sorted(optional_variables),993            "partial_variables": partial_vars,994            **kwargs,995        }996        cast("type[ChatPromptTemplate]", super()).__init__(messages=messages_, **kwargs)997 998    @classmethod999    def get_lc_namespace(cls) -> list[str]:1000        """Get the namespace of the LangChain object.1001 1002        Returns:1003            `["langchain", "prompts", "chat"]`1004        """1005        return ["langchain", "prompts", "chat"]1006 1007    def __add__(self, other: Any) -> ChatPromptTemplate:1008        """Combine two prompt templates.1009 1010        Args:1011            other: Another prompt template.1012 1013        Returns:1014            Combined prompt template.1015        """1016        partials = {**self.partial_variables}1017 1018        # Need to check that other has partial variables since it may not be1019        # a ChatPromptTemplate.1020        if hasattr(other, "partial_variables") and other.partial_variables:1021            partials.update(other.partial_variables)1022 1023        # Allow for easy combining1024        if isinstance(other, ChatPromptTemplate):1025            return ChatPromptTemplate(messages=self.messages + other.messages).partial(1026                **partials1027            )1028        if isinstance(1029            other, (BaseMessagePromptTemplate, BaseMessage, BaseChatPromptTemplate)1030        ):1031            return ChatPromptTemplate(messages=[*self.messages, other]).partial(1032                **partials1033            )1034        if isinstance(other, (list, tuple)):1035            other_ = ChatPromptTemplate.from_messages(other)1036            return ChatPromptTemplate(messages=self.messages + other_.messages).partial(1037                **partials1038            )1039        if isinstance(other, str):1040            prompt = HumanMessagePromptTemplate.from_template(other)1041            return ChatPromptTemplate(messages=[*self.messages, prompt]).partial(1042                **partials1043            )1044        msg = f"Unsupported operand type for +: {type(other)}"1045        raise NotImplementedError(msg)1046 1047    @model_validator(mode="before")1048    @classmethod1049    def validate_input_variables(cls, values: dict) -> Any:1050        """Validate input variables.1051 1052        If `input_variables` is not set, it will be set to the union of all input1053        variables in the messages.1054 1055        Args:1056            values: values to validate.1057 1058        Returns:1059            Validated values.1060 1061        Raises:1062            ValueError: If input variables do not match.1063        """1064        messages = values["messages"]1065        input_vars: set = set()1066        optional_variables = set()1067        input_types: dict[str, Any] = values.get("input_types", {})1068        for message in messages:1069            if isinstance(message, (BaseMessagePromptTemplate, BaseChatPromptTemplate)):1070                input_vars.update(message.input_variables)1071            if isinstance(message, MessagesPlaceholder):1072                if "partial_variables" not in values:1073                    values["partial_variables"] = {}1074                if (1075                    message.optional1076                    and message.variable_name not in values["partial_variables"]1077                ):1078                    values["partial_variables"][message.variable_name] = []1079                    optional_variables.add(message.variable_name)1080                if message.variable_name not in input_types:1081                    input_types[message.variable_name] = list[AnyMessage]1082        if "partial_variables" in values:1083            input_vars -= set(values["partial_variables"])1084        if optional_variables:1085            input_vars -= optional_variables1086        if "input_variables" in values and values.get("validate_template"):1087            if input_vars != set(values["input_variables"]):1088                msg = (1089                    "Got mismatched input_variables. "1090                    f"Expected: {input_vars}. "1091                    f"Got: {values['input_variables']}"1092                )1093                raise ValueError(msg)1094        else:1095            values["input_variables"] = sorted(input_vars)1096        if optional_variables:1097            values["optional_variables"] = sorted(optional_variables)1098        values["input_types"] = input_types1099        return values1100 1101    @classmethod1102    def from_template(cls, template: str, **kwargs: Any) -> ChatPromptTemplate:1103        """Create a chat prompt template from a template string.1104 1105        Creates a chat template consisting of a single message assumed to be from the1106        human.1107 1108        Args:1109            template: Template string1110            **kwargs: Keyword arguments to pass to the constructor.1111 1112        Returns:1113            A new instance of this class.1114        """1115        prompt_template = PromptTemplate.from_template(template, **kwargs)1116        message = HumanMessagePromptTemplate(prompt=prompt_template)1117        return cls.from_messages([message])1118 1119    @classmethod1120    def from_messages(1121        cls,1122        messages: Sequence[MessageLikeRepresentation],1123        template_format: PromptTemplateFormat = "f-string",1124    ) -> ChatPromptTemplate:1125        """Create a chat prompt template from a variety of message formats.1126 1127        Examples:1128            Instantiation from a list of message templates:1129 1130            ```python1131            template = ChatPromptTemplate.from_messages(1132                [1133                    ("human", "Hello, how are you?"),1134                    ("ai", "I'm doing well, thanks!"),1135                    ("human", "That's good to hear."),1136                ]1137            )1138            ```1139 1140            Instantiation from mixed message formats:1141 1142            ```python1143            template = ChatPromptTemplate.from_messages(1144                [1145                    SystemMessage(content="hello"),1146                    ("human", "Hello, how are you?"),1147                ]1148            )1149            ```1150        Args:1151            messages: Sequence of message representations.1152 1153                A message can be represented using the following formats:1154 1155                1. `BaseMessagePromptTemplate`1156                2. `BaseMessage`1157                3. 2-tuple of `(message type, template)`; e.g.,1158                    `('human', '{user_input}')`1159                4. 2-tuple of `(message class, template)`1160                5. A string which is shorthand for `('human', template)`; e.g.,1161                    `'{user_input}'`1162            template_format: Format of the template.1163 1164        Returns:1165            A chat prompt template.1166 1167        """1168        return cls(messages, template_format=template_format)1169 1170    def format_messages(self, **kwargs: Any) -> list[BaseMessage]:1171        """Format the chat template into a list of finalized messages.1172 1173        Args:1174            **kwargs: Keyword arguments to use for filling in template variables1175                in all the template messages in this chat template.1176 1177        Raises:1178            ValueError: If messages are of unexpected types.1179 1180        Returns:1181            List of formatted messages.1182        """1183        kwargs = self._merge_partial_and_user_variables(**kwargs)1184        result = []1185        for message_template in self.messages:1186            if isinstance(message_template, BaseMessage):1187                result.extend([message_template])1188            elif isinstance(1189                message_template, (BaseMessagePromptTemplate, BaseChatPromptTemplate)1190            ):1191                message = message_template.format_messages(**kwargs)1192                result.extend(message)1193            else:1194                msg = f"Unexpected input: {message_template}"1195                raise ValueError(msg)  # noqa: TRY0041196        return result1197 1198    async def aformat_messages(self, **kwargs: Any) -> list[BaseMessage]:1199        """Async format the chat template into a list of finalized messages.1200 

Showing the first 1,200 of 1492 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai