← Back to DevBytes

Building a Content Writing Agent with OpenAI Agents SDK: Complete Guide

What Is the OpenAI Agents SDK?

The OpenAI Agents SDK is a lightweight, production-ready framework from OpenAI designed specifically for building AI agents. Unlike traditional LLM libraries that focus on single-turn completions, the Agents SDK provides a structured way to create agents that can use tools, maintain context across multiple turns, delegate tasks to other agents, and enforce safety guardrails β€” all with minimal boilerplate.

At its core, the SDK gives you a Runner that executes agent workflows, an Agent class that encapsulates instructions and tools, and built-in support for tracing, streaming, and handoffs. Think of it as the evolution of the chat completions API β€” purpose-built for agentic patterns where the model needs to reason, act, and iterate.

Key Features at a Glance

Why Building a Content Writing Agent Matters

Content creation is one of the most practical and high-impact applications of AI agents today. A well-built content writing agent can:

Unlike prompting a single model and hoping for the best, an agent-based approach gives you control, observability, and reliability. You can trace every step, catch errors early, and build systems that produce consistent, high-quality output.

Setting Up Your Environment

Before building, let's get the SDK installed and configured. The Agents SDK requires Python 3.8+ and an OpenAI API key.

# Create a new project directory
mkdir content-agent-tutorial
cd content-agent-tutorial

# Create a virtual environment
python -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate

# Install the Agents SDK
pip install openai-agents openai

# Set your API key as an environment variable
export OPENAI_API_KEY="sk-your-key-here"  # On Windows: set OPENAI_API_KEY=sk-your-key-here

Create a file called agent.py β€” this will be our working file throughout the tutorial. Verify the installation with a quick test:

# test_install.py
from agents import Agent, Runner
import asyncio

async def main():
    agent = Agent(name="Test Agent", instructions="You are a helpful assistant.")
    result = await Runner.run(agent, "Say hello in exactly three words.")
    print(result.final_output)

asyncio.run(main())

If you see a concise three-word greeting, you're ready to go.

Understanding the Core Concepts

The Agents SDK revolves around four essential building blocks. Grasping these will make the rest of the tutorial straightforward.

Agents

An Agent is the fundamental unit in the SDK. It bundles together a name, instructions (the system prompt), an optional model configuration, tools the agent can call, and optional handoff targets. You create agents with a declarative constructor:

from agents import Agent

writer = Agent(
    name="Content Writer",
    instructions="You are a professional content writer specializing in clear, engaging blog posts.",
    model="gpt-4o",
    tools=[],  # We'll add tools later
)

The instructions string is the most critical part β€” it defines the agent's persona, behavior, and constraints. You can also pass a function that dynamically generates instructions based on context.

Tools

Tools are functions that agents can invoke during their execution. The SDK supports Python functions decorated with @tool or wrapped with FunctionTool. When an agent runs, it decides whether to call a tool, receives the result, and continues reasoning β€” all automatically managed by the Runner.

from agents import Agent, Runner, function_tool

@function_tool
def search_web(query: str) -> str:
    """Search the web for information on a given query."""
    # In production, this would call a real search API
    return f"Results for: {query}... [simulated search data]"

research_agent = Agent(
    name="Researcher",
    instructions="Use the search_web tool to find information, then summarize it.",
    tools=[search_web],
)

Handoffs

Handoffs allow one agent to delegate a conversation to another agent. This is perfect for multi-step content workflows β€” a coordinator agent can hand off to a researcher, then to a writer, then to an editor. The SDK handles the handoff seamlessly, preserving conversation context.

from agents import Agent, handoff

writer_agent = Agent(
    name="Writer",
    instructions="Write engaging content based on the research provided.",
)

researcher_agent = Agent(
    name="Researcher",
    instructions="Research topics thoroughly and provide structured notes.",
    handoffs=[handoff(writer_agent, description="Hand off to the writer when research is complete.")],
)

Guardrails

