Agentic Design Pattern: Constraint Specification

Written by

in


    """
Pattern 087: Constraint Specification Pattern

Description:
    The Constraint Specification pattern explicitly defines boundaries, rules, and
    limitations that the LLM must adhere to when generating responses. This pattern
    is crucial for controlling LLM behavior, ensuring compliance with requirements,
    and preventing undesired outputs. Constraints can be content-based, format-based,
    style-based, or domain-specific, and they guide the model toward appropriate
    responses while filtering out inappropriate ones.

    Constraint specification is essential for:
    - Safety and compliance requirements
    - Brand voice and style consistency
    - Content appropriateness filtering
    - Domain-specific requirements
    - Length and complexity control
    - Factual accuracy boundaries

Components:
    1. Constraint Types
       - Content constraints (what to include/exclude)
       - Format constraints (structure and presentation)
       - Style constraints (tone, formality, vocabulary)
       - Length constraints (word/character limits)
       - Domain constraints (topic boundaries)
       - Safety constraints (harmful content prevention)

    2. Constraint Expression
       - Explicit rules ("must", "must not")
       - Positive constraints (requirements)
       - Negative constraints (prohibitions)
       - Conditional constraints (if-then rules)
       - Priority levels (strict vs flexible)

    3. Enforcement Strategies
       - Pre-generation (prompt engineering)
       - Post-generation (validation and filtering)
       - Iterative refinement (generate-validate-refine)
       - Guardrails (safety layers)
       - Fallback handling (when constraints violated)

    4. Validation Methods
       - Rule-based checking
       - Pattern matching
       - Content analysis
       - Length verification
       - Format validation
       - Safety scoring

Use Cases:
    1. Content Safety
       - Prevent harmful content generation
       - Filter inappropriate language
       - Block sensitive topics
       - Ensure age-appropriate content
       - Compliance with platform policies

    2. Brand Consistency
       - Maintain brand voice
       - Use approved terminology
       - Follow style guidelines
       - Consistent tone across content
       - Corporate communication standards

    3. Domain Expertise
       - Stay within knowledge boundaries
       - Acknowledge uncertainty
       - Avoid medical/legal claims
       - Respect professional standards
       - Domain-specific terminology

    4. Format and Structure
       - Length limitations (tweets, abstracts)
       - Structural requirements (sections, headings)
       - Citation requirements
       - Formatting rules (markdown, HTML)
       - Template compliance

    5. Legal and Compliance
       - GDPR compliance (no PII without consent)
       - HIPAA compliance (no PHI exposure)
       - Copyright respect
       - Regulatory requirements
       - Terms of service adherence

LangChain Implementation:
    LangChain supports constraint specification through:
    - System messages with explicit rules
    - Constitutional AI principles
    - Output validators and filters
    - Custom guardrails
    - Retry mechanisms with corrections

Key Features:
    1. Multi-Level Constraints
       - Hard constraints (must be satisfied)
       - Soft constraints (preferred but flexible)
       - Conditional constraints (context-dependent)
       - Hierarchical constraints (priority ordering)

    2. Constraint Composition
       - Multiple constraints simultaneously
       - Constraint conflicts resolution
       - Priority-based enforcement
       - Constraint inheritance

    3. Validation and Feedback
       - Immediate validation
       - Detailed violation reporting
       - Correction suggestions
       - Iterative improvement

    4. Dynamic Constraints
       - Context-aware constraints
       - User-specific rules
       - Time-based constraints
       - Adaptive boundaries

Best Practices:
    1. Clarity and Specificity
       - State constraints explicitly
       - Provide examples of violations
       - Clarify edge cases
       - Use concrete language

    2. Prioritization
       - Identify critical constraints
       - Allow flexibility where possible
       - Balance constraints with quality
       - Avoid over-constraining

    3. Testing
       - Test constraint enforcement
       - Try boundary cases
       - Verify violation detection
       - Check false positives

    4. Documentation
       - Document all constraints
       - Explain rationale
       - Provide violation examples
       - Maintain constraint catalog

Trade-offs:
    Advantages:
    - Better control over outputs
    - Improved safety and compliance
    - Consistent brand voice
    - Reduced inappropriate content
    - Clear expectations
    - Easier validation

    Disadvantages:
    - May limit creativity
    - Can reduce output quality
    - Increases complexity
    - Requires careful design
    - May need frequent updates
    - Potential over-constraint

Production Considerations:
    1. Constraint Management
       - Centralized constraint definitions
       - Version control for constraints
       - Easy updates and modifications
       - Constraint testing framework
       - Documentation and examples

    2. Performance Impact
       - Validation overhead
       - Retry costs for violations
       - Caching validated outputs
       - Efficient constraint checking
       - Batch validation

    3. User Experience
       - Clear violation messages
       - Suggestion for corrections
       - Graceful degradation
       - Transparency about constraints
       - User constraint customization

    4. Monitoring
       - Track constraint violations
       - Analyze violation patterns
       - Measure enforcement effectiveness
       - Identify constraint conflicts
       - User feedback collection

    5. Evolution
       - Regular constraint reviews
       - Adapt to new requirements
       - Learn from violations
       - Community feedback
       - A/B test constraint changes
"""

import os
import re
from typing import List, Dict, Any, Optional, Callable
from dataclasses import dataclass
from enum import Enum
from dotenv import load_dotenv

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI

load_dotenv()


