Intermediate

Dynamic System Prompts and Context Injection

Lesson 4 of 4 Estimated Time 45 min

Dynamic System Prompts and Context Injection

Introduction

So far, you’ve learned about static system prompts - the same instructions for every user. But real applications need to adapt. A customer support agent should know the customer’s account status. A sales assistant should know what products are available. A content moderator should know the current policy rules.

Dynamic system prompts inject runtime context into the base system prompt. Instead of one generic prompt, you generate a customized prompt for each user or session. This is where system prompts become truly powerful.

Key Takeaway: Static system prompts are a starting point. Production systems customize prompts with user data, session context, and business rules. The “best” system prompt changes based on who’s asking and what they’re trying to do.

The Dynamic Prompt Concept

Instead of this:

System Prompt (static, same for everyone):
"You are a helpful customer support assistant"

You do this:

Base System Prompt (template):
"You are a helpful customer support assistant.
You are helping {customer_name} with their {account_type} account.
They have been a customer since {customer_since}.
..."

At runtime, inject values:
{
  customer_name: "Sarah Chen",
  account_type: "Enterprise",
  customer_since: "2021-03-15"
}

Generated System Prompt (specific to this customer):
"You are a helpful customer support assistant.
You are helping Sarah Chen with their Enterprise account.
They have been a customer since 2021-03-15.
..."

Building Dynamic System Prompt Templates

Start with a template that has placeholders:

class DynamicSystemPrompt:
    """Template-based system prompt with runtime injection"""

    BASE_TEMPLATE = """You are a {role} for {company}.

CUSTOMER CONTEXT:
- Name: {customer_name}
- Account Type: {account_type}
- Status: {account_status}
- Tenure: {customer_tenure}

RELEVANT BUSINESS CONTEXT:
{business_context}

{role_specific_instructions}

BEHAVIORAL GUIDELINES:
{behavioral_guidelines}
"""

    def __init__(self):
        self.variables = {}
        self.role_templates = {
            'support': self._support_instructions,
            'sales': self._sales_instructions,
            'billing': self._billing_instructions
        }

    def generate(self, role: str, context: dict) -> str:
        """Generate a customized system prompt"""

        # Merge defaults with provided context
        full_context = {
            'company': context.get('company', 'AcmeCorp'),
            'customer_name': context.get('customer_name', 'Valued Customer'),
            'account_type': context.get('account_type', 'Standard'),
            'account_status': context.get('account_status', 'Active'),
            'customer_tenure': self._format_tenure(context.get('customer_since')),
            'role': role,
            'business_context': self._get_business_context(context),
            'role_specific_instructions': self.role_templates[role](context),
            'behavioral_guidelines': self._get_behavioral_guidelines(context)
        }

        return self.BASE_TEMPLATE.format(**full_context)

    def _format_tenure(self, customer_since: str) -> str:
        """Format customer tenure"""
        from datetime import datetime
        if not customer_since:
            return "Unknown"

        start_date = datetime.fromisoformat(customer_since)
        today = datetime.now()
        years = (today - start_date).days // 365

        if years == 0:
            return "Less than a year"
        elif years == 1:
            return "1 year"
        else:
            return f"{years} years"

    def _get_business_context(self, context: dict) -> str:
        """Get relevant business context"""

        business_data = context.get('business_data', {})

        context_lines = [
            f"- Account Value: ${business_data.get('annual_value', 0):,.0f}",
            f"- Support Tier: {business_data.get('support_tier', 'Standard')}",
            f"- Active Services: {', '.join(business_data.get('services', []))}",
        ]

        return "\n".join(context_lines)

    def _support_instructions(self, context: dict) -> str:
        """Support-specific instructions"""

        tier = context.get('business_data', {}).get('support_tier', 'Standard')

        instructions = """YOUR ROLE:
Help this customer solve their issues efficiently.
"""
        if tier == 'Enterprise':
            instructions += """ENTERPRISE CUSTOMER - Priority handling:
- Escalate urgent issues immediately
- Provide direct contact for complex issues
- Reference SLA terms if needed
"""
        elif tier == 'Premium':
            instructions += """PREMIUM CUSTOMER:
- Provide expedited support
- Offer pro-active suggestions
- Go extra mile when reasonable
"""

        return instructions

    def _sales_instructions(self, context: dict) -> str:
        """Sales-specific instructions"""

        return """YOUR ROLE:
Help this customer understand how our products solve their needs.
Never pressure. Always listen first.
"""

    def _billing_instructions(self, context: dict) -> str:
        """Billing-specific instructions"""

        return """YOUR ROLE:
Help with billing questions and account management.
Be transparent about costs and options.
"""

    def _get_behavioral_guidelines(self, context: dict) -> str:
        """Get behavioral guidelines based on customer"""

        is_premium = context.get('business_data', {}).get('support_tier') in ['Enterprise', 'Premium']

        if is_premium:
            return """- Take ownership of issues
- Offer proactive suggestions
- Create tickets for follow-up
- Get manager approval for exceptions"""
        else:
            return """- Be helpful but efficient
- Follow standard procedures
- Escalate only when necessary
- Explain all costs upfront"""


