Agentic Design Pattern: Creative Agent

Written by

in


    """
Pattern 075: Creative Agent

Description:
    A Creative Agent is a specialized AI agent designed to generate original creative
    content across various domains including writing (stories, poetry, scripts), visual
    concepts (art descriptions, design ideas), music concepts, and other creative works.
    This pattern demonstrates how to build an intelligent agent that can understand
    creative requirements, generate diverse creative outputs, adapt styles, incorporate
    feedback, and maintain creative consistency.
    
    The agent combines creative ideation with structured generation techniques to produce
    high-quality, original content. It can work across multiple creative domains, adapt
    to different styles and tones, generate variations, and iteratively refine outputs
    based on feedback.

Components:
    1. Ideation Engine: Generates creative concepts and ideas
    2. Style Adapter: Adapts content to different styles and tones
    3. Content Generator: Creates structured creative outputs
    4. Variation Creator: Produces diverse alternatives
    5. Constraint Respector: Adheres to creative constraints
    6. Feedback Integrator: Incorporates critique and improvements
    7. Consistency Maintainer: Ensures coherent creative vision
    8. Multi-Modal Orchestrator: Coordinates different creative types

Key Features:
    - Cross-domain creative generation (text, visual concepts, music ideas)
    - Style and tone adaptation (formal, casual, poetic, technical)
    - Character and world-building for narratives
    - Creative constraint handling (theme, length, format)
    - Iterative refinement with feedback
    - Variation generation for exploration
    - Originality assessment
    - Creative inspiration from prompts
    - Collaborative creativity support
    - Genre and format flexibility

Use Cases:
    - Story and novel writing
    - Poetry and lyric generation
    - Screenplay and script writing
    - Marketing copy and slogans
    - Product naming and branding
    - Art concept development
    - Game narrative design
    - Content marketing
    - Creative brainstorming
    - Educational creative writing

LangChain Implementation:
    Uses ChatOpenAI with varying temperatures for different creative tasks,
    specialized chains for ideation, generation, and refinement.
"""

import os
import re
from typing import List, Dict, Any, Optional
from dataclasses import dataclass, field
from enum import Enum
from datetime import datetime
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 CreativeType(Enum):
    """Types of creative content"""
    STORY = "story"
    POEM = "poem"
    SCRIPT = "script"
    SONG_LYRICS = "song_lyrics"
    ARTICLE = "article"
    MARKETING_COPY = "marketing_copy"
    PRODUCT_NAME = "product_name"
    SLOGAN = "slogan"
    DIALOGUE = "dialogue"
    WORLD_BUILDING = "world_building"


class CreativeStyle(Enum):
    """Creative styles and tones"""
    FORMAL = "formal"
    CASUAL = "casual"
    POETIC = "poetic"
    HUMOROUS = "humorous"
    DRAMATIC = "dramatic"
    MINIMALIST = "minimalist"
    ELABORATE = "elaborate"
    MYSTERIOUS = "mysterious"
    ROMANTIC = "romantic"
    DARK = "dark"


class Genre(Enum):
    """Creative genres"""
    FANTASY = "fantasy"
    SCIENCE_FICTION = "science_fiction"
    MYSTERY = "mystery"
    ROMANCE = "romance"
    HORROR = "horror"
    THRILLER = "thriller"
    COMEDY = "comedy"
    DRAMA = "drama"
    ADVENTURE = "adventure"
    HISTORICAL = "historical"


@dataclass
class CreativePrompt:
    """Input prompt for creative generation"""
    type: CreativeType
    theme: str
    style: CreativeStyle
    genre: Optional[Genre] = None
    constraints: Dict[str, Any] = field(default_factory=dict)
    inspiration: List[str] = field(default_factory=list)
    target_audience: Optional[str] = None


@dataclass
class Character:
    """Character for narrative works"""
    name: str
    role: str  # protagonist, antagonist, supporting
    personality: List[str]
    background: str
    goals: List[str]
    conflicts: List[str]


@dataclass
class Setting:
    """Setting for creative works"""
    location: str
    time_period: str
    atmosphere: str
    key_features: List[str]
    description: str


@dataclass
class CreativeWork:
    """Generated creative content"""
    work_id: str
    type: CreativeType
    title: str
    content: str
    style: CreativeStyle
    genre: Optional[Genre]
    characters: List[Character] = field(default_factory=list)
    setting: Optional[Setting] = None
    themes: List[str] = field(default_factory=list)
    word_count: int = 0
    metadata: Dict[str, Any] = field(default_factory=dict)
    created_at: datetime = field(default_factory=datetime.now)


@dataclass
class CreativeFeedback:
    """Feedback on creative work"""
    work_id: str
    strengths: List[str]
    weaknesses: List[str]
    suggestions: List[str]
    overall_score: float  # 0.0-1.0
    specific_notes: Dict[str, str] = field(default_factory=dict)


