Building a content generation tool that scales beyond a simple script requires more than wrapping a chat.completions call in a loop. You need deterministic output formats, robust error handling, and a cost model that does not punish you for detailed system prompts or few-shot examples. This guide walks through a production-ready architecture using the OpenAI SDK, structured JSON outputs, and Oxlo.ai as the inference backend.
Architecture of a Minimal Content Generator
A reliable content generation pipeline has three layers: prompt assembly, inference, and post-processing. Prompt assembly combines static templates with dynamic user inputs and retrieval context. Inference calls the LLM with a strict schema constraint. Post-processing validates the returned structure and converts it into your internal content model. Keeping these layers separate makes unit testing straightforward and lets you swap models or providers without rewriting business logic.
SDK Setup and Authentication
Because Oxlo.ai is fully OpenAI SDK compatible, you can use the official Python or Node.js client with a single configuration change. Set the base URL to https://api.oxlo.ai/v1 and export your API key.
from openai import OpenAI
import os
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=os.environ["OXLO_API_KEY"]
)
This is a drop-in replacement. Every endpoint you need for content generation, including chat.completions, embeddings, and images/generations, uses the same signature you already know.
Prompt Engineering with Templates
Long system prompts and few-shot examples improve consistency, but on token-based providers they inflate costs linearly. Oxlo.ai uses request-based pricing: one flat cost per API request regardless of prompt length. That means you can include full style guides, brand voice documents, and previous high-performing examples in the context window without increasing the per-request price. You pay per article generated, not per token.
Keep your templates version-controlled and inject variables before the API call. A simple Jinja2 pattern works well:
from jinja2 import Template
system_tpl = Template("""
You are a senior editor for {{ brand }}.
Tone: {{ tone }}
Forbidden words: {{ forbidden | join(', ') }}
Return only the requested JSON.
""")
user_tpl = Template("""
Write an article about: {{ topic }}
Target length: {{ word_count }} words
Include sections: {{ sections | join(', ') }}
""")
Enforcing Structured Output with JSON Mode
Content tools rarely want raw markdown. They need structured data: headlines, meta descriptions, tags, and body copy. Oxlo.ai supports JSON mode, so you can set response_format={"type": "json_object"} and validate the output with Pydantic.
from pydantic import BaseModel, Field
class Article(BaseModel):
headline: str = Field(max_length=100)
meta_description: str = Field(max_length=160)
body: str = Field(min_length=200)
tags: list[str] = Field(max_length=5)
Always include explicit schema instructions in the system prompt, even when using JSON mode. This reduces the chance of the model emitting explanatory text before the JSON object.
A Reusable ContentGenerator Class
The class below ties together templating, structured generation, and basic retry logic. It targets the Oxlo.ai API and defaults to Llama 3.3 70B for general-purpose writing.
import os
import json
from typing import Optional
from openai import OpenAI, APIError
from pydantic import BaseModel, Field, ValidationError
class Article(BaseModel):
headline: str = Field(..., max_length=100)
meta_description: str = Field(..., max_length=160)
body: str
tags: list[str]
class ContentGenerator:
def init(
self,
api_key: Optional[str] = None,
model: str = "llama-3.3-70b"
):
self.client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=api_key or os.environ["OXLO_API_KEY"]
)
self.model = model
self.system_prompt = (
"You are an expert content writer. "
"Return only a JSON object matching the Article schema. "
"No markdown fences, no commentary."
)
def generate(self, topic: str, context: Optional[str] = None) -> Article:
user_msg = f"Topic: {topic}\n
Top comments (0)