class ConstraintType(Enum):
    """Types of constraints"""
    CONTENT = "content"
    LENGTH = "length"
    STYLE = "style"
    FORMAT = "format"
    SAFETY = "safety"
    DOMAIN = "domain"


class ConstraintSeverity(Enum):
    """Severity levels for constraints"""
    STRICT = "strict"  # Must be satisfied
    MODERATE = "moderate"  # Should be satisfied
    FLEXIBLE = "flexible"  # Nice to have


@dataclass
class Constraint:
    """Represents a single constraint"""
    name: str
    description: str
    constraint_type: ConstraintType
    severity: ConstraintSeverity
    validation_func: Optional[Callable[[str], bool]] = None
    violation_message: str = "Constraint violated"


@dataclass
class ConstraintConfig:
    """Configuration for constraint-based generation"""
    max_retries: int = 3
    temperature: float = 0.5
    model_name: str = "gpt-3.5-turbo"
    fail_on_violation: bool = False


class ConstraintSpecificationAgent:
    """
    Agent that enforces constraints on LLM outputs.
    
    This agent demonstrates:
    1. Defining multiple types of constraints
    2. Enforcing constraints during generation
    3. Validating outputs against constraints
    4. Handling constraint violations
    """
    
    def __init__(self, config: Optional[ConstraintConfig] = None):
        """
        Initialize constraint specification agent.
        
        Args:
            config: Configuration for constraint handling
        """
        self.config = config or ConstraintConfig()
        self.llm = ChatOpenAI(
            model=self.config.model_name,
            temperature=self.config.temperature
        )
        self.constraints: List[Constraint] = []
    
    def add_constraint(self, constraint: Constraint):
        """Add a constraint to the agent"""
        self.constraints.append(constraint)
    
    def clear_constraints(self):
        """Remove all constraints"""
        self.constraints = []
    
    def _build_constraint_instructions(self) -> str:
        """Build constraint instructions for prompt"""
        if not self.constraints:
            return ""
        
        instructions = ["You must follow these constraints:"]
        
        for i, constraint in enumerate(self.constraints, 1):
            severity_label = {
                ConstraintSeverity.STRICT: "MUST",
                ConstraintSeverity.MODERATE: "SHOULD",
                ConstraintSeverity.FLEXIBLE: "IDEALLY"
            }[constraint.severity]
            
            instructions.append(f"{i}. {severity_label}: {constraint.description}")
        
        return "\n".join(instructions)
    
    def _validate_constraints(self, text: str) -> Dict[str, Any]:
        """
        Validate text against all constraints.
        
        Args:
            text: Text to validate
            
        Returns:
            Validation results
        """
        violations = []
        
        for constraint in self.constraints:
            if constraint.validation_func:
                if not constraint.validation_func(text):
                    violations.append({
                        "constraint": constraint.name,
                        "severity": constraint.severity.value,
                        "message": constraint.violation_message
                    })
        
        return {
            "valid": len(violations) == 0,
            "violations": violations,
            "num_violations": len(violations)
        }
    
    def generate_with_constraints(
        self,
        prompt: str,
        task_description: str = "Generate a response"
    ) -> Dict[str, Any]:
        """
        Generate text while enforcing constraints.
        
        Args:
            prompt: User prompt
            task_description: Description of task
            
        Returns:
            Generation result with validation info
        """
        constraint_instructions = self._build_constraint_instructions()
        
        template = ChatPromptTemplate.from_messages([
            ("system", """{task_description}

{constraints}

Ensure your response satisfies all constraints."""),
            ("human", "{prompt}")
        ])
        
        chain = template | self.llm | StrOutputParser()
        
        for attempt in range(self.config.max_retries):
            # Generate
            result = chain.invoke({
                "task_description": task_description,
                "constraints": constraint_instructions,
                "prompt": prompt
            })
            
            # Validate
            validation = self._validate_constraints(result)
            
            if validation["valid"]:
                return {
                    "success": True,
                    "text": result,
                    "attempts": attempt + 1,
                    "validation": validation
                }
            
            # If not last attempt, provide feedback for retry
            if attempt  str:
        """
        Generate text with length constraints.
        
        Args:
            prompt: User prompt
            max_words: Maximum word count
            min_words: Optional minimum word count
            
        Returns:
            Generated text
        """
        self.clear_constraints()
        
        # Add length constraint
        def validate_length(text: str) -> bool:
            word_count = len(text.split())
            if min_words and word_count  max_words:
                return False
            return True
        
        length_desc = f"between {min_words} and {max_words} words" if min_words else f"at most {max_words} words"
        
        self.add_constraint(Constraint(
            name="length",
            description=f"Response must be {length_desc}",
            constraint_type=ConstraintType.LENGTH,
            severity=ConstraintSeverity.STRICT,
            validation_func=validate_length,
            violation_message=f"Length constraint violated (required: {length_desc})"
        ))
        
        result = self.generate_with_constraints(prompt)
        return result["text"] if result["success"] else result.get("error", "Generation failed")
    
    def generate_with_style_constraint(
        self,
        prompt: str,
        style: str = "professional"
    ) -> str:
        """
        Generate text with style constraints.
        
        Args:
            prompt: User prompt
            style: Desired style (professional, casual, formal)
            
        Returns:
            Generated text
        """
        self.clear_constraints()
        
        style_guidelines = {
            "professional": "Use professional language, avoid slang, maintain objective tone",
            "casual": "Use conversational language, contractions are fine, friendly tone",
            "formal": "Use formal language, no contractions, academic or business tone",
            "humorous": "Use humor and wit, light-hearted tone, creative wordplay"
        }
        
        guideline = style_guidelines.get(style.lower(), style_guidelines["professional"])
        
        self.add_constraint(Constraint(
            name="style",
            description=guideline,
            constraint_type=ConstraintType.STYLE,
            severity=ConstraintSeverity.MODERATE
        ))
        
        result = self.generate_with_constraints(
            prompt,
            task_description=f"Generate a {style} response"
        )
        
        return result["text"] if result["success"] else result.get("text", "")
    
    def generate_with_content_constraints(
        self,
        prompt: str,
        must_include: Optional[List[str]] = None,
        must_exclude: Optional[List[str]] = None
    ) -> str:
        """
        Generate text with content inclusion/exclusion constraints.
        
        Args:
            prompt: User prompt
            must_include: Terms that must appear
            must_exclude: Terms that must not appear
            
        Returns:
            Generated text
        """
        self.clear_constraints()
        
        # Inclusion constraint
        if must_include:
            def validate_inclusion(text: str) -> bool:
                text_lower = text.lower()
                return all(term.lower() in text_lower for term in must_include)
            
            self.add_constraint(Constraint(
                name="content_inclusion",
                description=f"Must include these terms: {', '.join(must_include)}",
                constraint_type=ConstraintType.CONTENT,
                severity=ConstraintSeverity.STRICT,
                validation_func=validate_inclusion,
                violation_message=f"Required terms missing: {', '.join(must_include)}"
            ))
        
        # Exclusion constraint
        if must_exclude:
            def validate_exclusion(text: str) -> bool:
                text_lower = text.lower()
                return not any(term.lower() in text_lower for term in must_exclude)
            
            self.add_constraint(Constraint(
                name="content_exclusion",
                description=f"Must NOT include these terms: {', '.join(must_exclude)}",
                constraint_type=ConstraintType.CONTENT,
                severity=ConstraintSeverity.STRICT,
                validation_func=validate_exclusion,
                violation_message=f"Prohibited terms found: {', '.join(must_exclude)}"
            ))
        
        result = self.generate_with_constraints(prompt)
        return result["text"] if result["success"] else result.get("text", "")
    
    def generate_with_format_constraint(
        self,
        prompt: str,
        format_type: str = "bullet_points"
    ) -> str:
        """
        Generate text with format constraints.
        
        Args:
            prompt: User prompt
            format_type: Format type (bullet_points, numbered_list, paragraphs)
            
        Returns:
            Generated text
        """
        self.clear_constraints()
        
        format_descriptions = {
            "bullet_points": "Use bullet points (- or •) for each item. No numbered lists.",
            "numbered_list": "Use numbered list format (1. 2. 3. etc.). No bullet points.",
            "paragraphs": "Write in paragraph form with clear topic sentences. No lists.",
            "single_sentence": "Provide answer as a single, concise sentence."
        }
        
        description = format_descriptions.get(format_type, format_descriptions["bullet_points"])
        
        self.add_constraint(Constraint(
            name="format",
            description=description,
            constraint_type=ConstraintType.FORMAT,
            severity=ConstraintSeverity.STRICT
        ))
        
        result = self.generate_with_constraints(
            prompt,
            task_description=f"Generate response in {format_type} format"
        )
        
        return result["text"] if result["success"] else result.get("text", "")
    
    def generate_with_safety_constraints(
        self,
        prompt: str
    ) -> str:
        """
        Generate text with safety constraints.
        
        Args:
            prompt: User prompt
            
        Returns:
            Generated text
        """
        self.clear_constraints()
        
        safety_rules = [
            "No harmful, hateful, or violent content",
            "No personal attacks or discrimination",
            "No illegal activities or advice",
            "No explicit or inappropriate content",
            "Respectful and inclusive language"
        ]
        
        for rule in safety_rules:
            self.add_constraint(Constraint(
                name=f"safety_{safety_rules.index(rule)}",
                description=rule,
                constraint_type=ConstraintType.SAFETY,
                severity=ConstraintSeverity.STRICT
            ))
        
        result = self.generate_with_constraints(
            prompt,
            task_description="Generate a safe and appropriate response"
        )
        
        return result["text"] if result["success"] else "Unable to generate safe content for this prompt."