@dataclass
class CreativeVariation:
    """Variation of a creative work"""
    original_id: str
    variation_id: str
    content: str
    changes_made: List[str]
    variation_type: str  # tone, structure, perspective, etc.


class CreativeAgent:
    """
    Agent for generating creative content across multiple domains.
    
    This agent can generate stories, poems, scripts, marketing copy, and other
    creative works while adapting to styles, genres, and constraints.
    """
    
    def __init__(self):
        """Initialize the creative agent with specialized LLMs"""
        # Ideation engine for brainstorming
        self.ideation_llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.9)
        
        # Generator for main content creation
        self.generator_llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.8)
        
        # Refiner for improving content
        self.refiner_llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.6)
        
        # Critic for evaluation
        self.critic_llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.3)
        
        # Creative works repository
        self.works: Dict[str, CreativeWork] = {}
    
    def generate_ideas(
        self,
        theme: str,
        creative_type: CreativeType,
        count: int = 5
    ) -> List[str]:
        """
        Generate creative ideas based on theme.
        
        Args:
            theme: Central theme or concept
            creative_type: Type of creative work
            count: Number of ideas to generate
            
        Returns:
            List of creative ideas
        """
        prompt = ChatPromptTemplate.from_messages([
            ("system", """You are a creative ideation expert. Generate original and
            imaginative ideas based on the theme and content type.
            
            Provide {count} ideas, one per line starting with a number."""),
            ("user", """Theme: {theme}
Content Type: {type}

Generate {count} creative ideas.""")
        ])
        
        chain = prompt | self.ideation_llm | StrOutputParser()
        
        try:
            response = chain.invoke({
                "theme": theme,
                "type": creative_type.value,
                "count": count
            })
            
            ideas = []
            for line in response.split('\n'):
                line = line.strip()
                if line and (line[0].isdigit() or line.startswith('-')):
                    # Remove numbering
                    idea = re.sub(r'^\d+[\.\)]\s*', '', line)
                    idea = re.sub(r'^[-*]\s*', '', idea)
                    if idea:
                        ideas.append(idea)
            
            return ideas[:count] if ideas else [f"Idea about {theme}" for _ in range(count)]
            
        except Exception as e:
            return [f"Creative idea {i+1} about {theme}" for i in range(count)]
    
    def create_characters(
        self,
        story_concept: str,
        character_count: int = 3
    ) -> List[Character]:
        """
        Create characters for a narrative work.
        
        Args:
            story_concept: Brief story concept
            character_count: Number of characters to create
            
        Returns:
            List of Character objects
        """
        prompt = ChatPromptTemplate.from_messages([
            ("system", """You are a character development expert. Create compelling
            characters for the story concept.
            
            For each character, provide:
            NAME: character name
            ROLE: protagonist/antagonist/supporting
            PERSONALITY: traits (comma-separated)
            BACKGROUND: brief background
            GOALS: goals (comma-separated)
            CONFLICTS: conflicts (comma-separated)
            ---"""),
            ("user", """Story Concept: {concept}

Create {count} characters.""")
        ])
        
        chain = prompt | self.ideation_llm | StrOutputParser()
        
        try:
            response = chain.invoke({
                "concept": story_concept,
                "count": character_count
            })
            
            characters = []
            current_char = {}
            
            for line in response.split('\n'):
                line = line.strip()
                
                if line == '---' and current_char:
                    # Create character from collected data
                    if 'NAME' in current_char:
                        characters.append(Character(
                            name=current_char.get('NAME', 'Unnamed'),
                            role=current_char.get('ROLE', 'supporting'),
                            personality=[p.strip() for p in current_char.get('PERSONALITY', '').split(',')],
                            background=current_char.get('BACKGROUND', ''),
                            goals=[g.strip() for g in current_char.get('GOALS', '').split(',')],
                            conflicts=[c.strip() for c in current_char.get('CONFLICTS', '').split(',')]
                        ))
                    current_char = {}
                elif ':' in line:
                    parts = line.split(':', 1)
                    key = parts[0].strip().upper()
                    value = parts[1].strip()
                    current_char[key] = value
            
            # Add last character if exists
            if current_char and 'NAME' in current_char:
                characters.append(Character(
                    name=current_char.get('NAME', 'Unnamed'),
                    role=current_char.get('ROLE', 'supporting'),
                    personality=[p.strip() for p in current_char.get('PERSONALITY', '').split(',')],
                    background=current_char.get('BACKGROUND', ''),
                    goals=[g.strip() for g in current_char.get('GOALS', '').split(',')],
                    conflicts=[c.strip() for c in current_char.get('CONFLICTS', '').split(',')]
                ))
            
            # Fallback if parsing failed
            if not characters:
                for i in range(character_count):
                    characters.append(Character(
                        name=f"Character {i+1}",
                        role="supporting" if i > 0 else "protagonist",
                        personality=["determined", "curious"],
                        background="To be developed",
                        goals=["Achieve their objective"],
                        conflicts=["Internal struggles"]
                    ))
            
            return characters[:character_count]
            
        except Exception as e:
            # Fallback characters
            return [
                Character(
                    name=f"Character {i+1}",
                    role="protagonist" if i == 0 else "supporting",
                    personality=["brave", "intelligent"],
                    background="Mysterious past",
                    goals=["Complete their quest"],
                    conflicts=["Face their fears"]
                )
                for i in range(character_count)
            ]
    
    def create_setting(
        self,
        story_concept: str,
        genre: Genre
    ) -> Setting:
        """
        Create a setting for a narrative work.
        
        Args:
            story_concept: Brief story concept
            genre: Genre of the work
            
        Returns:
            Setting object
        """
        prompt = ChatPromptTemplate.from_messages([
            ("system", """You are a world-building expert. Create a vivid setting.
            
            Provide:
            LOCATION: Where the story takes place
            TIME: Time period
            ATMOSPHERE: Overall mood/feeling
            FEATURES: Key features (comma-separated)
            DESCRIPTION: Detailed description (2-3 sentences)"""),
            ("user", """Story Concept: {concept}
Genre: {genre}

Create a compelling setting.""")
        ])
        
        chain = prompt | self.ideation_llm | StrOutputParser()
        
        try:
            response = chain.invoke({
                "concept": story_concept,
                "genre": genre.value
            })
            
            setting_data = {}
            current_key = None
            desc_lines = []
            
            for line in response.split('\n'):
                line = line.strip()
                if ':' in line and line.split(':')[0].strip().upper() in ['LOCATION', 'TIME', 'ATMOSPHERE', 'FEATURES', 'DESCRIPTION']:
                    parts = line.split(':', 1)
                    key = parts[0].strip().upper()
                    value = parts[1].strip()
                    setting_data[key] = value
                    current_key = key
                elif current_key == 'DESCRIPTION' and line:
                    desc_lines.append(line)
            
            if desc_lines:
                setting_data['DESCRIPTION'] = ' '.join(desc_lines)
            
            return Setting(
                location=setting_data.get('LOCATION', 'A mysterious place'),
                time_period=setting_data.get('TIME', 'Present day'),
                atmosphere=setting_data.get('ATMOSPHERE', 'Tense and mysterious'),
                key_features=[f.strip() for f in setting_data.get('FEATURES', '').split(',')],
                description=setting_data.get('DESCRIPTION', 'An intriguing setting awaits.')
            )
            
        except Exception as e:
            return Setting(
                location="An intriguing location",
                time_period="Modern times",
                atmosphere="Mysterious and engaging",
                key_features=["Unique architecture", "Hidden secrets"],
                description="A place full of wonder and possibility."
            )
    
    def generate_content(
        self,
        creative_prompt: CreativePrompt,
        characters: Optional[List[Character]] = None,
        setting: Optional[Setting] = None
    ) -> CreativeWork:
        """
        Generate creative content based on prompt.
        
        Args:
            creative_prompt: Creative prompt with requirements
            characters: Optional characters for narrative works
            setting: Optional setting for narrative works
            
        Returns:
            CreativeWork with generated content
        """
        # Build context
        context_parts = []
        
        if characters:
            char_desc = "\n".join([
                f"- {char.name} ({char.role}): {', '.join(char.personality[:2])}"
                for char in characters
            ])
            context_parts.append(f"Characters:\n{char_desc}")
        
        if setting:
            context_parts.append(f"Setting: {setting.location}, {setting.time_period}")
            context_parts.append(f"Atmosphere: {setting.atmosphere}")
        
        context = "\n\n".join(context_parts) if context_parts else "No additional context"
        
        # Generate based on type
        if creative_prompt.type == CreativeType.STORY:
            return self._generate_story(creative_prompt, context, characters, setting)
        elif creative_prompt.type == CreativeType.POEM:
            return self._generate_poem(creative_prompt, context)
        elif creative_prompt.type == CreativeType.MARKETING_COPY:
            return self._generate_marketing_copy(creative_prompt)
        else:
            return self._generate_generic(creative_prompt, context)
    
    def _generate_story(
        self,
        prompt: CreativePrompt,
        context: str,
        characters: Optional[List[Character]],
        setting: Optional[Setting]
    ) -> CreativeWork:
        """Generate a story"""
        template = ChatPromptTemplate.from_messages([
            ("system", """You are a master storyteller. Write an engaging story that
            captures the theme, style, and genre specified.
            
            The story should have:
            - Compelling opening
            - Character development
            - Rising action
            - Climax
            - Resolution
            
            Write in the specified style and maintain consistency."""),
            ("user", """Theme: {theme}
Style: {style}
Genre: {genre}

{context}

Constraints: {constraints}

Write the story.""")
        ])
        
        chain = template | self.generator_llm | StrOutputParser()
        
        try:
            content = chain.invoke({
                "theme": prompt.theme,
                "style": prompt.style.value,
                "genre": prompt.genre.value if prompt.genre else "general",
                "context": context,
                "constraints": str(prompt.constraints) if prompt.constraints else "None"
            })
            
            # Generate title
            title = self._generate_title(content, prompt.type, prompt.theme)
            
            return CreativeWork(
                work_id=f"work_{datetime.now().timestamp()}",
                type=prompt.type,
                title=title,
                content=content,
                style=prompt.style,
                genre=prompt.genre,
                characters=characters or [],
                setting=setting,
                themes=[prompt.theme],
                word_count=len(content.split()),
                metadata={"constraints": prompt.constraints}
            )
            
        except Exception as e:
            return self._fallback_work(prompt)
    
    def _generate_poem(
        self,
        prompt: CreativePrompt,
        context: str
    ) -> CreativeWork:
        """Generate a poem"""
        template = ChatPromptTemplate.from_messages([
            ("system", """You are an accomplished poet. Create a poem that explores
            the theme with creativity and emotional depth.
            
            Use vivid imagery, metaphor, and rhythm. Match the requested style."""),
            ("user", """Theme: {theme}
Style: {style}

{context}

Write the poem.""")
        ])
        
        chain = template | self.generator_llm | StrOutputParser()
        
        try:
            content = chain.invoke({
                "theme": prompt.theme,
                "style": prompt.style.value,
                "context": context
            })
            
            title = self._generate_title(content, prompt.type, prompt.theme)
            
            return CreativeWork(
                work_id=f"work_{datetime.now().timestamp()}",
                type=prompt.type,
                title=title,
                content=content,
                style=prompt.style,
                genre=prompt.genre,
                themes=[prompt.theme],
                word_count=len(content.split())
            )
            
        except Exception as e:
            return self._fallback_work(prompt)
    
    def _generate_marketing_copy(
        self,
        prompt: CreativePrompt
    ) -> CreativeWork:
        """Generate marketing copy"""
        template = ChatPromptTemplate.from_messages([
            ("system", """You are a creative marketing copywriter. Write compelling
            copy that engages the target audience and communicates the message clearly.
            
            Be persuasive, concise, and memorable."""),
            ("user", """Theme/Product: {theme}
Style: {style}
Target Audience: {audience}

Constraints: {constraints}

Write the marketing copy.""")
        ])
        
        chain = template | self.generator_llm | StrOutputParser()
        
        try:
            content = chain.invoke({
                "theme": prompt.theme,
                "style": prompt.style.value,
                "audience": prompt.target_audience or "general audience",
                "constraints": str(prompt.constraints) if prompt.constraints else "None"
            })
            
            title = f"Marketing Copy: {prompt.theme[:30]}"
            
            return CreativeWork(
                work_id=f"work_{datetime.now().timestamp()}",
                type=prompt.type,
                title=title,
                content=content,
                style=prompt.style,
                genre=None,
                themes=[prompt.theme],
                word_count=len(content.split())
            )
            
        except Exception as e:
            return self._fallback_work(prompt)
    
    def _generate_generic(
        self,
        prompt: CreativePrompt,
        context: str
    ) -> CreativeWork:
        """Generate generic creative content"""
        template = ChatPromptTemplate.from_messages([
            ("system", """You are a versatile creative writer. Generate content
            that matches the specified type, theme, and style."""),
            ("user", """Type: {type}
Theme: {theme}
Style: {style}

{context}

Generate the content.""")
        ])
        
        chain = template | self.generator_llm | StrOutputParser()
        
        try:
            content = chain.invoke({
                "type": prompt.type.value,
                "theme": prompt.theme,
                "style": prompt.style.value,
                "context": context
            })
            
            title = self._generate_title(content, prompt.type, prompt.theme)
            
            return CreativeWork(
                work_id=f"work_{datetime.now().timestamp()}",
                type=prompt.type,
                title=title,
                content=content,
                style=prompt.style,
                genre=prompt.genre,
                themes=[prompt.theme],
                word_count=len(content.split())
            )
            
        except Exception as e:
            return self._fallback_work(prompt)
    
    def _generate_title(
        self,
        content: str,
        content_type: CreativeType,
        theme: str
    ) -> str:
        """Generate a title for the work"""
        template = ChatPromptTemplate.from_messages([
            ("system", "Generate a creative, catchy title (5 words or less)."),
            ("user", "Content preview: {preview}\n\nGenerate title:")
        ])
        
        chain = template | self.refiner_llm | StrOutputParser()
        
        try:
            title = chain.invoke({"preview": content[:200]})
            return title.strip().strip('"\'')
        except:
            return f"{content_type.value.replace('_', ' ').title()}: {theme[:20]}"
    
    def _fallback_work(self, prompt: CreativePrompt) -> CreativeWork:
        """Create fallback work if generation fails"""
        return CreativeWork(
            work_id=f"work_{datetime.now().timestamp()}",
            type=prompt.type,
            title=f"{prompt.type.value.replace('_', ' ').title()}",
            content=f"A {prompt.style.value} {prompt.type.value} about {prompt.theme}.",
            style=prompt.style,
            genre=prompt.genre,
            themes=[prompt.theme],
            word_count=10
        )
    
    def critique_work(
        self,
        work: CreativeWork
    ) -> CreativeFeedback:
        """
        Provide critical feedback on creative work.
        
        Args:
            work: CreativeWork to critique
            
        Returns:
            CreativeFeedback with evaluation
        """
        prompt = ChatPromptTemplate.from_messages([
            ("system", """You are a creative writing critic. Provide constructive
            feedback on the work.
            
            Respond in this format:
            STRENGTHS: (one per line starting with -)
            WEAKNESSES: (one per line starting with -)
            SUGGESTIONS: (one per line starting with -)
            SCORE: (0.0-1.0)"""),
            ("user", """Title: {title}
Type: {type}
Style: {style}

Content:
{content}

Provide feedback.""")
        ])
        
        chain = prompt | self.critic_llm | StrOutputParser()
        
        try:
            response = chain.invoke({
                "title": work.title,
                "type": work.type.value,
                "style": work.style.value,
                "content": work.content[:1000]  # Limit length
            })
            
            strengths = []
            weaknesses = []
            suggestions = []
            score = 0.7
            
            current_section = None
            
            for line in response.split('\n'):
                line = line.strip()
                if not line:
                    continue
                
                if line.startswith('STRENGTHS:'):
                    current_section = 'strengths'
                elif line.startswith('WEAKNESSES:'):
                    current_section = 'weaknesses'
                elif line.startswith('SUGGESTIONS:'):
                    current_section = 'suggestions'
                elif line.startswith('SCORE:'):
                    try:
                        score = float(re.findall(r'[\d.]+', line)[0])
                    except:
                        pass
                elif line.startswith('-'):
                    content = line[1:].strip()
                    if current_section == 'strengths':
                        strengths.append(content)
                    elif current_section == 'weaknesses':
                        weaknesses.append(content)
                    elif current_section == 'suggestions':
                        suggestions.append(content)
            
            return CreativeFeedback(
                work_id=work.work_id,
                strengths=strengths if strengths else ["Creative and engaging"],
                weaknesses=weaknesses if weaknesses else ["Could be enhanced"],
                suggestions=suggestions if suggestions else ["Consider adding more detail"],
                overall_score=score
            )
            
        except Exception as e:
            return CreativeFeedback(
                work_id=work.work_id,
                strengths=["Shows creativity"],
                weaknesses=["Needs refinement"],
                suggestions=["Develop further"],
                overall_score=0.7
            )
    
    def create_variation(
        self,
        work: CreativeWork,
        variation_type: str = "tone"
    ) -> CreativeVariation:
        """
        Create a variation of existing work.
        
        Args:
            work: Original work
            variation_type: Type of variation (tone, structure, perspective)
            
        Returns:
            CreativeVariation with modified content
        """
        prompt = ChatPromptTemplate.from_messages([
            ("system", """You are a creative editor. Create a variation of the work
            by modifying the {variation_type}.
            
            Maintain the core story/message but change the specified aspect."""),
            ("user", """Original Work:
{content}

Create a variation focusing on: {variation_type}""")
        ])
        
        chain = prompt | self.generator_llm | StrOutputParser()
        
        try:
            varied_content = chain.invoke({
                "content": work.content,
                "variation_type": variation_type
            })
            
            return CreativeVariation(
                original_id=work.work_id,
                variation_id=f"var_{datetime.now().timestamp()}",
                content=varied_content,
                changes_made=[f"Modified {variation_type}"],
                variation_type=variation_type
            )
            
        except Exception as e:
            return CreativeVariation(
                original_id=work.work_id,
                variation_id=f"var_{datetime.now().timestamp()}",
                content=work.content,
                changes_made=["Minimal changes"],
                variation_type=variation_type
            )


