Introduction

Welcome to your third lesson in Basics of GenAI Foundation Models with Amazon Bedrock! You've mastered the fundamentals of connecting to Bedrock and have learned how to configure AI responses using inference parameters and system prompts. Now, we're ready to explore one of the most powerful techniques for building sophisticated AI applications: prompt templating and conversation chaining.

In our previous lessons, we've been crafting individual prompts for specific questions, treating each interaction as an isolated exchange. While this approach works well for simple queries, real-world applications demand more sophisticated conversation management. Today, we'll discover how to create reusable prompt templates with variable placeholders and how to chain multiple conversation turns together, maintaining context across extended interactions. These techniques transform simple Q&A sessions into intelligent conversations in which the AI remembers previous exchanges and builds upon them naturally. By the end of this lesson, you'll possess the skills to create scalable, maintainable AI applications that can handle complex, multi-step conversations while remaining flexible enough to adapt to diverse topics and scenarios.

Understanding Prompt Templates

Before diving into the implementation, let's build intuition around prompt templates and why they're essential for efficient AI conversations. Think of prompt templates as architectural blueprints: just as an architect creates a single blueprint that can be adapted for different building sites with minor modifications, prompt templates provide a consistent structure that can be customized with specific details for each use case.

Prompt templates work by incorporating variable placeholders like {aws_service} or {topic} that can be dynamically filled with different values at runtime. This approach offers several key advantages: reusability across different scenarios without code duplication, consistency in prompt structure and tone across your application, maintainability when you need to update prompt patterns globally, and scalability for applications that handle diverse topics or domains. When combined with conversation chaining, in which each prompt builds upon previous responses, templates become incredibly powerful tools for creating natural, contextual AI interactions. Consider a customer support scenario: instead of writing hundreds of individual prompts for different products, you create a single template that adapts to any product name, ensuring consistent quality while dramatically reducing development time.

While we're focusing on the core mechanics of templating in this course, it's worth noting that production applications should always sanitize user input before substituting values into templates to prevent injection attacks and ensure reliable behavior. Though we won't delve into input validation techniques here, remember that robust AI applications require careful attention to security and data integrity alongside the powerful templating capabilities we're exploring.

Setting Up Conversation Infrastructure

To implement effective prompt chaining, we need to establish a global conversation history that persists across multiple message exchanges. This infrastructure allows each new prompt to reference and build upon previous responses, creating coherent, contextual conversations:

import boto3

# Create a Bedrock Runtime client
client = boto3.client("bedrock-runtime")

# Define the model ID
MODEL_ID = "us.anthropic.claude-sonnet-4-20250514-v1:0"

# Initialize global conversation history and system prompt for prompt chaining
conversation = []
system_prompt = "You are an AWS Technical Assistant. Provide clear, accurate information about AWS services."

The conversation list serves as our persistent memory, storing both user messages and AI responses in the exact format that Bedrock expects. This global state enables us to build conversations in which later prompts can reference information from earlier exchanges, creating a natural flow of dialogue. Note that while this simple in-memory approach works perfectly for learning and single-user scenarios, production applications would need more sophisticated conversation management systems to handle multiple concurrent users and prevent memory leaks from accumulating conversation histories. The system_prompt remains consistent throughout the entire conversation, ensuring our AI maintains its technical assistant persona across all turns. Unlike our previous lessons, where each interaction stood alone, this infrastructure creates the foundation for sophisticated, multi-turn conversations that feel natural and maintain contextual awareness throughout the entire exchange.

Creating Reusable Prompt Templates

Now, let's create our parameterized prompt templates using Python's string formatting capabilities. These templates contain placeholder variables that make them reusable across different AWS services and topics:

# Template 1: Parameterized prompt template for detailed service overview
# Uses {aws_service} variable for reusability across different AWS services
detailed_overview_template = (
    "Please provide a brief overview of {aws_service}. "
    "Include key features, use cases, pricing models, and target scenarios."
)

# Template 2: Parameterized prompt template for specific topic inquiry - chains with first response
# Uses {topic} variable for asking about different service aspects
specific_topic_template = (
    "Based on the overview you provided, can you give me more detailed information "
    "specifically about {topic}?"
)

Notice how the first template focuses on gathering comprehensive service information with a structured request for specific aspects, while the second template explicitly references "the overview you provided" to create a conversational chain. The {aws_service} and {topic} placeholders make these templates highly reusable: we can easily substitute "Amazon Bedrock" with "Amazon Lambda" or "cost optimization strategies" with "security best practices" without rewriting the entire prompt structure. This separation of template structure from content values enables rapid development of conversational AI applications that can adapt to countless scenarios while maintaining consistent quality and behavior.

Managing Conversation State

The heart of our conversation chaining system is the send_message function, which orchestrates the bidirectional flow of messages and maintains our global conversation state. Let's examine the first critical part of this function:

def send_message(user_text):
    try:
        # Append user message to global conversation history
        conversation.append({
            "role": "user",
            "content": [{"text": user_text}]
        })

        # Prepare the API call parameters with global system prompt
        api_params = {
            "modelId": MODEL_ID,
            "messages": conversation,
            "system": [{"text": system_prompt}],
            "inferenceConfig": {
                "maxTokens": 300,
                "temperature": 0.3,
                "topP": 0.9,
            }
        }

