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.