# Usage
prompt_generator = DynamicSystemPrompt()

# Customer 1: Enterprise customer
enterprise_system_prompt = prompt_generator.generate(
    role='support',
    context={
        'customer_name': 'Sarah Chen',
        'account_type': 'Enterprise',
        'account_status': 'Active',
        'customer_since': '2019-03-15',
        'business_data': {
            'annual_value': 150000,
            'support_tier': 'Enterprise',
            'services': ['Analytics', 'Automation', 'Integrations']
        }
    }
)

# Customer 2: Standard customer
standard_system_prompt = prompt_generator.generate(
    role='support',
    context={
        'customer_name': 'John Doe',
        'account_type': 'Basic',
        'account_status': 'Active',
        'customer_since': '2024-01-01',
        'business_data': {
            'annual_value': 1200,
            'support_tier': 'Standard',
            'services': ['Analytics']
        }
    }
)

Context Injection Patterns

Pattern 1: User Profile Injection

def inject_user_profile(base_prompt: str, user_id: str) -> str:
    """Customize prompt with user profile data"""

    user_data = fetch_user_profile(user_id)

    user_context = f"""
CURRENT USER:
- Name: {user_data['name']}
- Role: {user_data['role']}
- Department: {user_data['department']}
- Preferences: {user_data['preferences']}
- Recent History: {user_data['recent_activity']}
"""

    return base_prompt + "\n" + user_context


def fetch_user_profile(user_id: str) -> dict:
    """Fetch user profile from database"""
    # Simulated
    return {
        'name': 'Alice Johnson',
        'role': 'Software Engineer',
        'department': 'Engineering',
        'preferences': {
            'detail_level': 'technical',
            'response_style': 'concise',
            'code_language': 'Python'
        },
        'recent_activity': 'Asked about async patterns'
    }

Pattern 2: Session State Injection

class SessionContextManager:
    """Track and inject session state into prompts"""

    def __init__(self, session_id: str):
        self.session_id = session_id
        self.context = {
            'started_at': datetime.now(),
            'turn_count': 0,
            'topics_discussed': [],
            'actions_taken': [],
            'user_intent': None
        }

    def update_context(self, user_message: str, assistant_response: str):
        """Update session context based on conversation"""

        self.context['turn_count'] += 1

        # Extract topics
        topics = self._extract_topics(user_message)
        self.context['topics_discussed'].extend(topics)

        # Track actions
        if 'create ticket' in assistant_response.lower():
            self.context['actions_taken'].append('ticket_created')

    def get_context_string(self) -> str:
        """Get session context as string for prompt injection"""

        return f"""SESSION CONTEXT:
- Turn Number: {self.context['turn_count']}
- Topics Discussed: {', '.join(set(self.context['topics_discussed']))}
- Actions Taken: {', '.join(self.context['actions_taken'])}
- Session Duration: {(datetime.now() - self.context['started_at']).seconds} seconds
"""

    def _extract_topics(self, message: str) -> list:
        """Extract topics from message"""

        topics = []
        keywords = {
            'password': ['password', 'reset', 'forgot', 'login'],
            'billing': ['bill', 'charge', 'invoice', 'payment'],
            'feature': ['feature', 'request', 'want', 'need'],
            'error': ['error', 'broken', 'fail', 'not working']
        }

        for topic, keywords_list in keywords.items():
            if any(k in message.lower() for k in keywords_list):
                topics.append(topic)

        return topics

    def inject_into_prompt(self, base_prompt: str) -> str:
        """Inject session context into prompt"""
        return base_prompt + "\n" + self.get_context_string()

Pattern 3: Business Rules Injection

def inject_business_rules(base_prompt: str, context: dict) -> str:
    """Inject current business rules and policies"""

    current_policies = get_active_policies(context.get('region'))

    rules_section = f"""
ACTIVE BUSINESS RULES (Last Updated: {current_policies['updated_at']}):

Pricing:
{chr(10).join(f"- {tier}: ${price}/month" for tier, price in current_policies['pricing'].items())}

Limitations:
{chr(10).join(f"- {limit_name}: {limit_value}" for limit_name, limit_value in current_policies['limits'].items())}

Promotions:
{chr(10).join(f"- {promo['name']}: {promo['description']}" for promo in current_policies['active_promotions'])}

Do NOT mention policies or promotions not listed above.
If customer asks about unlisted policies, say 'That policy is not currently active'.
"""

    return base_prompt + "\n" + rules_section