This initial section performs two crucial operations: it adds each user message to our global conversation history in Bedrock's required format, then prepares the complete API parameters, including the entire conversation context. The inferenceConfig maintains consistent response characteristics throughout the conversation, ensuring reliable behavior across all turns. Now, let's see how we handle the response and maintain conversation continuity:

        # Call the Bedrock model
        response = client.converse(**api_params)

        # Get the response message
        output_message = response.get("output", {}).get("message", {})

        # Directly add the assistant's response to conversation history for chaining
        conversation.append(output_message)

        # Extract text for display purposes only
        parts = output_message.get("content", [])
        text_chunks = [part.get("text", "") for part in parts if isinstance(part, dict)]
        response_text = "".join(text_chunks).strip()

        return response_text

    except Exception as e:
        print(f"Error: {e}")
        return None

The response handling preserves the complete message structure in our conversation history while extracting clean text for display. This dual approach ensures perfect conversation continuity for the AI while providing readable output for users, creating a seamless experience in which each exchange builds naturally upon previous interactions.

First Turn: Service Overview Generation

With our infrastructure ready, let's demonstrate the power of prompt templates in action. We'll start by using our parameterized template to generate a comprehensive service overview:

# Set variables for template substitution
aws_service = "Amazon Bedrock"
topic = "cost optimization strategies"

# Turn 1: Use parameterized template to generate detailed service overview prompt
user_message_1 = detailed_overview_template.format(aws_service=aws_service)
response_1 = send_message(user_message_1)
print(f"User:\n{user_message_1}")
print(f"Assistant:\n{response_1}\n")

Output:

User: 
Please provide a brief overview of Amazon Bedrock. Include key features, use cases, 
pricing models, and target scenarios.
Assistant: # Amazon Bedrock Overview

## What is Amazon Bedrock?
Amazon Bedrock is a fully managed service that provides access to high-performing foundation models (FMs) from leading AI companies through a single API. It enables you to build and scale generative AI applications without managing infrastructure.

## Key Features

### **Foundation Model Access**
- Pre-trained models from Amazon, Anthropic, AI21 Labs, Cohere, Meta, Mistral AI, and Stability AI
- Models for text generation, chat, image generation, and embeddings
- No need to manage model hosting or scaling

### **Model Customization**
- **Fine-tuning**: Customize models with your own data
- **Retrieval Augmented Generation (RAG)**: Connect models to your knowledge bases
- **Continued pre-training**: Further train models on domain-specific data

### **Enterprise-Ready Features**
- Data privacy and security (data not used to train base models)
- VPC support and encryption
- AWS IAM integration
- Compliance with SOC, HIPAA, and other standards

### **Development Tools**
- Model evaluation and comparison
- Guardrails for responsible AI
- Integration with AWS services (Lambda, SageMaker, etc.)

The .format() method replaces the {aws_service} placeholder with our specified value, transforming our generic template into a specific, actionable prompt. Notice how the AI delivers exactly what we requested: a structured overview covering key features, use cases, and target scenarios. This comprehensive response now becomes part of our conversation history, establishing the foundation for our next chained interaction.

Second Turn: Contextual Follow-up Chaining

Now comes the magic of conversation chaining. Our second prompt will build directly upon the previous response, demonstrating how templates can create natural conversational flow:

# Turn 2: Chain prompts with parameterized follow-up about specific topic
# This demonstrates prompt chaining with two parameterized templates
user_message_2 = specific_topic_template.format(topic=topic)
response_2 = send_message(user_message_2)
print(f"User:\n{user_message_2}")
print(f"Assistant:\n{response_2}")

Output:

User: 
Based on the overview you provided, can you give me more detailed information specifically about cost optimization strategies?
Assistant: 
# Amazon Bedrock Cost Optimization Strategies

## Understanding Bedrock Pricing Models

### **On-Demand Pricing**
- Pay per token (input/output tokens priced separately)
- No upfront commitments
- Best for: Variable workloads, experimentation, development

### **Provisioned Throughput**
- Reserve model capacity for consistent performance
- Hourly pricing with commitment discounts
- Best for: Predictable, high-volume production workloads

## Cost Optimization Strategies

### **1. Model Selection Optimization**
- **Choose appropriate model sizes**: Smaller models (e.g., Claude Haiku vs. Claude Sonnet) for simpler tasks
- **Compare model pricing**: Different providers have varying token costs
- **Use embeddings models efficiently**: For RAG applications, optimize embedding generation

### **2. Token Usage Optimization**
Input Token Strategies:
- Minimize prompt length while maintaining effectiveness
- Use system prompts efficiently
- Implement prompt caching where possible
- Remove unnecessary context in conversations

Output Token Strategies:
- Set appropriate max_tokens limits
- Use structured outputs to reduce verbose responses
- Implement early stopping for streaming responses

### **3. Workload Management**
- **Batch processing**: Group similar requests to reduce overhead
- **Caching strategies**

This second turn demonstrates true conversation chaining in action: the prompt explicitly references "the overview you provided," and because our conversation history contains the full context from the first exchange, the AI delivers targeted cost optimization strategies that build directly upon the Bedrock foundation information. The result is a natural, flowing conversation that progressively builds knowledge rather than treating each exchange as an isolated interaction. Notice how the AI's response is specifically tailored to Amazon Bedrock's pricing models and optimization opportunities, showcasing the power of maintaining conversational context across multiple turns.

Conclusion and Next Steps

Outstanding progress! You've successfully mastered the art of prompt templating and conversation chaining with Amazon Bedrock, transforming yourself from someone who sends individual prompts into an architect of sophisticated conversational AI systems. These powerful techniques enable you to build scalable, maintainable applications that can handle complex, multi-turn conversations while remaining flexible enough to adapt to countless scenarios through simple variable substitution.

The combination of parameterized templates with persistent conversation state creates AI interactions that feel natural and contextual, building knowledge progressively rather than starting fresh with each exchange. Get ready to put these templating and chaining techniques into practice with hands-on exercises that will solidify your mastery of efficient AI conversation design!

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal