All guides
Sven Böttger|June 10, 2026|11 min

The Practical Guide to XML Prompting

How to produce predictable, parseable and production-safe AI outputs with structured XML prompts

The Practical Guide to XML Prompting

At myos we build AI operating systems for real businesses. The difference between a pretty demo and a robust production workflow almost always comes down to one place: the structure of the prompt. XML prompting is one of the most reliable methods for making model outputs predictable, machine-readable and safe to wire into downstream code.

This guide is our working reference. We reach for it when we design extraction pipelines, routing layers and structured generation. You can adopt the templates directly or adapt the tag names to your domain.

Why XML for prompts?

XML is particularly well suited for prompts for several reasons:

  • Clear structure: you cleanly separate instructions, context, inputs and expected outputs via tags.
  • Parser-friendly: the output can be read with any standard XML library and is far more robust than homemade delimiters.
  • Extensible: you can add new tags without breaking older ones.
  • Human-readable: developers and business teams alike can read and edit prompts.

Use XML to enforce outputs, extract information, route tasks, enforce formats, mark up few-shot examples and run self-checks. And all of that without requiring hidden step-by-step reasoning (chain-of-thought).

Rule of thumb: XML or JSON?

If your prompts or outputs contain a lot of free text or code, XML plays to its strengths. For purely numerical, flat data structures, JSON can be the more compact choice.

Core rules that save you trouble

  1. Always produce well-formed XML: one root tag, every tag closed, no stray special characters in the text (except escaped or in CDATA).
  2. Name tags after the domain: prefer <invoice>, <clause> or <persona> over generic <section1>.
  3. Separate cleanly: instructions, examples, inputs and outputs belong in their own blocks (<instructions>, <examples>, <input>, <output_format>).
  4. Define the behavior in the error case: specify an <error> schema and define when it is used.
  5. Skip chain-of-thought: do not require step-by-step reasoning, but short justifications or checklists (such as <key_points> with an upper limit).
  6. Use CDATA for code, JSON, regex and anything with curly or angle brackets.
  7. State the output schema clearly: an <output_format> with all required tags and constraints.
  8. Version your prompts: a <meta version="1.2" id="email-reply-v12"/> makes changes traceable.
<code><![CDATA[
def add(a, b): return a + b
]]></code>

A minimal, reusable skeleton

Start every new prompt with this skeleton. It contains metadata, task, instructions, input, output format and an error handler.

<prompt>
  <meta version="1.0" id="GEN-001"/>
  <task>Fasse einen langen Artikel für eine vielbeschäftigte Führungskraft zusammen.</task>

  <instructions>
    - Schreibe in einfacher Sprache.
    - Halte dich an 120 bis 150 Woerter.
    - Ergaenze 3 stichpunktartige Highlights.
  </instructions>

  <input>
    <article><![CDATA[
      {{ARTIKEL HIER EINFUEGEN}}
    ]]></article>
  </input>

  <output_format>
    <summary>120 bis 150 Woerter.</summary>
    <highlights>
      <bullet>Praegnante Aussage</bullet>
      <bullet>Praegnante Aussage</bullet>
      <bullet>Praegnante Aussage</bullet>
    </highlights>
  </output_format>

  <error_handler>
    Wenn die Eingabe fehlt oder nicht auswertbar ist, gib zurueck:
    <error code="INPUT_INVALID" message="Grund hier"/>
  </error_handler>
</prompt>

Prompt library: ready-to-use templates

All templates deliberately avoid hidden chain-of-thought. Adopt them as-is or adapt the tag names to your domain.

1) Structured extraction

<prompt>
  <task>Extrahiere Firma, Produkt, Preis und Stimmung aus einer Rezension.</task>

  <input>
    <review><![CDATA[
      Ich liebe den Acme Air 2000, nur 249 Dollar und leiser als mein alter Ventilator.
    ]]></review>
  </input>

  <output_format>
    <extraction>
      <company>string</company>
      <product>string</product>
      <price currency="USD">number</price>
      <sentiment one_of="positive|neutral|negative">string</sentiment>
      <key_points max="3">stichpunktartige Phrasen</key_points>
    </extraction>
  </output_format>

  <instructions>
    - Ist ein Feld unbekannt, setze ein leeres Tag (z. B. <price/>).
    - Halte <key_points> auf hoechstens 3 kurze Stichpunkte.
  </instructions>
</prompt>

2) Classification with fixed labels

<prompt>
  <task>Klassifiziere die Absicht eines Support-Tickets.</task>
  <labels>
    <label id="bug">Fehlermeldung</label>
    <label id="billing">Abrechnung</label>
    <label id="feature">Feature-Wunsch</label>
    <label id="other">Sonstiges</label>
  </labels>
  <input>
    <ticket>Meine Karte wurde diesen Monat zweimal belastet.</ticket>
  </input>
  <output_format>
    <classification>
      <label_id one_of="bug|billing|feature|other">string</label_id>
      <justification max_chars="180">Ein bis zwei Saetze.</justification>
    </classification>
  </output_format>
</prompt>

3) Email reply (professional and safe)

<prompt>
  <persona>
    <role>Customer Success Manager</role>
    <tone>Professionell, hilfsbereit, knapp</tone>
    <signature>Viele Gruesse, Alex (Customer Success)</signature>
  </persona>

  <task>Entwirf eine Antwort, die bestaetigt, beantwortet und naechste Schritte vorschlaegt.</task>

  <input>
    <email_from_customer><![CDATA[
      Hallo, ich komme nach dem Zuruecksetzen meines Passworts nicht mehr ins Dashboard.
    ]]></email_from_customer>
  </input>

  <output_format>
    <email>
      <subject>string</subject>
      <body>Klartext, kurze Absaetze</body>
      <next_steps>
        <step>Stichpunkt</step>
      </next_steps>
    </email>
  </output_format>
