Skip to content

Native Language Engine - Architektur

Stand: 11.10.2026. Gehoert zum Auftrag "LENNY - NATIVE LANGUAGE ENGINE" (NLG-001..053). Der Ausgangspfad steht in IST_SPRACHPFAD.md, die bekannten Grenzen in SPRACHGRENZEN.md, der Abschlussbericht in ../LENNY_NATIVE_LANGUAGE_ENGINE_ABSCHLUSS.md.

1. Grundsatz

Lenny entscheidet, was gesagt werden darf (Wissen, Sicherheit, Konflikte, Admin-Sperren, Tenant-Grenzen). Die Native Language Engine entscheidet nur, wie es auf Deutsch gesagt wird. Sie erfindet keine Aussage, sie nimmt keine Sperre zurueck, und sie ruft kein generatives Modell auf - weder als Vorlage noch als Umformulierung, Politur oder Rueckfall. Ist keine gute Formulierung moeglich, spricht sie einen schlichten, immer grammatischen Satz (oder sagt ehrlich, dass sie nichts Belegtes sagen kann); nie ein Modell.

2. Die Pipeline

Router (ask_lenny, unveraendert: WAS gesagt werden darf)
   |  Mitschreiber legacy_capture an der Naht zwischen Wissen und Wortlaut (20 Wortlautfunktionen und drei Schnittstellen: Konflikt, Aussage, Aufgabe)
   v
Semantic Answer Frame (frame.py, frames_legacy.py)   Claims + Herkunft -> Sicherheitsklasse, Unknowns, Konflikte, Constraints, Stil, Scope   [NLG-001/002/003]
   v
Diskursplaner (discourse.py)        je Intent ein fester Antwortaufbau; wichtigste Aussage zuerst; must_include nie verlieren          [NLG-003/004]
   v
Satzplaene (constructions.py, sentence_plan.py)   Claim-Typ -> abstrakte Konstruktion mit Claim-IDs; noch kein String                  [NLG-005]
   v
Aggregation + Konnektoren (aggregation.py, connectors.py)   nur ohne neue Semantik; Konnektor nur bei geplanter Beziehung            [NLG-010/011]
   v
Realizer + Morphologie (realizer_de.py, morphology_de.py, lexicon.py)   Verbzweit/-end, Kasus, Genus, Numerus, Kontraktionen, "kein Raten"   [NLG-006/007/008]
   v
Referenz (reference.py)             Pronomen nur bei eindeutigem Bezug; sonst das Nomen                                                   [NLG-009]
   v
Anti-Wiederholung, Stil, Laenge (repetition.py, style.py)  veraendern nie Fakten                                                       [NLG-012/013/014]
   v
Native Quality Gates NG1-NG10 (quality.py)   unabhaengig vom Erzeuger; ein Hard-Fail verwirft den Kandidaten                           [NLG-030/031]
   v
Kandidatenwahl (engine.py)          mehrere Kandidaten je Versuch, Ranking nur unter den Gate-bestandenen                              [NLG-018/019]
   v
Selbstkorrektur (<= 3 interne Versuche) -> ehrliche Notantwort, nie LLM                                                              [NLG-037/038]
   v
Ausgangsweg des Servers (Fusszeile aus dem Feld, Umlaute, Status-Footer-Waechter, Sicherheitsgrad) - unveraendert

Alles in der Engine laeuft in firewall.native_scope(): kein Netz, kein generativer Aufruf.

3. Module

Modul Aufgabe NLG
frame.py Frame, Claim-Vertrag, Validierung (Claims, Unknowns, Konflikte, Constraints) 001, 002, 003
frames_legacy.py, legacy_capture.py Frames aus dem Mitschrieb des bestehenden Routers (Vertrauensregel, Sperre, Bestreitung schon angewandt); Schnittstellen melde_konflikt, melde_aussage, melde_aufgabe 001, 039
discourse.py Diskursplaner je Intent (Definition, Ja/Nein, Fakt, Kategorie, Liste, Vergleich, Warum, Zusammenfassung, Konflikt, Creative, Unknown ...) 003, 004
constructions.py, sentence_plan.py Satzplaene aus Claims 005, 010
lexicon.py, entries.py, morphology_de.py Lexikon (Nomen/Verben/Adjektive, Genus, Plural, Valenz), Morphologie 006, 007
realizer_de.py Syntax: Haupt-/Nebensatz, Relativsatz, Modalverb, Perfekt, trennbare Verben, Negation, Aufzaehlung 008
reference.py, context.py Referenz/Koreferenz, Gespraechskontext, Follow-ups (clarification/expansion/correction/comparison) 009, 035, 036
aggregation.py, connectors.py, repetition.py Aggregation, Konnektoren, Anti-Wiederholung 010, 011, 013
style.py, structure.py Stilprofile, Laengenstufen, Listen/Absaetze/Tabellen aus dem Plan 012, 014, 034
epistemic.py Unsicherheit, Konflikte, Creative - sprachlich nur aus dem epistemischen Zustand 015, 016, 017
quality.py Hard-Gates NG1-NG10, Metriken, weiches Ranking 019, 030, 031
engine.py Orchestrierung, Kandidaten, Selbstkorrektur, Notantwort 018, 019, 037, 038, 050
patterns.py, registry.py Sprachmuster-Speicher mit Lebenszyklus, Lernsignalen, Admin-Sperre; Verzeichnis aller eingebauten Muster 020-023, 046
audit.py Audit je Antwort, Sprach-Aenderungsprotokoll (language_change_id) 024, 047
firewall.py LLM-Call-Firewall (drei Schichten), Probe-Bereich 025, 048
modes.py, admin_routes.py Betriebsmodi, Admin-Deckel, Admin-Schnittstelle 026, 046
integration.py Anbindung an den Chat-Weg: begin/finish, Shadow-Arbeiter, Zaehler, /health 026, 027, 040, 042
identity.py Versionen (Engine, Lexikon, Grammatik, Pattern-Generation, Stil, Goldset) 051
gaps.py, probes.py, probe_realizer.py Abbildung auf die Luecken-Klassen des Selbstverbesserungskreises, Laufzeitproben, E-N12-Probe 044, 045

4. Anbindung an den Antwortpfad

  • api_server.py: _native_beginnen vor dem Router, _native_abschliessen danach. Der Import ist abgesichert (_NativeNichtGeladen): fehlt das Paket, laeuft der Server im Modus off weiter.
  • Naht: der Router sammelt seine Fakten und ruft eine Wortlautfunktion. Der Mitschreiber haengt sich genau dort ein und notiert Weg, Subjekt und die schon ausgewaehlten, vertrauensgefilterten Fakten. Daraus entsteht der Frame. Der Router entscheidet nichts anderes als zuvor.
  • Bezug im Gespraech (nur im Modus native): ein eindeutig aufgeloester Bezug ("Was ist das?") wird in die Frage geschrieben; fuer die ausgeschriebene Frage laeuft die Suche (Namensraum, Gegenprobe, Trefferguete) noch einmal, damit der Router eine passende Basis hat. Bei zwei moeglichen Bezuegen fragt die Engine nach, statt zu raten. Im Modus shadow sieht der Router immer die Frage des Nutzers.
  • Systemzugaenge (selfimprove, traverse-field) bekommen den Altwortlaut (Header X-Lenny-Sprache: aktuell waehlt ihn ausdruecklich): die Messungen des Selbstverbesserungskreises bleiben vergleichbar.
  • Gesetztes Wissen (persoenliches Gedaechtnis, Firmenwissen): die Engine bekommt die Saetze je Schicht und formuliert sie woertlich hinter dem Vorbehalt ihrer Herkunft; Widerspruchshinweise, die sich nicht als Saetze fassen lassen, bleiben deterministischer Altwortlaut (kein Modell), gezaehlt als kein_frame:schichten.
  • Konflikte: der bestehende Router hat keine eigene Konfliktquelle (der gewichtete Speicher schliesst widerspruechliche Eintraege vor der Antwort aus). legacy_capture.melde_konflikt(subjekt, seiten, text) ist die Schnittstelle fuer einen Weg, der einen Widerspruch kennt; die Engine stellt dann beide Seiten dar und entscheidet nichts.

  • Aussagen und Aufgaben (Nachrichtentyp aussage/aufgabe, zusammen rund 14 % des echten Verkehrs): die Reaktion des Routers (api_server._aussage_reaction und der Fallback am Ende der Pipeline) meldet ueber melde_aussage/melde_aufgabe, WELCHE Art von Reaktion es ist (deckt sich / neu / unbelegt / keine Grundlage) und mit welchen eigenen Fakten. Daraus entsteht ein Frame mit den Fakten als Claims (Herkunft und Admin-Sperre wie jeder Claim) und einem Unknown der Art statement_new|statement_unverified|statement_no_basis|task_no_basis; bei Deckung steht die Meldung ("statement", "matches") im Frame-Meta, und der Planer sagt das vor den Fakten. Der Inhalt der Nutzer-Aussage wird nie Claim und steht nie im Text; das Messprotokoll des Shadow-Betriebs enthaelt ihn ebenfalls nicht (weder Frage noch Altwortlaut).