def demonstrate_constraint_specification():
    """Demonstrate constraint specification patterns"""
    print("=" * 80)
    print("CONSTRAINT SPECIFICATION PATTERN DEMONSTRATION")
    print("=" * 80)
    
    agent = ConstraintSpecificationAgent()
    
    # Example 1: Length Constraints
    print("\n" + "=" * 80)
    print("EXAMPLE 1: Length Constraints")
    print("=" * 80)
    
    prompt = "Explain artificial intelligence"
    print(f"\nPrompt: {prompt}")
    print("\nConstraint: Maximum 50 words\n")
    
    short_response = agent.generate_with_length_constraint(prompt, max_words=50)
    print(f"Response ({len(short_response.split())} words):")
    print(short_response)
    
    print("\nConstraint: 80-120 words\n")
    medium_response = agent.generate_with_length_constraint(prompt, max_words=120, min_words=80)
    print(f"Response ({len(medium_response.split())} words):")
    print(medium_response)
    
    # Example 2: Style Constraints
    print("\n" + "=" * 80)
    print("EXAMPLE 2: Style Constraints")
    print("=" * 80)
    
    prompt = "Describe the benefits of exercise"
    print(f"\nPrompt: {prompt}\n")
    
    styles = ["professional", "casual", "formal"]
    for style in styles:
        print(f"\n{style.upper()} STYLE:")
        print("-" * 40)
        response = agent.generate_with_style_constraint(prompt, style=style)
        print(response)
    
    # Example 3: Content Inclusion/Exclusion
    print("\n" + "=" * 80)
    print("EXAMPLE 3: Content Constraints (Must Include/Exclude)")
    print("=" * 80)
    
    prompt = "Write about healthy eating habits"
    must_include = ["vegetables", "protein", "hydration"]
    must_exclude = ["diet pills", "supplements"]
    
    print(f"\nPrompt: {prompt}")
    print(f"Must include: {must_include}")
    print(f"Must exclude: {must_exclude}\n")
    
    response = agent.generate_with_content_constraints(
        prompt,
        must_include=must_include,
        must_exclude=must_exclude
    )
    print("Response:")
    print(response)
    
    # Example 4: Format Constraints
    print("\n" + "=" * 80)
    print("EXAMPLE 4: Format Constraints")
    print("=" * 80)
    
    prompt = "List the steps to start a business"
    print(f"\nPrompt: {prompt}\n")
    
    formats = ["bullet_points", "numbered_list", "paragraphs"]
    for fmt in formats:
        print(f"\n{fmt.upper().replace('_', ' ')} FORMAT:")
        print("-" * 40)
        response = agent.generate_with_format_constraint(prompt, format_type=fmt)
        print(response)
    
    # Example 5: Multiple Constraints
    print("\n" + "=" * 80)
    print("EXAMPLE 5: Multiple Simultaneous Constraints")
    print("=" * 80)
    
    agent.clear_constraints()
    
    # Add multiple constraints
    agent.add_constraint(Constraint(
        name="length",
        description="Response must be 60-80 words",
        constraint_type=ConstraintType.LENGTH,
        severity=ConstraintSeverity.STRICT,
        validation_func=lambda t: 60 <= len(t.split()) <= 80,
        violation_message="Length must be 60-80 words"
    ))
    
    agent.add_constraint(Constraint(
        name="style",
        description="Use professional, objective tone",
        constraint_type=ConstraintType.STYLE,
        severity=ConstraintSeverity.MODERATE
    ))
    
    agent.add_constraint(Constraint(
        name="content",
        description="Must mention 'innovation' and 'technology'",
        constraint_type=ConstraintType.CONTENT,
        severity=ConstraintSeverity.STRICT,
        validation_func=lambda t: "innovation" in t.lower() and "technology" in t.lower(),
        violation_message="Must include 'innovation' and 'technology'"
    ))
    
    prompt = "Describe the future of work"
    print(f"\nPrompt: {prompt}")
    print("\nConstraints:")
    print("1. Length: 60-80 words")
    print("2. Style: Professional, objective")
    print("3. Content: Must mention 'innovation' and 'technology'\n")
    
    result = agent.generate_with_constraints(prompt)
    print(f"Success: {result['success']}")
    print(f"Attempts: {result['attempts']}")
    print(f"\nResponse ({len(result['text'].split())} words):")
    print(result['text'])
    
    # Example 6: Safety Constraints
    print("\n" + "=" * 80)
    print("EXAMPLE 6: Safety Constraints")
    print("=" * 80)
    
    safe_prompt = "Give advice on managing workplace conflicts"
    print(f"\nPrompt: {safe_prompt}")
    print("\nApplying safety constraints...\n")
    
    response = agent.generate_with_safety_constraints(safe_prompt)
    print("Response:")
    print(response)
    
    # Summary
    print("\n" + "=" * 80)
    print("CONSTRAINT SPECIFICATION SUMMARY")
    print("=" * 80)
    print("""
Constraint Specification Pattern Benefits:
1. Control: Precise control over LLM outputs
2. Compliance: Ensures regulatory and policy adherence
3. Consistency: Maintains brand voice and standards
4. Safety: Prevents inappropriate content
5. Quality: Enforces quality standards
6. Integration: Easier to integrate with systems

Constraint Types Demonstrated:
1. Length Constraints: Word/character limits
2. Style Constraints: Tone, formality, voice
3. Content Constraints: Required/prohibited terms
4. Format Constraints: Structure and presentation
5. Safety Constraints: Harmful content prevention
6. Multiple Constraints: Combined requirements

Constraint Severity Levels:
- STRICT: Must be satisfied (violations cause failure)
- MODERATE: Should be satisfied (violations logged)
- FLEXIBLE: Nice to have (soft preferences)

Enforcement Strategies:
1. Pre-generation: Include constraints in prompt
2. Validation: Check outputs against rules
3. Iteration: Retry with feedback on violations
4. Fallback: Alternative approach when constraints can't be met

Best Practices:
1. Be explicit and specific with constraints
2. Prioritize constraints (strict vs flexible)
3. Provide examples of acceptable outputs
4. Test constraint enforcement thoroughly
5. Handle violations gracefully
6. Monitor constraint effectiveness
7. Update constraints based on feedback

Common Use Cases:
- Content moderation (safety)
- Brand consistency (style)
- Legal compliance (domain rules)
- Format standardization (structure)
- Length requirements (summaries, tweets)
- Quality control (standards)

Production Considerations:
- Balance constraints with creativity
- Allow appropriate flexibility
- Provide clear violation messages
- Implement retry mechanisms
- Monitor constraint violation rates
- A/B test constraint effectiveness
- Document all constraints clearly
- Version control constraint rules

Constraint Design Tips:
1. Start with essential constraints only
2. Add constraints incrementally
3. Test against diverse inputs
4. Avoid over-constraining
5. Make constraints measurable
6. Provide violation feedback
7. Allow for constraint evolution

When to Use Constraints:
- Safety-critical applications
- Regulated industries
- Brand-sensitive content
- System integration requirements
- Quality assurance needs
- Compliance requirements

Trade-offs:
✅ Better control and safety
✅ Consistent outputs
✅ Easier validation
❌ May limit creativity
❌ Requires careful design
❌ Can be overly restrictive
""")
    
    print("\n" + "=" * 80)
    print("Pattern 087 (Constraint Specification) demonstration complete!")
    print("=" * 80)


