[Feat] Accept non-dict if only 1 prompt input variable (#19156)

For prompt templates with only 1 variable (common in e.g.,
MessageGraph), it's convenient to wrap the incoming object in the
variable before formatting.


The downside of this, of course, would be that some number of
invocations will successfully format when the user may have intended to
format it properly before
pull/19246/head^2
William FH 6 months ago committed by GitHub
parent d9396bdec1
commit 68298cdc82
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -89,10 +89,15 @@ class BasePromptTemplate(
def _format_prompt_with_error_handling(self, inner_input: Dict) -> PromptValue:
if not isinstance(inner_input, dict):
raise TypeError(
f"Expected mapping type as input to {self.__class__.__name__}. "
f"Received {type(inner_input)}."
)
if len(self.input_variables) == 1:
var_name = self.input_variables[0]
inner_input = {var_name: inner_input}
else:
raise TypeError(
f"Expected mapping type as input to {self.__class__.__name__}. "
f"Received {type(inner_input)}."
)
missing = set(self.input_variables).difference(inner_input)
if missing:
raise KeyError(

@ -574,11 +574,51 @@ class ChatPromptTemplate(BaseChatPromptTemplate):
("human", "{user_input}"),
])
messages = template.format_messages(
name="Bob",
user_input="What is your name?"
prompt_value = template.invoke(
{
"name": "Bob",
"user_input": "What is your name?"
}
)
"""
# Output:
# 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?')
# ]
#)
Single-variable template:
If your prompt has only a single input variable (i.e., 1 instance of "{variable_nams}"),
and you invoke the template with a non-dict object, the prompt template will
inject the provided argument into that variable location.
.. 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!")
# Equivalent to
# prompt_value = template.invoke({"user_input": "Hello, there!"})
# Output:
# ChatPromptValue(
# messages=[
# SystemMessage(content='You are a helpful AI bot. Your name is Carl.'),
# HumanMessage(content='Hello, there!'),
# ]
# )
""" # noqa: E501
input_variables: List[str]
"""List of input variables in template messages. Used for validation."""

@ -533,3 +533,16 @@ def test_chat_prompt_message_placeholder_partial() -> None:
assert prompt.format_messages() == []
prompt = prompt.partial(history=[("system", "foo")])
assert prompt.format_messages() == [SystemMessage(content="foo")]
def test_messages_prompt_accepts_list() -> None:
prompt = ChatPromptTemplate.from_messages([MessagesPlaceholder("history")])
value = prompt.invoke([("user", "Hi there")]) # type: ignore
assert value.to_messages() == [HumanMessage(content="Hi there")]
# Assert still raises a nice error
prompt = ChatPromptTemplate.from_messages(
[("system", "You are a {foo}"), MessagesPlaceholder("history")]
)
with pytest.raises(TypeError):
prompt.invoke([("user", "Hi there")]) # type: ignore

Loading…
Cancel
Save