ChatPromptTemplate.from_template(): the simplest pattern
Why this matters
This is how you parameterize prompts in production LangChain workflows: instead of concatenating strings, you define a template once and pass variables safely through invoke().
Explanation
ChatPromptTemplate.from_template() is the fastest way to convert a string with placeholder variables into a reusable prompt object that integrates with LangChain's chain syntax. It takes a single string argument where variables are marked with curly braces like {variable_name}. When you call .invoke({'variable_name': 'value'}), it substitutes the values and returns a formatted prompt ready to pass to an LLM. This pattern is foundational because it separates prompt structure from data: you define the template once and reuse it across different inputs without rebuilding strings.
Analogy
Think of it like an f-string factory: instead of creating a new f-string every time you have new data, you define the template once, then feed it different dictionaries. The template is the blueprint; invoke() is the production run.
Code
from langchain_core.prompts import ChatPromptTemplate
template = "You are a helpful assistant. The user asked: {user_input}"
prompt = ChatPromptTemplate.from_template(template)
result = prompt.invoke({"user_input": "What is the capital of France?"})
print(result)
print(type(result)) messages=[ HumanMessage(content="You are a helpful assistant. The user asked: What is the capital of France?") ] <class 'langchain_core.prompt_values.ChatPromptValue'>
What just happened?
The code created a ChatPromptTemplate object by parsing the template string and identifying {user_input} as a variable placeholder. When invoke() was called with a dictionary containing that variable, it substituted the value into the template and returned a ChatPromptValue object: a structured message format that LangChain chains expect. This object wraps the substituted prompt as a HumanMessage, ready to be piped to an LLM.
Common gotcha
Developers often expect invoke() to return a plain string, but it returns a ChatPromptValue object. If you need the raw string, call .to_string() on the result: or use PromptTemplate (not ChatPromptTemplate) if you're not building a chat-based chain. Also, if you pass a key that doesn't exist in your template dictionary, you'll get a KeyError: check that every {placeholder} in your template has a matching key in invoke().
Error recovery
KeyErrorTypeError: from_template() missing required argumentAttributeError: 'str' object has no attribute 'invoke'Experienced dev note
Many developers coming from prompt engineering think they should use .format() or f-strings directly. Don't. The reason: ChatPromptTemplate integrates with LangChain's streaming, caching, and debugging tools. A plain f-string breaks that integration. Also, ChatPromptTemplate automatically handles message structuring: it wraps your template in a HumanMessage, so when you pipe it to an LLM, the LLM knows this is a user input, not a system instruction. This saves you from having to manually build message lists.
Check your understanding
If your template has three placeholders: {user_input}, {context}, and {language}: but you only pass two of them in invoke(), what error do you get and why? How would you fix it?
Show answer hint
A correct answer must mention that invoke() raises a KeyError for the missing key, explain that all placeholders in the template must have matching keys in the invoke() dictionary, and suggest either adding the missing key-value pair to invoke() or removing it from the template.