def demonstrate_creative_agent():
    """Demonstrate the creative agent capabilities"""
    print("=" * 80)
    print("CREATIVE AGENT DEMONSTRATION")
    print("=" * 80)
    
    agent = CreativeAgent()
    
    # Demo 1: Story Generation
    print("\n" + "=" * 80)
    print("DEMO 1: Story Generation")
    print("=" * 80)
    
    print("\nGenerating story concept ideas...")
    ideas = agent.generate_ideas(
        theme="artificial intelligence gaining consciousness",
        creative_type=CreativeType.STORY,
        count=3
    )
    
    print("\nStory Ideas:")
    for i, idea in enumerate(ideas, 1):
        print(f"{i}. {idea}")
    
    print("\nCreating characters...")
    characters = agent.create_characters(
        story_concept=ideas[0],
        character_count=2
    )
    
    print("\nCharacters:")
    for char in characters:
        print(f"\n  {char.name} ({char.role})")
        print(f"  Personality: {', '.join(char.personality[:3])}")
        print(f"  Background: {char.background[:80]}...")
    
    print("\nCreating setting...")
    setting = agent.create_setting(
        story_concept=ideas[0],
        genre=Genre.SCIENCE_FICTION
    )
    
    print(f"\nSetting:")
    print(f"  Location: {setting.location}")
    print(f"  Time: {setting.time_period}")
    print(f"  Atmosphere: {setting.atmosphere}")
    print(f"  Description: {setting.description[:150]}...")
    
    print("\nGenerating story...")
    story_prompt = CreativePrompt(
        type=CreativeType.STORY,
        theme="AI consciousness and human connection",
        style=CreativeStyle.DRAMATIC,
        genre=Genre.SCIENCE_FICTION,
        constraints={"max_length": "short story"}
    )
    
    story = agent.generate_content(story_prompt, characters, setting)
    
    print(f"\nGenerated Story:")
    print(f"Title: {story.title}")
    print(f"Word Count: {story.word_count}")
    print(f"Style: {story.style.value}")
    print(f"\nContent Preview:")
    print(story.content[:400] + "...")
    
    # Demo 2: Poetry Generation
    print("\n" + "=" * 80)
    print("DEMO 2: Poetry Generation")
    print("=" * 80)
    
    poem_prompt = CreativePrompt(
        type=CreativeType.POEM,
        theme="the passage of time",
        style=CreativeStyle.POETIC,
        constraints={"form": "free verse"}
    )
    
    print(f"\nGenerating poem about '{poem_prompt.theme}'...")
    poem = agent.generate_content(poem_prompt)
    
    print(f"\nGenerated Poem:")
    print(f"Title: {poem.title}")
    print(f"Style: {poem.style.value}")
    print(f"\nContent:")
    print(poem.content)
    
    # Demo 3: Marketing Copy
    print("\n" + "=" * 80)
    print("DEMO 3: Marketing Copy Generation")
    print("=" * 80)
    
    marketing_prompt = CreativePrompt(
        type=CreativeType.MARKETING_COPY,
        theme="eco-friendly smart home device",
        style=CreativeStyle.CASUAL,
        target_audience="environmentally conscious millennials",
        constraints={"length": "short", "include": "call-to-action"}
    )
    
    print(f"\nGenerating marketing copy...")
    marketing = agent.generate_content(marketing_prompt)
    
    print(f"\nGenerated Marketing Copy:")
    print(f"Title: {marketing.title}")
    print(f"Target Audience: {marketing_prompt.target_audience}")
    print(f"\nContent:")
    print(marketing.content)
    
    # Demo 4: Creative Feedback
    print("\n" + "=" * 80)
    print("DEMO 4: Creative Feedback")
    print("=" * 80)
    
    print(f"\nGetting feedback on story: {story.title}")
    feedback = agent.critique_work(story)
    
    print(f"\nFeedback:")
    print(f"Overall Score: {feedback.overall_score:.2f}/1.0")
    print(f"\nStrengths:")
    for strength in feedback.strengths[:3]:
        print(f"  + {strength}")
    print(f"\nWeaknesses:")
    for weakness in feedback.weaknesses[:2]:
        print(f"  - {weakness}")
    print(f"\nSuggestions:")
    for suggestion in feedback.suggestions[:2]:
        print(f"  → {suggestion}")
    
    # Demo 5: Content Variation
    print("\n" + "=" * 80)
    print("DEMO 5: Content Variation")
    print("=" * 80)
    
    print(f"\nCreating variation of poem with different tone...")
    variation = agent.create_variation(poem, variation_type="tone")
    
    print(f"\nVariation Created:")
    print(f"Variation Type: {variation.variation_type}")
    print(f"Changes: {', '.join(variation.changes_made)}")
    print(f"\nVaried Content Preview:")
    print(variation.content[:300] + "...")
    
    # Summary
    print("\n" + "=" * 80)
    print("SUMMARY")
    print("=" * 80)
    
    summary = """
The Creative Agent demonstrates comprehensive creative content generation:

KEY CAPABILITIES:
1. Ideation: Generates creative concepts and ideas from themes
2. Character Development: Creates compelling characters with depth
3. World-Building: Designs rich settings and atmospheres
4. Content Generation: Produces stories, poems, marketing copy, and more
5. Style Adaptation: Adjusts tone, style, and voice appropriately
6. Critical Evaluation: Provides constructive feedback on works
7. Variation Creation: Generates alternative versions of content

BENEFITS:
- Accelerates creative writing and content creation
- Provides diverse creative options and variations
- Maintains stylistic consistency across works
- Offers constructive feedback for improvement
- Adapts to different genres, styles, and formats
- Supports brainstorming and ideation processes

USE CASES:
- Story and novel writing
- Poetry and creative writing
- Screenplay and script development
- Marketing and advertising copy
- Brand messaging and slogans
- Content marketing
- Game narrative design
- Creative brainstorming sessions
- Educational writing exercises
- Literary exploration

PRODUCTION CONSIDERATIONS:
1. Content Quality: Implement multi-stage refinement for polish
2. Originality: Add plagiarism detection and originality scoring
3. Style Consistency: Maintain voice across longer works
4. Genre Knowledge: Deep understanding of genre conventions
5. Feedback Integration: Iterative improvement based on critique
6. Collaboration: Support co-creation with human writers
7. Version Control: Track revisions and variations
8. Rights Management: Handle attribution and licensing
9. Cultural Sensitivity: Ensure appropriate content for audiences
10. Performance: Optimize for longer form content generation

ADVANCED EXTENSIONS:
- Multi-chapter novel generation
- Interactive storytelling with branching narratives
- Character arc tracking across long works
- World consistency maintenance
- Dialogue generation with character voices
- Plot structure analysis and optimization
- Genre blending and hybrid works
- Collaborative writing with multiple agents
- Real-time creative writing assistance
- Personalized content based on reader preferences

The agent transforms creative writing from a solitary struggle into an
assisted, iterative process with AI as a creative partner.
"""
    
    print(summary)