Guardrails validate agent inputs and outputs. Input guardrails can reject or modify user messages before they reach the agent. Output guardrails can check agent responses against safety or quality criteria. The SDK provides built-in guardrails and lets you define custom ones.

from agents import GuardrailFunctionOutput, guardrail

@guardrail
def no_offensive_content(output: str) -> GuardrailFunctionOutput:
    """Check that the output contains no offensive or inappropriate content."""
    forbidden_words = ["hack", "exploit", "illegal"]
    for word in forbidden_words:
        if word in output.lower():
            return GuardrailFunctionOutput(
                allowed=False,
                reason=f"Output contains forbidden word: {word}"
            )
    return GuardrailFunctionOutput(allowed=True, reason="Content is appropriate")

Building a Basic Content Writing Agent

Let's start with a single-agent content writer. This agent takes a topic and produces a well-structured blog post. We'll build it incrementally, testing at each stage.

import asyncio
from agents import Agent, Runner

# Define the content writing agent
content_writer = Agent(
    name="Blog Writer",
    instructions="""You are an expert blog writer. When given a topic:
1. Start with an engaging introduction that hooks the reader
2. Structure the body with clear subheadings
3. Use concrete examples and analogies
4. End with a compelling conclusion and a call-to-action
5. Keep paragraphs short (2-4 sentences) for readability
6. Maintain a conversational yet authoritative tone""",
    model="gpt-4o",
)

async def write_blog_post(topic: str) -> str:
    """Generate a blog post on the given topic."""
    prompt = f"Write a complete blog post about: {topic}. Include an introduction, 3-4 body sections with subheadings, and a conclusion."
    result = await Runner.run(content_writer, prompt)
    return result.final_output

# Run the agent
async def main():
    post = await write_blog_post("the benefits of async Python for web development")
    print(post)
    print("\n" + "="*50 + "\n")
    # The Runner also gives you access to the full trajectory
    print("Tokens used:", result.usage.total_tokens if hasattr(result, 'usage') else "Check RunResult")

if __name__ == "__main__":
    asyncio.run(main())

Run this and you'll get a complete blog post. The Runner.run() method returns a RunResult object containing final_output (the last message as a string), along with information about tool calls, token usage, and the full message history.

Adding Research Capabilities with Tools

A content writer that only relies on its training data will produce generic content. Let's give our agent a research tool so it can incorporate up-to-date information. In a real application, you'd connect this to a search API like Tavily, SerpAPI, or Brave Search. For the tutorial, we'll simulate search results to keep things self-contained.

import asyncio
from agents import Agent, Runner, function_tool

# Simulated research tool β€” replace with real API in production
@function_tool
def research_topic(query: str) -> str:
    """Search for recent information, statistics, and facts about a topic.
    
    Args:
        query: The search query string
    
    Returns:
        A formatted string with research findings
    """
    # In production, call a real search API here
    # Example: results = tavily_search(query)
    
    # Simulated research data for demonstration
    research_db = {
        "async python": """Research findings on async Python:
- Python's asyncio module, introduced in Python 3.4, enables concurrent code using coroutines
- Async web frameworks like FastAPI and aiohttp can handle 10,000+ concurrent connections
- According to FastAPI's benchmarks, async endpoints outperform sync endpoints by 3-5x under load
- The 2024 Python Developer Survey shows 67% of web developers now use async patterns
- Key advantage: non-blocking I/O allows handling multiple requests without thread overhead
- Common use cases: real-time APIs, WebSocket servers, microservices, data pipelines
- Libraries like httpx, asyncpg, and aioredis provide async database and HTTP clients""",
        
        "content marketing": """Research findings on content marketing:
- 73% of B2B marketers use content marketing as their primary lead generation strategy (Content Marketing Institute, 2024)
- Long-form content (2000+ words) generates 3x more organic traffic than short posts
- Companies that publish 16+ blog posts per month get 4.5x more leads (HubSpot research)
- Video content is growing fastest β€” 91% of businesses now use video in marketing
- AI-assisted content creation has grown 240% since 2023
- The average blog post takes 4 hours to write but only 10 minutes with AI assistance""",
        
        "default": f"General research on '{query}': This topic has significant relevance in the current landscape. Recent developments show increasing adoption and interest. Experts recommend a balanced approach combining theory with practical application."
    }
    
    # Fuzzy match to our demo database
    query_lower = query.lower()
    for key in research_db:
        if key in query_lower or any(word in query_lower for word in key.split()):
            return research_db[key]
    return research_db["default"]