def get_active_policies(region: str = 'US') -> dict:
    """Get current policies for region"""
    # Simulated - would connect to policy database
    return {
        'updated_at': '2024-03-19',
        'pricing': {
            'Basic': 9.99,
            'Pro': 29.99,
            'Enterprise': 'Custom'
        },
        'limits': {
            'API calls per day': '10,000',
            'Storage': '100GB',
            'Concurrent connections': '100'
        },
        'active_promotions': [
            {
                'name': 'New Year Special',
                'description': '30% off annual plans through March 31'
            }
        ]
    }

Pattern 4: Retrieval-Augmented System Prompts

Sometimes context comes from documents or knowledge bases:

class RAGSystemPrompt:
    """System prompt augmented with retrieved context"""

    def __init__(self, base_prompt: str, retriever):
        self.base_prompt = base_prompt
        self.retriever = retriever

    def generate(self, user_query: str) -> str:
        """Generate prompt with relevant context from knowledge base"""

        # Retrieve relevant documents
        relevant_docs = self.retriever.search(user_query, top_k=3)

        # Build context section
        context_section = "RELEVANT INFORMATION:\n\n"

        for doc in relevant_docs:
            context_section += f"- {doc['title']}: {doc['summary']}\n"

        return self.base_prompt + "\n\n" + context_section


class SimpleRetriever:
    """Simple document retriever"""

    def __init__(self, documents: list):
        self.documents = documents

    def search(self, query: str, top_k: int = 3) -> list:
        """Find relevant documents"""

        scores = []

        for doc in self.documents:
            # Simple keyword matching
            score = sum(1 for word in query.lower().split()
                       if word in doc['content'].lower())

            if score > 0:
                scores.append((doc, score))

        # Return top K by score
        scores.sort(key=lambda x: x[1], reverse=True)
        return [doc for doc, score in scores[:top_k]]


# Usage
documents = [
    {
        'title': 'API Rate Limits',
        'content': 'Free tier: 100 requests/minute. Pro: 1000 requests/minute.',
        'summary': 'Rate limiting policy'
    },
    {
        'title': 'Refund Policy',
        'content': 'Refunds allowed within 30 days of purchase. Must contact support.',
        'summary': 'How to get a refund'
    },
    {
        'title': 'Data Privacy',
        'content': 'We encrypt all user data. GDPR compliant.',
        'summary': 'Data protection practices'
    }
]

rag_prompt = RAGSystemPrompt(
    base_prompt="You are a helpful customer support agent.",
    retriever=SimpleRetriever(documents)
)

# When answering a question:
user_query = "What are your rate limits?"
system_prompt = rag_prompt.generate(user_query)
print(system_prompt)

A/B Testing Dynamic Prompts

Dynamic prompts create new testing opportunities:

def ab_test_dynamic_prompts(control_prompt_fn: callable,
                           variant_prompt_fn: callable,
                           test_contexts: list,
                           model_fn: callable) -> dict:
    """A/B test two different dynamic prompt generators"""

    results = {
        'control': [],
        'variant': [],
        'metrics': {}
    }

    for context in test_contexts:
        # Generate prompts
        control = control_prompt_fn(context)
        variant = variant_prompt_fn(context)

        # Test each
        control_response = model_fn(control, context['user_query'])
        variant_response = model_fn(variant, context['user_query'])

        # Evaluate
        control_score = evaluate_response(control_response, context)
        variant_score = evaluate_response(variant_response, context)

        results['control'].append(control_score)
        results['variant'].append(variant_score)

    # Summary
    control_avg = sum(results['control']) / len(results['control'])
    variant_avg = sum(results['variant']) / len(results['variant'])

    results['metrics'] = {
        'control_avg': control_avg,
        'variant_avg': variant_avg,
        'improvement': variant_avg - control_avg,
        'improvement_percent': ((variant_avg - control_avg) / control_avg * 100)
    }

    return results


def evaluate_response(response: str, context: dict) -> float:
    """Score a response (0-1)"""

    score = 0.5

    # Positive signals
    if context.get('account_type') == 'Enterprise':
        if 'enterprise' in response.lower() or 'priority' in response.lower():
            score += 0.2

    # Check accuracy
    if 'inaccurate' not in context.get('feedback', '').lower():
        score += 0.3

    return min(1.0, score)

Context Window Management with Dynamic Prompts

More context uses more tokens. Be strategic:

class EfficientDynamicPrompt:
    """Dynamic prompt that optimizes token usage"""

    def __init__(self, base_prompt: str):
        self.base_prompt = base_prompt

    def generate(self, context: dict, token_budget: int = 500) -> str:
        """Generate prompt within token budget"""

        prompt = self.base_prompt
        used_tokens = self._estimate_tokens(prompt)

        remaining_budget = token_budget - used_tokens

        # Add context in priority order
        if remaining_budget > 100:
            prompt += self._get_user_context(context)
            remaining_budget -= 100

        if remaining_budget > 50:
            prompt += self._get_session_context(context)
            remaining_budget -= 50

        if remaining_budget > 30:
            prompt += self._get_business_context(context)

        return prompt

    def _estimate_tokens(self, text: str) -> int:
        """Rough token estimate (1 token ~4 chars)"""
        return len(text) // 4

    def _get_user_context(self, context: dict) -> str:
        """User context (required)"""
        return f"\nUser: {context.get('user_name', 'Unknown')}"

    def _get_session_context(self, context: dict) -> str:
        """Session context (important)"""
        return f"\nSession turn: {context.get('turn_count', 0)}"

    def _get_business_context(self, context: dict) -> str:
        """Business context (nice to have)"""
        return f"\nAccount: {context.get('account_type', 'Standard')}"

Production Example: E-Commerce Support

Here’s how this all comes together in a real system:

class DynamicECommerceSupport:
    """Dynamic system prompt for e-commerce support"""

    def __init__(self):
        self.session_manager = SessionContextManager(session_id='new')
        self.rag_retriever = SimpleRetriever(self._get_knowledge_base())

    def generate_system_prompt(self, user_id: str, session_id: str) -> str:
        """Generate customized system prompt for this user"""

        # Get user data
        user = self._fetch_user(user_id)

        # Get business context
        policies = get_active_policies()

        # Build prompt
        base = f"""You are a helpful e-commerce support specialist.

CUSTOMER:
- Name: {user['name']}
- Account Status: {user['status']}
- Lifetime Value: ${user['lifetime_value']:,}
- VIP: {'Yes' if user['lifetime_value'] > 10000 else 'No'}

CURRENT POLICIES:
- Free shipping: {policies['free_shipping_threshold']}
- Return window: {policies['return_days']} days
- Refund method: {policies['refund_method']}

SESSION:
- Turn: {self.session_manager.context['turn_count']}
- Topics: {', '.join(self.session_manager.context['topics_discussed'])}

GUIDELINES:
- For VIP customers, offer alternatives and be flexible
- For standard customers, follow policy strictly
- Always be polite but efficient
- Escalate complex issues to manager"""

        return base

    def handle_message(self, user_id: str, user_message: str,
                      model_fn: callable) -> str:
        """Process user message with dynamic prompt"""

        # Generate dynamic prompt
        system_prompt = self.generate_system_prompt(user_id, 'current_session')

        # Call model
        response = model_fn(system_prompt, user_message)

        # Update session context
        self.session_manager.update_context(user_message, response)

        return response

    def _fetch_user(self, user_id: str) -> dict:
        """Get user from database"""
        return {
            'name': 'Sarah',
            'status': 'Active',
            'lifetime_value': 15000
        }

    def _get_knowledge_base(self) -> list:
        """Get support knowledge base"""
        return [
            {'title': 'Shipping Policy', 'content': '...', 'summary': '...'},
            {'title': 'Returns', 'content': '...', 'summary': '...'},
        ]

Exercise: Build a Dynamic Prompt System

Create a complete dynamic system prompt system for a SaaS product support chatbot:

  1. Base prompt template with placeholders for:

    • Customer name
    • Account type (Free/Pro/Enterprise)
    • Days as customer
    • Recent issues
    • Account status
  2. Context injection functions:

    • User profile injection
    • Session state injection
    • Business rules injection
  3. Prompt generation that creates customized prompts for:

    • A brand new free user
    • A Pro customer with 2+ years tenure
    • An Enterprise customer
    • A customer with past escalations
  4. A/B test comparison showing:

    • Static vs dynamic prompts on 5 test cases
    • Improvement metrics
    • Token usage analysis
  5. Production code showing how you’d integrate this into a real system

Deliverables:

  • Prompt template with placeholders
  • Context injection code (3+ types)
  • Prompt generation function
  • 3-4 example generated prompts
  • A/B test results
  • Integration example

Summary

In this lesson, you’ve learned:

  • How to build template-based dynamic system prompts
  • Context injection patterns for user data, session state, and business rules
  • Retrieval-augmented system prompts that pull context from knowledge bases
  • How to test and A/B test dynamic prompts
  • Token budget management when adding context
  • A complete production example

You’ve now completed Module 2 on System Prompts. Next, Module 3 covers multimodal prompting: working with images, audio, video, and documents.