</prompt>

4) SQL generation with schema context

<prompt>
  <task>Erzeuge eine SQL-Abfrage aus einer natuerlichsprachlichen Frage und einem Schema.</task>
  <schema><![CDATA[
  tables:
    orders(order_id, customer_id, total, created_at)
    customers(customer_id, region)
  ]]></schema>
  <input>
    <question>Gesamtumsatz pro Region fuer das laufende Jahr 2024.</question>
  </input>
  <output_format>
    <sql><![CDATA[
      SELECT ...
    ]]></sql>
    <assumptions max="3">
      <item>kurzer Satz</item>
    </assumptions>
    <safety_checks>
      <check>Sind die Datumsfilter korrekt?</check>
      <check>Verbinden die Joins die richtigen Schluessel?</check>
    </safety_checks>
  </output_format>
</prompt>

5) Meeting notes to action items

<prompt>
  <task>Wandle ein Meeting-Transkript in strukturierte Notizen um.</task>
  <input>
    <transcript><![CDATA[(Transkript einfuegen)]]></transcript>
  </input>
  <output_format>
    <notes>
      <topics>
        <topic>...</topic>
      </topics>
      <decisions>
        <decision>...</decision>
      </decisions>
      <action_items>
        <item owner="Name" due="YYYY-MM-DD">...</item>
      </action_items>
    </notes>
  </output_format>
</prompt>

6) Intent routing (switch)

<prompt>
  <task>Leite die Nutzereingabe an den richtigen Handler weiter.</task>
  <handlers>
    <handler id="KB_SEARCH">Wissensdatenbank-Suche</handler>
    <handler id="HUMAN_HANDOFF">Uebergabe an Mensch</handler>
    <handler id="ORDER_STATUS">Bestellstatus</handler>
  </handlers>
  <input>
    <utterance>Wo ist meine Bestellung Nr. 1234?</utterance>
  </input>
  <output_format>
    <routing>
      <handler_id one_of="KB_SEARCH|HUMAN_HANDOFF|ORDER_STATUS">ORDER_STATUS</handler_id>
      <entities>
        <order_id>1234</order_id>
      </entities>
      <confidence>0-1</confidence>
    </routing>
  </output_format>
</prompt>

7) Critique and improve (self-check)

<prompt>
  <task>Kritisiere und verbessere den Entwurf, begrenze die Begruendung.</task>
  <constraints>
    <rationale_limit>120 Zeichen</rationale_limit>
  </constraints>
  <input>
    <draft><![CDATA[(Entwurf einfuegen)]]></draft>
  </input>
  <output_format>
    <improvement>
      <revised><![CDATA[(ueberarbeiteter Text)]]></revised>
      <rationale>max. 120 Zeichen</rationale>
      <checks>
        <check id="clarity">pass|fail</check>
        <check id="tone">pass|fail</check>
        <check id="length">pass|fail</check>
      </checks>
    </improvement>
  </output_format>
</prompt>

Parsing and validation

With the Python standard library you can read the XML output in just a few lines:

import xml.etree.ElementTree as ET

def parse_extraction(xml_text: str):
    root = ET.fromstring(xml_text)
    ext = root.find('extraction')
    return {
        "company": (ext.findtext('company') or '').strip(),
        "product": (ext.findtext('product') or '').strip(),
        "price": (ext.findtext('price') or '').strip(),
        "sentiment": (ext.findtext('sentiment') or '').strip(),
        "key_points": [e.text.strip() for e in ext.findall('key_points/bullet') if e.text]
    }

Validation checklist:

  • The root tag matches the expectation.
  • All required children exist (not empty, unless empty is permitted).
  • Allowed enumerations are respected (one_of attributes).
  • No unexpected tags (optional, but useful).

Robustness and anti-patterns

A few proven techniques make your prompts considerably more stable:

Anti-patternSolution
"Think step by step and show your reasoning."Ask for short key points or a checklist: <key_points max="5">.
Unnamed or generic tags like <section1>.Use domain nouns: <risks>, <mitigations>, <decision>.
Instructions mixed with examples.Put <instructions> and <examples> in separate blocks.
Free-text outputs when structure is needed.Specify an <output_format> with required children.
Code embedded without CDATA.Always wrap code, JSON and regex in CDATA.
Optional fields not specified.Define how unknowns are represented (empty tag).

FAQ

Why XML instead of Markdown headings? XML is machine-parseable and consistent. Markdown is good for humans, but ambiguous for machines.

Can I mix XML with Markdown? Yes. Keep the machine-readable parts in XML, human notes can sit as bullet points inside <instructions>.

What about security and compliance? Use <checks> to enforce rules such as no personal data or no medical or legal advice. On a violation, output an <error>.

How do I avoid rambling justifications? Limit them via attributes such as max_chars or max and prefer checklists over prose.

Three principles to take away

  • Short, specific tag names beat clever ones.
  • Show one complete example per prompt so the model imitates the format.
  • Prefer constraints over prose (150 words maximum, 3 bullet points, fixed enumerations).

Ready for your
AI Operating System?

Start today, and within a few weeks your first AI teammate takes over its first task. We only take on a handful of build slots per month.

by people.
for people.