Learnixo
Back to blog
AI Systemsintermediate

Output Format Control

Constrain and shape LLM outputs with format instructions, examples, and schema definitions. Get consistent JSON, structured text, and typed responses every time.

Asma Hafeez KhanMay 16, 20266 min read
Prompt EngineeringOutput FormatJSONStructured Output
Share:𝕏

Why Output Format Matters

Uncontrolled model output is prose — inconsistent structure, varying levels of detail, and difficult to parse programmatically. For production systems, you need predictable structure. Format control techniques range from simple prompt instructions to schema-constrained generation.


Format Instructions in Prompts

The simplest approach: tell the model exactly what format to produce:

Python
from openai import OpenAI

client = OpenAI()

def extract_drug_interactions(clinical_text: str) -> str:
    prompt = f"""Extract all drug interactions from the following clinical note.

Format your response EXACTLY as follows:

INTERACTION 1: Drug A: [drug name] Drug B: [drug name] Severity: [Major | Moderate | Minor] Mechanism: [one sentence] Action Required: [specific clinical action]

INTERACTION 2: ...


If no interactions are present, respond with: NO INTERACTIONS IDENTIFIED

Clinical note:
{clinical_text}"""

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": prompt}],
        temperature=0,
    )
    return response.choices[0].message.content

note = """
Patient is a 68-year-old male on warfarin 5mg daily and aspirin 81mg daily
for a history of atrial fibrillation and coronary artery disease.
New prescription: clarithromycin 500mg BID for 10 days for community-acquired pneumonia.
"""
print(extract_drug_interactions(note))

JSON Output with Prompt Instructions

Python
import json

def extract_medications_json(clinical_text: str) -> list[dict]:
    prompt = f"""Extract all medications from the following clinical text.

Return a JSON array. Each medication must have these exact keys:
- "name": string (drug name as written)
- "dose": string (dose and unit, or null if not specified)
- "frequency": string (e.g., "daily", "twice daily", or null if not specified)
- "route": string (e.g., "oral", "IV", or null if not specified)
- "indication": string (why the drug is given, or null if not stated)

Return ONLY valid JSON, no other text, no markdown code blocks.

Clinical text:
{clinical_text}"""

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": prompt}],
        temperature=0,
    )

    try:
        return json.loads(response.choices[0].message.content)
    except json.JSONDecodeError as e:
        raise ValueError(f"Model returned invalid JSON: {e}\nOutput: {response.choices[0].message.content}")

medications = extract_medications_json("""
Mr. Johnson takes warfarin 5mg orally each evening for atrial fibrillation,
metoprolol succinate 50mg oral daily for rate control,
and atorvastatin 40mg at bedtime for hyperlipidemia.
New: clarithromycin 500mg PO BID × 10 days for CAP.
""")

for med in medications:
    print(json.dumps(med, indent=2))

Structured Output with OpenAI (JSON Mode)

OpenAI's response_format parameter guarantees valid JSON:

Python
from openai import OpenAI
import json

client = OpenAI()

response = client.chat.completions.create(
    model="gpt-4o",
    response_format={"type": "json_object"},  # Guarantees valid JSON output
    messages=[
        {
            "role": "system",
            "content": """You are a drug interaction analyzer. 
Always respond with a JSON object containing:
{
  "interactions": [array of interaction objects],
  "summary": "one sentence overall assessment",
  "action_required": "immediate | monitor | routine | none"
}""",
        },
        {
            "role": "user",
            "content": "Analyze: patient on warfarin starting clarithromycin",
        },
    ],
    temperature=0,
)

result = json.loads(response.choices[0].message.content)
print(f"Action required: {result['action_required']}")
print(f"Interactions: {len(result['interactions'])}")

Structured Output with Pydantic (OpenAI beta)

Python
from openai import OpenAI
from pydantic import BaseModel, Field
from typing import Literal

client = OpenAI()

class DrugInteraction(BaseModel):
    drug_a: str
    drug_b: str
    severity: Literal["major", "moderate", "minor"]
    mechanism: str
    management: str
    monitoring_parameters: list[str]

class InteractionAnalysis(BaseModel):
    interactions: list[DrugInteraction]
    overall_risk: Literal["high", "moderate", "low", "none"]
    primary_concern: str = Field(description="The most clinically significant issue in one sentence")
    recommend_pharmacist_review: bool

# OpenAI structured output (beta API)
response = client.beta.chat.completions.parse(
    model="gpt-4o",
    messages=[
        {
            "role": "system",
            "content": "You are a clinical pharmacologist. Analyze drug interactions and return structured data.",
        },
        {
            "role": "user",
            "content": "Analyze interactions for a patient on warfarin 5mg daily, starting clarithromycin 500mg BID.",
        },
    ],
    response_format=InteractionAnalysis,
)

