Fragenformat

tech-exam liest Fragen aus einer Datei ein. Diese Seite beschreibt, wie sie aufgebaut sein muss — damit eine KI Ihrer Wahl Fragen schreiben kann, die Sie danach in Ihre Sammlung übernehmen. Alle Beispiele hier sind der Inhalt, mit dem ein neues Konto startet, und liessen sich unverändert einlesen. Das Fach darin ist ein Beispiel und kein Vorbild: Gefragt ist der Aufbau, nicht das Thema.

Mit einer eigenen KI zu Fragen kommen

  1. In der Fragensammlung «Mit eigener KI» wählen und dort Thema, Anzahl und Aufgabentyp vorgeben.
  2. Den fertigen Auftrag in einem KI-Dienst öffnen oder ihn kopieren. Er verweist auf diese Seite, damit die KI den Aufbau kennt.
  3. Das Ergebnis aus dem Chat kopieren und im selben Dialog einfügen — oder als Datei sichern und über «Aus Datei» einlesen. Gehören Bilder dazu, gibt die KI ein ZIP aus, das im selben Dialog hochgeladen wird.
  4. Die Fragen in der Sammlung durchlesen, bevor eine Prüfung damit gehalten wird. Erfundene Fragen enthalten mitunter Fehler, die glaubwürdig aussehen.

Ohne Kopieren: die KI direkt verbinden

Statt Fragen hin- und herzukopieren, lässt sich ein KI-Werkzeug wie Claude oder ChatGPT direkt mit der eigenen Fragensammlung verbinden: als Konnektor mit der Adresse «https://tech-exam.ch/mcp». Wie das in den einzelnen Werkzeugen geht und was die KI damit darf, steht unter KI-Werkzeug verbinden. Ein verbundenes Werkzeug kennt den Aufbau der Fragen bereits; die Beschreibung unten braucht es nicht.

Der Aufbau

Aussen stehen eine Kennung, eine Versionsnummer und die Liste der Fragen. Alles Weitere gehört zu den Fragen selbst. Ein Feld, das seinen Vorgabewert trägt, wird weggelassen — so sehen die Beispiele auf dieser Seite aus, und so darf auch eine geschriebene Datei aussehen.

{
  "format": "tech-exam/questions",
  "formatVersion": 2,
  "questions": [
    {
      "folder": [
        "Beispielfragen",
        "Fragetypen",
        "Multiple Choice"
      ],
      "title": "Aussagen über Listen",
      "contentType": "mc",
      "maxPoints": 4,
      "description": "Welche Aussagen über Listen in Python sind richtig?",
      "answerSpec": {
        "kind": "mc",
        "options": [
          {
            "id": "o1",
            "text": "Eine Liste ist veränderbar."
          },
          {
            "id": "o2",
            "text": "Eine Liste kann nur Zahlen enthalten."
          },
          {
            "id": "o3",
            "text": "Eine Liste mit $n$ Einträgen hat die Indizes $0$ bis $n-1$."
          },
          {
            "id": "o4",
            "text": "`len(zahlen)` gibt den grössten Wert der Liste zurück."
          }
        ],
        "multiple": true,
        "scoring": {
          "mode": "allOrNothing"
        }
      },
      "answerKey": {
        "kind": "mc",
        "correct": [
          "o1",
          "o3"
        ]
      }
    },
    {
      "folder": [
        "Beispielfragen",
        "Fragetypen",
        "Langtext"
      ],
      "title": "Wann Liste, wann Dictionary?",
      "contentType": "langtext",
      "maxPoints": 6,
      "description": "Begründe in einem Abschnitt, wann sich eine Liste besser eignet als ein Dictionary – und wann umgekehrt. Nenne je ein Beispiel.",
      "solution": "Eine Liste passt, wenn die Reihenfolge zählt und alle Einträge der Reihe nach durchlaufen werden, etwa eine Rangliste.\n\nEin Dictionary passt, wenn ein Wert über einen Schlüssel gefunden werden soll, etwa die Note zu einem Namen: Der Zugriff bleibt gleich schnell, egal wie viele Einträge dazukommen.\n",
      "criteria": [
        {
          "text": "Die Begründung trifft das Entscheidende: Reihenfolge und Durchlaufen bei der Liste, Zugriff über den Schlüssel beim Dictionary.",
          "points": 3
        },
        {
          "text": "Zu beiden Fällen steht ein konkretes Beispiel, das das genannte Merkmal wirklich braucht.",
          "points": 3
        }
      ]
    }
  ]
}

