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_beginnenvor dem Router,_native_abschliessendanach. 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 Modusshadowsieht der Router immer die Frage des Nutzers. - Systemzugaenge (
selfimprove,traverse-field) bekommen den Altwortlaut (HeaderX-Lenny-Sprache: aktuellwaehlt 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_reactionund der Fallback am Ende der Pipeline) meldet uebermelde_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 Artstatement_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 aufoff(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-SandboxLENNY_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.pysimuliert den Standnativeunabhaengig vom Repository und haelt das fest.
6. LLM-Firewall (NLG-025/048)¶
Drei unabhaengige Schichten, unabhaengig von den Schaltern der Altpfade:
- 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/healthsind nicht generativ und bleiben erlaubt. - Netz-Sperre: waehrend
native_scope()(die gesamte Sprachgenerierung einer Antwort) ist jeder Verbindungsaufbau dieses Threads verboten - Native braucht kein Netz. - Harter Schalter: im Modus
native(oder mitLENNY_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 nachactive) sowieblocked(adminoderauto). Lernsignale (erneute Erklaerung, "unverstaendlich", Grammatik-Korrektur, Variantenpraeferenz, interne Grammatik-/Fidelity-/Goldfall-Ergebnisse) wirken nur auf die Sprache und nie auf die Wahrheit:record_signallehnt 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 mitlanguage_change_idim 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 weiterhincore/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).