if __name__ == "__main__":
    demonstrate_creative_agent()

    

Agentic Design Pattern: Creative Agent

Pattern 075: Creative Agent – Line-by-Line Explanation

Overview

This document provides a detailed line-by-line explanation of the Creative Agent pattern implementation.


Pattern Description

Pattern 075: Creative Agent

Description: A Creative Agent is a specialized AI agent designed to generate original creative content across various domains including writing (stories, poetry, scripts), visual concepts (art descriptions, design ideas), music concepts, and other creative works. This pattern demonstrates how to build an intelligent agent that can understand creative requirements, generate diverse creative outputs, adapt styles, incorporate feedback, and maintain creative consistency.

The agent combines creative ideation with structured generation techniques to produce
high-quality, original content. It can work across multiple creative domains, adapt
to different styles and tones, generate variations, and iteratively refine outputs
based on feedback.

Components: 1. Ideation Engine: Generates creative concepts and ideas 2. Style Adapter: Adapts content to different styles and tones 3. Content Generator: Creates structured creative outputs 4. Variation Creator: Produces diverse alternatives 5. Constraint Respector: Adheres to creative constraints 6. Feedback Integrator: Incorporates critique and improvements 7. Consistency Maintainer: Ensures coherent creative vision 8. Multi-Modal Orchestrator: Coordinates different creative types

