Source code for langchain_core.prompts.few_shot_with_templates

"""Prompt template that contains few shot examples."""

from pathlib import Path
from typing import Any, Optional, Union

from pydantic import ConfigDict, model_validator
from typing_extensions import Self

from langchain_core.prompts.prompt import PromptTemplate
from langchain_core.prompts.string import (
    DEFAULT_FORMATTER_MAPPING,
    PromptTemplateFormat,
    StringPromptTemplate,
)


[docs] class FewShotPromptWithTemplates(StringPromptTemplate): """Prompt template that contains few shot examples.""" examples: Optional[list[dict]] = None """Examples to format into the prompt. Either this or example_selector should be provided.""" example_selector: Any = None """ExampleSelector to choose the examples to format into the prompt. Either this or examples should be provided.""" example_prompt: PromptTemplate """PromptTemplate used to format an individual example.""" suffix: StringPromptTemplate """A PromptTemplate to put after the examples.""" example_separator: str = "\n\n" """String separator used to join the prefix, the examples, and suffix.""" prefix: Optional[StringPromptTemplate] = None """A PromptTemplate to put before the examples.""" template_format: PromptTemplateFormat = "f-string" """The format of the prompt template. Options are: 'f-string', 'jinja2', 'mustache'.""" validate_template: bool = False """Whether or not to try validating the template.""" @classmethod def get_lc_namespace(cls) -> list[str]: """Get the namespace of the langchain object.""" return ["langchain", "prompts", "few_shot_with_templates"] @model_validator(mode="before") @classmethod def check_examples_and_selector(cls, values: dict) -> Any: """Check that one and only one of examples/example_selector are provided.""" examples = values.get("examples") example_selector = values.get("example_selector") if examples and example_selector: msg = "Only one of 'examples' and 'example_selector' should be provided" raise ValueError(msg) if examples is None and example_selector is None: msg = "One of 'examples' and 'example_selector' should be provided" raise ValueError(msg) return values @model_validator(mode="after") def template_is_valid(self) -> Self: """Check that prefix, suffix, and input variables are consistent.""" if self.validate_template: input_variables = self.input_variables expected_input_variables = set(self.suffix.input_variables) expected_input_variables |= set(self.partial_variables) if self.prefix is not None: expected_input_variables |= set(self.prefix.input_variables) missing_vars = expected_input_variables.difference(input_variables) if missing_vars: msg = ( f"Got input_variables={input_variables}, but based on " f"prefix/suffix expected {expected_input_variables}" ) raise ValueError(msg) else: self.input_variables = sorted( set(self.suffix.input_variables) | set(self.prefix.input_variables if self.prefix else []) - set(self.partial_variables) ) return self model_config = ConfigDict( arbitrary_types_allowed=True, extra="forbid", ) def _get_examples(self, **kwargs: Any) -> list[dict]: 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 async def _aget_examples(self, **kwargs: Any) -> list[dict]: 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
[docs] def format(self, **kwargs: Any) -> str: """Format the prompt with the inputs. Args: kwargs: Any arguments to be passed to the prompt template. Returns: A formatted string. Example: .. code-block:: python prompt.format(variable1="foo") """ kwargs = self._merge_partial_and_user_variables(**kwargs) # Get the examples to use. examples = self._get_examples(**kwargs) # Format the examples. example_strings = [ self.example_prompt.format(**example) for example in examples ] # Create the overall prefix. if self.prefix is None: prefix = "" else: prefix_kwargs = { k: v for k, v in kwargs.items() if k in self.prefix.input_variables } for k in prefix_kwargs: kwargs.pop(k) prefix = self.prefix.format(**prefix_kwargs) # Create the overall suffix suffix_kwargs = { k: v for k, v in kwargs.items() if k in self.suffix.input_variables } for k in suffix_kwargs: kwargs.pop(k) suffix = self.suffix.format( **suffix_kwargs, ) pieces = [prefix, *example_strings, suffix] template = self.example_separator.join([piece for piece in pieces if piece]) # Format the template with the input variables. return DEFAULT_FORMATTER_MAPPING[self.template_format](template, **kwargs)
[docs] async def aformat(self, **kwargs: Any) -> str: """Async format the prompt with the inputs. Args: kwargs: Any arguments to be passed to the prompt template. Returns: A formatted string. """ kwargs = self._merge_partial_and_user_variables(**kwargs) # Get the examples to use. examples = await self._aget_examples(**kwargs) # Format the examples. example_strings = [ # We can use the sync method here as PromptTemplate doesn't block self.example_prompt.format(**example) for example in examples ] # Create the overall prefix. if self.prefix is None: prefix = "" else: prefix_kwargs = { k: v for k, v in kwargs.items() if k in self.prefix.input_variables } for k in prefix_kwargs: kwargs.pop(k) prefix = await self.prefix.aformat(**prefix_kwargs) # Create the overall suffix suffix_kwargs = { k: v for k, v in kwargs.items() if k in self.suffix.input_variables } for k in suffix_kwargs: kwargs.pop(k) suffix = await self.suffix.aformat( **suffix_kwargs, ) pieces = [prefix, *example_strings, suffix] template = self.example_separator.join([piece for piece in pieces if piece]) # Format the template with the input variables. return DEFAULT_FORMATTER_MAPPING[self.template_format](template, **kwargs)
@property def _prompt_type(self) -> str: """Return the prompt type key.""" return "few_shot_with_templates"
[docs] def save(self, file_path: Union[Path, str]) -> None: """Save the prompt to a file. Args: file_path: The path to save the prompt to. Raises: ValueError: If example_selector is provided. """ if self.example_selector: msg = "Saving an example selector is not currently supported" raise ValueError(msg) return super().save(file_path)