Die Felder

Drei Felder muss eine Frage tragen: Titel, Aufgabentyp und Punktzahl. Alle übrigen dürfen fehlen — dann gilt, was in der dritten Spalte steht. Eine Datei mit drei richtigen Feldern ist mehr wert als eine mit lauter geratenen.

Aussen um die Fragen

FeldWerteFehlt es, giltBedeutung
format"tech-exam/questions"PflichtDie Kennung, an der die Datei erkannt wird. Sie lautet immer gleich.
formatVersion2PflichtDie Nummer des Aufbaus.
questions[ … ]PflichtDie Fragen. Jede ist entweder eine Frage mit Antwortbereich oder eine Frage mit Teilfragen.

An jeder Frage

FeldWerteFehlt es, giltBedeutung
titleTextPflichtDer Titel, der über der Aufgabe steht.
contentType"svg" · "tigerpython" · "tigerpython_robotik" · "python" · "python_robotik" · "mc" · "lueckentext" · "langtext" · "zuordnung" · "zeichnung"PflichtWomit geantwortet wird: «mc» Auswahl, «lueckentext» Lücken im Text, «zuordnung» Paare, «langtext» Fliesstext, «python» und «tigerpython» Programmcode, «tigerpython_robotik» und «python_robotik» ein Programm für den micro:bit oder einen Roboter daran, «svg» eine SVG-Grafik, «zeichnung» Handschrift oder Skizze.
maxPoints≥ 0.5PflichtWie viele Punkte die Frage höchstens gibt.
folder[ "Text", … ][]Der Ordnerweg in der Sammlung, von oben: ["Ordner", "Unterordner", …]. Leer heisst ohne Ordner.
descriptionTextnullDie Aufgabenstellung. Beim Lückentext bleibt sie leer, weil dessen Text in den Segmenten steht.
descriptionFormat"markdown" · "html""markdown"Wie die Aufgabenstellung gesetzt ist. Markdown kennt Tabellen, Code-Blöcke und Mathe zwischen Dollarzeichen.
solutionTextnullDie Musterlösung. Nur für Lehrpersonen sichtbar.
starterCodeTextnullCode, der im Editor schon dasteht, wenn die Aufgabe geöffnet wird.
answerSpec{ … }nullDie Antwortmöglichkeiten. Nötig bei Auswahl, Lückentext und Zuordnung, bei der Zeichnung die Zeichenfläche, sonst weglassen.
answerKey{ … }nullDie richtige Antwort. Sie benutzt dieselben Kennungen wie answerSpec.
criteria[ … ][]Korrekturanweisungen: je ein Text für die Lernenden und die Punkte dazu. Punkte mit Plus kommen zur Bewertung dazu, Punkte mit Minus gehen weg.
graderCodeTextnullPython-Code, der die Punkte dieser Frage selbst vergibt, statt sie von Hand geben zu lassen. Er wird ausgeführt, sobald damit korrigiert wird.
graderRules{ … }{}Was gilt, wenn das Programm einer Abgabe nicht läuft oder nicht fertig wird. Nur bei «python» und «tigerpython» von Bedeutung.

Programmieren und Zeichnen