Key Features: – Cross-domain creative generation (text, visual concepts, music ideas) – Style and tone adaptation (formal, casual, poetic, technical) – Character and world-building for narratives – Creative constraint handling (theme, length, format) – Iterative refinement with feedback – Variation generation for exploration – Originality assessment – Creative inspiration from prompts – Collaborative creativity support – Genre and format flexibility

Use Cases: – Story and novel writing – Poetry and lyric generation – Screenplay and script writing – Marketing copy and slogans – Product naming and branding – Art concept development – Game narrative design – Content marketing – Creative brainstorming – Educational creative writing

LangChain Implementation: Uses ChatOpenAI with varying temperatures for different creative tasks, specialized chains for ideation, generation, and refinement.


File Statistics

  • Total Lines: 1064
  • Classes: 10
  • Functions: 1
  • Constants: 0

Module Documentation

"""
Pattern 075: Creative Agent

Description:
    A Creative Agent is a specialized AI agent designed to generate original creative
    content across various domains including writing (stories, poetry, scripts), visual
    concepts (art descriptions, design ideas), music concepts, and other creative works.
    This pattern demonstrates how to build an intelligent agent that can understand
    creative requirements, generate diverse creative outputs, adapt styles, incorporate
    feedback, and maintain creative consistency.

    The agent combines creative ideation with structured generation techniques to produce
    high-quality, original content. It can work across multiple creative domains, adapt
    to different styles and tones, generate variations, and iteratively refine outputs
    based on feedback.

Components:
    1. Ideation Engine: Generates creative concepts and ideas
    2. Style Adapter: Adapts content to different styles and tones
    3. Content Generator: Creates structured creative outputs
    4. Variation Creator: Produces diverse alternatives
    5. Constraint Respector: Adheres to creative constraints
    6. Feedback Integrator: Incorporates critique and improvements
    7. Consistency Maintainer: Ensures coherent creative vision
    8. Multi-Modal Orchestrator: Coordinates different creative types

Key Features:
    - Cross-domain creative generation (text, visual concepts, music ideas)
    - Style and tone adaptation (formal, casual, poetic, technical)
    - Character and world-building for narratives
    - Creative constraint handling (theme, length, format)
    - Iterative refinement with feedback
    - Variation generation for exploration
    - Originality assessment
    - Creative inspiration from prompts
    - Collaborative creativity support
    - Genre and format flexibility

Use Cases:
    - Story and novel writing
    - Poetry and lyric generation
    - Screenplay and script writing
    - Marketing copy and slogans
    - Product naming and branding
    - Art concept development
    - Game narrative design
    - Content marketing
    - Creative brainstorming
    - Educational creative writing

LangChain Implementation:
    Uses ChatOpenAI with varying temperatures for different creative tasks,
    specialized chains for ideation, generation, and refinement.
"""

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