# Create the research-enhanced content writer
content_writer_with_research = Agent(
    name="Research-Backed Content Writer",
    instructions="""You are a professional content writer who creates well-researched blog posts.
    
Your process:
1. FIRST, use the research_topic tool to gather facts, statistics, and current information
2. Incorporate the research findings naturally into your writing
3. Cite specific statistics and data points from the research
4. Structure the post with: engaging intro, body sections with subheadings, and conclusion
5. Keep a conversational yet authoritative tone
6. Use short paragraphs for readability""",
    model="gpt-4o",
    tools=[research_topic],
)

async def write_researched_post(topic: str) -> str:
    """Generate a research-backed blog post."""
    prompt = f"""Write a comprehensive blog post about: {topic}
    
Requirements:
- Use the research_topic tool to gather supporting facts and data
- Include at least 3 specific statistics or data points from the research
- Structure: Introduction, 3-4 body sections, Conclusion
- Target length: 800-1200 words
- Make it engaging and actionable"""
    
    result = await Runner.run(content_writer_with_research, prompt)
    return result.final_output

async def main():
    post = await write_researched_post("async Python for web development")
    print(post)

if __name__ == "__main__":
    asyncio.run(main())

Now when you run this, the agent will first call the research tool, receive the structured research data, and then weave those facts into the blog post. You can observe this by looking at the RunResult object more closely β€” it contains a history of every step the agent took.

Implementing a Multi-Agent Content Workflow

Real content teams have specialists: researchers, writers, editors. The Agents SDK shines here β€” you can model this exact workflow with multiple agents and handoffs. Let's build a three-agent system that researches, writes, and then edits content.

The Research Agent

This agent's sole job is to gather comprehensive research on a topic and produce structured notes.

from agents import Agent, function_tool

@function_tool
def deep_research(topic: str) -> str:
    """Perform deep research on a topic, returning structured findings.
    
    Args:
        topic: The topic to research
    
    Returns:
        Comprehensive research notes with sources
    """
    # Simulated deep research β€” replace with real APIs (Tavily, Perplexity, etc.)
    research_data = {
        "python async web development": """
DEEP RESEARCH: Python Async Web Development
============================================

1. MARKET OVERVIEW:
   - Async Python web frameworks now power 40% of new web applications (JetBrains Survey 2024)
   - FastAPI is the fastest-growing Python web framework, with 200% growth in 2 years
   - Average salary for async Python developers: $135,000 (US, 2024)

2. TECHNICAL FOUNDATIONS:
   - Python's event loop model (asyncio) enables cooperative multitasking
   - Key difference from threading: no GIL contention for I/O-bound tasks
   - async/await syntax introduced in Python 3.5, matured significantly by 3.11
   - Starlette (FastAPI's foundation) uses ASGI protocol for async request handling

3. PERFORMANCE BENCHMARKS:
   - FastAPI handles 25,000 requests/second on modest hardware (TechEmpower benchmarks)
   - Async database queries with asyncpg show 3x improvement over synchronous psycopg2
   - WebSocket connections: async servers handle 50,000+ concurrent connections

4. KEY LIBRARIES & TOOLS:
   - FastAPI: REST API framework with automatic OpenAPI docs
   - aiohttp: Async HTTP client/server
   - httpx: Modern async HTTP client with HTTP/2 support
   - asyncpg: High-performance async PostgreSQL driver
   - aioredis: Async Redis client
   - Celery with asyncio: Background task processing

5. BEST PRACTICES:
   - Use async for I/O-bound operations, not CPU-bound
   - Mix sync and async carefully β€” blocking calls in async code kill performance
   - Use connection pooling for databases
   - Implement proper error handling with try/except in coroutines
   - Leverage middleware for cross-cutting concerns

6. REAL-WORLD CASE STUDIES:
   - Netflix: Migrated recommendation engine to async Python, 40% latency reduction
   - Uber: Async microservices handle 100M+ daily requests
   - Microsoft: FastAPI powers internal ML model serving infrastructure
""",
        "default": f"COMPREHENSIVE RESEARCH ON: {topic}\n\nKey findings, market data, technical details, and case studies would be populated here from live APIs."
    }
    
    topic_lower = topic.lower()
    for key in research_data:
        if key in topic_lower or any(word in topic_lower for word in key.split()[:3]):
            return research_data[key]
    return research_data["default"]

