10 LangChain Prompt Templates (Few-Shot, Chat, Partial)
Build reusable LangChain prompts with PromptTemplate, ChatPromptTemplate, FewShotPromptTemplate, and partial variables — 10 practical patterns with Python code.
Get more content like this on Telegram!
Daily AI tips, notes & resources — free
Prompt engineering is where most LLM application quality comes from. The model matters, the retrieval matters, but the prompt is what actually tells the model what to do, how to respond, and in what format. LangChain's prompt template system gives you reusable, composable, testable prompt components instead of string concatenation scattered across your codebase.
This guide covers 10 prompt template patterns — from basic to advanced — with working Python code for each. These are the patterns you will reach for repeatedly when building LangChain applications.
Why Prompt Templates Matter
Hard-coded f-strings work for demos. For production systems, they create problems:
- No validation — a missing variable silently produces a broken prompt
- No reusability — each chain reimplements the same prompt structure
- No composability — you cannot mix and match prompt components
- No serialization — you cannot save and load prompts from disk
- No observability — logging and tracing tools cannot parse raw strings
LangChain's PromptTemplate and ChatPromptTemplate solve all of these. They validate inputs at construction time, support serialization to JSON/YAML, integrate with LangSmith for tracing, and compose cleanly with chains using LCEL.
Setup
pip install langchain langchain-openai chromadb
import os
os.environ["OPENAI_API_KEY"] = "your-key-here"
Template 1: Basic PromptTemplate
The foundation — a string template with named variables:
from langchain_core.prompts import PromptTemplate
# Define template with named placeholders
template = PromptTemplate(
input_variables=["topic", "audience", "tone"],
template="""Write a {tone} explanation of {topic} for {audience}.
Keep it under 150 words and avoid technical jargon unless necessary."""
)
# Validate inputs automatically — raises ValueError for missing vars
prompt_text = template.format(
topic="neural networks",
audience="high school students",
tone="friendly and encouraging"
)
print(prompt_text)
# Or use format_prompt() to get a PromptValue object
prompt_value = template.format_prompt(
topic="transformers",
audience="business executives",
tone="professional"
)
You can also use the shorthand:
from langchain_core.prompts import PromptTemplate
# from_template infers input_variables automatically
template = PromptTemplate.from_template(
"Summarize the following text in {num_sentences} sentences:\n\n{text}"
)
print(template.input_variables) # ['num_sentences', 'text']
Template 2: ChatPromptTemplate
The most important template for modern LLM applications. Chat models expect a sequence of role-tagged messages, not a single string.
from langchain_core.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate
# Full verbose construction
system_prompt = SystemMessagePromptTemplate.from_template(
"You are a {role} who specializes in {specialty}. "
"Always respond in {language}. "
"Be {tone}."
)
human_prompt = HumanMessagePromptTemplate.from_template("{user_input}")
chat_template = ChatPromptTemplate.from_messages([
system_prompt,
human_prompt,
])
messages = chat_template.format_messages(
role="software engineer",
specialty="distributed systems",
language="English",
tone="direct and technical",
user_input="What is eventual consistency?",
)
print(messages)
# [SystemMessage(...), HumanMessage(...)]
Shorthand using tuples — cleaner for most use cases:
from langchain_core.prompts import ChatPromptTemplate
chat_template = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant specializing in {domain}."),
("human", "Question: {question}"),
("ai", "I'll help you with that. Let me think through {question} step by step."),
("human", "Good. Now please give me the full answer."),
])
# The multi-turn structure guides the model's response style
messages = chat_template.format_messages(
domain="machine learning",
question="What is the curse of dimensionality?"
)
Template 3: MessagesPlaceholder for Conversation History
For conversational agents, you need to inject the full chat history into the prompt. MessagesPlaceholder handles this cleanly.
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessage, AIMessage
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
chat_template = ChatPromptTemplate.from_messages([
("system", "You are a helpful coding assistant. Be concise. Prefer Python examples."),
MessagesPlaceholder(variable_name="history"), # injects full history here
("human", "{message}"),
])
llm = ChatOpenAI(model="gpt-4o-mini")
chain = chat_template | llm | StrOutputParser()
# Simulate multi-turn conversation
history = []
def chat(message: str) -> str:
response = chain.invoke({
"message": message,
"history": history,
})
# Append to history for next turn
history.append(HumanMessage(content=message))
history.append(AIMessage(content=response))
return response
print(chat("How do I read a CSV file in Python?"))
print(chat("How do I filter rows where column 'age' > 25?")) # uses history context
Template 4: FewShotPromptTemplate
Few-shot examples dramatically improve model accuracy on structured tasks like classification, extraction, and formatting. FewShotPromptTemplate manages the example pool and formats them consistently.
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
# Define how each example should be formatted
example_template = PromptTemplate(
input_variables=["input", "output"],
template="Input: {input}\nOutput: {output}"
)
# Your example pool
examples = [
{"input": "The product arrived broken.", "output": "negative"},
{"input": "Absolutely love this! Best purchase ever.", "output": "positive"},
{"input": "It's okay, nothing special.", "output": "neutral"},
{"input": "Terrible customer service, will never buy again.", "output": "negative"},
{"input": "Works exactly as described.", "output": "positive"},
]
few_shot_template = FewShotPromptTemplate(
examples=examples,
example_prompt=example_template,
prefix="Classify the sentiment of the following review. Respond with only: positive, negative, or neutral.\n",
suffix="\nInput: {review}\nOutput:",
input_variables=["review"],
example_separator="\n\n",
)
prompt = few_shot_template.format(review="The battery life is impressive but the screen is dim.")
print(prompt)
Template 5: FewShotChatMessagePromptTemplate
For chat models, you need few-shot examples in message format rather than string format:
from langchain_core.prompts import (
FewShotChatMessagePromptTemplate,
ChatPromptTemplate,
)
# Define example message structure
example_prompt = ChatPromptTemplate.from_messages([
("human", "{question}"),
("ai", "{answer}"),
])
# Structured few-shot examples for a specific task
examples = [
{
"question": "What is 15% of 240?",
"answer": "15% of 240 = 0.15 × 240 = 36",
},
{
"question": "If a shirt costs $45 and is 30% off, what do I pay?",
"answer": "Discount = 30% of $45 = $13.50. Final price = $45 - $13.50 = $31.50",
},
{
"question": "A recipe calls for 2 cups of flour but I want to make 1.5x the amount. How much flour?",
"answer": "1.5 × 2 cups = 3 cups of flour",
},
]
few_shot_chat = FewShotChatMessagePromptTemplate(
example_prompt=example_prompt,
examples=examples,
)
# Embed in a full chat template
final_template = ChatPromptTemplate.from_messages([
("system", "You are a math assistant. Show your work step by step."),
few_shot_chat, # few-shot examples injected here
("human", "{question}"),
])
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
chain = final_template | llm | StrOutputParser()
result = chain.invoke({"question": "What is 22% of 350?"})
print(result)
Template 6: SemanticSimilarityExampleSelector
A fixed few-shot example set is fine for narrow tasks. For broader tasks, dynamically selecting examples based on semantic similarity to the current input works much better.
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
from langchain_core.example_selectors import SemanticSimilarityExampleSelector
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
example_pool = [
{"input": "Convert 100 Fahrenheit to Celsius", "output": "(100-32) × 5/9 = 37.78°C"},
{"input": "Convert 0 Celsius to Fahrenheit", "output": "0 × 9/5 + 32 = 32°F"},
{"input": "How many meters in a mile?", "output": "1 mile = 1,609.34 meters"},
{"input": "Convert 5 kilometers to miles", "output": "5 × 0.6214 = 3.107 miles"},
{"input": "How many pounds in a kilogram?", "output": "1 kg = 2.2046 pounds"},
{"input": "Convert 70 kg to pounds", "output": "70 × 2.2046 = 154.32 pounds"},
]
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
example_selector = SemanticSimilarityExampleSelector.from_examples(
example_pool,
embeddings,
Chroma,
k=2, # select 2 most similar examples
)
example_template = PromptTemplate(
input_variables=["input", "output"],
template="Input: {input}\nOutput: {output}"
)
dynamic_few_shot = FewShotPromptTemplate(
example_selector=example_selector, # dynamic selection
example_prompt=example_template,
prefix="Convert the following measurement. Show your calculation:\n",
suffix="\nInput: {input}\nOutput:",
input_variables=["input"],
)
# The selector will pick the 2 most relevant examples for this specific query
prompt = dynamic_few_shot.format(input="Convert 85 kg to pounds")
print(prompt)
Template 7: Partial Variables
Partial variables let you pre-fill some template inputs and leave others for runtime. This is useful for shared base templates that differ only in one or two parameters:
from langchain_core.prompts import PromptTemplate
from datetime import datetime
base_template = PromptTemplate(
input_variables=["date", "language", "task"],
template="""Today is {date}. You are an assistant who responds only in {language}.
Task: {task}
Complete the task thoroughly and accurately."""
)
# Create a specialized version with date and language pre-filled
english_template = base_template.partial(
date=datetime.now().strftime("%B %d, %Y"),
language="English",
)
# Now only needs 'task'
prompt = english_template.format(task="List the top 5 programming languages in 2026")
print(prompt)
# Another specialization — different language
spanish_template = base_template.partial(
date=datetime.now().strftime("%B %d, %Y"),
language="Spanish",
)
# Dynamic partial — use a function instead of a fixed value
def get_current_datetime():
return datetime.now().strftime("%Y-%m-%d %H:%M UTC")
dynamic_template = PromptTemplate(
input_variables=["current_time", "user_timezone", "query"],
template="""Current time: {current_time} (user is in {user_timezone})
Query: {query}
Answer:"""
)
# partial() with a callable — called fresh each time format() is invoked
time_partial = dynamic_template.partial(current_time=get_current_datetime)
print(time_partial.format(user_timezone="US/Eastern", query="What day is it?"))
Template 8: PipelinePromptTemplate
When you need to compose multiple prompt sections together — such as a reusable instruction block combined with a task-specific section — PipelinePromptTemplate handles the composition:
from langchain_core.prompts import PipelinePromptTemplate, PromptTemplate
# Reusable components
intro_template = PromptTemplate.from_template(
"You are an AI assistant at {company_name}. "
"Always be helpful, accurate, and professional."
)
guidelines_template = PromptTemplate.from_template(
"Guidelines:\n"
"- Respond in {response_language}\n"
"- Keep responses under {max_words} words\n"
"- If uncertain, say so rather than guessing"
)
task_template = PromptTemplate.from_template(
"User request: {user_request}\n\n"
"Your response:"
)
# Combine into a pipeline
full_template = PromptTemplate.from_template(
"{intro}\n\n{guidelines}\n\n{task}"
)
pipeline_prompt = PipelinePromptTemplate(
final_prompt=full_template,
pipeline_prompts=[
("intro", intro_template),
("guidelines", guidelines_template),
("task", task_template),
],
)
result = pipeline_prompt.format(
company_name="AiTechWorlds",
response_language="English",
max_words=200,
user_request="Explain the difference between RAG and fine-tuning",
)
print(result)
Template 9: JSON Output Prompts with Format Instructions
When you need structured output, combining ChatPromptTemplate with format instructions from output parsers is the cleanest approach:
from langchain_core.prompts import ChatPromptTemplate
from langchain.output_parsers import PydanticOutputParser
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field
class ProductReview(BaseModel):
sentiment: str = Field(description="positive, negative, or neutral")
score: int = Field(description="Rating from 1-10")
key_points: list[str] = Field(description="Main points from the review (2-4 points)")
summary: str = Field(description="One sentence summary")
parser = PydanticOutputParser(pydantic_object=ProductReview)
template = ChatPromptTemplate.from_messages([
("system", "You are a review analysis assistant. Extract structured information from product reviews.\n\n{format_instructions}"),
("human", "Analyze this review:\n\n{review}"),
])
# Inject format instructions as a partial variable
template = template.partial(format_instructions=parser.get_format_instructions())
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
chain = template | llm | parser
result = chain.invoke({
"review": "I've been using this laptop for 3 months. The performance is excellent — boots in 8 seconds, handles video editing smoothly. Battery lasts about 7 hours. The keyboard feels premium. Only complaint is the webcam quality, which is average for the price."
})
print(f"Sentiment: {result.sentiment}")
print(f"Score: {result.score}/10")
print(f"Key points: {result.key_points}")
print(f"Summary: {result.summary}")
Template 10: Loading and Saving Prompt Templates
Templates should be version-controlled and loadable from files, not hardcoded:
from langchain_core.prompts import ChatPromptTemplate, load_prompt
import json
# Define a template
template = ChatPromptTemplate.from_messages([
("system", "You are a {persona} assistant. Your expertise is {domain}."),
("human", "{question}"),
])
# Save to JSON
template.save("prompts/chat_assistant.json")
# Load from JSON
loaded_template = load_prompt("prompts/chat_assistant.json")
# Programmatic creation from dict (useful for database-backed prompts)
template_dict = {
"_type": "prompt",
"input_variables": ["topic", "style"],
"template": "Write a {style} article about {topic}.",
}
dynamic_template = PromptTemplate(**{
"input_variables": template_dict["input_variables"],
"template": template_dict["template"]
})
# Use langchain hub for community prompts
# from langchain import hub
# rag_prompt = hub.pull("rlm/rag-prompt")
Comparison Table: LangChain Prompt Template Types
| Template Type | Use Case | Chat Model | Completion Model | Few-Shot | Dynamic Examples |
|---|---|---|---|---|---|
| PromptTemplate | Simple string prompts | No | Yes | Manual | No |
| ChatPromptTemplate | Chat model prompts | Yes | No | Manual | No |
| FewShotPromptTemplate | Fixed few-shot | No | Yes | Yes | No |
| FewShotChatMessagePromptTemplate | Chat few-shot | Yes | No | Yes | No |
| SemanticSimilarityExampleSelector | Dynamic few-shot | Both | Both | Yes | Yes |
| PipelinePromptTemplate | Composed templates | Both | Both | No | No |
| MessagesPlaceholder | Chat history injection | Yes | No | No | No |
Practical Tips for Prompt Template Design
Keep system prompts short but specific. "You are a helpful assistant" provides almost no guidance. "You are a Python developer who answers questions with minimal working code examples, no theory unless asked" gives the model clear behavioral parameters.
Use partial variables for environment-specific settings. Date, user locale, company name, and similar configuration values should be partial variables — pre-filled at startup, not at request time.
Name your variables descriptively. {q} is hard to debug. {user_question} tells you exactly what goes there when you read the template six months later.
Test prompts with adversarial inputs. Try empty strings, very long inputs, inputs in unexpected languages, and inputs that try to override the system prompt. LangChain's input validation catches type errors but not semantic attacks — that is your prompt's job.
Version your prompts. Save templates to JSON, commit them to git, and treat prompt changes as code changes. LangSmith's prompt hub makes this even easier for team workflows.
Integration with LangChain Chains
Prompt templates compose naturally with any LangChain component via LCEL:
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
llm = ChatOpenAI(model="gpt-4o-mini")
# Any of the templates above slot in here
chain = few_shot_template | llm | StrOutputParser()
# Async invocation for FastAPI endpoints
result = await chain.ainvoke({"review": "Great product, fast shipping!"})
Prompt templates are the foundation of every pattern in LangChain tutorial 2025 and Build AI agent with LangChain. Getting them right early means your agent prompts, RAG prompts, and tool-use prompts all follow the same patterns and are easy to debug with AI agent memory and planning.
Frequently Asked Questions
What is the difference between PromptTemplate and ChatPromptTemplate in LangChain?
PromptTemplate produces a single string prompt, which works with older completion-style APIs. ChatPromptTemplate produces a list of role-tagged messages (system, human, AI) that matches the input format expected by chat models like GPT-4o, Claude, and Gemini. Use ChatPromptTemplate for all modern chat models — it gives you explicit control over the system message and conversation structure.
How do partial variables work in LangChain prompt templates?
Partial variables let you pre-fill some template variables while leaving others for later. Call template.partial(variable_name='value') to return a new template with that variable locked in. You can also pass a callable instead of a value, and LangChain will call it each time the template is formatted. This is useful for date/time stamps, user locale, and other context that is the same for an entire session.
Can I use few-shot examples dynamically based on the input in LangChain?
Yes. Use SemanticSimilarityExampleSelector to select examples from a pool based on cosine similarity to the user's input. This dynamically picks the most relevant few-shot examples for each query rather than using a fixed set. The selector stores your examples in a vector store and retrieves the k most similar at prompt-formatting time. This typically improves accuracy by 10–20% on structured tasks compared to fixed few-shot examples.
Frequently Asked Questions
AiTechWorlds Team
✓ Verified WriterThe AiTechWorlds team is passionate about AI, technology, and education. We create high-quality, research-backed content to help you learn, grow, and succeed in the modern digital world.
Related Articles
AutoGen vs LangChain: Which for Multi-Agent Systems in 2026?
AutoGen vs LangChain for multi-agent systems in 2026 — feature comparison, same use case in both frameworks, and an honest verdict on when each wins.
AutoGPT vs LangChain Agents: Which is More Autonomous?
Compare AutoGPT's zero-shot autonomy against LangChain's ReAct agents. Discover which handles complex tasks better and when to choose each framework.
10 LangChain Retrieval Strategies for Better RAG Results
Go beyond basic similarity search with ParentDocumentRetriever, MultiQueryRetriever, EnsembleRetriever, HyDE, and 6 more LangChain retrieval strategies — with code for each.
Build a LangChain Agent with Memory and Tools (Full Example)
Build a complete LangChain conversational agent with persistent memory, multiple tools, and step-by-step trace — from setup to a production-ready implementation with code.