Import Statements

Standard Library Imports

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

Purpose: Core Python functionality: – dataclasses.dataclass: Simplified class definitions with @dataclass – dataclasses.field: Simplified class definitions with @dataclass – datetime.datetime: Date and time handling – 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.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: CreativeType

Lines 71-82

Inherits from: Enum

Purpose:

Types of creative content

Class: CreativeStyle

Lines 85-96

Inherits from: Enum

Purpose:

Creative styles and tones

Class: Genre

Lines 99-110

Inherits from: Enum

Purpose:

Creative genres

Class: CreativePrompt

Lines 114-122

Purpose:

Input prompt for creative generation

Class: Character

Lines 126-133

Purpose:

Character for narrative works

Class: Setting

Lines 137-143

Purpose:

Setting for creative works

Class: CreativeWork

Lines 147-160

Purpose:

Generated creative content

Class: CreativeFeedback

Lines 164-171

Purpose:

Feedback on creative work

Class: CreativeVariation

Lines 175-181

Purpose:

Variation of a creative work

Class: CreativeAgent

Lines 184-848

Purpose:

Agent for generating creative content across multiple domains.

This agent can generate stories, poems, scripts, marketing copy, and other
creative works while adapting to styles, genres, and constraints.

Methods:

__init__(self)

Lines 192-207

