mirror of
https://github.com/hwchase17/langchain
synced 2024-11-06 03:20:49 +00:00
prompt ergonomics (#7799)
This commit is contained in:
parent
d81d6e874f
commit
cbf2fc8af8
@ -0,0 +1,358 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "4de4e022",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"# Prompt Pipelining\n",
|
||||||
|
"\n",
|
||||||
|
"The idea behind prompt pipelining is to expose a user friendly interface for composing different parts of prompts together. You can do this with either string prompts or chat prompts. Constructing prompts this way allows for easy reuse of components."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "c3190650",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## String Prompt Pipelining\n",
|
||||||
|
"\n",
|
||||||
|
"When working with string prompts, each template is joined togther. You can work with either prompts directly or strings (the first element in the list needs to be a prompt)."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 1,
|
||||||
|
"id": "69b17f05",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stderr",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"/Users/harrisonchase/.pyenv/versions/3.9.1/envs/langchain/lib/python3.9/site-packages/deeplake/util/check_latest_version.py:32: UserWarning: A newer version of deeplake (3.6.12) is available. It's recommended that you update to the latest version using `pip install -U deeplake`.\n",
|
||||||
|
" warnings.warn(\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"from langchain.prompts import PromptTemplate"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 2,
|
||||||
|
"id": "d6ac7a48",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"prompt = (\n",
|
||||||
|
" PromptTemplate.from_template(\"Tell me a joke about {topic}\")\n",
|
||||||
|
" + \", make it funny\"\n",
|
||||||
|
" + \"\\n\\nand in {language}\"\n",
|
||||||
|
")"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 3,
|
||||||
|
"id": "348d7131",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"PromptTemplate(input_variables=['language', 'topic'], output_parser=None, partial_variables={}, template='Tell me a joke about {topic}, make it funny\\n\\nand in {language}', template_format='f-string', validate_template=True)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 3,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"prompt"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 4,
|
||||||
|
"id": "dbba24ba",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"'Tell me a joke about sports, make it funny\\n\\nand in spanish'"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 4,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"prompt.format(topic=\"sports\", language=\"spanish\")"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "8239bf42",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"You can also use it in an LLMChain, just like before."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 5,
|
||||||
|
"id": "bb11649a",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"from langchain.chat_models import ChatOpenAI\n",
|
||||||
|
"from langchain.chains import LLMChain"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 6,
|
||||||
|
"id": "2dd36787",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"model = ChatOpenAI()"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 7,
|
||||||
|
"id": "2c12ba34",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"chain = LLMChain(llm=model, prompt=prompt)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 8,
|
||||||
|
"id": "a1559246",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"'¿Por qué el futbolista llevaba un paraguas al partido?\\n\\nPorque pronosticaban lluvia de goles.'"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 8,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"chain.run(topic=\"sports\", language=\"spanish\")"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "4e4f6a8a",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Chat Prompt Pipelining"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "a50ce9b8",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"A chat prompt is made up a of a list of messages. Purely for developer experience, we've added a convinient way to create these prompts. In this pipeline, each new element is a new message in the final prompt."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 1,
|
||||||
|
"id": "2a180f75",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stderr",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"/Users/harrisonchase/.pyenv/versions/3.9.1/envs/langchain/lib/python3.9/site-packages/deeplake/util/check_latest_version.py:32: UserWarning: A newer version of deeplake (3.6.10) is available. It's recommended that you update to the latest version using `pip install -U deeplake`.\n",
|
||||||
|
" warnings.warn(\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"from langchain.prompts import ChatPromptTemplate, HumanMessagePromptTemplate\n",
|
||||||
|
"from langchain.schema import HumanMessage, AIMessage, SystemMessage"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "8554bae5",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"First, let's initialize the base ChatPromptTemplate with a system message. It doesn't have to start with a system, but it's often good practice"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 2,
|
||||||
|
"id": "cab8dd65",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"prompt = SystemMessage(content=\"You are a nice pirate\")"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "30656ef8",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"You can then easily create a pipeline combining it with other messages OR message templates.\n",
|
||||||
|
"Use a `Message` when there is no variables to be formatted, use a `MessageTemplate` when there are variables to be formatted. You can also use just a string -> note that this will automatically get inferred as a HumanMessagePromptTemplate."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 3,
|
||||||
|
"id": "a2ddd0a1",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"new_prompt = (\n",
|
||||||
|
" prompt\n",
|
||||||
|
" + HumanMessage(content=\"hi\")\n",
|
||||||
|
" + AIMessage(content=\"what?\")\n",
|
||||||
|
" + \"{input}\"\n",
|
||||||
|
")"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "72294e1b",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Under the hood, this creates an instance of the ChatPromptTemplate class, so you can use it just as you did before!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 4,
|
||||||
|
"id": "297932de",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"[SystemMessage(content='You are a nice pirate', additional_kwargs={}),\n",
|
||||||
|
" HumanMessage(content='hi', additional_kwargs={}, example=False),\n",
|
||||||
|
" AIMessage(content='what?', additional_kwargs={}, example=False),\n",
|
||||||
|
" HumanMessage(content='i said hi', additional_kwargs={}, example=False)]"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 4,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"new_prompt.format_messages(input=\"i said hi\")"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "850357c0",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"You can also use it in an LLMChain, just like before"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 5,
|
||||||
|
"id": "710d6b15",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"from langchain.chat_models import ChatOpenAI\n",
|
||||||
|
"from langchain.chains import LLMChain"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 6,
|
||||||
|
"id": "d363c2a4",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"model = ChatOpenAI()"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 7,
|
||||||
|
"id": "88393b87",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"chain = LLMChain(llm=model, prompt=new_prompt)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 8,
|
||||||
|
"id": "8492cfa9",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"'Oh, hello! How can I assist you today?'"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 8,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"chain.run(\"i said hi\")"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "58196f6b",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3 (ipykernel)",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython3",
|
||||||
|
"version": "3.9.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 5
|
||||||
|
}
|
@ -56,6 +56,10 @@ class BaseMessagePromptTemplate(Serializable, ABC):
|
|||||||
List of input variables.
|
List of input variables.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def __add__(self, other: Any) -> ChatPromptTemplate:
|
||||||
|
prompt = ChatPromptTemplate(messages=[self])
|
||||||
|
return prompt + other
|
||||||
|
|
||||||
|
|
||||||
class MessagesPlaceholder(BaseMessagePromptTemplate):
|
class MessagesPlaceholder(BaseMessagePromptTemplate):
|
||||||
"""Prompt template that assumes variable is already list of messages."""
|
"""Prompt template that assumes variable is already list of messages."""
|
||||||
@ -261,6 +265,18 @@ class ChatPromptTemplate(BaseChatPromptTemplate, ABC):
|
|||||||
messages: List[Union[BaseMessagePromptTemplate, BaseMessage]]
|
messages: List[Union[BaseMessagePromptTemplate, BaseMessage]]
|
||||||
"""List of messages."""
|
"""List of messages."""
|
||||||
|
|
||||||
|
def __add__(self, other: Any) -> ChatPromptTemplate:
|
||||||
|
# Allow for easy combining
|
||||||
|
if isinstance(other, ChatPromptTemplate):
|
||||||
|
return ChatPromptTemplate(messages=self.messages + other.messages)
|
||||||
|
elif isinstance(other, (BaseMessagePromptTemplate, BaseMessage)):
|
||||||
|
return ChatPromptTemplate(messages=self.messages + [other])
|
||||||
|
elif isinstance(other, str):
|
||||||
|
prompt = HumanMessagePromptTemplate.from_template(other)
|
||||||
|
return ChatPromptTemplate(messages=self.messages + [prompt])
|
||||||
|
else:
|
||||||
|
raise NotImplementedError(f"Unsupported operand type for +: {type(other)}")
|
||||||
|
|
||||||
@root_validator(pre=True)
|
@root_validator(pre=True)
|
||||||
def validate_input_variables(cls, values: dict) -> dict:
|
def validate_input_variables(cls, values: dict) -> dict:
|
||||||
"""
|
"""
|
||||||
|
@ -43,6 +43,42 @@ class PromptTemplate(StringPromptTemplate):
|
|||||||
validate_template: bool = True
|
validate_template: bool = True
|
||||||
"""Whether or not to try validating the template."""
|
"""Whether or not to try validating the template."""
|
||||||
|
|
||||||
|
def __add__(self, other: Any) -> PromptTemplate:
|
||||||
|
# Allow for easy combining
|
||||||
|
if isinstance(other, PromptTemplate):
|
||||||
|
if self.template_format != "f-string":
|
||||||
|
raise ValueError(
|
||||||
|
"Adding prompt templates only supported for f-strings."
|
||||||
|
)
|
||||||
|
if other.template_format != "f-string":
|
||||||
|
raise ValueError(
|
||||||
|
"Adding prompt templates only supported for f-strings."
|
||||||
|
)
|
||||||
|
input_variables = list(
|
||||||
|
set(self.input_variables) | set(other.input_variables)
|
||||||
|
)
|
||||||
|
template = self.template + other.template
|
||||||
|
# If any do not want to validate, then don't
|
||||||
|
validate_template = self.validate_template and other.validate_template
|
||||||
|
partial_variables = {k: v for k, v in self.partial_variables.items()}
|
||||||
|
for k, v in other.partial_variables.items():
|
||||||
|
if k in partial_variables:
|
||||||
|
raise ValueError("Cannot have same variable partialed twice.")
|
||||||
|
else:
|
||||||
|
partial_variables[k] = v
|
||||||
|
return PromptTemplate(
|
||||||
|
template=template,
|
||||||
|
input_variables=input_variables,
|
||||||
|
partial_variables=partial_variables,
|
||||||
|
template_format="f-string",
|
||||||
|
validate_template=validate_template,
|
||||||
|
)
|
||||||
|
elif isinstance(other, str):
|
||||||
|
prompt = PromptTemplate.from_template(other)
|
||||||
|
return self + prompt
|
||||||
|
else:
|
||||||
|
raise NotImplementedError(f"Unsupported operand type for +: {type(other)}")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _prompt_type(self) -> str:
|
def _prompt_type(self) -> str:
|
||||||
"""Return the prompt type key."""
|
"""Return the prompt type key."""
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from typing import List, Sequence
|
from typing import TYPE_CHECKING, Any, List, Sequence
|
||||||
|
|
||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
|
|
||||||
from langchain.load.serializable import Serializable
|
from langchain.load.serializable import Serializable
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from langchain.prompts.chat import ChatPromptTemplate
|
||||||
|
|
||||||
|
|
||||||
def get_buffer_string(
|
def get_buffer_string(
|
||||||
messages: Sequence[BaseMessage], human_prefix: str = "Human", ai_prefix: str = "AI"
|
messages: Sequence[BaseMessage], human_prefix: str = "Human", ai_prefix: str = "AI"
|
||||||
@ -77,6 +80,12 @@ class BaseMessage(Serializable):
|
|||||||
"""Whether this class is LangChain serializable."""
|
"""Whether this class is LangChain serializable."""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def __add__(self, other: Any) -> ChatPromptTemplate:
|
||||||
|
from langchain.prompts.chat import ChatPromptTemplate
|
||||||
|
|
||||||
|
prompt = ChatPromptTemplate(messages=[self])
|
||||||
|
return prompt + other
|
||||||
|
|
||||||
|
|
||||||
class HumanMessage(BaseMessage):
|
class HumanMessage(BaseMessage):
|
||||||
"""A Message from a human."""
|
"""A Message from a human."""
|
||||||
|
Loading…
Reference in New Issue
Block a user