if __name__ == "__main__":
    demonstrate_constraint_specification()

    

Agentic Design Pattern: Constraint Specification

Pattern 087: Constraint Specification – Line-by-Line Explanation

Overview

This document provides a detailed line-by-line explanation of the Constraint Specification pattern implementation.


Pattern Description

Pattern 087: Constraint Specification Pattern

Description: The Constraint Specification pattern explicitly defines boundaries, rules, and limitations that the LLM must adhere to when generating responses. This pattern is crucial for controlling LLM behavior, ensuring compliance with requirements, and preventing undesired outputs. Constraints can be content-based, format-based, style-based, or domain-specific, and they guide the model toward appropriate responses while filtering out inappropriate ones.

Constraint specification is essential for:
- Safety and compliance requirements
- Brand voice and style consistency
- Content appropriateness filtering
- Domain-specific requirements
- Length and complexity control
- Factual accuracy boundaries

Components: 1. Constraint Types – Content constraints (what to include/exclude) – Format constraints (structure and presentation) – Style constraints (tone, formality, vocabulary) – Length constraints (word/character limits) – Domain constraints (topic boundaries) – Safety constraints (harmful content prevention)

2. Constraint Expression
   - Explicit rules ("must", "must not")
   - Positive constraints (requirements)
   - Negative constraints (prohibitions)
   - Conditional constraints (if-then rules)
   - Priority levels (strict vs flexible)