research_agent = Agent(
    name="Research Specialist",
    instructions="""You are a world-class research analyst. Your job:
1. Use the deep_research tool to gather comprehensive information
2. Organize findings into structured notes with clear sections
3. Extract key statistics, quotes, and data points
4. Identify trends and patterns in the research
5. Pass your complete research dossier to the writer when done
6. Do NOT write the final content yourself β€” hand off to the writer""",
    model="gpt-4o",
    tools=[deep_research],
)

The Writing Agent

The writer takes research output and crafts compelling content.

writing_agent = Agent(
    name="Content Writer",
    instructions="""You are an award-winning content writer and journalist. Your process:
1. Review the research dossier provided by the research specialist
2. Identify the most compelling narrative angle
3. Write a draft that is engaging, clear, and factually accurate
4. Use the Pyramid Principle: start with the key message, then support with details
5. Include specific data points and citations from the research
6. Write in an active voice with vivid language
7. After completing the draft, hand off to the editor for review""",
    model="gpt-4o",
)

The Editing Agent

The editor reviews the draft for quality, accuracy, and style.

editing_agent = Agent(
    name="Senior Editor",
    instructions="""You are a meticulous senior editor. Review the draft for:
1. Factual accuracy β€” cross-check all statistics against the original research
2. Clarity and flow β€” ensure smooth transitions between sections
3. Grammar and style β€” fix any errors, improve sentence structure
4. Engagement β€” strengthen hooks, examples, and calls-to-action
5. SEO optimization β€” suggest title improvements, ensure keyword coverage
6. Provide the final, polished version as output
7. If major issues exist, explain what needs to be revised""",
    model="gpt-4o",
)

Orchestrating with Handoffs

Now we wire the agents together using handoffs. The research agent hands off to the writer, who hands off to the editor. We also create an orchestrator agent that manages the overall workflow.

from agents import handoff

# Wire up handoffs
research_agent_with_handoff = Agent(
    name="Research Specialist",
    instructions="""You are a world-class research analyst. Your job:
1. Use the deep_research tool to gather comprehensive information
2. Organize findings into structured notes with clear sections
3. Extract key statistics, quotes, and data points
4. When your research is complete and comprehensive, hand off to the Content Writer
5. Do NOT write the final content yourself""",
    model="gpt-4o",
    tools=[deep_research],
    handoffs=[
        handoff(
            writing_agent,
            description="Hand off complete research dossier to the Content Writer for drafting",
        )
    ],
)

writing_agent_with_handoff = Agent(
    name="Content Writer",
    instructions="""You are an award-winning content writer and journalist. Your process:
1. Review the research dossier provided
2. Identify the most compelling narrative angle
3. Write a complete draft that is engaging, clear, and factually accurate
4. Include specific data points and citations from the research
5. When the draft is complete, hand off to the Senior Editor for review""",
    model="gpt-4o",
    handoffs=[
        handoff(
            editing_agent,
            description="Hand off complete draft to the Senior Editor for review and polishing",
        )
    ],
)

