Unpacking Prompt Templates with LangChain
Data Mastery Series — Episode 27: LangChain Website (Part 2)
Unpacking Prompt Templates with LangChain
Data Mastery Series — Episode 27: LangChain Website (Part 2)

Connect with me and follow our journey: Linkedin, Facebook
Hey everyone! Welcome back to the Data Mastery Series! We’re continuing our Generative AI adventure with LangChain. If you’re just joining us, make sure to check out Part 1 here:
- Part 1: LangChain Model I/O Basics
Note: As we dive into LangChain, I’ll be sharing insights and key notes from my own study of the LangChain documentation. Let’s jump in and explore some fascinating features in today’s episode!
Source: https://python.langchain.com/v0.1/docs/modules/model%5Fio/prompts/
Today, we’re diving into the heart of AI communication: Prompt. Think of prompts like instructions you give to a helpful robot. The clearer your instructions, the better the robot understands what you want. LangChain provides some handy tools called Prompt Templates to make this whole process easier. Let’s explore!
A. Quick Reference:
1. Your Basic Prompt Recipes
LangChain offers two main types of prompt templates:
- PromptTemplate: In real-world applications, prompts need to be task-specific. With PromptTemplate, you can create dynamic prompts that include user input without showing the full prompt. For example, if you want the AI to tell a joke, you could create a template like
"Tell me a {adjective} joke about {content}."Then, you simply plug in user inputs for the adjectives and content.
Example - PromptTemplate
prompt_template = PromptTemplate.from_template("Tell me a {adjective} joke about {content}.")
result = prompt_template.format(adjective="funny", content="chickens")
result
Output
'''
Tell me a funny joke about chickens.
'''
You can also create a simpler prompt without variables:
Example - Without PromptTemplate
prompt_template = PromptTemplate.from_template("Tell me a joke")
prompt_template.format()
Output
'''
Tell me a joke
'''
- ChatPromptTemplate: This one’s perfect for chatbots! It helps you create back-and-forth conversations by assigning roles like “system” (the AI’s personality), “human” (the user), and “ai” (the AI’s responses). Think of it like writing a script for a play.
Example - ChatPromptTemplate
chat_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}"),
]
)
messages = chat_template.format_messages(name="Bob", user_input="What is your name?")
messages
Output
'''
[SystemMessage(content='You are a helpful AI bot. Your name is Bob.', additional_kwargs={}, response_metadata={}),
HumanMessage(content='Hello, how are you doing?', additional_kwargs={}, response_metadata={}),
AIMessage(content="I'm doing well, thanks!", additional_kwargs={}, response_metadata={}),
HumanMessage(content='What is your name?', additional_kwargs={}, response_metadata={})]
Tell me a funny joke about chickens.
'''
This example shows how you can structure a conversation with multiple messages, each with a specified role, and the ChatPromptTemplate.from_messages function simplifies creating complex, multi-message interactions. For even more customization, you can combine ChatPromptTemplate with other objects like MessagePromptTemplate to use a template for a more specific task.
Example - OpenAI
chat_template = ChatPromptTemplate.from_messages(
[
SystemMessage(
content=(
"You are a helpful assistant that re-writes the user's text to "
"sound more upbeat."
)
),
HumanMessagePromptTemplate.from_template("{text}"),
]
)
messages = chat_template.format_messages(text="I don't like eating tasty things")
print(messages)
Output
'''
[SystemMessage(content="You are a helpful assistant that re-writes the user's text to sound more upbeat.", additional_kwargs={}, response_metadata={}),
HumanMessage(content="I don't like eating tasty things", additional_kwargs={}, response_metadata={})]
'''
2. Message Prompts: Adding Flexibility to the Conversation
Once you’ve grasped the basics of prompts, you can enhance your interaction with Message Templates, which allow you to customize messages for different roles. Let’s dive into two types of templates that add more flexibility to your prompts.
- ChatMessagePromptTemplate: This lets you create messages with custom roles beyond the standard “system,” “human,” and “AI.” Imagine you want your AI to act like a Jedi. You could set the role as “Jedi” and use a template like “May the {subject} be with you.”
Example - ChatMessagePromptTemplate
prompt = "May the {subject} be with you"
chat_message_prompt = ChatMessagePromptTemplate.from_template(
role="Jedi", template=prompt
)
chat_message_prompt.format(subject="force")
Output
'''
ChatMessage(content='May the force be with you', additional_kwargs={}, response_metadata={}, role='Jedi')
'''
- MessagesPlaceholder: Imagine inserting a whole chunk of conversation into a prompt. That’s what MessagesPlaceholder lets you do, making prompts dynamic and adaptable.
Example - MessagesPlaceholder
human_prompt = "Summarize our conversation so far in {word_count} words."
human_message_template = HumanMessagePromptTemplate.from_template(human_prompt)
chat_prompt = ChatPromptTemplate.from_messages(
[MessagesPlaceholder(variable_name="conversation"), human_message_template]
)
human_message = HumanMessage(content="What is the best way to learn programming?")
ai_message = AIMessage(
content="""\
- Choose a programming language: Decide on a programming language that you want to learn.
- Start with the basics: Familiarize yourself with the basic programming concepts such as variables, data types and control structures.
- Practice, practice, practice: The best way to learn programming is through hands-on experience\
"""
)
chat_prompt.format_prompt(
conversation=[human_message, ai_message], word_count="10"
).to_messages()
Output
'''
[HumanMessage(content='What is the best way to learn programming?', additional_kwargs={}, response_metadata={}),
AIMessage(content='1. Choose a programming language: Decide on a programming language that you want to learn.\n\n2. Start with the basics: Familiarize yourself with the basic programming concepts such as variables, data types and control structures.\n\n3. Practice, practice, practice: The best way to learn programming is through hands-on experience', additional_kwargs={}, response_metadata={}),
HumanMessage(content='Summarize our conversation so far in 10 words.', additional_kwargs={}, response_metadata={})]"
'''
3. LCEL: Making Prompts Dynamic and Powerful
LangChain Expression Language (LCEL) adds a layer of customization to prompts, making them not only flexible but also powerful. Here’s a quick example of how LCEL can make prompts dynamic:
Example - LCEL
chat_template = ChatPromptTemplate.from_messages(
[
SystemMessage(
content=(
"You are a helpful assistant that re-writes the user's text to "
"sound more upbeat."
)
),
HumanMessagePromptTemplate.from_template("{text}"),
]
)
chat_val = chat_template.invoke({"text": "i dont like eating tasty things."})
chat_val.to_messages()
Output
'''
[SystemMessage(content="You are a helpful assistant that re-writes the user's text to sound more upbeat.", additional_kwargs={}, response_metadata={}),
HumanMessage(content='i dont like eating tasty things.', additional_kwargs={}, response_metadata={})]
'''
Example - LCEL (continues)
chat_val.to_string()
Output
'''
System: You are a helpful assistant that re-writes the user's text to sound more upbeat.
Human: i dont like eating tasty things.
'''
B. Example Selectors: Controlling Prompt Length
In certain situations, it’s essential to control the length and relevance of the input to a language model. LangChain provides various example selectors to help manage this, each with a unique approach. Today, we’ll explore four of these methods:
- 1) Length-Based Selector
The Length-Based Example Selector picks examples based on token count, ensuring that the prompt stays within a specific length.
Example - Length-Based
List of examples for a task, such as creating antonyms:
examples = [
{"input": "happy", "output": "sad"},
{"input": "tall", "output": "short"},
{"input": "energetic", "output": "lethargic"},
{"input": "sunny", "output": "gloomy"},
{"input": "windy", "output": "calm"},
]
Define the template for examples
example_prompt = PromptTemplate(
input_variables=["input", "output"],
template="Input: {input}\nOutput: {output}",
)
Initialize the Length-Based Example Selector with a maximum length
example_selector = LengthBasedExampleSelector(
examples=examples,
example_prompt=example_prompt,
max_length=25, # Maximum allowed length for the examples
)
Define the main prompt template with the selector
dynamic_prompt = FewShotPromptTemplate(
example_selector=example_selector,
example_prompt=example_prompt,
prefix="Give the antonym of every input",
suffix="Input: {adjective}\nOutput:",
input_variables=["adjective"],
)
Format the prompt with a sample input
formatted_prompt = dynamic_prompt.format(adjective="big")
print("Formatted Prompt:", formatted_prompt)
Output Example
'''
Formatted Prompt: Give the antonym of every input
Input: happy
Output: sad
Input: tall
Output: short
Input: energetic
Output: lethargic
Input: sunny
Output: gloomy
Input: windy
Output: calm
Input: big
Output: small
Input: big
Output:
'''
The Length-Based Example Selector carefully selects examples that fit within the specified length, providing a concise list of antonyms for shorter inputs. As the input length increases, the selector dynamically adjusts by removing examples to keep the prompt within the allowed token count. Let’s explore how it performs with a longer input string.
Example with a longer input string
long_string = "big and huge and massive and large and gigantic and tall and much much much much much bigger than everything else"
long_formatted_prompt = dynamic_prompt.format(adjective=long_string)
print("Formatted Prompt:", long_formatted_prompt)
Output Example
'''
Formatted Prompt: Give the antonym of every input
Input: happy
Output: sad
Input: big and huge and massive and large and gigantic and tall and much much much much much bigger than everything else
Output:
'''
- 2) Maximal Marginal Relevance (MMR) Selector
MMR Selector balances similarity and diversity, ensuring that selected examples are relevant but varied.
Example - MaxMarginalRelevanceExampleSelector
example_prompt = PromptTemplate(
input_variables=["input", "output"],
template="Input: {input}\nOutput: {output}",
)
examples = [
{"input": "happy", "output": "sad"},
{"input": "tall", "output": "short"},
{"input": "energetic", "output": "lethargic"},
{"input": "sunny", "output": "gloomy"},
{"input": "windy", "output": "calm"},
]
example_selector = MaxMarginalRelevanceExampleSelector.from_examples(
examples,
OpenAIEmbeddings(),
FAISS,
k=2,
)
mmr_prompt = FewShotPromptTemplate(
example_selector=example_selector,
example_prompt=example_prompt,
prefix="Give the antonym of every input",
suffix="Input: {adjective}\nOutput:",
input_variables=["adjective"],
)
print(mmr_prompt.format(adjective="worried"))
Output Example
'''
Give the antonym of every input
Input: happy
Output: sad
Input: windy
Output: calm
Input: worried
Output:
'''
The MaxMarginalRelevanceExampleSelector selects examples by balancing similarity to the input with diversity among the chosen examples. In the example above, when we input “worried,” the MMR selector identifies “happy/sad” as the closest match and “windy/calm” for added diversity. If we want to focus purely on similarity, we can use Semantic Similarity instead, as shown in the code below.
Example - SemanticSimilarityExampleSelector
example_selector = SemanticSimilarityExampleSelector.from_examples(
examples,
OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY),
FAISS,
k=2,
)
similar_prompt = FewShotPromptTemplate(
example_selector=example_selector,
example_prompt=example_prompt,
prefix="Give the antonym of every input",
suffix="Input: {adjective}\nOutput:",
input_variables=["adjective"],
)
)
print(mmr_prompt.format(adjective="worried"))
Output Example
'''
Give the antonym of every input
Input: happy
Output: sad
Input: sunny
Output: gloomy
Input: worried
Output:
'''
- 3) N-Gram Overlap Selector:
The N-Gram Overlap Selector picks examples based on shared word sequences (n-grams) with the input. By adjusting the threshold, you can control which examples are included.
Example - SemanticSimilarityExampleSelector
example_prompt = PromptTemplate(
input_variables=["input", "output"],
template="Input: {input}\nOutput: {output}",
)
examples = [
{"input": "See Spot run.", "output": "Ver correr a Spot."},
{"input": "My dog barks.", "output": "Mi perro ladra."},
{"input": "Spot can run.", "output": "Spot puede correr."},
]
example_selector = NGramOverlapExampleSelector(
examples=examples,
example_prompt=example_prompt,
threshold=-1.0,
)
dynamic_prompt = FewShotPromptTemplate(
example_selector=example_selector,
example_prompt=example_prompt,
prefix="Give the Spanish translation of every input",
suffix="Input: {sentence}\nOutput:",
input_variables=["sentence"],
)
print(dynamic_prompt.format(sentence="Spot can play fetch.")) #Spot น่าจะเป็นชื่อสุนัข
Output Example
'''
Give the Spanish translation of every input
Input: Spot can run.
Output: Spot puede correr.
Input: See Spot run.
Output: Ver correr a Spot.
Input: My dog barks.
Output: Mi perro ladra.
Input: Spot can play fetch.
Output:
'''
In the example above, with a threshold set to -1.0, no examples are excluded; they are simply ranked by similarity. To observe how changing the threshold impacts the results, we’ll gradually increase it step-by-step.
Example - threshold = 0.0
example_selector.threshold = 0.0
print(dynamic_prompt.format(sentence="Spot can run fast."))
Output Example
'''
Give the Spanish translation of every input
Input: Spot can run.
Output: Spot puede correr.
Input: See Spot run.
Output: Ver correr a Spot.
Input: Spot can play fetch.
Output:
'''
################################################################
Example - threshold = 0.09
example_selector.threshold = 0.09
print(dynamic_prompt.format(sentence="Spot can play fetch."))
Output Example
'''
Give the Spanish translation of every input
Input: Spot can run.
Output: Spot puede correr.
Input: Spot can play fetch.
Output:
'''
################################################################
Example - threshold = 1.0 + 1e-9
example_selector.threshold = 1.0 + 1e-9
print(dynamic_prompt.format(sentence="Spot can play fetch."))
Output Example
'''
Give the Spanish translation of every input
Input: Spot can play fetch.
Output:
'''
################################################################
- Threshold = 0.0: The example “My dog barks” is removed, as it has no overlap with the input.
- Threshold = 0.09: Both “My dog barks” and “See Spot run” are excluded.
- Threshold = 1.0 + 1e-9: All examples, including “My dog barks,” “See Spot run,” and “Spot can run,” are removed.
The N-Gram Overlap Selector orders or excludes examples based on similarity to the input, using n-gram overlap as a measure. By adjusting the threshold, you can control which examples are included or excluded based on their similarity to the input.
- 4) Similarity-Based Selector
The Similarity-Based Example Selector focuses on semantic similarity, finding examples closely aligned with the input’s meaning.
Example - SemanticSimilarityExampleSelector
example_prompt = PromptTemplate(
input_variables=["input", "output"],
template="Input: {input}\nOutput: {output}",
)
examples = [
{"input": "happy", "output": "sad"},
{"input": "tall", "output": "short"},
{"input": "energetic", "output": "lethargic"},
{"input": "sunny", "output": "gloomy"},
{"input": "windy", "output": "calm"},
]
example_selector = SemanticSimilarityExampleSelector.from_examples(
examples,
OpenAIEmbeddings(),
Chroma,
k=1,
)
similar_prompt = FewShotPromptTemplate(
example_selector=example_selector,
example_prompt=example_prompt,
prefix="Give the antonym of every input",
suffix="Input: {adjective}\nOutput:",
input_variables=["adjective"],
)
print(similar_prompt.format(adjective="worried"))
Output Example
'''
Give the antonym of every input
Input: happy
Output: sad
Input: worried
Output:
'''
In the example above, when the input is “worried,” the selector identifies “happy/sad” as the most semantically similar match.
With LangChain’s Example Selectors, you can tailor prompts to fit your needs by controlling length, ensuring diversity, and selecting relevant examples. Next, we’ll dive into Few-Shot Prompts and Partial Prompts in our exploration of LangChain. Thanks for reading, and happy prompt crafting!
Thank you for joining me, and happy prompt crafting!
Data Science Explore the world of data science with Donato_Story
Dashboard Discover the power of data visualization with Donato_Story
Donato_Journey Join me on my journey (Thai version)
Course_Review Discover the training courses with Donato_Story (Thai version)
I really value your thoughts and feedback. Please share any comments or questions you have below, or reach out to me on:
Medium: medium.com/donato-story
Facebook: web.facebook.com/DonatoStory
Linkedin: linkedin.com/in/nattapong-thanngam
Originally published on Medium
Related
Chat with Document: A Closer Look at Splitting, Embeddings, and RAG
Data Mastery Series — Episode 21: The Chat with Document and Langchain Series (Part 2)
Chat with Document: Basics and Demonstrations
Data Mastery Series — Episode 20: The Chat with Document and Langchain Series (Part 1)
Continue Exploring Chat Models with LangChain
Data Mastery Series — Episode 31: LangChain Website (Part 6)
Continue Exploring Retrievers with LangChain
Data Mastery Series — Episode 39: LangChain Website (Part 14 )