3. Enforcement Strategies
   - Pre-generation (prompt engineering)
   - Post-generation (validation and filtering)
   - Iterative refinement (generate-validate-refine)
   - Guardrails (safety layers)
   - Fallback handling (when constraints violated)

4. Validation Methods
   - Rule-based checking
   - Pattern matching
   - Content analysis
   - Length verification
   - Format validation
   - Safety scoring

Use Cases: 1. Content Safety – Prevent harmful content generation – Filter inappropriate language – Block sensitive topics – Ensure age-appropriate content – Compliance with platform policies

2. Brand Consistency
   - Maintain brand voice
   - Use approved terminology
   - Follow style guidelines
   - Consistent tone across content
   - Corporate communication standards

3. Domain Expertise
   - Stay within knowledge boundaries
   - Acknowledge uncertainty
   - Avoid medical/legal claims
   - Respect professional standards
   - Domain-specific terminology

4. Format and Structure
   - Length limitations (tweets, abstracts)
   - Structural requirements (sections, headings)
   - Citation requirements
   - Formatting rules (markdown, HTML)
   - Template compliance

5. Legal and Compliance
   - GDPR compliance (no PII without consent)
   - HIPAA compliance (no PHI exposure)
   - Copyright respect
   - Regulatory requirements
   - Terms of service adherence

LangChain Implementation: LangChain supports constraint specification through: – System messages with explicit rules – Constitutional AI principles – Output validators and filters – Custom guardrails – Retry mechanisms with corrections

Key Features: 1. Multi-Level Constraints – Hard constraints (must be satisfied) – Soft constraints (preferred but flexible) – Conditional constraints (context-dependent) – Hierarchical constraints (priority ordering)

2. Constraint Composition
   - Multiple constraints simultaneously
   - Constraint conflicts resolution
   - Priority-based enforcement
   - Constraint inheritance

3. Validation and Feedback
   - Immediate validation
   - Detailed violation reporting
   - Correction suggestions
   - Iterative improvement

4. Dynamic Constraints
   - Context-aware constraints
   - User-specific rules
   - Time-based constraints
   - Adaptive boundaries

Best Practices: 1. Clarity and Specificity – State constraints explicitly – Provide examples of violations – Clarify edge cases – Use concrete language

2. Prioritization
   - Identify critical constraints
   - Allow flexibility where possible
   - Balance constraints with quality
   - Avoid over-constraining

3. Testing
   - Test constraint enforcement
   - Try boundary cases
   - Verify violation detection
   - Check false positives

4. Documentation
   - Document all constraints
   - Explain rationale
   - Provide violation examples
   - Maintain constraint catalog

Trade-offs: Advantages: – Better control over outputs – Improved safety and compliance – Consistent brand voice – Reduced inappropriate content – Clear expectations – Easier validation

Disadvantages:
- May limit creativity
- Can reduce output quality
- Increases complexity
- Requires careful design
- May need frequent updates
- Potential over-constraint