editing_agent_with_handoff = Agent(
    name="Senior Editor",
    instructions="""You are a meticulous senior editor. Review the draft for:
1. Factual accuracy β€” cross-check all statistics against the research
2. Clarity and flow β€” ensure smooth transitions
3. Grammar and style β€” fix errors, improve structure
4. Engagement β€” strengthen hooks, examples, and CTAs
5. Provide the final, polished version as your output""",
    model="gpt-4o",
)

# Orchestrator agent that starts the workflow
orchestrator = Agent(
    name="Content Workflow Orchestrator",
    instructions="""You manage a content creation workflow. When given a topic:
1. Immediately hand off to the Research Specialist to begin research
2. The research agent will then hand off to the writer
3. The writer will hand off to the editor
4. The editor produces the final polished content""",
    model="gpt-4o",
    handoffs=[
        handoff(research_agent_with_handoff, description="Start the research phase for content creation"),
    ],
)

async def run_content_workflow(topic: str) -> str:
    """Run the full multi-agent content creation workflow."""
    prompt = f"""Create comprehensive, well-researched content about: {topic}
    
The workflow should:
1. Research the topic thoroughly
2. Write an engaging draft based on the research
3. Edit and polish the final piece
    
Please start the process."""
    
    result = await Runner.run(orchestrator, prompt)
    return result.final_output

async def main():
    topic = "Python async web development best practices"
    final_content = await run_content_workflow(topic)
    print("FINAL POLISHED CONTENT:")
    print("="*60)
    print(final_content)

if __name__ == "__main__":
    asyncio.run(main())

When you run this, the orchestrator immediately hands off to the research agent. The research agent calls the deep_research tool, organizes the findings, then hands off to the writer. The writer crafts a draft and hands off to the editor. The editor reviews, polishes, and produces the final output. The entire multi-step workflow happens in a single Runner.run() call β€” the SDK manages all the state transitions.

Advanced Features for Production Content Agents

Custom Instructions and Dynamic Personas

For a content agent that adapts to different brands, audiences, or content types, you can use a function to generate instructions dynamically:

from agents import Agent, Runner
from typing import Dict

def build_writer_instructions(context: Dict) -> str:
    """Generate dynamic instructions based on brand and audience context."""
    brand = context.get("brand", "General")
    audience = context.get("audience", "General readers")
    content_type = context.get("content_type", "blog post")
    tone = context.get("tone", "conversational")
    
    return f"""You are a content writer for {brand}.
    
Brand voice: {tone}
Target audience: {audience}
Content type: {content_type}

Guidelines:
- Write in {tone} tone that resonates with {audience}
- Use examples and references relevant to {audience}
- Maintain {brand}'s positioning as a thought leader
- Structure content for maximum engagement with {audience}
- Include a clear call-to-action appropriate for {content_type}
- Keep paragraphs short and scannable"""

# Create agent with dynamic instructions
adaptive_writer = Agent(
    name="Adaptive Content Writer",
    instructions=lambda context: build_writer_instructions(context.get("context", {})),
    model="gpt-4o",
)

async def write_for_brand():
    context = {
        "brand": "TechNova AI",
        "audience": "CTOs and engineering leaders",
        "content_type": "thought leadership article",
        "tone": "visionary yet pragmatic"
    }
    
    result = await Runner.run(
        adaptive_writer,
        "Write about the future of AI-native development workflows",
        context={"context": context}
    )
    return result.final_output

Output Types and Structured Responses

For content workflows that need structured output (like generating an article with separate title, meta description, body, and tags), use the SDK's output type system:

from agents import Agent, Runner
from pydantic import BaseModel
from typing import List, Optional

class BlogPost(BaseModel):
    title: str
    meta_description: str
    slug: str
    introduction: str
    sections: List[dict]  # Each section has a heading and body
    conclusion: str
    call_to_action: str
    tags: List[str]
    estimated_read_time_minutes: int