Bei «tigerpython», «tigerpython_robotik», «python», «python_robotik» und «svg» wird in einer eingebetteten Umgebung geantwortet. Bei «tigerpython_robotik» und «python_robotik» ist dort das Gerät eingeschaltet: Die Umgebung zeigt den Simulator des micro:bit, und sobald das Programm eine Roboterbibliothek einbindet, auch den des Roboters. «starterCode» legt hinein, was dort schon dasteht, wenn die Aufgabe geöffnet wird. «graderCode» vergibt die Punkte selbst: eine Python-Funktion «grade(answer, task, run)», die Punkte und Rückmeldung zurückgibt — «answer» ist die Abgabe, «task» die Aufgabe samt ihrer Punktzahl, «run» der Lauf des Programms mit seiner Ausgabe. «graderRules» nimmt ihr die beiden Fälle ab, in denen ein Programm gar nicht erst durchläuft. Bewertungscode wird ausgeführt, sobald damit korrigiert wird; beim Einlesen wird eigens darauf hingewiesen, und er gehört vorher gelesen.

{
  "format": "tech-exam/questions",
  "formatVersion": 2,
  "questions": [
    {
      "folder": [
        "Beispielfragen",
        "Programmieren",
        "TigerPython"
      ],
      "title": "Quadrat mit repeat",
      "contentType": "tigerpython",
      "maxPoints": 6,
      "description": "Zeichne mit der Turtle ein Quadrat mit Seitenlänge 100. Nutze dafür die `repeat`-Schleife von TigerPython.",
      "solution": "from gturtle import *\n\nmakeTurtle()\nrepeat 4:\n    forward(100)\n    right(90)\n",
      "criteria": [
        {
          "text": "`repeat 4:` wiederholt den eingerückten Block viermal – für ein Quadrat braucht es genau vier Durchgänge.",
          "points": 3
        },
        {
          "text": "Im Schleifenkörper gehören `forward(100)` und `right(90)` zusammen; ohne die Drehung entsteht eine Linie statt eines Quadrats.",
          "points": 3
        },
        {
          "text": "Ohne `makeTurtle()` gibt es nichts, was zeichnen könnte – das Programm bleibt gleich zu Beginn stehen.",
          "points": -1
        }
      ]
    },
    {
      "folder": [
        "Beispielfragen",
        "Programmieren",
        "Roboter"
      ],
      "title": "Zwei Sekunden geradeaus",
      "contentType": "tigerpython_robotik",
      "maxPoints": 3,
      "description": "Lass den Roboter zwei Sekunden geradeaus fahren und danach anhalten.",
      "solution": "from mbrobot import *\n\nforward()\ndelay(2000)\nstop()\n",
      "criteria": [
        {
          "text": "`forward()` setzt den Roboter in Bewegung, `stop()` hält ihn wieder an.",
          "points": 2
        },
        {
          "text": "`delay(2000)` lässt dazwischen zwei Sekunden verstreichen – ohne die Wartezeit steht er, bevor er losgefahren ist.",
          "points": 1
        }
      ]
    },
    {
      "folder": [
        "Beispielfragen",
        "Programmieren",
        "Python"
      ],
      "title": "Summe zweier Zahlen",
      "contentType": "python",
      "maxPoints": 10,
      "description": "Schreibe eine Funktion `add(a, b)`, die die Summe der beiden Argumente zurückgibt.",
      "solution": "def add(a, b):\n    return a + b\n",
      "starterCode": "def add(a, b):\n    # Gib hier die Summe von a und b zurück.\n    pass\n",
      "graderCode": "def grade(answer, task, run):\n    # Die Abgabe ausführen und die Funktion aus der Musterlösung holen. Ob sie\n    # sich überhaupt ausführen lässt, entscheiden die Regeln über diesem Feld.\n    umgebung = {}\n    exec(answer[\"value\"], umgebung)\n\n    funktion = umgebung.get(\"add\")  # Name aus der Musterlösung\n    if not callable(funktion):\n        return {\"points\": 0, \"feedback\": \"Die Funktion «add» fehlt.\"}\n\n    faelle = [((1, 2), 3), ((-1, 1), 0), ((0, 0), 0)]  # (Argumente, erwartet)\n    treffer = 0\n    for argumente, erwartet in faelle:\n        try:\n            if funktion(*argumente) == erwartet:\n                treffer += 1\n        except Exception:\n            pass\n\n    return {\n        \"points\": round(task[\"maxPoints\"] * treffer / len(faelle), 2),\n        \"feedback\": f\"{treffer} von {len(faelle)} Testfällen bestanden.\",\n    }\n",
      "graderRules": {
        "error": {
          "points": 0,
          "feedback": "Das Programm läuft nicht."
        },
        "timeout": {
          "points": 0,
          "feedback": "Das Programm wird nicht fertig."
        }
      }
    },
    {
      "folder": [
        "Beispielfragen",
        "Programmieren",
        "Knöpfe"
      ],
      "title": "Losfahren auf Knopfdruck",
      "contentType": "python_robotik",
      "maxPoints": 4,
      "description": "Knopf A lässt den Roboter geradeaus losfahren, Knopf B hält ihn wieder an – beliebig oft, bis das Programm gestoppt wird.\n\nEine `repeat`-Schleife gibt es in dieser Umgebung nicht; verwende `while True:`.",
      "solution": "from microbit import *\nfrom mbrobot import *\n\nwhile True:\n    if button_a.was_pressed():\n        forward()\n    if button_b.was_pressed():\n        stop()\n    sleep(10)\n",
      "criteria": [
        {
          "text": "Die Abfragen stehen in einer `while True:`-Schleife – ohne sie prüft das Programm die Knöpfe ein einziges Mal, gleich beim Start.",
          "points": 2
        },
        {
          "text": "Knopf A startet mit `forward()`, Knopf B hält mit `stop()` an.",
          "points": 2
        }
      ]
    },
    {
      "folder": [
        "Beispielfragen",
        "Programmieren",
        "SVG"
      ],
      "title": "Roter Kreis",
      "contentType": "svg",
      "maxPoints": 10,
      "description": "Zeichne mit SVG einen roten Kreis mit Radius 50 in der Mitte einer Zeichenfläche von $200 * 200$.",
      "solution": "<svg viewBox=\"0 0 200 200\">\n  <circle cx=\"100\" cy=\"100\" r=\"50\" fill=\"red\" />\n</svg>\n",
      "starterCode": "<svg viewBox=\"0 0 200 200\">\n  <!-- Zeichne den Kreis hier hinein. -->\n</svg>\n",
      "criteria": [
        {
          "text": "`cx` und `cy` liegen bei `100`, also in der Mitte der Zeichenfläche, und `r` bei `50`.",
          "points": 6
        },
        {
          "text": "`fill=\"red\"` füllt den Kreis rot – ohne `fill` zeichnet der Browser schwarz.",
          "points": 4
        }
      ]
    }
  ]
}