Production Considerations: 1. Constraint Management – Centralized constraint definitions – Version control for constraints – Easy updates and modifications – Constraint testing framework – Documentation and examples

2. Performance Impact
   - Validation overhead
   - Retry costs for violations
   - Caching validated outputs
   - Efficient constraint checking
   - Batch validation

3. User Experience
   - Clear violation messages
   - Suggestion for corrections
   - Graceful degradation
   - Transparency about constraints
   - User constraint customization

4. Monitoring
   - Track constraint violations
   - Analyze violation patterns
   - Measure enforcement effectiveness
   - Identify constraint conflicts
   - User feedback collection

5. Evolution
   - Regular constraint reviews
   - Adapt to new requirements
   - Learn from violations
   - Community feedback
   - A/B test constraint changes

File Statistics

  • Total Lines: 835
  • Classes: 5
  • Functions: 1
  • Constants: 0

Module Documentation

"""
Pattern 087: Constraint Specification Pattern

Description:
    The Constraint Specification pattern explicitly defines boundaries, rules, and
    limitations that the LLM must adhere to when generating responses. This pattern
    is crucial for controlling LLM behavior, ensuring compliance with requirements,
    and preventing undesired outputs. Constraints can be content-based, format-based,
    style-based, or domain-specific, and they guide the model toward appropriate
    responses while filtering out inappropriate ones.

    Constraint specification is essential for:
    - Safety and compliance requirements
    - Brand voice and style consistency
    - Content appropriateness filtering
    - Domain-specific requirements
    - Length and complexity control
    - Factual accuracy boundaries

Components:
    1. Constraint Types
       - Content constraints (what to include/exclude)
       - Format constraints (structure and presentation)
       - Style constraints (tone, formality, vocabulary)
       - Length constraints (word/character limits)
       - Domain constraints (topic boundaries)
       - Safety constraints (harmful content prevention)

    2. Constraint Expression
       - Explicit rules ("must", "must not")
       - Positive constraints (requirements)
       - Negative constraints (prohibitions)
       - Conditional constraints (if-then rules)
       - Priority levels (strict vs flexible)

    3. Enforcement Strategies
       - Pre-generation (prompt engineering)
       - Post-generation (validation and filtering)
       - Iterative refinement (generate-validate-refine)
       - Guardrails (safety layers)
       - Fallback handling (when constraints violated)

    4. Validation Methods
       - Rule-based checking
       - Pattern matching
       - Content analysis
       - Length verification
       - Format validation
       - Safety scoring

Use Cases:
    1. Content Safety
       - Prevent harmful content generation
       - Filter inappropriate language
       - Block sensitive topics
       - Ensure age-appropriate content
       - Compliance with platform policies

    2. Brand Consistency
       - Maintain brand voice
       - Use approved terminology
       - Follow style guidelines
       - Consistent tone across content
       - Corporate communication standards

    3. Domain Expertise
       - Stay within knowledge boundaries
       - Acknowledge uncertainty
       - Avoid medical/legal claims
       - Respect professional standards
       - Domain-specific terminology

    4. Format and Structure
       - Length limitations (tweets, abstracts)
       - Structural requirements (sections, headings)
       - Citation requirements
       - Formatting rules (markdown, HTML)
       - Template compliance

    5. Legal and Compliance
       - GDPR compliance (no PII without consent)
       - HIPAA compliance (no PHI exposure)
       - Copyright respect
       - Regulatory requirements
       - Terms of service adherence

LangChain Implementation:
    LangChain supports constraint specification through:
    - System messages with explicit rules
    - Constitutional AI principles
    - Output validators and filters
    - Custom guardrails
    - Retry mechanisms with corrections

Key Features:
    1. Multi-Level Constraints
       - Hard constraints (must be satisfied)
       - Soft constraints (preferred but flexible)
       - Conditional constraints (context-dependent)
       - Hierarchical constraints (priority ordering)

    2. Constraint Composition
       - Multiple constraints simultaneously
       - Constraint conflicts resolution
       - Priority-based enforcement
       - Constraint inheritance

    3. Validation and Feedback
       - Immediate validation
       - Detailed violation reporting
       - Correction suggestions
       - Iterative improvement

    4. Dynamic Constraints
       - Context-aware constraints
       - User-specific rules
       - Time-based constraints
       - Adaptive boundaries

Best Practices:
    1. Clarity and Specificity
       - State constraints explicitly
       - Provide examples of violations
       - Clarify edge cases
       - Use concrete language

    2. Prioritization
       - Identify critical constraints
       - Allow flexibility where possible
       - Balance constraints with quality
       - Avoid over-constraining

    3. Testing
       - Test constraint enforcement
       - Try boundary cases
       - Verify violation detection
       - Check false positives

    4. Documentation
       - Document all constraints
       - Explain rationale
       - Provide violation examples
       - Maintain constraint catalog

Trade-offs:
    Advantages:
    - Better control over outputs
    - Improved safety and compliance
    - Consistent brand voice
    - Reduced inappropriate content
    - Clear expectations
    - Easier validation

    Disadvantages:
    - May limit creativity
    - Can reduce output quality
    - Increases complexity
    - Requires careful design
    - May need frequent updates
    - Potential over-constraint

Production Considerations:
    1. Constraint Management
       - Centralized constraint definitions
       - Version control for constraints
       - Easy updates and modifications
       - Constraint testing framework
       - Documentation and examples

    2. Performance Impact
       - Validation overhead
       - Retry costs for violations
       - Caching validated outputs
       - Efficient constraint checking
       - Batch validation

    3. User Experience
       - Clear violation messages
       - Suggestion for corrections
       - Graceful degradation
       - Transparency about constraints
       - User constraint customization

    4. Monitoring
       - Track constraint violations
       - Analyze violation patterns
       - Measure enforcement effectiveness
       - Identify constraint conflicts
       - User feedback collection

    5. Evolution
       - Regular constraint reviews
       - Adapt to new requirements
       - Learn from violations
       - Community feedback
       - A/B test constraint changes
"""