class SEOMetadata(BaseModel):
    primary_keyword: str
    secondary_keywords: List[str]
    search_intent: str
    recommended_title_length: int

structured_writer = Agent(
    name="Structured Content Writer",
    instructions="""You are a professional content writer who produces structured blog posts.
    
When given a topic:
1. Research and plan the article structure
2. Write a compelling title optimized for SEO
3. Craft each section with clear headings and body content
4. Include a strong conclusion and call-to-action
5. Provide accurate metadata and tags""",
    model="gpt-4o",
    output_type=BlogPost,
)

async def generate_structured_post(topic: str) -> BlogPost:
    """Generate a blog post with full structured output."""
    result = await Runner.run(
        structured_writer,
        f"Write a comprehensive blog post about: {topic}"
    )
    # result.final_output is automatically parsed into a BlogPost object
    return result.final_output

async def main():
    post = await generate_structured_post("microservices orchestration patterns")
    print(f"Title: {post.title}")
    print(f"Slug: {post.slug}")
    print(f"Read time: {post.estimated_read_time_minutes} minutes")
    print(f"Tags: {', '.join(post.tags)}")
    print(f"\nIntroduction: {post.introduction[:200]}...")
    print(f"\nSections: {len(post.sections)}")
    for section in post.sections:
        print(f"  - {section['heading']}")
    print(f"\nCTA: {post.call_to_action}")

if __name__ == "__main__":
    asyncio.run(main())

Using output_type with Pydantic models gives you type-safe, validated structured output that integrates directly with downstream systems like CMS platforms, email automation tools, or content databases.

Tracing and Debugging

The Agents SDK includes built-in tracing via OpenTelemetry. When debugging complex multi-agent content workflows, tracing shows you every agent transition, tool call, and guardrail check.

from agents import Agent, Runner, trace
from agents.tracing import TraceConfig

# Enable tracing globally
TraceConfig.set_default(enable_tracing=True)

async def traced_content_workflow(topic: str):
    """Run the content workflow with full tracing."""
    with trace("Content Creation Workflow", trace_id=f"content-{topic[:20]}") as span:
        # The orchestrator will create child spans for each agent handoff
        result = await Runner.run(orchestrator, f"Create content about: {topic}")
        
        # Access trace information
        span.set_attribute("topic", topic)
        span.set_attribute("final_length", len(result.final_output))
        
        # The RunResult contains detailed step information
        print(f"Workflow steps: {len(result.new_items)}")
        for item in result.new_items:
            if hasattr(item, 'agent_name'):
                print(f"  Agent: {item.agent_name}")
            if hasattr(item, 'tool_calls'):
                for call in item.tool_calls:
                    print(f"    Tool: {call.name}")
    
    return result.final_output

For production systems, you can export traces to any OpenTelemetry-compatible backend (Jaeger, Datadog, Honeycomb, etc.) for monitoring and debugging.

Complete Production-Ready Content Writing Agent

Let's assemble everything into a production-ready content writing system. This example includes research capabilities, multi-agent handoffs, guardrails, structured output, and error handling.

"""
production_content_agent.py
A production-ready content writing agent system using the OpenAI Agents SDK.
"""

import asyncio
import logging
from typing import Dict, List, Optional
from dataclasses import dataclass, field

from agents import (
    Agent, Runner, function_tool, handoff, guardrail,
    GuardrailFunctionOutput, InputGuardrail, trace
)
from agents.tracing import TraceConfig
from pydantic import BaseModel

# Configure logging and tracing
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
TraceConfig.set_default(enable_tracing=True)

# ============================================================================
# DATA MODELS
# ============================================================================

class ContentBrief(BaseModel):
    """A structured content brief that guides the entire workflow."""
    topic: str
    target_audience: str
    content_type: str  # blog_post, whitepaper, social_media, email
    tone: str
    key_points: List[str]
    word_count_target: int
    seo_keywords: List[str]
    competitor_urls: List[str] = []

