mirror of
https://github.com/hwchase17/langchain.git
synced 2025-07-23 13:02:59 +00:00
core[patch]: allow "placeholder" type in from_messages tuples (#19152)
Co-authored-by: Erick Friis <erick@langchain.dev>
This commit is contained in:
parent
f6bcd42421
commit
e980c14d6a
@ -551,7 +551,10 @@ MessageLike = Union[BaseMessagePromptTemplate, BaseMessage, BaseChatPromptTempla
|
|||||||
|
|
||||||
MessageLikeRepresentation = Union[
|
MessageLikeRepresentation = Union[
|
||||||
MessageLike,
|
MessageLike,
|
||||||
Tuple[Union[str, Type], Union[str, List[dict], List[object]]],
|
Tuple[
|
||||||
|
Union[str, Type],
|
||||||
|
Union[str, List[dict], List[object]],
|
||||||
|
],
|
||||||
str,
|
str,
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -590,6 +593,45 @@ class ChatPromptTemplate(BaseChatPromptTemplate):
|
|||||||
# ]
|
# ]
|
||||||
#)
|
#)
|
||||||
|
|
||||||
|
Messages Placeholder:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# In addition to Human/AI/Tool/Function messages,
|
||||||
|
# you can initialize the template with a MessagesPlaceholder
|
||||||
|
# either using the class directly or with the shorthand tuple syntax:
|
||||||
|
|
||||||
|
template = ChatPromptTemplate.from_messages([
|
||||||
|
("system", "You are a helpful AI bot."),
|
||||||
|
# Means the template will receive an optional list of messages under
|
||||||
|
# the "conversation" key
|
||||||
|
("placeholder", "{conversation}")
|
||||||
|
# Equivalently:
|
||||||
|
# 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.")
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Output:
|
||||||
|
# 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.'),
|
||||||
|
# ]
|
||||||
|
#)
|
||||||
|
|
||||||
Single-variable template:
|
Single-variable template:
|
||||||
|
|
||||||
If your prompt has only a single input variable (i.e., 1 instance of "{variable_nams}"),
|
If your prompt has only a single input variable (i.e., 1 instance of "{variable_nams}"),
|
||||||
@ -949,6 +991,36 @@ def _create_template_from_message_type(
|
|||||||
message = AIMessagePromptTemplate.from_template(cast(str, template))
|
message = AIMessagePromptTemplate.from_template(cast(str, template))
|
||||||
elif message_type == "system":
|
elif message_type == "system":
|
||||||
message = SystemMessagePromptTemplate.from_template(cast(str, template))
|
message = SystemMessagePromptTemplate.from_template(cast(str, template))
|
||||||
|
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:
|
else:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Unexpected message type: {message_type}. Use one of 'human',"
|
f"Unexpected message type: {message_type}. Use one of 'human',"
|
||||||
|
@ -535,6 +535,25 @@ def test_chat_prompt_message_placeholder_partial() -> None:
|
|||||||
assert prompt.format_messages() == [SystemMessage(content="foo")]
|
assert prompt.format_messages() == [SystemMessage(content="foo")]
|
||||||
|
|
||||||
|
|
||||||
|
def test_chat_prompt_message_placeholder_tuple() -> None:
|
||||||
|
prompt = ChatPromptTemplate.from_messages([("placeholder", "{convo}")])
|
||||||
|
assert prompt.format_messages(convo=[("user", "foo")]) == [
|
||||||
|
HumanMessage(content="foo")
|
||||||
|
]
|
||||||
|
|
||||||
|
assert prompt.format_messages() == []
|
||||||
|
|
||||||
|
# Is optional = True
|
||||||
|
optional_prompt = ChatPromptTemplate.from_messages(
|
||||||
|
[("placeholder", ["{convo}", False])]
|
||||||
|
)
|
||||||
|
assert optional_prompt.format_messages(convo=[("user", "foo")]) == [
|
||||||
|
HumanMessage(content="foo")
|
||||||
|
]
|
||||||
|
with pytest.raises(KeyError):
|
||||||
|
assert optional_prompt.format_messages() == []
|
||||||
|
|
||||||
|
|
||||||
def test_messages_prompt_accepts_list() -> None:
|
def test_messages_prompt_accepts_list() -> None:
|
||||||
prompt = ChatPromptTemplate.from_messages([MessagesPlaceholder("history")])
|
prompt = ChatPromptTemplate.from_messages([MessagesPlaceholder("history")])
|
||||||
value = prompt.invoke([("user", "Hi there")]) # type: ignore
|
value = prompt.invoke([("user", "Hi there")]) # type: ignore
|
||||||
|
Loading…
Reference in New Issue
Block a user