DEV Community

shashank ms
shashank ms

Posted on

LLMs for Content Creation: A Guide

In this tutorial we are building a multi-format content generator that turns a one-line brief into a blog post, a Twitter thread, and a newsletter section. It is aimed at indie hackers and small marketing teams who need to ship content daily without scaling headcount. The whole pipeline runs on Oxlo.ai, so you only pay per request even when you throw long prompts at it.

What you'll need

Python 3.10 or newer, the OpenAI SDK, and an API key from https://portal.oxlo.ai. Install the SDK with pip:

pip install openai

Step 1: Scaffold the Oxlo.ai client

I start by importing the OpenAI client and pointing it at Oxlo.ai. Because Oxlo.ai is fully OpenAI SDK compatible, this is the only setup required.

from openai import OpenAI
import os

client = OpenAI(
    base_url="https://api.oxlo.ai/v1",
    api_key=os.environ.get("OXLO_API_KEY")
)

Step 2: Lock in the system prompt

The system prompt defines the voice and structure rules. I keep it in a constant so I can tweak tone without touching the rest of the logic.

SYSTEM_PROMPT = """You are a senior content strategist.
Your job is to turn a raw brief into three distinct assets:
1. A blog post (500 words, markdown, H2 sections)
2. A Twitter thread (5 tweets, each under 280 characters)
3. A newsletter blurb (2 paragraphs, friendly and direct)

Rules:
- Use the brief's keywords naturally.
- Output each asset inside XML-like tags: <blog>, <thread>, <newsletter>.
- Do not include a preamble."""

Step 3: Build the core generation function

I write a single function that sends the brief to Oxlo.ai and returns the raw text. I use Llama 3.3 70B because it handles long-form instruction following reliably.

def generate_assets(brief: str) -> str:
    response = client.chat.completions.create(
        model="llama-3.3-70b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": f"Brief: {brief}"},
        ],
        temperature=0.7,
        max_tokens=2048,
    )
    return response.choices[0].message.content

Step 4: Parse and display the output

The model returns all three assets in one block. I add a small parser to split them so the script prints clean sections.

import re

def parse_assets(raw: str):
    pattern = r"<(blog|thread|newsletter)>(.*?)</\1>"
    matches = re.findall(pattern, raw, re.DOTALL)
    return {tag: content.strip() for tag, content in matches}

def run(brief: str):
    raw = generate_assets(brief)
    assets = parse_assets(raw)
    
    for name, content in assets.items():
        print(f"\n=== {name.upper()} ===")
        print(content)
        print("=" * 40)

Step 5: Add a self-edit loop

First drafts are rarely final. I add a second pass where the model critiques its own output and returns a refined version. Because Oxlo.ai uses request-based pricing, a long critique plus rewrite costs the same flat rate regardless of how many tokens pass through the context window. You can compare plans at https://oxlo.ai/pricing.

def refine_asset(asset_type: str, draft: str, brief: str) -> str:
    critique_prompt = (
        f"You wrote the following {asset_type} based on this brief: '{brief}'. "
        f"Critique it for clarity, voice, and keyword fit. "
        f"Then output the improved version inside <{asset_type}> tags."
    )
    
    response = client.chat.completions.create(
        model="llama-3.3-70b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "assistant", "content": draft},
            {"role": "user", "content": critique_prompt},
        ],
        temperature=0.6,
        max_tokens=2048,
    )
    return response.choices[0].message.content

def run_with_refinement(brief: str):
    raw = generate_assets(brief)
    assets = parse_assets(raw)
    
    final = {}
    for name, draft in assets.items():
        print(f"Refining {name}...")
        improved_raw = refine_asset(name, draft, brief)
        improved_parsed = parse_assets(improved_raw)
        final[name] = improved_parsed.get(name, draft)
    
    for name, content in final.items():
        print(f"\n=== {name.upper()} ===")
        print(content)
        print("=" * 40)
    
    return final

Run it

I test the pipeline with a real brief. The script below generates the draft, runs the refinement pass, and prints the results.

if __name__ == "__main__":
    brief = (
        "Launching Oxlo.ai, an AI inference platform with flat per-request pricing. "
        "Target audience is developers and AI startups burned by unpredictable token bills."
    )
    
    run_with_refinement(brief)

Example output from a live run:

Refining blog...
Refining thread...
Refining newsletter...

=== BLOG ===
Why Token-Based Pricing Is Killing Your AI Budget

Developers love large language models, but they hate the bill at the end of the month...

=== THREAD ===
1/ Your LLM bill is unpredictable because you pay per token...

=== NEWSLETTER ===
Hey builder,

If you have ever opened an invoice from your AI provider and felt your stomach drop, you are not alone...

========================================

The full text will vary run to run, but the structure stays consistent. If you want faster iteration, swap in deepseek-v3.2 for the first draft. It is efficient and sits on Oxlo.ai's free tier.

Next steps

Wire the run_with_refinement function into a Slack slash command or a Streamlit UI so your marketing team can trigger it without touching Python. Alternatively, add a tool-calling step that fetches trending keywords from an SEO API and injects them into the brief before generation.

Top comments (0)