Lückentext

Der Lückentext ist der einzige Typ, dessen Aufgabenstellung nicht in «description» steht: Sein Text liegt vollständig in den Segmenten. Eine Lücke ohne Auswahl wird getippt, eine mit Auswahl angeklickt — und jede Lücke braucht dieselbe Kennung auf beiden Seiten.

{
  "format": "tech-exam/questions",
  "formatVersion": 2,
  "questions": [
    {
      "folder": [
        "Beispielfragen",
        "Fragetypen",
        "Lückentext"
      ],
      "title": "Klammern in Python",
      "contentType": "lueckentext",
      "maxPoints": 2,
      "answerSpec": {
        "kind": "cloze",
        "segments": [
          {
            "type": "text",
            "text": "Eine Liste wird mit "
          },
          {
            "type": "gap",
            "id": "g1",
            "choices": null
          },
          {
            "type": "text",
            "text": " erzeugt, ein Dictionary mit "
          },
          {
            "type": "gap",
            "id": "g2",
            "choices": [
              {
                "id": "g2c1",
                "text": "geschweiften Klammern"
              },
              {
                "id": "g2c2",
                "text": "runden Klammern"
              },
              {
                "id": "g2c3",
                "text": "spitzen Klammern"
              }
            ]
          },
          {
            "type": "text",
            "text": "."
          }
        ],
        "compare": {
          "caseSensitive": false,
          "normalizeWhitespace": true,
          "numericTolerance": null
        }
      },
      "answerKey": {
        "kind": "cloze",
        "gaps": {
          "g1": {
            "type": "text",
            "accepted": [
              "eckigen Klammern"
            ]
          },
          "g2": {
            "type": "choice",
            "correct": [
              "g2c1"
            ]
          }
        }
      }
    }
  ]
}

