Prompt templates#

In previous recipes, a prompt was just a simple Python string. We already encountered a situation, where we needed to use a variable in the prompt. For example, let’s say we want to create a pun generator that creates a pun based on a general topic. Every time we prompt the model, only the topic part of the prompt will change. So what is an efficient, convenient way to handle this?

from langchain_dartmouth.llms import ChatDartmouth
from dotenv import find_dotenv, load_dotenv

load_dotenv(find_dotenv())
True

Building prompts with basic Python strings#

As we have done before, we could create a simple string prompt and add the topic to it through string concatenation. First, we define the part of the prompt that does not change:

prompt = "You are a pun generator. Your task is to generate a pun based on the following topic: "

Then, we add the missing piece when we prompt the model:

llm = ChatDartmouth(model_name="meta.llama-3.2-11b-vision-instruct")
response = llm.invoke(prompt + "computer programming")

print(response.content)
Here's one:

Why did the programmer quit his job? Because he didn't get arrays of fulfillment, and his code was always crashing - it was a byte of a problem.

That works, but it is a little clunky. The main issue here is that we have to design the prompt in a way that puts all the variable parts at the end. For short prompts like this one, this might be acceptable. It greatly limits our design space, though, when we are dealing with longer instructions. What if want more than one variable part with a constant part in between?

Prompt templates#

Prompt templates (e.g., the PromptTemplate class) are components in the LangChain ecosystem that allow you to define your prompts more flexibly by using placeholders and then filling them with actual values when needed.

Let’s create the same pun generator as above using a PromptTemplate:

from langchain_core.prompts import PromptTemplate

prompt = PromptTemplate(
    template="You are a pun generator. Your task is to generate a pun based on the following topic: {topic}"
)

Notice the special substring {topic}! This is how we define a location and a name for a placeholder in the prompt!

Note

Prompt templates are similar to Python’s f-strings or format strings, but offer some additional convenience when using them with other LangChain components, as we will see in some later recipes. Most importantly, they do not require the placeholders to be filled when the string is first defined, but can defer this to a later time when they are invoked (see below).

We can fill in the placeholder using the PromptTemplate component’s invoke method to fully specify the prompt:

print(prompt.invoke("computer science"))
text='You are a pun generator. Your task is to generate a pun based on the following topic: computer science'

We can pass the now complete prompt directly to our LLM:

response = llm.invoke(prompt.invoke("computer science"))
print(response.content)
Here's a pun for you:

Why did the programmer quit his job? 

Because he didn't get arrays of opportunities, and his code was always crashing - he just couldn't debug his future!

So if we want to run this repeatedly for different topics, we only need to change the prompt template’s argument:

topics = ["college", "soccer", "cooking"]

for topic in topics:
    response = llm.invoke(prompt.invoke(topic))
    print(response.content)
    print("-" * 10)
Here's one: 

"Why did the college student bring a ladder to class? They wanted to reach their full potential!"
----------
Here's one that's sure to score:

"Why did the soccer player bring a pillow onto the field? He wanted to have a soft defense!"

Hope that one kicked your interest!
----------
"Knead to know" that I've got a recipe for a tasty pun - Why did the cookie go to the doctor? Because it felt crumby!
----------

We could also extend this technique to multiple placeholders. Here is what the prompt template would look like in that case:

prompt = PromptTemplate(
    template="You are a pun generator. Your task is to generate a pun based on the following topic: {topic}. Your current mood is {mood}."
)

Now that we have more than placeholder, we cannot simply pass a single argument to the invoke method, though, because the prompt would not know which placeholder to map it to. Instead, we pass in a dictionary, using the placeholder names as keys and the desired text to fill-in as values:

placeholder_fillers = {"topic": "computer science", "mood": "exhilirated"}
print(prompt.invoke(placeholder_fillers))
text='You are a pun generator. Your task is to generate a pun based on the following topic: computer science. Your current mood is exhilirated.'

Now we can iterate through two lists t of topics and moods to generate pun for each pair:

moods = ["giggly", "dramatic", "whimsical"]

for topic, mood in zip(topics, moods):
    response = llm.invoke(prompt.invoke({"topic": topic, "mood": mood}))
    print(response.content)
    print("-" * 10)
I'm feeling a little "book-smart" today, aren't I? Here's a pun that's sure to "grade" high:

Why did the college student bring a ladder to class?

Because they wanted to reach their full potential!
----------
*Sigh* Oh, the weight of expectation bears down upon me. I must conjure a pun worthy of the beautiful game. And so, with a heavy heart, I present to you...

"Why did the soccer ball go to therapy? Because it was feeling deflated. But little did it know, it was just going through a phase... of possession. *Sobs*"

There, I've done it. May this pun be a goal for the ages... or a penalty for my sanity.
----------
I'm feeling saucy today. Here's a whippin' good pun for ya: 

"Why did the chef go to the party? Because he heard it was a 'recipe' for a great time, and he didn't want to be a 'butter' disappointment!"
----------

Since PromptTemplate objects are more than just strings, they have a few methods and fields that can be useful in the right circumstances. For example, you can learn the names of the required placeholders using the field input_variables:

prompt.input_variables
['mood', 'topic']

Chat prompt templates#

You can also create and use templates for chat prompts with a sequence of messages of different types:

from langchain_core.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate(
    [("system", "You are a {animal}."), ("human", "Tell us about {topic}.")]
)

prompt.invoke({"animal": "dog", "topic": "your day"})
ChatPromptValue(messages=[SystemMessage(content='You are a dog.', additional_kwargs={}, response_metadata={}), HumanMessage(content='Tell us about your day.', additional_kwargs={}, response_metadata={})])
response = llm.invoke(prompt.invoke({"animal": "dog", "topic": "your day"}))
print(response.content)
*wags tail* Oh boy, I had such a great day! It started early, as it usually does. My human, whom I lovingly refer to as "The Food Lady," woke me up by scratching behind my ears. I love that spot! I stretched my paws out and arched my back, giving a good yawn to signal the start of my day.

After a quick breakfast, we went for a walk around the block. I love walks! I get to sniff all the interesting smells and mark my territory. The Food Lady always laughs at me when I try to chase squirrels. I'm not really sure why they're so fast, but I'm determined to catch them one day.

When we got back home, The Food Lady gave me a nice belly rub, and I settled in for a nap. I'm a dog, after all, and napping is one of my favorite activities.

Later in the day, The Food Lady played fetch with me in the backyard. I love chasing after balls and bringing them back to her. I'm not always the best at catching them, but it's all about the thrill of the chase, right?

Now I'm just relaxing with The Food Lady on the couch, enjoying some quality time together. Life is good as a dog! *panting happily*

Summary#

Prompt templates allow us to create a consistent structure for our prompts and make them more re-usable across different applications or tasks. This makes it easier to generate the right kind of input for an AI model, while also making the code cleaner and more readable.