LangChain Prompt Templates
LangChain prompt templates turn reusable prompt text plus variables into the messages a chat model expects. Instead of building strings with f-strings everywhere, you define the prompt once and fill it in with different inputs.
Creating a ChatPromptTemplate
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
("system", "You are an expert {field} teacher. Keep answers under 40 words."),
("human", "Explain {topic} to a beginner."),
])
value = prompt.invoke({"field": "physics", "topic": "gravity"})
for m in value.to_messages():
print(type(m).__name__, ":", m.content)SystemMessage : You are an expert physics teacher. Keep answers under 40 words. HumanMessage : Explain gravity to a beginner.
Curly braces mark variables. invoke fills them and returns a prompt value that can be passed straight to a chat model. If you need literal braces, for example JSON in your prompt, double them: {{ and }}.
Sending a Template to the Model
from langchain_ollama import ChatOllama
llm = ChatOllama(model="llama3.2", temperature=0)
messages = prompt.invoke({"field": "biology", "topic": "photosynthesis"})
print(llm.invoke(messages).content)Sample output: Photosynthesis is how plants use sunlight, water and carbon dioxide to make sugar for energy, releasing oxygen as a by-product.
MessagesPlaceholder for Chat History
A placeholder inserts a whole list of messages, which is how you put conversation history into a template:
from langchain_core.prompts import MessagesPlaceholder
from langchain_core.messages import HumanMessage, AIMessage
chat_prompt = ChatPromptTemplate.from_messages([
("system", "You are a friendly assistant."),
MessagesPlaceholder("history"),
("human", "{question}"),
])
value = chat_prompt.invoke({
"history": [HumanMessage("My name is Sara."), AIMessage("Nice to meet you, Sara!")],
"question": "What is my name?",
})
print(len(value.to_messages()))4
Few-Shot Prompting
Showing the model a few examples often improves format and accuracy more than long instructions. You can write the examples as alternating human and AI messages:
few_shot = ChatPromptTemplate.from_messages([
("system", "Classify the sentiment as positive, negative or neutral."),
("human", "I love this phone!"), ("ai", "positive"),
("human", "The delivery was late."), ("ai", "negative"),
("human", "{review}"),
])
print(llm.invoke(few_shot.invoke({"review": "Battery life is amazing"})).content)Sample output: positive
Prompt Template Tips
- Keep instructions in the system message and user data in the human message.
- Use partial(...) to pre-fill variables that rarely change, such as today's date.
- Ask for a specific format and length; small local models follow explicit rules better.
- Version your prompts in code or in LangSmith so you can compare changes.
Frequently asked questions
What is the difference between PromptTemplate and ChatPromptTemplate?
PromptTemplate produces a single string. ChatPromptTemplate produces a list of role-tagged messages, which is what chat models use. Prefer ChatPromptTemplate.
How do I include curly braces in a LangChain prompt?
Double them. Write {{ and }} to get literal { and } in the final text.
Can prompt templates use Jinja2?
Yes. Pass template_format="jinja2" when creating a template, though f-string style is the default and works for most cases.