🎯 By the end of this module, you will:
Creating Reusable Dynamic Prompt Templates
Hardcoded f-strings break in production. Real agent systems decouple prompt engineering from application logic using structured, composable templates with role isolation, history placeholders, and partial variable binding.
# ❌ THE F-STRING ANTI-PATTERN — fragile in production
role = "Cloud Security Auditor"
user_query = "Review this IAM policy: {policy_json}" # Breaks if user sends {}!
# Collapses system + user into one unstructured blob
prompt = f"""System: You are a {role}.
User: {user_query}"""
# PROBLEMS:
# 1. No role boundaries — the model may confuse system vs. user text
# 2. {policy_json} in user query causes a KeyError crash
# 3. No injection protection — user can write: "Ignore system. Do X"
# 4. Cannot unit test prompt logic without calling the LLM
# 5. No variable validation — missing keys fail at runtime, not startup📄 Anatomy of a Production Agent Prompt
You are a {domain} expert. Tone: {tone}.MessagesPlaceholder(variable_name='chat_history'){input}🔬 Prompt Template Studio
Dynamic ChatPromptTemplate StudioReusable Variables
Design multi-message prompt templates with dynamic variable injection and MessagesPlaceholder
from langchain_core.prompts import (
ChatPromptTemplate, MessagesPlaceholder
)
prompt = ChatPromptTemplate.from_messages([
("system", "You are an expert {persona}. Tone: {tone}."),
MessagesPlaceholder("history"),
("user", "{user_input}")
])Prompt Template Traps
If your prompt text contains literal JSON like {"key": "value"}, ChatPromptTemplate will try to resolve it as a variable and raise a KeyError. Escape literal braces by doubling them: {{"key": "value"}} in the template string.
Without MessagesPlaceholder in your template, conversation history has nowhere to inject. Many developers add history to the Human message as a raw string — this collapses roles and breaks the model's ability to distinguish user from assistant turns.
Key Takeaways
- 1.Treat Prompts as Code: Version-control templates in YAML or Python config files. Code-review all prompt changes. A 5-word prompt change can cause catastrophic behavior shifts in production.
- 2.partial() for Config Separation: Pre-fill env-dependent variables (model persona, language, tone) at application startup via template.partial(). Runtime callers only need to provide user-facing inputs like {input} and {history}.
- 3.LCEL for Composable Chains: The pipe operator (template | model | parser) builds reusable, testable, composable chains. Each component is independently testable and swappable without touching other parts.
Implementing Input Validation & Guardrails
Build a 3-tier Defense-in-Depth pipeline — regex circuit breakers, XML quarantine isolation, and semantic LLM judges — to protect your agent from adversarial inputs.