From 2ba76e40dd17e7bce0b467d2be4b0bb1c9505f2b Mon Sep 17 00:00:00 2001 From: team3 Date: Wed, 24 Jun 2026 19:41:34 +0200 Subject: [PATCH] update --- backend/config.py | 2 +- backend/lernen.py | 29 ++++++++++++--------- templates/Prompt/Baustein-Frage-Variante.md | 1 + templates/Prompt/Baustein-Frage.md | 1 + templates/Prompt/Baustein-Lueckentext.md | 2 +- templates/Prompt/Baustein-Lueckwahl.md | 2 +- templates/Prompt/Baustein-Quiz.md | 2 +- 7 files changed, 22 insertions(+), 17 deletions(-) diff --git a/backend/config.py b/backend/config.py index f2a3914..11d9d66 100644 --- a/backend/config.py +++ b/backend/config.py @@ -25,7 +25,7 @@ LESBARKEIT_HART_ANTEIL = 0.30 # … ODER wenn dieser Anteil der Sätze hart ist # Eigene Spur für interaktive Aufrufe (Chat, Elemente), damit sie nicht hinter # laufenden Writern in der Warteschlange hängen. MAX_CONCURRENT_AGENTS = 10 -MAX_CONCURRENT_INTERACTIVE = 4 +MAX_CONCURRENT_INTERACTIVE = 8 # Grace-Fenster der Konsens-Races (Bausteine, Guide, OnePager): Nach dem ersten # gültigen Ergebnis dürfen die übrigen Agenten noch so viele Sekunden fertig diff --git a/backend/lernen.py b/backend/lernen.py index e28415e..8762206 100644 --- a/backend/lernen.py +++ b/backend/lernen.py @@ -148,21 +148,22 @@ def _bewertung_schema(data) -> dict | None: return {"feedback": feedback, "niveau": niveau} -async def _gen_call(name: str, role: str, schema, provider: str, timeout: int = PRUEFUNG_TIMEOUT, **kwargs) -> dict | None: - """Generator-Agent: Template füllen, laufen lassen, per schema parsen · None bei Fehler.""" +async def _gen_call(name: str, role: str, schema, provider: str, timeout: int = PRUEFUNG_TIMEOUT, lane: str = "interactive", **kwargs) -> dict | None: + """Generator-Agent: Template füllen, laufen lassen, per schema parsen · None bei Fehler. + lane="batch" für Hintergrund (Vorladen, Genau-Bewertung) → eigene Slot-Schlange.""" returncode, stdout, _ = await run_agent( name.lower() + "-" + str(uuid.uuid4()), _prompt(name, **kwargs), timeout, - provider=provider, role=role, capabilities="none", lane="interactive", + provider=provider, role=role, capabilities="none", lane=lane, ) return schema(_parse_json_text(stdout)) if returncode == 0 else None -async def _kritik_call(name: str, provider: str, role: str = "judge", timeout: int = PRUEFUNG_TIMEOUT, **kwargs) -> list[str]: +async def _kritik_call(name: str, provider: str, role: str = "judge", timeout: int = PRUEFUNG_TIMEOUT, lane: str = "interactive", **kwargs) -> list[str]: """Kritiker-Agent (Default role judge): leere Liste = in Ordnung. Fail-open: Ausfall des Kritikers darf den Turn nicht blockieren, also dann ebenfalls leere Liste.""" returncode, stdout, _ = await run_agent( name.lower() + "-" + str(uuid.uuid4()), _prompt(name, **kwargs), timeout, - provider=provider, role=role, capabilities="none", lane="interactive", + provider=provider, role=role, capabilities="none", lane=lane, ) if returncode != 0: return [] @@ -204,7 +205,7 @@ async def _frage_mit_kritik( frage = None for _ in range(KRITIK_MAX_RUNDEN): data = await _gen_call( - "Baustein-Frage", "guide", _frage_schema, provider, + "Baustein-Frage", "guide", _frage_schema, provider, lane="batch", topic=topic, baustein=baustein, section_block=section_block, kompakt_block=kompakt_block, transcript=transcript, vermeide_block=vermeide_block, typ_block=typ_block, fokus_block=fokus_block, kritik_block=kritik_block, @@ -213,7 +214,7 @@ async def _frage_mit_kritik( return None frage = data["frage"] probleme = await _kritik_call( - "Baustein-Frage-Kritik", provider, role="guide", # starke KI prüft die Regeln + "Baustein-Frage-Kritik", provider, role="guide", lane="batch", # starke KI prüft die Regeln topic=topic, baustein=baustein, section_block=section_block, kompakt_block=kompakt_block, transcript=transcript, vermeide_block=vermeide_block, typ_block=typ_block, fokus_block=fokus_block, frage=frage, @@ -238,11 +239,13 @@ async def _bewertung_mit_kritik( `role` = "judge" (schnell) oder "guide" (gründlich, starkes Modell mit Thinking). """ timeout = GRUENDLICH_TIMEOUT if role == "guide" else PRUEFUNG_TIMEOUT + # Gründlich (role guide) = Nutzer wartet → interaktiv. Hintergrund-Genau (judge) → batch. + lane = "interactive" if role == "guide" else "batch" kritik_block = "(keine)" bew = None for _ in range(KRITIK_MAX_RUNDEN): bew = await _gen_call( - "Baustein-Bewertung", role, _bewertung_schema, provider, timeout, + "Baustein-Bewertung", role, _bewertung_schema, provider, timeout, lane=lane, topic=topic, baustein=baustein, section_block=section_block, kompakt_block=kompakt_block, frage=frage, transcript=transcript, begruendung_block=begruendung_block, kritik_block=kritik_block, @@ -250,7 +253,7 @@ async def _bewertung_mit_kritik( if bew is None: return None probleme = await _kritik_call( - "Baustein-Bewertung-Kritik", provider, role=role, timeout=timeout, + "Baustein-Bewertung-Kritik", provider, role=role, timeout=timeout, lane=lane, topic=topic, baustein=baustein, section_block=section_block, kompakt_block=kompakt_block, frage=frage, transcript=transcript, bewertung_block=_bewertung_text(bew), @@ -309,7 +312,7 @@ async def pruefung_frage_variante( try: section_block, kompakt_block = _bloecke(section, kompakt) data = await _gen_call( - "Baustein-Frage-Variante", "guide", _frage_schema, provider, + "Baustein-Frage-Variante", "guide", _frage_schema, provider, lane="batch", topic=topic, baustein=baustein, section_block=section_block, kompakt_block=kompakt_block, muster=muster, ) @@ -378,7 +381,7 @@ async def quiz_generieren( "GENAU EINE Option ist richtig, die anderen drei sind klar falsch." ) return await _gen_call( - "Baustein-Quiz", "guide", (lambda d: _quiz_schema(d, schwer=schwer)), provider, + "Baustein-Quiz", "guide", (lambda d: _quiz_schema(d, schwer=schwer)), provider, lane="batch", topic=topic, baustein=baustein, section_block=section_block, kompakt_block=kompakt_block, muster=muster, anzahl_block=anzahl_block, ) @@ -396,7 +399,7 @@ async def lueckwahl_generieren( try: section_block, kompakt_block = _bloecke(section, kompakt) return await _gen_call( - "Baustein-Lueckwahl", "guide", _lueckwahl_schema, provider, + "Baustein-Lueckwahl", "guide", _lueckwahl_schema, provider, lane="batch", topic=topic, baustein=baustein, section_block=section_block, kompakt_block=kompakt_block, muster=muster, ) @@ -427,7 +430,7 @@ async def lueckentext_generieren( try: section_block, kompakt_block = _bloecke(section, kompakt) return await _gen_call( - "Baustein-Lueckentext", "guide", _lueck_schema, provider, + "Baustein-Lueckentext", "guide", _lueck_schema, provider, lane="batch", topic=topic, baustein=baustein, section_block=section_block, kompakt_block=kompakt_block, muster=muster, ) diff --git a/templates/Prompt/Baustein-Frage-Variante.md b/templates/Prompt/Baustein-Frage-Variante.md index fe3a7ab..bf4fc46 100644 --- a/templates/Prompt/Baustein-Frage-Variante.md +++ b/templates/Prompt/Baustein-Frage-Variante.md @@ -16,6 +16,7 @@ HARTE REGELN: - Gleiche Kernfrage wie das Muster, nur anders formuliert — KEINE neue Sache, KEINE wörtliche Kopie. - Frag nur, was aus dem Material beantwortbar ist. Keine erfundenen Zusatzannahmen. - Sprich den Lerner direkt an, klares Deutsch, keine Floskeln. +- `$…$` NUR für echte Mathematik. Code, Pfade, Namespaces, Dateinamen, JSON-Schlüssel/-Werte und Bezeichner gehören in Backticks oder Klartext — NIE in `$…$` (nicht `$Acme\Example$`, sondern `Acme\Example` in Backticks). Gib NUR dieses JSON aus (kein weiterer Text): {{"frage": "genau eine kurze Frage"}} diff --git a/templates/Prompt/Baustein-Frage.md b/templates/Prompt/Baustein-Frage.md index eeea7c3..7aa1184 100644 --- a/templates/Prompt/Baustein-Frage.md +++ b/templates/Prompt/Baustein-Frage.md @@ -31,6 +31,7 @@ HARTE REGELN FÜR DIE FRAGE — wichtiger als alles andere: FACHLICHE REFERENZ — WICHTIG: - Die Guide-Fassung und die Vertiefung oben sind die Referenz. Deine Frage darf ihr NIE widersprechen. - Erfinde keine Zusatzannahmen (z. B. fehlende Eingaben, geänderte Definitionen). Frag nur, was aus dem Material folgt. +- `$…$` NUR für echte Mathematik. Code, Pfade, Namespaces, Dateinamen, JSON-Schlüssel/-Werte und Bezeichner gehören in Backticks oder Klartext — NIE in `$…$` (nicht `$Acme\Example$`, sondern `Acme\Example` in Backticks). HINWEISE DES PRÜFERS ZUR LETZTEN FASSUNG: {kritik_block} diff --git a/templates/Prompt/Baustein-Lueckentext.md b/templates/Prompt/Baustein-Lueckentext.md index c0d9c66..c925a7d 100644 --- a/templates/Prompt/Baustein-Lueckentext.md +++ b/templates/Prompt/Baustein-Lueckentext.md @@ -17,7 +17,7 @@ AUFGABE: von `$…$` (nie innerhalb einer Formel). - Die Lücke prüft aktives Abrufen — sie steht für einen zentralen Fachbegriff, nicht für ein Füllwort. - Der Satz gibt genug Kontext, dass die Lösung eindeutig ist (keine Raterei). -- Fachbegriffe/Formeln dürfen als $…$ gesetzt werden (z. B. $V(w,c)$). +- `$…$` NUR für echte Mathematik (Variablen, Symbole, Formeln, z. B. $V(w,c)$). Code, Pfade, Namespaces, Dateinamen, JSON-Schlüssel/-Werte und Bezeichner gehören in Backticks oder Klartext — NIE in `$…$`. Beispiel: nicht `$Acme\Example$`, sondern `Acme\Example` in Backticks. - `loesung` = der erwartete Begriff (kurz, wie er in die Lücke gehört). - `alternativen` = akzeptierte Synonyme/Schreibweisen (kann leer sein), KEINE falschen. - Klares Deutsch, ein Satz, genau ein `___`. diff --git a/templates/Prompt/Baustein-Lueckwahl.md b/templates/Prompt/Baustein-Lueckwahl.md index 52b3a06..3167f73 100644 --- a/templates/Prompt/Baustein-Lueckwahl.md +++ b/templates/Prompt/Baustein-Lueckwahl.md @@ -16,7 +16,7 @@ AUFGABE: - Biete GENAU VIER Begriffe als Optionen — **genau einer** passt in die Lücke. - Die drei falschen sind plausibel, aber klar falsch (Verwechslung, verwandter Begriff) — keine Albernheiten. - Optionen kurz (Begriff oder kurzer Halbsatz), ähnlich lang. -- Fachbegriffe/Formeln dürfen als $…$ gesetzt werden. +- `$…$` NUR für echte Mathematik (Variablen, Symbole, Formeln). Code, Pfade, Namespaces, Dateinamen, JSON-Schlüssel/-Werte und Bezeichner gehören in Backticks oder Klartext — NIE in `$…$`. Beispiel: nicht `$Acme\Example$`, sondern `Acme\Example` in Backticks. Gib NUR dieses JSON aus (kein weiterer Text): {{"satz": "Ein ___ ist eine endliche Menge von Symbolen.", "optionen": [ diff --git a/templates/Prompt/Baustein-Quiz.md b/templates/Prompt/Baustein-Quiz.md index f9080e6..4e23826 100644 --- a/templates/Prompt/Baustein-Quiz.md +++ b/templates/Prompt/Baustein-Quiz.md @@ -18,7 +18,7 @@ AUFGABE: KEINE ganzen Sätze, KEIN „Weil …"-Vorspann, keine Begründungs-Prosa. Nur der Kern. - Alle vier Optionen ähnlich lang und im gleichen Stil. Keine verräterischen Hinweise. - Die Frage selbst knapp (1 Satz). Klares Deutsch. -- Fachbegriffe/Formeln dürfen als $…$ gesetzt werden (z. B. $V(w,c)=A(w)$). +- `$…$` NUR für echte Mathematik (Variablen, Symbole, Formeln, z. B. $V(w,c)=A(w)$). Code, Pfade, Namespaces, Dateinamen, JSON-Schlüssel/-Werte und Bezeichner gehören in Backticks oder Klartext — NIE in `$…$`. Beispiel: nicht `$Acme\Example$`, sondern `Acme\Example` in Backticks. Gib NUR dieses JSON aus (kein weiterer Text): {{"frage": "die Frage", "optionen": [