Purpose: This module implements the Constraint Specification pattern, providing a structured approach to agent design and implementation.


Import Statements

Standard Library Imports

import dataclasses.dataclass
import enum.Enum
import langchain_core.output_parsers.StrOutputParser
import langchain_core.prompts.ChatPromptTemplate
import os
import re
import typing.Any
import typing.Callable
import typing.Dict
import typing.List
import typing.Optional

Purpose: Core Python functionality: – dataclasses.dataclass: Simplified class definitions with @dataclass – enum.Enum: Enumeration support – langchain_core.output_parsers.StrOutputParser: Regular expression operations – langchain_core.prompts.ChatPromptTemplate: Regular expression operations – os: Environment variable access and system operations – re: Regular expression operations – typing.Any: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Callable: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Dict: Type hints for better code documentation (List, Dict, Any, Optional) – typing.List: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Optional: Type hints for better code documentation (List, Dict, Any, Optional)

LangChain Imports

from langchain_openai.ChatOpenAI

Purpose: LangChain framework components: – LLM Interface: Wrapper for OpenAI models – Chains: Composable building blocks for complex workflows

Other Imports

from dotenv.load_dotenv

Purpose: Additional dependencies for specialized functionality.


Classes

Class: ConstraintType

Lines 213-220

Inherits from: Enum

Purpose:

Types of constraints

Class: ConstraintSeverity

Lines 223-227

Inherits from: Enum

Purpose:

Severity levels for constraints

Class: Constraint

Lines 231-238

Purpose:

Represents a single constraint

Class: ConstraintConfig

Lines 242-247

Purpose:

Configuration for constraint-based generation

Class: ConstraintSpecificationAgent

Lines 250-604

Purpose:

Agent that enforces constraints on LLM outputs.

This agent demonstrates:
1. Defining multiple types of constraints
2. Enforcing constraints during generation
3. Validating outputs against constraints
4. Handling constraint violations

Methods:

__init__(self, config)

Lines 261-273

Purpose:

Initialize constraint specification agent.

Args:
    config: Configuration for constraint handling

Parameters: – config: Config

add_constraint(self, constraint)

Lines 275-277

Purpose:

Add a constraint to the agent

Parameters: – constraint: Constraint

clear_constraints(self)

Lines 279-281

Purpose:

Remove all constraints

Parameters:

_build_constraint_instructions(self)

Lines 283-299

Purpose:

Build constraint instructions for prompt

Parameters:

Returns: str

_validate_constraints(self, text)

Lines 301-326

Purpose:

Validate text against all constraints.

Args:
    text: Text to validate

Returns:
    Validation results

Parameters: – text: Text

Returns: <ast.Subscript object at 0x000001A06D7F4B90>

generate_with_constraints(self, prompt, task_description)

Lines 328-392

Purpose:

Generate text while enforcing constraints.

Args:
    prompt: User prompt
    task_description: Description of task

Returns:
    Generation result with validation info

Parameters: – prompt: Prompt template or text – task_description: Task description

Returns: <ast.Subscript object at 0x000001A06D849590>

generate_with_length_constraint(self, prompt, max_words, min_words)

Lines 394-434

Purpose:

Generate text with length constraints.

Args:
    prompt: User prompt
    max_words: Maximum word count
    min_words: Optional minimum word count

Returns:
    Generated text

Parameters: – prompt: Prompt template or text – max_words: Max words – min_words: Min words

Returns: str

generate_with_style_constraint(self, prompt, style)

Lines 436-474

Purpose:

Generate text with style constraints.

Args:
    prompt: User prompt
    style: Desired style (professional, casual, formal)

Returns:
    Generated text

Parameters: – prompt: Prompt template or text – style: Style

Returns: str

generate_with_content_constraints(self, prompt, must_include, must_exclude)

Lines 476-526

Purpose:

Generate text with content inclusion/exclusion constraints.

Args:
    prompt: User prompt
    must_include: Terms that must appear
    must_exclude: Terms that must not appear

Returns:
    Generated text

Parameters: – prompt: Prompt template or text – must_include: Must include – must_exclude: Must exclude

Returns: str

generate_with_format_constraint(self, prompt, format_type)

Lines 528-566

Purpose:

Generate text with format constraints.

Args:
    prompt: User prompt
    format_type: Format type (bullet_points, numbered_list, paragraphs)

Returns:
    Generated text

Parameters: – prompt: Prompt template or text – format_type: Format type

Returns: str

generate_with_safety_constraints(self, prompt)

Lines 568-604

Purpose:

Generate text with safety constraints.

Args:
    prompt: User prompt

Returns:
    Generated text

Parameters: – prompt: Prompt template or text