5. Betriebsmodi

Modus Wirkung
off Altpfad. Die Engine laeuft nicht. (Standard)
shadow Der Nutzer bekommt den Altwortlaut; die Engine laeuft in einem Arbeiter-Thread mit und wird gemessen (shadow.jsonl: Frage, Weg, Native-Text, Legacy-Text, Gates, Zeit, llm_calls).
native Der Native-Text ist final. Die LLM-Verbalisation ist verboten (LENNY_ALLOW_LLM_VERBALIZER=0, Firewall prozessweit gesperrt); die Altschalter fuer Modellantworten sind wirkungslos.

Der wirksame Modus ist das Minimum aus Umgebung und Admin-Deckel. LENNY_LANGUAGE_MODE (Standard off); LENNY_ENABLE_NATIVE_SHADOW=1 / LENNY_ENABLE_NATIVE_LANGUAGE=1 heben den Modus nur an (die Schalter des Selbstverbesserungskreises kennen nur LENNY_ENABLE_*=1); in der Sandbox (LENNY_SI_SANDBOX=1) ist der wirksame Modus immer off.

Messwerkzeuge und Tests sind vom Sprachmodus unabhaengig (Fund vom 12.10.2026: der Umschaltkandidat - genau die eine Zeile LENNY_ENABLE_NATIVE_LANGUAGE=1 - scheiterte an Gate G2 mit 29 Fehlschlaegen, weil Werkzeuge und Tests den Stand 0 still voraussetzten):

  • Der Offline-Messlauf (ops/messung/offline_antwort.py) und der Probelauf nehmen die Schalter der Compose-Datei, setzen den Sprachmodus aber fest auf off (SPRACHMODUS_AUS, messschalter()). Sie messen Wege und Inhalte; wer die Sprachschicht messen will, uebergibt die Schalter ausdruecklich (schalter=).
  • Die lokale Instanz (ops/selfimprove/instance.py) setzt wie die Server-Sandbox LENNY_SI_SANDBOX=1: Vorher/Nachher und die Gates des Kreises messen am Altpfad, die Sprachschicht pruefen GN1-GN3 und die Native-Tests direkt.
  • Tests, die die Compose-Zeile selbst pruefen, kennen beide Staende (0 vor, 1 nach der Umschaltung). tests/test_native_schalterunabhaengig.py simuliert den Stand native unabhaengig vom Repository und haelt das fest.

6. LLM-Firewall (NLG-025/048)

Drei unabhaengige Schichten, unabhaengig von den Schaltern der Altpfade:

  1. Endpunkt-Sperre auf http.client.HTTPConnection.putrequest (der gemeinsame Boden von urllib, requests/urllib3 und http.client): generative Endpunkte (/api/generate, /api/chat, /v1/chat/completions, /v1/completions, /v1/messages, /v1/responses, :generateContent) werden gezaehlt und blockiert. Einbettung (/api/embed), Modellliste (/api/tags) und /health sind nicht generativ und bleiben erlaubt.
  2. Netz-Sperre: waehrend native_scope() (die gesamte Sprachgenerierung einer Antwort) ist jeder Verbindungsaufbau dieses Threads verboten - Native braucht kein Netz.
  3. Harter Schalter: im Modus native (oder mit LENNY_ALLOW_LLM_VERBALIZER=0) sind generative Endpunkte im ganzen Prozess gesperrt (set_global_block), auch ausserhalb des Scopes.

Ein Versuch ist ein Hard-Fail: er wird gezaehlt (llm_calls der Antwort, STATS.attempts), blockiert und als LlmFirewallViolation (ein ConnectionError) ausgeloest - so verhalten sich die Altpfade wie bei einem nicht erreichbaren Modell. Die Firewall bewertet nie Text, sie schaut nur auf den Weg eines Aufrufs.