Purpose:

Initialize the creative agent with specialized LLMs

Parameters:

generate_ideas(self, theme, creative_type, count)

Lines 209-259

Purpose:

Generate creative ideas based on theme.

Args:
    theme: Central theme or concept
    creative_type: Type of creative work
    count: Number of ideas to generate

Returns:
    List of creative ideas

Parameters: – theme: Theme – creative_type: Creative type – count: Count

Returns: <ast.Subscript object at 0x000001A06D64BD10>

create_characters(self, story_concept, character_count)

Lines 261-362

Purpose:

Create characters for a narrative work.

Args:
    story_concept: Brief story concept
    character_count: Number of characters to create

Returns:
    List of Character objects

Parameters: – story_concept: Story concept – character_count: Character count

Returns: <ast.Subscript object at 0x000001A06D66B810>

create_setting(self, story_concept, genre)

Lines 364-435

Purpose:

Create a setting for a narrative work.

Args:
    story_concept: Brief story concept
    genre: Genre of the work

Returns:
    Setting object

Parameters: – story_concept: Story concept – genre: Genre

Returns: Setting

generate_content(self, creative_prompt, characters, setting)

Lines 437-478

Purpose:

Generate creative content based on prompt.

Args:
    creative_prompt: Creative prompt with requirements
    characters: Optional characters for narrative works
    setting: Optional setting for narrative works