Zuordnung

Bei «zuordnung» stehen in «answerSpec» die Begriffe («items») und die Antworten, unter denen gewählt wird («choices»); «answerKey» nennt zu jedem Begriff die Kennung seiner Antwort. Mehrere Begriffe dürfen dieselbe Antwort haben, und eine Antwort, auf die kein Begriff zeigt, macht das Raten schwerer. Die Lernenden wählen pro Begriff aus einer Liste, jedes richtige Paar zählt gleich viel.

{
  "format": "tech-exam/questions",
  "formatVersion": 2,
  "questions": [
    {
      "folder": [
        "Beispielfragen",
        "Fragetypen",
        "Zuordnung"
      ],
      "title": "Datentypen erkennen",
      "contentType": "zuordnung",
      "maxPoints": 4,
      "description": "Ordne jedem Wert seinen Datentyp in Python zu.",
      "answerSpec": {
        "kind": "matching",
        "items": [
          {
            "id": "i1",
            "text": "[1, 2, 3]"
          },
          {
            "id": "i2",
            "text": "{\"note\": 5}"
          },
          {
            "id": "i3",
            "text": "(1, 2)"
          },
          {
            "id": "i4",
            "text": "\"Hallo\""
          }
        ],
        "choices": [
          {
            "id": "c1",
            "text": "Dictionary"
          },
          {
            "id": "c2",
            "text": "Liste"
          },
          {
            "id": "c3",
            "text": "Menge"
          },
          {
            "id": "c4",
            "text": "String"
          },
          {
            "id": "c5",
            "text": "Tupel"
          }
        ]
      },
      "answerKey": {
        "kind": "matching",
        "pairs": {
          "i1": "c2",
          "i2": "c1",
          "i3": "c5",
          "i4": "c4"
        }
      }
    }
  ]
}

Zeichnung

Bei «zeichnung» steht in «answerSpec» die Zeichenfläche: «grid» schaltet das karierte Raster ein, «text» erlaubt getippten Text (sonst nur Handschrift und Formen), «background» ist ein Vorlagebild, auf dem gezeichnet wird, oder «null». Jedes Feld darf fehlen. Bewertet wird von Hand, nach Musterlösung und Korrekturanweisungen.

{
  "format": "tech-exam/questions",
  "formatVersion": 2,
  "questions": [
    {
      "folder": [
        "Beispielfragen",
        "Fragetypen",
        "Zeichnung"
      ],
      "title": "Suchbaum skizzieren",
      "contentType": "zeichnung",
      "maxPoints": 3,
      "description": "Füge die Zahlen 5, 3, 8 und 1 in dieser Reihenfolge in einen leeren binären Suchbaum ein. Zeichne den Baum, der dabei entsteht.",
      "solution": "Die 5 ist die Wurzel. Die 3 hängt links an der 5, die 8 rechts. Die 1 hängt links an der 3.\n",
      "answerSpec": {
        "kind": "drawing",
        "grid": true,
        "text": true,
        "background": null
      },
      "criteria": [
        {
          "text": "Die Wurzel ist die 5, mit der 3 links und der 8 rechts.",
          "points": 2
        },
        {
          "text": "Die 1 hängt links an der 3.",
          "points": 1
        }
      ]
    }
  ]
}

Fragen mit Teilfragen

Gehören mehrere Teilaufgaben zu einer gemeinsamen Aufgabenstellung, treten an die Stelle von Aufgabentyp und Punktzahl die Teilfragen. Der gemeinsame Text steht dann oben, alles Übrige bei ihnen. So kommt die Frage in die Fragensammlung wie in eine Prüfung: als eine Frage mit ihren Teilfragen darunter. Weiter oben auf dieser Seite stehen dieselben drei Fragen einzeln, so wie sie im Beispielinhalt der Sammlung liegen. Hier tragen sie nur Titel, Aufgabentyp und Punktzahl, denn mehr verlangt eine Teilfrage nicht.

