> ## Documentation Index
> Fetch the complete documentation index at: https://genai.codewithsiva.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# 2. Chat Prompt Template

> Define structured message prompts using ChatPromptTemplate and class constructors

In this section, you will learn how to define structured message-based prompts using `ChatPromptTemplate` and send them to Chat Models.

## Objectives

1. Construct a structured prompt template using the helper classmethod `.from_messages()` with Tuples.
2. Construct a prompt template using the direct class constructor `ChatPromptTemplate(...)`.
3. Format templates into messages, invoke models, and display responses.
4. Understand when to use `.from_messages()` versus the direct constructor, and string templates versus chat templates.

***

## Code Implementation

Each step of the implementation is preceded by extensive comments explaining the code logic.

### Method 1: Construction via `.from_messages()` with Tuples

This is the most common method. You pass a list of `("role", "template_string")` tuples, and LangChain automatically parses roles and placeholder values.

```python theme={null}
# Import environmental loader from dotenv
from dotenv import load_dotenv

# Import prompt templates and model initialization helpers
from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import init_chat_model

# Load keys and environment settings from local .env
load_dotenv()

# Initialize the Groq model using core abstractions
model = init_chat_model("llama-3.3-70b-versatile", model_provider="groq")

# Define system behavior and human instructions using tuples
messages_tuples = [
    ("system", "You are a comedian who tells jokes about {topic}."),
    ("human", "Tell me {joke_count} jokes."),
]

# Instantiate the chat template using the helper classmethod
chat_prompt_template = ChatPromptTemplate.from_messages(messages_tuples)

print("----- Method 1: .from_messages() with Tuples -----")

# Format the chat template by invoking it with specific values
formatted_prompt = chat_prompt_template.invoke({"topic": "lawyers", "joke_count": 3})

# Invoke the model passing the formatted prompt values
result = model.invoke(formatted_prompt)

# Print the textual content returned by the LLM
print("Model Response:")
print(result.content)
```

***

### Method 2: Construction via Direct Class Constructor

You can initialize `ChatPromptTemplate` directly by passing a list of message objects or message template objects using the `messages` parameter in the constructor.

```python theme={null}
# Import environmental loader from dotenv
from dotenv import load_dotenv

# Import prompt templates, message classes, and model initialization helpers
from langchain.prompts import ChatPromptTemplate
from langchain_core.messages import SystemMessage, HumanMessage
from langchain.chat_models import init_chat_model

# Load keys and environment settings from local .env
load_dotenv()

# Initialize the Groq model using core abstractions
model = init_chat_model("llama-3.3-70b-versatile", model_provider="groq")

# Instantiate the class constructor directly with static message wrappers
# Note: Since these messages are static classes, we do not define dynamic string templates here
chat_prompt_direct = ChatPromptTemplate(
    messages=[
        SystemMessage(content="You are a polite receptionist."),
        HumanMessage(content="Hello, is anyone there?")
    ]
)

print("\n----- Method 2: Direct Class Instantiation -----")

# Invoke the directly instantiated template
formatted_prompt_direct = chat_prompt_direct.invoke({})

# Invoke the model passing the formatted prompt values
result = model.invoke(formatted_prompt_direct)

# Print the model response content
print("Model Response:")
print(result.content)
```

***

### Caveat: Mixing Message Objects and Placeholders

When defining templates, you must format variables dynamically using tuples. If you pass an instantiated Message class (like `HumanMessage`) with placeholder variables in its string content, LangChain's formatter will fail to detect and inject the variables.

##### 1. Instantiating a Message without dynamic placeholders (Works)

```python theme={null}
from langchain.prompts import ChatPromptTemplate
from langchain_core.messages import HumanMessage

# System role uses a tuple with a placeholder; HumanMessage is static
messages = [
    ("system", "You are a comedian who tells jokes about {topic}."),
    HumanMessage(content="Tell me 3 jokes."),
]

# Create template
prompt_template = ChatPromptTemplate.from_messages(messages)

# Invoke with only the topic variable (since joke_count is hardcoded in HumanMessage)
prompt = prompt_template.invoke({"topic": "lawyers"})
print("\n----- Hardcoded Message Instance (Works) -----")
print(prompt)
```

##### 2. Placing placeholders inside Message classes (Fails)

```python theme={null}
from langchain.prompts import ChatPromptTemplate
from langchain_core.messages import HumanMessage

# Attempting to define a placeholder within an instantiated HumanMessage class
messages = [
    ("system", "You are a comedian who tells jokes about {topic}."),
    HumanMessage(content="Tell me {joke_count} jokes."),
]

# Instantiate template
prompt_template = ChatPromptTemplate.from_messages(messages)

# This invocation will catch an error since the HumanMessage content is not parsed at runtime
try:
    prompt = prompt_template.invoke({"topic": "lawyers", "joke_count": 3})
except Exception as e:
    print("\n----- Dynamic Message Instance (Expected Failure) -----")
    print(f"Caught Expected Error: {e}")
```

> \[!WARNING]
> Always use the tuple format `("role", "template string")` when you want placeholders to be dynamically populated at runtime inside a chat prompt template.

***

## When to Use What

### 1. `.from_messages()` vs. Direct Constructor

* **`.from_messages()`**: Best when you want to quickly build a dynamic sequence of messages (such as system instructions combined with user input) using the simplified `("role", "template")` tuple structure.
* **Direct Class Constructor** (`ChatPromptTemplate(messages=[...])`): Best when you already have pre-constructed message templates or message objects (e.g., loading them from a database or memory log) and need to pass them directly.

### 2. `PromptTemplate` vs. `ChatPromptTemplate`

* **`PromptTemplate`**: Use when working with completion-style language models that accept a single plain string as input.
* **`ChatPromptTemplate`**: Use when building applications for Chat Models (like ChatGPT, Claude, or Gemini) which expect structured lists of conversation messages representing different participant roles.

### 3. `ChatPromptTemplate.from_template()` vs `ChatPromptTemplate.from_messages()`

`ChatPromptTemplate.from_template()` is a convenient shortcut for creating a chat prompt with a **single human message**, while `ChatPromptTemplate.from_messages()` is used when you need **multiple messages or different message roles** such as `system`, `human`, and `ai`.

| Method            | Use                                         |
| ----------------- | ------------------------------------------- |
| `from_template()` | One human message; simple prompts           |
| `from_messages()` | Multiple messages; supports different roles |

```python theme={null}
from langchain_core.prompts import ChatPromptTemplate

# from_template()
prompt = ChatPromptTemplate.from_template(
    "Explain {topic} in simple terms."
)

# Equivalent to:
prompt = ChatPromptTemplate.from_messages([
    ("human", "Explain {topic} in simple terms.")
])

# from_messages()
prompt = ChatPromptTemplate.from_messages([
    ("system", "You are an expert Python teacher."),
    ("human", "Explain {topic} in simple terms.")
])
```

***

## Practice & Exercises

To practice feeding prompt templates into chat models, open the interactive notebook:

<CardGroup cols={1}>
  <Card title="Practice & Exercises" icon="laptop-code">
    Practice formatting dynamic chat messages, using message list wrappers, and invoking models.

    [💻 VS Code](vscode://file/Users/sivaprasad/Downloads/GenAI%20With%20Python/public/notebooks/langchain/2_chat_prompt_template.ipynb) | [🚀 Colab](https://colab.research.google.com/github/prasad230776/genai-course/blob/master/public/notebooks/langchain/2_chat_prompt_template.ipynb) | <a href="/public/notebooks/langchain/2_chat_prompt_template.ipynb" download>📥 Download</a>
  </Card>
</CardGroup>