Returns:
    CreativeWork with generated content

Parameters: – creative_prompt: Prompt template or text – characters: Characters – setting: Setting

Returns: CreativeWork

_generate_story(self, prompt, context, characters, setting)

Lines 480-540

Purpose:

Generate a story

Parameters: – prompt: Prompt template or text – context: Context – characters: Characters – setting: Setting

Returns: CreativeWork

_generate_poem(self, prompt, context)

Lines 542-584

Purpose:

Generate a poem

Parameters: – prompt: Prompt template or text – context: Context

Returns: CreativeWork

_generate_marketing_copy(self, prompt)

Lines 586-629

Purpose:

Generate marketing copy

Parameters: – prompt: Prompt template or text

Returns: CreativeWork

_generate_generic(self, prompt, context)

Lines 631-673

Purpose:

Generate generic creative content

Parameters: – prompt: Prompt template or text – context: Context

Returns: CreativeWork

_generate_title(self, content, content_type, theme)

Lines 675-693

Purpose:

Generate a title for the work

Parameters: – content: Content – content_type: Content type – theme: Theme

Returns: str

_fallback_work(self, prompt)

Lines 695-706

Purpose:

Create fallback work if generation fails

Parameters: – prompt: Prompt template or text

Returns: CreativeWork

critique_work(self, work)

Lines 708-797

Purpose:

Provide critical feedback on creative work.

Args:
    work: CreativeWork to critique

Returns:
    CreativeFeedback with evaluation

Parameters: – work: Work

Returns: CreativeFeedback

create_variation(self, work, variation_type)

Lines 799-848

Purpose:

Create a variation of existing work.

Args:
    work: Original work
    variation_type: Type of variation (tone, structure, perspective)

Returns:
    CreativeVariation with modified content

Parameters: – work: Work – variation_type: Variation type

Returns: CreativeVariation


Functions

demonstrate_creative_agent()

Lines 851-1059

Purpose:

Demonstrate the creative agent capabilities

Key Concepts Summary

Pattern Overview

The Creative Agent 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 074
  • Pattern 076

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 Creative Agent 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: 075_creative_agent.py
Total Lines: 1064
Pattern Category: AI Agent Design Pattern #075


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 *