mirror of
https://github.com/hwchase17/langchain.git
synced 2025-06-29 18:08:36 +00:00
core[patch]: fix loss of partially initialized variables during prompt composition (#30096)
**Description:** This PR addresses the loss of partially initialised variables when composing different prompts. I.e. it allows the following snippet to run: ```python from langchain_core.prompts import ChatPromptTemplate prompt = ChatPromptTemplate.from_messages([('system', 'Prompt {x} {y}')]).partial(x='1') appendix = ChatPromptTemplate.from_messages([('system', 'Appendix {z}')]) (prompt + appendix).invoke({'y': '2', 'z': '3'}) ``` Previously, this would have raised a `KeyError`, stating that variable `x` remains undefined. **Issue** References issue #30049 **Todo** - [x] **Add tests and docs**: If you're adding a new integration, please include 1. a test for the integration, preferably unit tests that do not rely on network access, 2. an example notebook showing its use. It lives in `docs/docs/integrations` directory. - [x] **Lint and test**: Run `make format`, `make lint` and `make test` from the root of the package(s) you've modified. See contribution guidelines for more: https://python.langchain.com/docs/contributing/ --------- Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
This commit is contained in:
parent
e7883d5b9f
commit
372dc7f991
@ -1040,19 +1040,34 @@ class ChatPromptTemplate(BaseChatPromptTemplate):
|
|||||||
Returns:
|
Returns:
|
||||||
Combined prompt template.
|
Combined prompt template.
|
||||||
"""
|
"""
|
||||||
|
partials = {**self.partial_variables}
|
||||||
|
|
||||||
|
# Need to check that other has partial variables since it may not be
|
||||||
|
# a ChatPromptTemplate.
|
||||||
|
if hasattr(other, "partial_variables") and other.partial_variables:
|
||||||
|
partials.update(other.partial_variables)
|
||||||
|
|
||||||
# Allow for easy combining
|
# Allow for easy combining
|
||||||
if isinstance(other, ChatPromptTemplate):
|
if isinstance(other, ChatPromptTemplate):
|
||||||
return ChatPromptTemplate(messages=self.messages + other.messages) # type: ignore[call-arg]
|
return ChatPromptTemplate(messages=self.messages + other.messages).partial(
|
||||||
|
**partials
|
||||||
|
) # type: ignore[call-arg]
|
||||||
elif isinstance(
|
elif isinstance(
|
||||||
other, (BaseMessagePromptTemplate, BaseMessage, BaseChatPromptTemplate)
|
other, (BaseMessagePromptTemplate, BaseMessage, BaseChatPromptTemplate)
|
||||||
):
|
):
|
||||||
return ChatPromptTemplate(messages=self.messages + [other]) # type: ignore[call-arg]
|
return ChatPromptTemplate(messages=self.messages + [other]).partial(
|
||||||
|
**partials
|
||||||
|
) # type: ignore[call-arg]
|
||||||
elif isinstance(other, (list, tuple)):
|
elif isinstance(other, (list, tuple)):
|
||||||
_other = ChatPromptTemplate.from_messages(other)
|
_other = ChatPromptTemplate.from_messages(other)
|
||||||
return ChatPromptTemplate(messages=self.messages + _other.messages) # type: ignore[call-arg]
|
return ChatPromptTemplate(messages=self.messages + _other.messages).partial(
|
||||||
|
**partials
|
||||||
|
) # type: ignore[call-arg]
|
||||||
elif isinstance(other, str):
|
elif isinstance(other, str):
|
||||||
prompt = HumanMessagePromptTemplate.from_template(other)
|
prompt = HumanMessagePromptTemplate.from_template(other)
|
||||||
return ChatPromptTemplate(messages=self.messages + [prompt]) # type: ignore[call-arg]
|
return ChatPromptTemplate(messages=self.messages + [prompt]).partial(
|
||||||
|
**partials
|
||||||
|
) # type: ignore[call-arg]
|
||||||
else:
|
else:
|
||||||
msg = f"Unsupported operand type for +: {type(other)}"
|
msg = f"Unsupported operand type for +: {type(other)}"
|
||||||
raise NotImplementedError(msg)
|
raise NotImplementedError(msg)
|
||||||
|
@ -582,6 +582,23 @@ def test_chat_message_partial() -> None:
|
|||||||
assert template2.format(input="hello") == get_buffer_string(expected)
|
assert template2.format(input="hello") == get_buffer_string(expected)
|
||||||
|
|
||||||
|
|
||||||
|
def test_chat_message_partial_composition() -> None:
|
||||||
|
"""Test composition of partially initialized messages."""
|
||||||
|
prompt = ChatPromptTemplate.from_messages([("system", "Prompt {x} {y}")]).partial(
|
||||||
|
x="1"
|
||||||
|
)
|
||||||
|
|
||||||
|
appendix = ChatPromptTemplate.from_messages([("system", "Appendix {z}")])
|
||||||
|
|
||||||
|
res = (prompt + appendix).format_messages(y="2", z="3")
|
||||||
|
expected = [
|
||||||
|
SystemMessage(content="Prompt 1 2"),
|
||||||
|
SystemMessage(content="Appendix 3"),
|
||||||
|
]
|
||||||
|
|
||||||
|
assert res == expected
|
||||||
|
|
||||||
|
|
||||||
async def test_chat_tmpl_from_messages_multipart_text() -> None:
|
async def test_chat_tmpl_from_messages_multipart_text() -> None:
|
||||||
template = ChatPromptTemplate.from_messages(
|
template = ChatPromptTemplate.from_messages(
|
||||||
[
|
[
|
||||||
|
Loading…
Reference in New Issue
Block a user