Content Creation Agent with Brand Voice
What is a Creative Writing Agent?
Creative writing agents generate high-quality content across formats (blog posts, social media, emails, scripts) while maintaining consistent brand voice and optimizing for engagement. They combine creative generation with data-driven optimization.
The key capabilities are: brand voice training and enforcement, multi-format content generation, SEO keyword integration, storytelling structure application, and content performance prediction.
These agents transform content marketing from manual writing to strategic oversight, enabling teams to produce more content at higher quality.
Project Overview
We will build a creative writing agent that:
- Maintains and enforces brand voice across content
- Generates blog posts, social media, and email content
- Optimizes content for SEO keywords
- Applies storytelling frameworks (AIDA, PAS, etc.)
- Edits and refines generated content
- Adapts content for different platforms
Expected outcome: An agent that produces brand-consistent, SEO-optimized content.
Difficulty: Advanced (requires understanding of content marketing, SEO, and creative writing)
Architecture
Tools & Setup
| Tool | Version | Purpose |
|---|---|---|
| Python | 3.11+ | Core language |
| openai | 1.0+ | LLM backbone |
| pydantic | 2.0+ | Data models |
| tiktoken | 0.5+ | Token counting |
| textstat | 0.7+ | Readability analysis |
Step 1: Environment Setup
python -m venv venv
source venv/bin/activate
pip install openai pydantic tiktoken textstat
export OPENAI_API_KEY="sk-your-key"
Step 2: Project Structure
content-agent/
βββ brand/
β βββ __init__.py
β βββ voice.py
βββ generation/
β βββ __init__.py
β βββ blog.py
β βββ social.py
β βββ email.py
βββ optimization/
β βββ __init__.py
β βββ seo.py
β βββ editor.py
βββ frameworks/
β βββ __init__.py
β βββ storytelling.py
βββ agent.py
βββ main.py
Step 3: Brand Voice Manager
# brand/voice.py
from openai import OpenAI
from typing import Dict
import json
class BrandVoiceManager:
def __init__(self, model: str = "gpt-4-turbo-preview"):
self.client = OpenAI()
self.model = model
self.voices: Dict[str, Dict] = {}
def create_voice(
self,
name: str,
tone: str,
values: list,
do_s: list,
dont_s: list,
sample_content: str = "",
) -> Dict:
voice = {
"name": name,
"tone": tone,
"values": values,
"do_s": do_s,
"dont_s": dont_s,
"sample_content": sample_content,
}
self.voices[name] = voice
return voice
def get_voice_prompt(self, name: str) -> str:
voice = self.voices.get(name, {})
return f"""Brand Voice: {voice.get('name', 'Default')}
Tone: {voice.get('tone', 'Professional')}
Values: {', '.join(voice.get('values', []))}
Do: {'; '.join(voice.get('do_s', []))}
Don't: {'; '.join(voice.get('dont_s', []))}"""
def analyze_voice(self, content: str) -> Dict:
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": """Analyze the brand voice of this content.
Return JSON: {"tone": "...", "formality": "formal|casual|mixed", "personality": "...", "target_audience": "..."}"""},
{"role": "user", "content": content[:2000]},
],
temperature=0.0,
)
try:
return json.loads(response.choices[0].message.content)
except:
return {"tone": "professional", "formality": "formal"}
Step 4: Content Generators
# generation/blog.py
from openai import OpenAI
from typing import Dict
class BlogGenerator:
def __init__(self, model: str = "gpt-4-turbo-preview"):
self.client = OpenAI()
self.model = model
def generate(
self,
topic: str,
brand_voice: str,
word_count: int = 1500,
keywords: list = None,
framework: str = "AIDA",
) -> Dict:
keyword_str = ", ".join(keywords) if keywords else "none specified"
prompt = f"""Write a {word_count}-word blog post about: {topic}
Brand voice: {brand_voice}
Framework: {framework}
Target keywords: {keyword_str}
Structure:
1. Compelling headline
2. Hook introduction (100-150 words)
3. Main sections with H2/H3 headings
4. Conclusion with CTA
Rules:
- Use short paragraphs (2-3 sentences)
- Include transition sentences
- Add bullet points for lists
- Reference data/examples where possible
- Optimize for readability (Flesch score 60+)"""
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": "You are an expert content writer and SEO specialist."},
{"role": "user", "content": prompt},
],
temperature=0.7,
max_tokens=4000,
)
content = response.choices[0].message.content
return {
"content": content,
"word_count": len(content.split()),
"framework": framework,
}
# generation/social.py
from openai import OpenAI
from typing import Dict, List
class SocialGenerator:
def __init__(self, model: str = "gpt-4-turbo-preview"):
self.client = OpenAI()
self.model = model
def generate_thread(
self, topic: str, brand_voice: str, num_tweets: int = 5
) -> List[Dict]:
prompt = f"""Create a Twitter thread about: {topic}
Brand voice: {brand_voice}
Number of tweets: {num_tweets}
Rules:
- First tweet hooks attention
- Each tweet provides value
- Use numbers and data
- End with summary and CTA
- Under 280 chars per tweet
Return JSON array of tweets."""
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": "Create engaging Twitter threads."},
{"role": "user", "content": prompt},
],
temperature=0.8,
)
import json
try:
return json.loads(response.choices[0].message.content)
except:
return [{"content": response.choices[0].message.content}]
def generate_linkedin(
self, topic: str, brand_voice: str
) -> Dict:
prompt = f"""Write a LinkedIn post about: {topic}
Brand voice: {brand_voice}
Rules:
- Hook in first 2 lines
- Use line breaks for readability
- Include personal insight
- End with question for engagement
- 150-300 words"""
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": "Write engaging LinkedIn content."},
{"role": "user", "content": prompt},
],
temperature=0.7,
)
return {"content": response.choices[0].message.content, "platform": "linkedin"}
Step 5: SEO Optimizer and Editor
# optimization/seo.py
from openai import OpenAI
from typing import Dict
class SEOOptimizer:
def __init__(self, model: str = "gpt-4-turbo-preview"):
self.client = OpenAI()
self.model = model
def optimize(self, content: str, target_keywords: list) -> Dict:
prompt = f"""Optimize this content for SEO.
Target keywords: {', '.join(target_keywords)}
Provide:
1. Optimized title (under 60 chars)
2. Meta description (under 160 chars)
3. Suggested H2/H3 headings
4. Internal linking opportunities
5. Keyword density check
6. Readability score
Return JSON with these fields."""
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": "You are an SEO expert. Optimize content for search engines."},
{"role": "user", "content": f"Content:\n{content[:3000]}\n\n{prompt}"},
],
temperature=0.3,
)
import json
try:
return json.loads(response.choices[0].message.content)
except:
return {"title": "", "meta_description": "", "headings": []}
# optimization/editor.py
from openai import OpenAI
class ContentEditor:
def __init__(self, model: str = "gpt-4-turbo-preview"):
self.client = OpenAI()
self.model = model
def edit(self, content: str, instructions: str = "Improve clarity and flow") -> str:
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": f"Edit this content. {instructions}. Maintain the original voice and meaning."},
{"role": "user", "content": content},
],
temperature=0.3,
)
return response.choices[0].message.content
def proofread(self, content: str) -> dict:
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": """Proofread this content.
Return JSON: {"corrected": "corrected text", "changes": ["list of changes"], "grammar_issues": count}"""},
{"role": "user", "content": content},
],
temperature=0.0,
)
import json
try:
return json.loads(response.choices[0].message.content)
except:
return {"corrected": content, "changes": [], "grammar_issues": 0}
Step 6: Complete Agent
# agent.py
from brand.voice import BrandVoiceManager
from generation.blog import BlogGenerator
from generation.social import SocialGenerator
from optimization.seo import SEOOptimizer
from optimization.editor import ContentEditor
from typing import Dict, List
class CreativeWritingAgent:
def __init__(self, model: str = "gpt-4-turbo-preview"):
self.brand = BrandVoiceManager(model)
self.blog = BlogGenerator(model)
self.social = SocialGenerator(model)
self.seo = SEOOptimizer(model)
self.editor = ContentEditor(model)
def create_blog(
self,
topic: str,
brand: str = "default",
word_count: int = 1500,
keywords: list = None,
) -> Dict:
voice_prompt = self.brand.get_voice_prompt(brand)
result = self.blog.generate(topic, voice_prompt, word_count, keywords)
seo = self.seo.optimize(result["content"], keywords or [])
return {**result, "seo": seo}
def create_social_campaign(
self, topic: str, brand: str, platforms: list = None
) -> Dict:
platforms = platforms or ["twitter", "linkedin"]
voice = self.brand.get_voice_prompt(brand)
content = {}
if "twitter" in platforms:
content["twitter"] = self.social.generate_thread(topic, voice)
if "linkedin" in platforms:
content["linkedin"] = self.social.generate_linkedin(topic, voice)
return {"topic": topic, "content": content}
def edit_content(self, content: str, style: str = "professional") -> str:
return self.editor.edit(content, f"Make it {style} while maintaining quality")
Mathematical Foundation
Readability Score (Flesch-Kincaid):
Where each parameter means:
- β total words
- β total sentences
Intuition: Higher scores indicate easier readability. Target 60-70 for general audiences.
SEO Keyword Density:
Where is keyword occurrences and is total words.
Intuition: Optimal density is 1-2%. Higher risks keyword stuffing penalties.
Testing & Evaluation
import pytest
from agent import CreativeWritingAgent
def test_blog_creation():
agent = CreativeWritingAgent()
agent.brand.create_voice("tech", "Technical but accessible", ["innovation"], ["Use data"], ["Jargon"])
result = agent.create_blog("AI agents", "tech", word_count=500)
assert "content" in result
assert result["word_count"] > 0
def test_brand_voice():
manager = BrandVoiceManager()
manager.create_voice("test", "casual", ["fun"], [], [])
prompt = manager.get_voice_prompt("test")
assert "casual" in prompt
Performance Metrics
| Metric | Value | Notes |
|---|---|---|
| Blog Generation | 10-30s | 1500 words |
| Social Thread | 5-15s | 5 tweets |
| SEO Optimization | 5-10s | Analysis + suggestions |
| Editing Pass | 3-8s | Content refinement |
| Voice Consistency | 90%+ | When well-trained |
Deployment
# main.py
from agent import CreativeWritingAgent
def main():
agent = CreativeWritingAgent()
agent.brand.create_voice(
"tech_startup",
"Innovative, forward-thinking, accessible",
["Innovation", "Simplicity", "Impact"],
["Use data", "Be concise", "Include examples"],
["Use jargon", "Be vague", "Overpromise"],
)
print("Content Agent Ready\n")
while True:
cmd = input("Command (blog/social/quit): ").strip()
if cmd == "quit":
break
elif cmd == "blog":
topic = input("Topic: ").strip()
result = agent.create_blog(topic, "tech_startup")
print(f"\n{result['content'][:500]}...\n")
if __name__ == "__main__":
main()
Real-World Use Cases
- Content Marketing: Blog and article production at scale
- Social Media Management: Platform-specific content creation
- Email Marketing: Campaign content and newsletters
- Product Descriptions: E-commerce content generation
- Thought Leadership: Executive content and ghostwriting
Common Pitfalls & Solutions
| Pitfall | Solution |
|---|---|
| Generic content | Deep brand voice training |
| SEO keyword stuffing | Natural integration, density monitoring |
| Inconsistent voice | Few-shot examples, style guides |
| Plagiarism risk | Original content generation, plagiarism checks |
| Content fatigue | Variety in frameworks and angles |
Summary with Key Takeaways
- Brand voice training ensures consistent, recognizable content
- SEO optimization integrates naturally without keyword stuffing
- Storytelling frameworks (AIDA, PAS) structure compelling narratives
- Multi-format adaptation maximizes content reach
- Always review and humanize AI-generated content before publishing