Returns: str


Functions

demonstrate_constraint_specification()

Lines 607-830

Purpose:

Demonstrate constraint specification patterns

Key Concepts Summary

Pattern Overview

The Constraint Specification pattern provides a structured approach to building AI agents with specific capabilities and behaviors. This implementation leverages LangChain’s composable components to create a robust and maintainable solution.

Core Components

  1. Agent Class: Main implementation of the pattern logic
  2. Prompt Engineering: Carefully crafted prompts to guide LLM behavior
  3. Tool Integration: Optional tools for extended functionality
  4. Memory Management: State handling across interactions
  5. Output Parsing: Structured response processing

When to Use

✅ Good for: – Scenarios requiring this specific pattern’s strengths – Applications needing structured agent behavior – Systems where explainability is important – Production environments requiring reliability

❌ Not ideal for: – Simple single-prompt tasks – Scenarios requiring different pattern characteristics – Resource-constrained environments (if computationally intensive)


Best Practices Demonstrated

1. Environment Configuration

  • ✅ Use .env files for API keys
  • ✅ Never hardcode credentials
  • ✅ Validate environment variables on startup

2. Error Handling

  • ✅ Graceful degradation on failures
  • ✅ Informative error messages
  • ✅ Logging for debugging

3. Prompt Engineering

  • ✅ Clear, specific instructions
  • ✅ Structured output formats
  • ✅ Few-shot examples when beneficial

4. Code Organization

  • ✅ Separation of concerns (class-based design)
  • ✅ Type hints for clarity
  • ✅ Docstrings for documentation

5. Performance Optimization

  • ✅ Appropriate temperature settings
  • ✅ Token budget management
  • ✅ Caching where applicable

LangChain Components Used

  • ChatOpenAI: OpenAI model interface
  • Chains: Sequential component composition

Why LangChain? – Composable abstractions for LLM applications – Rich ecosystem of integrations – Production-ready patterns – Active community and development


Execution Flow

1. Initialize agent with configuration
   ↓
2. Load environment and dependencies
   ↓
3. Prepare prompt with input data
   ↓
4. Invoke LLM through LangChain
   ↓
5. Parse and validate response
   ↓
6. Return formatted result

Key Decision Points: – Model selection (temperature, model type) – Prompt structure (few-shot vs zero-shot) – Error handling strategy – Output format validation


Performance Considerations

Computational Cost

  • LLM Calls: Primary cost factor (based on tokens)
  • Latency: Depends on model and input size
  • Memory: Minimal for most patterns

Optimization Strategies

  1. Prompt Optimization: Minimize tokens while maintaining clarity
  2. Caching: Cache repeated queries/responses
  3. Model Selection: Use smaller models when appropriate
  4. Batch Processing: Group similar requests
  5. Streaming: For long responses, stream tokens

Cost Estimates (Approximate)

  • GPT-3.5-turbo: ~$0.002 per request
  • GPT-4: ~$0.03 per request
  • GPT-4-turbo: ~$0.01 per request

Actual costs vary based on input/output token counts


Common Pitfalls to Avoid

1. Prompt Design Issues

❌ Vague or ambiguous instructions
✅ Clear, specific, testable prompts

2. Error Handling

❌ Ignoring API errors or rate limits
✅ Implement retry logic and graceful degradation

3. Token Management

❌ Exceeding model token limits
✅ Truncate inputs, chunk processing

4. Security

❌ Exposing API keys in code
✅ Use environment variables

5. Testing

❌ Only testing happy paths
✅ Test edge cases, failures, malformed inputs

6. Cost Management

❌ Unmonitored API usage
✅ Implement budgets, alerts, and monitoring


Further Improvements

Production Enhancements

  1. Monitoring: Add logging, metrics, tracing
  2. Validation: Input/output schema validation
  3. Rate Limiting: Implement request throttling
  4. Caching: Redis or in-memory cache for responses
  5. Async Support: Non-blocking operations for scalability

Feature Extensions

  1. Multi-Model Support: Switch between providers
  2. Fallback Models: Graceful degradation strategy
  3. Custom Tools: Domain-specific function calling
  4. Advanced Memory: Vector stores for long-term memory
  5. Evaluation: Automated testing and benchmarking

Code Quality

  1. Testing: Unit tests, integration tests
  2. Documentation: API docs, usage examples
  3. Type Safety: Stricter type hints
  4. Configuration: Externalized config files

Related Patterns

  • Pattern 086
  • Pattern 088

Pattern Families: – Reasoning Patterns (001-011) – Multi-Agent Patterns (012-019) – Tool Use Patterns (020-025) – Memory Patterns (026-031) – And many more…


Summary

The Constraint Specification pattern provides a powerful approach to building AI agents with specific capabilities. This implementation demonstrates:

✅ Key Strengths: – Clean, maintainable code structure – LangChain integration for composability – Type hints and documentation – Production-ready patterns

🎯 Best Use Cases: – Applications requiring this pattern’s characteristics – Systems needing structured agent behavior – Production environments requiring reliability

📚 Learning Resources: – LangChain Documentation: https://python.langchain.com/ – Pattern Documentation: See related patterns – OpenAI API Reference: https://platform.openai.com/docs/


File: 087_constraint_specification.py
Total Lines: 835
Pattern Category: AI Agent Design Pattern #087


Generated from actual implementation code
For educational and reference purposes

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *