Format des questions
tech-exam lit les questions depuis un fichier. Cette page décrit comment ce fichier doit être construit — afin qu'une IA de votre choix écrive des questions que vous reprenez ensuite dans votre collection. Tous les exemples présentés ici sont le contenu avec lequel démarre un nouveau compte et s'importeraient tels quels. La discipline qui y figure est un exemple et non un modèle : c'est la structure qui compte, pas le sujet.
Obtenir des questions avec sa propre IA
- Dans la collection de questions, choisir « Avec votre propre IA » et indiquer le thème, le nombre et le type de question.
- Ouvrir la consigne terminée dans un service d'IA ou la copier. Elle renvoie à cette page, afin que l'IA connaisse la construction du fichier.
- Copier le résultat depuis la conversation et le coller dans le même dialogue — ou l'enregistrer comme fichier et le lire via « Depuis un fichier ».
- Relire les questions dans la collection avant de tenir un examen avec elles. Les questions inventées contiennent parfois des erreurs qui paraissent crédibles.
La construction
À l'extérieur se trouvent un identifiant, un numéro de version et la liste des questions. Tout le reste appartient aux questions elles-mêmes. Un champ qui porte sa valeur par défaut est omis — c'est ainsi que se présentent les exemples de cette page, et un fichier rédigé à la main peut faire de même.
{
"format": "tech-exam/questions",
"formatVersion": 1,
"questions": [
{
"topic": "Beispielfragen",
"subtopic": "Fragetypen",
"subsubtopic": "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 behält die Reihenfolge der Einträge."
},
{
"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"
]
}
},
{
"topic": "Beispielfragen",
"subtopic": "Fragetypen",
"subsubtopic": "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
}
]
}
]
}Les champs
Une question doit porter trois champs : titre, type de question et points. Tous les autres peuvent manquer — c'est alors la troisième colonne qui s'applique. Un fichier avec trois champs justes vaut mieux qu'un fichier rempli de champs devinés.
Autour des questions
| Champ | Valeurs | S'il manque | Signification |
|---|---|---|---|
| format | "tech-exam/questions" | Obligatoire | L'identifiant auquel le fichier se reconnaît. Il est toujours le même. |
| formatVersion | 1 | Obligatoire | Le numéro de la construction. |
| questions | [ … ] | Obligatoire | Les questions. Chacune est soit une question avec zone de réponse, soit une question avec des sous-questions. |
Sur chaque question
| Champ | Valeurs | S'il manque | Signification |
|---|---|---|---|
| title | Text | Obligatoire | Le titre affiché au-dessus de la question. |
| contentType | "svg" · "tigerpython" · "tigerpython_robotik" · "python" · "mc" · "lueckentext" · "langtext" | Obligatoire | Comment on répond : « mc » un choix, « lueckentext » des lacunes dans un texte, « langtext » du texte suivi, « python » et « tigerpython » du code, « tigerpython_robotik » un programme pour le micro:bit ou un robot qui le porte, « svg » un dessin. |
| maxPoints | ≥ 0.5 | Obligatoire | Le nombre de points que la question donne au maximum. |
| topic | Text | "" | Le dossier dans la collection. |
| subtopic | Text | "" | Le sous-dossier. |
| subsubtopic | Text | "" | Le sous-sous-dossier. |
| description | Text | null | L'énoncé. Pour un texte à trous il reste vide, car ce texte se trouve dans les segments. |
| descriptionFormat | "markdown" · "html" | "markdown" | Comment l'énoncé est composé. Markdown connaît les tableaux, les blocs de code et les formules entre signes dollar. |
| solution | Text | null | Le corrigé. Visible uniquement par les enseignants. |
| starterCode | Text | null | Du code déjà présent dans l'éditeur à l'ouverture de la question. |
| answerSpec | { … } | null | Les réponses proposées. Nécessaire pour un choix et pour un texte à trous, à omettre sinon. |
| answerKey | { … } | null | La bonne réponse. Elle utilise les mêmes identifiants que answerSpec. |
| criteria | [ … ] | [] | Les consignes de correction : un texte pour les élèves et les points correspondants. Les points avec un plus s'ajoutent à l'évaluation, ceux avec un moins en sont retirés. |
| graderCode | Text | null | Du code Python qui attribue lui-même les points de cette question, au lieu de les donner à la main. Il est exécuté dès qu'on corrige avec lui. |
| graderRules | { … } | {} | Ce qui s'applique lorsque le programme d'un rendu ne s'exécute pas ou ne se termine pas. N'a de sens que pour « python » et « tigerpython ». |
Programmer et dessiner
Pour « tigerpython », « tigerpython_robotik », « python » et « svg », la réponse se donne dans un environnement intégré. Avec « tigerpython_robotik », l'appareil y est activé : l'environnement affiche le simulateur du micro:bit et, dès que le programme importe une bibliothèque robotique, celui du robot. « starterCode » y dépose ce qui figure déjà à l'ouverture de la question. « graderCode » attribue les points lui-même : une fonction Python « grade(answer, task, run) » qui renvoie des points et un retour — « answer » est le rendu, « task » la question avec ses points, « run » l'exécution du programme et sa sortie. « graderRules » prend en charge les deux cas où un programme ne s'exécute pas jusqu'au bout. Le code de correction est exécuté dès qu'on corrige avec lui ; l'import le signale expressément, et il se lit avant d'être repris.
{
"format": "tech-exam/questions",
"formatVersion": 1,
"questions": [
{
"topic": "Beispielfragen",
"subtopic": "Programmieren",
"subsubtopic": "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
}
]
},
{
"topic": "Beispielfragen",
"subtopic": "Programmieren",
"subsubtopic": "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
}
]
},
{
"topic": "Beispielfragen",
"subtopic": "Programmieren",
"subsubtopic": "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."
}
}
},
{
"topic": "Beispielfragen",
"subtopic": "Programmieren",
"subsubtopic": "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
}
]
}
]
}Texte à trous
Le texte à trous est le seul type dont l'énoncé ne figure pas dans « description » : son texte se trouve entièrement dans les segments. Une lacune sans choix se saisit au clavier, une lacune avec choix se clique — et chaque lacune a besoin du même identifiant des deux côtés.
{
"format": "tech-exam/questions",
"formatVersion": 1,
"questions": [
{
"topic": "Beispielfragen",
"subtopic": "Fragetypen",
"subsubtopic": "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"
]
}
}
}
}
]
}Questions avec sous-questions
Lorsque plusieurs parties partagent un même énoncé, les sous-questions prennent la place du type et des points. Le texte commun figure alors en haut, le reste auprès d'elles. Dans la collection, chaque partie devient une question à part entière qui emporte le texte commun. — c'est pourquoi ces trois-là figurent aussi séparément plus haut sur cette page. Ici, elles ne portent que le titre, le type et les points, car une sous-question n'exige rien de plus.
| Champ | Valeurs | S'il manque | Signification |
|---|---|---|---|
| title | Text | Obligatoire | Le titre affiché au-dessus de la question. |
| subQuestions | [ … ] | Obligatoire | Les sous-questions. Chacune porte son propre type et ses propres points. |
| description | Text | null | L'énoncé. Pour un texte à trous il reste vide, car ce texte se trouve dans les segments. |
{
"format": "tech-exam/questions",
"formatVersion": 1,
"questions": [
{
"title": "Robotik mit dem micro:bit",
"description": "Die beiden Teilfragen programmieren dasselbe Gerät: zuerst sein Display, dann den Roboter, auf dem es sitzt.\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
}
]
}
]
}Ce qui vaut encore
- Les points valent au moins 0.5 et ont au plus 2 décimales.
- Chaque identifiant de « answerKey » doit exister dans « answerSpec », sans quoi la question ne s'ouvre pas.
- Une question à choix a besoin d'au moins deux réponses et d'au moins une réponse juste.
- Le fichier n'emporte pas d'images. Elles s'ajoutent ensuite dans l'éditeur.
- Le fichier ne contient rien d'autre que les questions — aucune phrase avant, aucune explication après.