core: mustache prompt templates (#19980)

Co-authored-by: Erick Friis <erick@langchain.dev>
This commit is contained in:
Nuno Campos
2024-04-10 11:25:32 -07:00
committed by GitHub
parent 4cb5f4c353
commit 15271ac832
6 changed files with 904 additions and 12 deletions

View File

@@ -191,6 +191,34 @@ async def test_chat_prompt_template_from_messages_using_role_strings() -> None:
assert messages == expected
def test_chat_prompt_template_from_messages_mustache() -> None:
"""Test creating a chat prompt template from role string messages."""
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}}"),
],
"mustache",
)
messages = template.format_messages(name="Bob", user_input="What is your name?")
assert messages == [
SystemMessage(
content="You are a helpful AI bot. Your name is Bob.", additional_kwargs={}
),
HumanMessage(
content="Hello, how are you doing?", additional_kwargs={}, example=False
),
AIMessage(
content="I'm doing well, thanks!", additional_kwargs={}, example=False
),
HumanMessage(content="What is your name?", additional_kwargs={}, example=False),
]
def test_chat_prompt_template_with_messages(
messages: List[BaseMessagePromptTemplate],
) -> None:

View File

@@ -38,6 +38,135 @@ def test_prompt_from_template() -> None:
assert prompt == expected_prompt
def test_mustache_prompt_from_template() -> None:
"""Test prompts can be constructed from a template."""
# Single input variable.
template = "This is a {{foo}} test."
prompt = PromptTemplate.from_template(template, template_format="mustache")
assert prompt.format(foo="bar") == "This is a bar test."
assert prompt.input_variables == ["foo"]
assert prompt.input_schema.schema() == {
"title": "PromptInput",
"type": "object",
"properties": {"foo": {"title": "Foo", "type": "string"}},
}
# Multiple input variables.
template = "This {{bar}} is a {{foo}} test."
prompt = PromptTemplate.from_template(template, template_format="mustache")
assert prompt.format(bar="baz", foo="bar") == "This baz is a bar test."
assert prompt.input_variables == ["bar", "foo"]
assert prompt.input_schema.schema() == {
"title": "PromptInput",
"type": "object",
"properties": {
"bar": {"title": "Bar", "type": "string"},
"foo": {"title": "Foo", "type": "string"},
},
}
# Multiple input variables with repeats.
template = "This {{bar}} is a {{foo}} test {{foo}}."
prompt = PromptTemplate.from_template(template, template_format="mustache")
assert prompt.format(bar="baz", foo="bar") == "This baz is a bar test bar."
assert prompt.input_variables == ["bar", "foo"]
assert prompt.input_schema.schema() == {
"title": "PromptInput",
"type": "object",
"properties": {
"bar": {"title": "Bar", "type": "string"},
"foo": {"title": "Foo", "type": "string"},
},
}
# Nested variables.
template = "This {{obj.bar}} is a {{obj.foo}} test {{foo}}."
prompt = PromptTemplate.from_template(template, template_format="mustache")
assert prompt.format(obj={"bar": "foo", "foo": "bar"}, foo="baz") == (
"This foo is a bar test baz."
)
assert prompt.input_variables == ["foo", "obj"]
assert prompt.input_schema.schema() == {
"title": "PromptInput",
"type": "object",
"properties": {
"foo": {"title": "Foo", "type": "string"},
"obj": {"$ref": "#/definitions/obj"},
},
"definitions": {
"obj": {
"title": "obj",
"type": "object",
"properties": {
"foo": {"title": "Foo", "type": "string"},
"bar": {"title": "Bar", "type": "string"},
},
}
},
}
# . variables
template = "This {{.}} is a test."
prompt = PromptTemplate.from_template(template, template_format="mustache")
assert prompt.format(foo="baz") == ("This {'foo': 'baz'} is a test.")
assert prompt.input_variables == []
assert prompt.input_schema.schema() == {
"title": "PromptInput",
"type": "object",
"properties": {},
}
# section/context variables
template = """This{{#foo}}
{{bar}}
{{/foo}}is a test."""
prompt = PromptTemplate.from_template(template, template_format="mustache")
assert prompt.format(foo={"bar": "yo"}) == (
"""This
yo
is a test."""
)
assert prompt.input_variables == ["foo"]
assert prompt.input_schema.schema() == {
"title": "PromptInput",
"type": "object",
"properties": {"foo": {"$ref": "#/definitions/foo"}},
"definitions": {
"foo": {
"title": "foo",
"type": "object",
"properties": {"bar": {"title": "Bar", "type": "string"}},
}
},
}
# section/context variables with repeats
template = """This{{#foo}}
{{bar}}
{{/foo}}is a test."""
prompt = PromptTemplate.from_template(template, template_format="mustache")
assert prompt.format(foo=[{"bar": "yo"}, {"bar": "hello"}]) == (
"""This
yo
hello
is a test."""
)
assert prompt.input_variables == ["foo"]
assert prompt.input_schema.schema() == {
"title": "PromptInput",
"type": "object",
"properties": {"foo": {"$ref": "#/definitions/foo"}},
"definitions": {
"foo": {
"title": "foo",
"type": "object",
"properties": {"bar": {"title": "Bar", "type": "string"}},
}
},
}
def test_prompt_from_template_with_partial_variables() -> None:
"""Test prompts can be constructed from a template with partial variables."""
# given