Dazu: probe_scope() fuer absichtliche Probe-Versuche (gezaehlt als probe_blocked), Quelltext-Tests (kein Importweg von der Engine zum Legacy-Verbalizer; core/legacy_llm_verbalizer.py ist die einzige Anschlussschicht), und die Laufzeitprobe native_llm_frei (Invariante des Selbstverbesserungskreises, Probation-Watcher).

7. Quality Gates (NLG-030)

NG1 Semantic Fidelity - NG2 No Hallucination - NG3 Negation korrekt - NG4 Admin-Sperren - NG5 Truth/Creative - NG6 Unknown - NG7 Reference - NG8 Grammar Critical - NG9 LLM Independence - NG10 Tenant. Hard-Gates werden nie gegeneinander verrechnet. Ein Kandidat mit Hard-Fail ist verworfen, egal wie gut Stil oder Lesbarkeit sind. Kein Kandidat besteht: Selbstkorrektur (gezielt aus den gescheiterten Gates, dann minimal), danach die ehrliche Notantwort mit hard_fail=True (ein Sprach-Codefehler, der gemeldet wird).

8. Lernen und Admin

  • Gelernt werden abstrahierte Muster (Pattern-ID + Metadaten), nie Antworten; der Speicher enthaelt keinen einzigen Satz. Lebenszyklus: candidate -> tested -> active -> degraded (und zurueck nach active) sowie blocked (admin oder auto). Lernsignale (erneute Erklaerung, "unverstaendlich", Grammatik-Korrektur, Variantenpraeferenz, interne Grammatik-/Fidelity-/Goldfall-Ergebnisse) wirken nur auf die Sprache und nie auf die Wahrheit: record_signal lehnt jedes Signal ab, das Claims oder Fakten anfasst (NLG-023). Signale mit Scope aendern nur das Gewicht des Musters fuer diesen Scope.
  • Ein Admin kann Muster, Stilprofile und Lexeme sperren, Genus/Plural korrigieren und den Modus senken (/v1/admin/native/...). Eine Automatik hebt nie auf, was ein Admin gesetzt hat (AdminBlockError); jede Aenderung steht mit language_change_id im Protokoll.

9. Selbstverbesserung (NLG-044..047)

  • Sprachdefizite werden auf die bestehenden Klassen abgebildet (gaps.py): LANGUAGE_GRAMMAR / LEXICON / PATTERN / STYLE / REFERENCE_GAP -> DATA_GAP / RULE_GAP / CONFIG_GAP / CODE_GAP. Die Entscheidung trifft weiterhin core/si_klassifikation.
  • Coding-KI: Sprachcode wird nur ueber CODE_GAP -> Change-Spec -> Coding-KI -> Sandbox -> Language Goldset und allgemeine Gates -> Deploy -> Probation verbessert (keine eigene Strecke). Die Change-Spec fordert fuer Sprachpfade die Gates GN1-GN3 (Goldset, LLM-Freiheit, Sprachproben); sie laufen im Evaluator gegen die eingefrorenen Gates der Baseline in einem eigenen Worktree.
  • Invarianten im Planer: probe_native_realizer (Realizer-Fehler als CODE_GAP-Ausloeser, E-N12), native_llm_frei (hard_gate_verletzt, critical), native_sprachproben (hard_gate_verletzt, high).
  • Umschaltung shadow -> native ist ein CONFIG_GAP-Lauf (LENNY_ENABLE_NATIVE_LANGUAGE=1) mit Vorbedingungspruefung (controller erkenne-native-umschaltung: bewertete Basis, Vergleich, Shadow-Bericht, Benchmark mit Pruefsummen) und 24 Stunden Probation: der Host-Watcher prueft Antwortfehler, Native-Fallbackrate, LLM-Firewall, Goldset, Tenant, Admin-Sperren, Unknown, Konflikt und Creative; ein Hard-Fail setzt den Sprachmodus automatisch auf den vorigen Stand zurueck.

10. Identitaet und Reproduzierbarkeit (NLG-050/051)

/health -> native_language traegt Modus, Zaehler (Antworten, Fallbacks, Fehler, llm_calls), p95 der Latenz, Firewall-Zustand, Admin-Zustand und die Identitaet: language_engine_version, lexicon_version, grammar_version, pattern_generation, style_version, language_goldset_version. Mit festem Frame, Seed (LENNY_NATIVE_SEED), Lexikon-/Pattern-Version und Stil ist die Ausgabe Zeichen fuer Zeichen reproduzierbar (Test: wiederholte Laeufe ueber das Goldset).