analysis: InteractionAnalysis = response.choices[0].message.parsed
print(f"Overall risk: {analysis.overall_risk}")
print(f"Primary concern: {analysis.primary_concern}")
for interaction in analysis.interactions:
    print(f"\n{interaction.drug_a} + {interaction.drug_b}: {interaction.severity}")
    print(f"  Management: {interaction.management}")

Markdown and Structured Text

For human-readable output with consistent structure:

Python
def generate_drug_monograph(drug_name: str) -> str:
    """Generate a consistently structured drug monograph."""
    prompt = f"""Write a clinical drug monograph for {drug_name}.

Use EXACTLY this structure (use the exact headers shown):

# {drug_name}

## Classification
[Drug class and subclass]

## Mechanism of Action
[2-3 sentences on MOA]

## Indications
- [Indication 1]
- [Indication 2]
...

## Dosing
| Indication | Dose | Frequency | Notes |
|---|---|---|---|
| ... | ... | ... | ... |

## Monitoring Parameters
- [Parameter]: [Target / Frequency]
...

## Key Drug Interactions
| Interacting Drug | Severity | Mechanism | Management |
|---|---|---|---|
| ... | ... | ... | ... |

## Contraindications
- [Contraindication 1]
...

## Patient Counseling Points
1. [Point 1]
2. [Point 2]
...

Keep the entire monograph under 600 words."""

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": prompt}],
        temperature=0,
    )
    return response.choices[0].message.content

monograph = generate_drug_monograph("warfarin")
print(monograph)

Output Length Control

Python
LENGTH_INSTRUCTIONS = {
    "ultra_brief": "Respond in exactly one sentence.",
    "brief": "Keep your response under 100 words.",
    "standard": "Keep your response under 300 words.",
    "detailed": "Provide a comprehensive response. No length limit.",
    "tabular": "Present your answer as a table. Use no prose.",
    "bullet_only": "Respond ONLY with a bulleted list. No paragraphs, no introduction.",
}

def ask_with_length_control(question: str, length_mode: str = "standard") -> str:
    instruction = LENGTH_INSTRUCTIONS.get(length_mode, "")
    system = f"You are a clinical pharmacology assistant. {instruction}"

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": system},
            {"role": "user", "content": question},
        ],
        temperature=0,
    )
    return response.choices[0].message.content

question = "What are the main drug interactions with warfarin?"
for mode in ["ultra_brief", "brief", "tabular", "bullet_only"]:
    print(f"\n=== {mode.upper()} ===")
    print(ask_with_length_control(question, mode))

Few-Shot Format Examples

Showing examples of desired format is often more reliable than describing it:

Python
FEW_SHOT_SYSTEM = """You are a drug interaction classifier. 
For each interaction, classify it and provide the output in this format:

Example 1:
Input: warfarin + aspirin
Output:
severity: major
type: pharmacodynamic
mechanism: additive bleeding risk via platelet inhibition
action: use with extreme caution; monitor for bleeding; consider risk-benefit

Example 2:
Input: metformin + alcohol
Output:
severity: moderate
type: pharmacodynamic
mechanism: both increase lactic acid risk; alcohol impairs hepatic gluconeogenesis
action: advise patient to limit alcohol; monitor for lactic acidosis symptoms

Now classify the following interaction in the same format:"""

def classify_interaction(drug_a: str, drug_b: str) -> str:
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": FEW_SHOT_SYSTEM},
            {"role": "user", "content": f"{drug_a} + {drug_b}"},
        ],
        temperature=0,
    )
    return response.choices[0].message.content

print(classify_interaction("clarithromycin", "warfarin"))

Parsing and Validation

Always validate structured output before using it:

Python
import json
from typing import Any

def safe_parse_json(raw: str, fallback: Any = None) -> Any:
    """Parse JSON, stripping markdown code fences if present."""
    # Remove markdown code blocks that models sometimes add despite instructions
    clean = raw.strip()
    if clean.startswith("```"):
        clean = clean.split("\n", 1)[1]  # Remove first line (```json)
    if clean.endswith("```"):
        clean = clean.rsplit("\n", 1)[0]  # Remove last line (```)
    clean = clean.strip()

    try:
        return json.loads(clean)
    except json.JSONDecodeError:
        if fallback is not None:
            return fallback
        raise

def validate_interaction_structure(data: dict) -> bool:
    """Validate that interaction data has required fields."""
    required = {"drug_a", "drug_b", "severity", "mechanism", "management"}
    valid_severities = {"major", "moderate", "minor"}

    if not isinstance(data, dict):
        return False
    if not required.issubset(data.keys()):
        return False
    if data.get("severity") not in valid_severities:
        return False
    if not all(isinstance(data.get(k), str) for k in ["drug_a", "drug_b", "mechanism", "management"]):
        return False
    return True

Format control + validation is the foundation of reliable LLM pipelines. Never trust raw model output in production without parsing and validation.

Enjoyed this article?

Explore the AI Systems learning path for more.

Found this helpful?

Share:𝕏

Leave a comment

Have a question, correction, or just found this helpful? Leave a note below.