FeldWerteFehlt es, giltBedeutung
titleTextPflichtDer Titel, der über der Aufgabe steht.
subQuestions[ … ]PflichtDie Teilfragen. Aufgabentyp und Punkte trägt jede von ihnen selbst.
descriptionTextnullDie Aufgabenstellung. Beim Lückentext bleibt sie leer, weil dessen Text in den Segmenten steht.
{
  "format": "tech-exam/questions",
  "formatVersion": 2,
  "questions": [
    {
      "title": "Robotik mit dem micro:bit",
      "description": "Die drei Teilfragen programmieren dasselbe Gerät: zuerst sein Display, dann den Roboter, auf dem es sitzt, und zuletzt beides zusammen – diesmal in Python ohne die TigerJython-Erweiterungen.\n\nZum Ausprobieren braucht es keine Hardware – die Programmierumgebung zeigt beides im Simulator.",
      "subQuestions": [
        {
          "title": "Ein blinkendes Herz",
          "contentType": "tigerpython_robotik",
          "maxPoints": 4
        },
        {
          "title": "Zwei Sekunden geradeaus",
          "contentType": "tigerpython_robotik",
          "maxPoints": 3
        },
        {
          "title": "Losfahren auf Knopfdruck",
          "contentType": "python_robotik",
          "maxPoints": 4
        }
      ]
    }
  ]
}

Bilder

Braucht eine Frage ein Bild — ein Diagramm, eine Schaltung, eine Skizze —, kommt die Datei in ein ZIP: «questions.json» zuoberst, die Bilder im Ordner «images» daneben. Im Text verweist die Frage mit einem Markdown-Bild darauf, etwa «![Schaltung](images/schaltung.png)». Das geht überall, wo Text steht: in «description», in «solution», in den Textsegmenten eines Lückentexts und in den Antwortmöglichkeiten. Wie breit das Bild erscheint, steht in Anführungszeichen dahinter: «![Schaltung](images/schaltung.png "w=50")» zeigt es halb so breit wie die Textspalte. Die Zahl ist eine ganze Zahl von 1 bis 100 und meint Prozent der Spaltenbreite. Ohne Angabe erscheint das Bild in seiner eigenen Grösse, höchstens so breit wie die Spalte.

{
  "format": "tech-exam/questions",
  "formatVersion": 2,
  "questions": [
    {
      "folder": [
        "Beispielfragen",
        "Programmieren",
        "TigerPython"
      ],
      "title": "Quadrat mit repeat",
      "contentType": "tigerpython",
      "maxPoints": 6,
      "description": "Zeichne mit der Turtle ein Quadrat mit Seitenlänge 100. Nutze dafür die `repeat`-Schleife von TigerPython.\n\n![Quadrat](images/quadrat.png \"w=40\")"
    }
  ]
}

Ein HTML-Tag wie «<img src="images/schaltung.png" width="200">» erscheint in einem Markdown-Text nicht — die Breite gehört dort immer in die Anführungszeichen. Nur wenn die Frage «descriptionFormat»: «html» trägt, steht das Bild als «<img src="images/schaltung.png" style="width: 50%">». Die Bilddatei selbst kleiner zu machen, ist nicht nötig, um ein Bild kleiner zu zeigen. Erlaubt sind PNG, JPEG, WebP, GIF und SVG, jedes Bild höchstens 5 MB; beim Einlesen werden sie verkleinert. Ein Bild, auf das keine Frage verweist, wird nicht übernommen. Ohne Bilder genügt die Datei allein. Eine Bildadresse aus dem Internet gehört nicht hinein: Sie kann verschwinden und lädt in der Prüfung womöglich nicht.

Was sonst noch gilt

  • Die Punktzahl ist mindestens 0.5 und hat höchstens 2 Nachkommastellen.
  • Jede Kennung in «answerKey» muss es in «answerSpec» geben, sonst lässt sich die Frage nicht öffnen.
  • Eine Auswahlfrage braucht mindestens zwei Antwortmöglichkeiten und mindestens eine richtige.
  • Die Datei enthält nichts ausser den Fragen — keinen einleitenden Satz davor, keine Erklärung danach.