DEV Community

shashank ms
shashank ms

Posted on

LLM Model Training Datasets

We are building a synthetic dataset generator that produces structured instruction-response pairs for fine-tuning open-source LLMs. It uses Oxlo.ai to run an agentic pipeline that generates, critiques, and formats examples. This is useful for ML engineers who need domain-specific data but want to avoid manual annotation costs.

What you'll need

Step 1: Set up the Oxlo.ai client and define the dataset schema

I start by initializing the client and creating a dataclass to keep every row consistent. I also load my API key from the environment so I do not hardcode secrets.

import os
import json
from dataclasses import dataclass, asdict
from openai import OpenAI

@dataclass
class TrainingExample:
    instruction: str
    input: str
    output: str
    category: str

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

Step 2: Generate instruction-response pairs

I use Qwen 3 32B because it handles agentic workflows and strict formatting reliably. The system prompt forces valid JSON so I can parse the response directly without regex.

GENERATION_SYSTEM_PROMPT = """You are a dataset engineer. Given a domain topic, generate a diverse, high-quality instruction-response pair for training an LLM.

Rules:
- The instruction must be clear, specific, and require domain knowledge.
- The output must be accurate, concise, and helpful.
- Respond ONLY with a JSON object in this exact schema:
  {"instruction": "...", "input": "...", "output": "...", "category": "..."}
- Do not include markdown code fences or explanatory text."""
def generate_example(topic: str) -> TrainingExample:
    user_message = f"Generate one training example for the topic: {topic}"
    response = client.chat.completions.create(
        model="qwen-3-32b",
        messages=[
            {"role": "system", "content": GENERATION_SYSTEM_PROMPT},
            {"role": "user", "content": user_message},
        ],
        temperature=0.8,
    )
    raw = response.choices[0].message.content.strip()
    data = json.loads(raw)
    return TrainingExample(**data)

Step 3: Critique and filter low-quality examples

Not every sample is worth keeping. I run a second pass with Llama 3.3 70B to score each example on accuracy and clarity, discarding anything below a 4 out of 5.

CRITIQUE_SYSTEM_PROMPT = """You are a data quality reviewer. Review the provided training example and rate it from 1 to 5 based on accuracy, clarity, and usefulness for fine-tuning.

Respond with ONLY a JSON object: {"score": int, "reason": "..."}"""

def critique_example(ex: TrainingExample) -> dict:
    user_message = json.dumps(asdict(ex), ensure_ascii=False)
    response = client.chat.completions.create(
        model="llama-3.3-70b",
        messages=[
            {"role": "system", "content": CRITIQUE_SYSTEM_PROMPT},
            {"role": "user", "content": user_message},
        ],
        temperature=0.2,
    )
    return json.loads(response.choices[0].message.content.strip())

def is_quality_passed(ex: TrainingExample) -> bool:
    result = critique_example(ex)
    return result.get("score", 0) >= 4

Step 4: Export to JSONL for training frameworks

Once I have a clean list, I write the records to JSONL in Alpaca format. This loads directly into training frameworks like LLaMA-Factory or Axolotl.

def save_dataset(examples: list[TrainingExample], path: str = "dataset.jsonl"):
    with open(path, "w", encoding="utf-8") as f:
        for ex in examples:
            record = {
                "instruction": ex.instruction,
                "input": ex.input,
                "output": ex.output,
                "category": ex.category,
            }
            f.write(json.dumps(record, ensure_ascii=False) + "\n")
    print(f"Saved {len(examples)} examples to {path}")

Run it

This pipeline generates five examples about Python debugging, filters them through the critique agent, and exports the survivors. Because Oxlo.ai uses flat per-request pricing, long system prompts and multi-turn critique loops do not inflate costs the way token-based billing would. See https://oxlo.ai/pricing for current plan details.

if __name__ == "__main__":
    topic = "Python debugging with pdb"
    raw_examples = [generate_example(topic) for _ in range(5)]
    clean_examples = [ex for ex in raw_examples if is_quality_passed(ex)]
    save_dataset(clean_examples)

    for ex in clean_examples[:2]:
        print("Instruction:", ex.instruction)
        print("Output:", ex.output[:120] + "...")
        print()

Example output:

Saved 4 examples to dataset.jsonl

Instruction: How do I set a conditional breakpoint in pdb that only triggers when a variable exceeds 100?
Output: Use the condition command. First set a breakpoint with b 15, then condition 1 x > 100. The debugger will pause only when the condition is met...

Instruction: Explain the difference between the 'step' and 'next' commands in pdb.
Output: The 'step' command executes the current line and pauses at the first opportunity, which may enter a function call. The 'next' command runs...

Wrap-up and next steps

Feed the JSONL into Unsloth or LLaMA-Factory to fine-tune a model on your domain. After training, evaluate the fine-tuned model by running inference back through Oxlo.ai, where request-based pricing keeps long-prompt evaluation costs predictable.

Top comments (0)