class ResearchDossier(BaseModel):
    """Structured research output."""
    topic_summary: str
    key_statistics: List[Dict[str, str]]
    competitor_analysis: str
    expert_quotes: List[str]
    trends_and_patterns: str
    source_notes: str

class FinalArticle(BaseModel):
    """The final polished article."""
    title: str
    subtitle: str
    meta_description: str
    body_markdown: str
    word_count: int
    reading_time_minutes: int
    seo_score: float  # 0-100
    citations: List[str]

@dataclass
class ContentWorkflowState:
    """Tracks workflow state across agent handoffs."""
    brief: Optional[ContentBrief] = None
    research: Optional[ResearchDossier] = None
    draft: Optional[str] = None
    revision_count: int = 0
    max_revisions: int = 3

# ============================================================================
# TOOLS
# ============================================================================

@function_tool
async def search_for_research(query: str, num_results: int = 5) -> str:
    """Search the web for current information on a topic.
    
    Args:
        query: The search query
        num_results: Number of results to return
    
    Returns:
        Formatted search results
    """
    logger.info(f"Searching for: {query}")
    # In production, integrate with Tavily, SerpAPI, or Brave Search
    # Example with Tavily:
    # from tavily import TavilyClient
    # client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
    # results = client.search(query, max_results=num_results)
    
    # Simulated results for the tutorial
    return f"""Search results for '{query}' (top {num_results}):
    
    1. [Source: Industry Report 2024] - Key findings show significant growth in this area
    2. [Source: Technical Documentation] - Best practices emphasize structured approaches
    3. [Source: Expert Interview] - Industry leaders recommend starting with fundamentals
    4. [Source: Case Study] - Real-world implementation shows 40% improvement
    5. [Source: Academic Paper] - Research validates the effectiveness of this approach
    
    Detailed data would come from live APIs in production."""

@function_tool
async def analyze_competitor_content(url: str) -> str:
    """Analyze a competitor's content for insights.
    
    Args:
        url: The competitor's content URL
    
    Returns:
        Analysis of the competitor's content strategy
    """
    logger.info(f"Analyzing competitor: {url}")
    # In production, fetch and analyze the actual URL
    return f"""Competitor Analysis for {url}:
    - Content length: ~1500 words
    - Key themes: Similar topic coverage
    - Content gaps: Missing practical examples section
    - Engagement signals: Strong on social proof, weak on data
    - Our opportunity: Provide more concrete data and actionable takeaways"""

@function_tool
async def check_facts(statement: str) -> Dict[str, any]:
    """Verify factual claims against trusted sources.
    
    Args:
        statement: The factual claim to verify
    
    Returns:
        Verification result with confidence score
    """
    logger.info(f"Fact-checking: {statement[:100]}...")
    # In production, use a fact-checking API or knowledge base
    return {
        "statement": statement,
        "verified": True,
        "confidence": 0.92,
        "source": "Cross-referenced with industry benchmarks",
        "correction": None
    }

# ============================================================================
# GUARDRAILS
# ============================================================================

@guardrail
def content_quality_guard(output: str) -> GuardrailFunctionOutput:
    """Ensure content meets minimum quality standards."""
    min_length = 300
    issues = []
    
    if len(output) < min_length:
        issues.append(f"Content too short: {len(output)} chars (min: {min_length})")
    
    # Check for common AI giveaways
    filler_phrases = [
        "in today's digital age",
        "in this blog post we will",
        "without further ado",
        "in conclusion",
    ]
    found_fillers = [p for p in filler_phrases if p.lower() in output.lower()]
    if found_fillers:
        issues.append(f"Found clichΓ© phrases: {found_fillers}")
    
    if issues:
        return GuardrailFunctionOutput(
            allowed=False,
            reason="; ".join(issues)
        )
    
    return GuardrailFunctionOutput(
        allowed=True,
        reason=f

β€” Ad β€”

Google AdSense will appear here after approval

← Back to all articles