Dieses Paket vertieft am realen System, was die veröffentlichte Seite „KI steuert lokale Hardware über eine Brücke" exemplarisch zeigt. Ein KI-Agent mit eigenem Sprachmodell richtet auf einem Windows-Rechner Python ein, schreibt ein Programm für einen ESP32, überspielt es — und entfernt sich danach restlos. Alles läuft aus einem Ordner, vom Stick oder von der Festplatte. Nichts wird installiert, kein Netz wird gebraucht, keine Adminrechte.
Nicht nur für den ESP32: Der Agent schreibt auf Anforderung jedes Python-Programm — einen Taschenrechner mit Fenster (tkinter liegt im Paket), ein Skript, das rechnet — und führt es mit dem Paket-Python aus, bevor er es für fertig erklärt.
Die veröffentlichte Seite führt vor, wie eine KI über eine Brücke Hardware am Arbeitsplatz steuert. Dort sieht man zu. Hier hat man es selbst in der Hand: eigenes Modell, eigener ESP32, kein Netz, ein Ordner — derselbe Kreis aus Anforderung, Bau, Abnahme und Nachweis, nur dass jeder Schritt auf dem eigenen Rechner läuft und geprüft wird.
Dieses Paket zeigt an einem kleinen, vollständig laufenden Beispiel, wie Entwicklung mit einem Sprachmodell wirklich abläuft — nicht als Folienvortrag, sondern als Vorgang, den man anstoßen und zusehen kann. Es ist derselbe Ablauf, mit dem auch dieses Paket selbst entstanden ist, nur im kleinen Rahmen.
| Schritt | wer | warum er nicht wegfallen darf | |
|---|---|---|---|
| 1 | Anforderung | Mensch | Ein Satz auf Deutsch. Was nicht gesagt wurde, kann auch nicht geprüft werden. |
| 2 | Bau | Modell | Das Modell schreibt den Quelltext. Das ist der Teil, über den alle reden — und der kleinste. |
| 3 | Abnahme | Werkzeug | Das Programm läuft, und das Gemessene wird mit dem Angekündigten verglichen. Hier entscheidet sich alles. |
| 4 | Berichtigen | Modell | Fällt die Abnahme durch, geht es zurück zu 2 — mit der Fehlermeldung als Eingabe. |
| 5 | Auslieferung | Werkzeug | Erst nach bestandener Abnahme geht dieselbe Datei auf die Hardware. |
| 6 | Rücklesen | Werkzeug | Das Gerät selbst meldet, was blinkt: Pegel, Wechsel, Takt — gegen dieselbe Erwartung. Der zweite, unabhängige Weg. |
| 7 | Nachweis | Werkzeug | Was hat sich am Rechner geändert? Gemessen, nicht behauptet. |
Schritt 3 ist der eigentliche Inhalt des Kurses. Ein Sprachmodell schreibt in Sekunden ein Programm, das plausibel aussieht. Ob es tut, was verlangt war, steht damit nicht fest — und genau diese Lücke schließt kein besseres Modell, sondern eine Prüfung, die durchfallen kann.
Deshalb nimmt programm_testen eine Erwartung entgegen:
"erwartet": {"pins": [2], "takt_hz": 1.0}
Ohne diese Zeile ist der Lauf eine Vorführung: etwas blinkt, und niemand hat vorher gesagt, was hätte blinken sollen. Mit ihr ist es eine Abnahme.
Üblicherweise liegen die drei Teile auf drei Rechnern: das Sprachmodell bei einem Anbieter, der Agent auf einem Server, die Hardware am Arbeitsplatz — verbunden über eine Brücke. Hier sind alle drei derselbe Rechner.
| Teil | großer Aufbau | dieses Paket |
|---|---|---|
| Sprachmodell | beim Anbieter, über das Netz | llama-server auf 127.0.0.1 |
| Agent und Werkzeuge | auf einem Server | derselbe Rechner, Ordner agent\ |
| Hardware | am Arbeitsplatz, über eine Brücke | am selben USB-Anschluss |
Am Ablauf ändert das nichts — und das ist der Punkt. Wer ihn hier verstanden hat, hat ihn auch für den verteilten Fall verstanden; dort kommen Strecke und Rechteverwaltung dazu, nicht aber ein anderer Vorgang.
Die Anforderungen an dieses Paket stehen geschrieben, nicht im Kopf: ANFORDERUNGEN.md
führt 55 Punkte in neun Gruppen, jeder so gefasst, dass er scheitern kann, mit
der Angabe, woran er gemessen wird.
| Gruppe | Kern |
|---|---|
| A — Autarkie | Der Kursrechner hat Windows und sonst nichts. Das Paket bringt alles mit, sucht kein vorhandenes Python und benutzt auch keines. |
| B — keine Störung | Läuft dort schon Thonny oder ein eigenes Python, bleibt daran alles unberührt — auch Benutzerpakete, pip-Zwischenspeicher, PATH, Ports und COM-Anschlüsse. |
| C — nur im Kursordner | Geschrieben wird ausschließlich in ablage\, und das wird erzwungen, nicht gehofft. |
| D — restlos entfernbar | Ein Ordner, ein Befehl, danach wird nachgezählt. |
| E — Weitergabe | Derselbe Stick startet auf jedem Rechner; das Modell wird beim Start gewählt. |
| F — Bedienung | Doppelklick, anklicken, zusehen. Keine Kommandozeile. |
| G — der Lehrinhalt | Bauen, Abnahme gegen eine vorher genannte Zahl, berichtigen, erst dann ausliefern. |
| H — Hardware | Fabrikneu oder vorprogrammiert, mit oder ohne Treiber, mit oder ohne Steckbrett. |
| I — Ferndiagnose | Ein Befehl schreibt alles Nötige in eine Datei — ohne Benutzer- und Rechnernamen. |
python pruefe_alles.py
arbeitet die maschinell prüfbaren Punkte ab — derzeit 17 — und nennt, welche von Hand zu prüfen bleiben. Beim Schreiben dieses Prüfskripts fielen zwei eigene Fehler auf: eine Prüfung, die ihr Ergebnis behauptete statt es abzulesen, und eine, die „bestanden" meldete, obwohl der geprüfte Lauf gar nicht stattgefunden hatte.
Eine blinkende Leuchtdiode ist die kleinste Aufgabe, an der sich die ganze Kette zeigen lässt: sie ist in sechs Zeilen geschrieben, in vier Sekunden geprüft und am Ergebnis sieht man sofort, ob es stimmt. Aufgezeichnet wird aber jeder Anschluss — ein Programm mit drei Pins und verschiedenen Takten läuft genauso durch, ebenso Pulsweitenmodulation und Analogeingänge.
| Ordner | Inhalt | Eigenschaft |
|---|---|---|
paket\ | Python, pip, Pakete, MicroPython, llama.cpp, Sprachmodell, Treiber | wird nur gelesen — nie beschrieben |
agent\ | die Schleife, die Modellanbindung, neun Werkzeuge | der Programmteil, rund 60 kB |
ablage\ | das entpackte Python, installierte Pakete, erzeugte Dateien, Protokoll | wird am Ende restlos gelöscht |
Diese Trennung ist das ganze Sicherheitskonzept. Geschrieben wird
ausschließlich in ablage\; das erzwingt der Werkzeugrahmen, indem er jeden
Schreibpfad auflöst und prüft, bevor eine Datei entsteht. Deshalb ist das Aufräumen
ein Beweis und keine Behauptung: es löscht genau einen Ordner und zählt hinterher nach.
| Teil | Datei | Größe | wofür |
|---|---|---|---|
| Python, ausgepackt | python_vorlage\ | 22 MB | wird kopiert, nicht installiert — dies ist der Weg, den START.bat geht |
| Python als Archiv | python-3.12.10-embed-amd64.zip | 11,1 MB | Rückfall, falls die Vorlage fehlt. Wird nur entpackt, nie installiert |
| pip | get-pip.py | 2,2 MB | richtet die Paketverwaltung im entpackten Python ein |
| Python-Pakete | pakete\ — 25 Dateien | 8,4 MB | esptool und mpremote samt allem, was dazugehört |
| MicroPython | firmware\*.bin | 1,8 MB | die Firmware für den ESP32 |
| llama.cpp | llama\llama-server.exe | 95 MB | führt das Sprachmodell aus |
| Sprachmodell | modell\*.gguf | 1,0–4,7 GB | entscheidet, welches Werkzeug wann läuft |
| USB-Treiber | treiber\*.zip | 1,4 MB | falls Windows den Wandler nicht kennt |
Ohne Modell sind das 137 MB; mit dem mittleren Modell (3b) rund 2,1 GB, und mit beiden Modellen — so wird der Stick gebaut — rund 6,8 GB.
Die folgenden Zahlen sind gemessen, nicht geschätzt: am laufenden Paket,
mit ps am Modellserver abgelesen, auf einem Rechner mit 20 Kernen ohne
Grafikbeschleunigung.
| Modell | Datei | Speicher gemessen | braucht RAM | Ladezeit | Urteil aus dem Prüflauf |
|---|---|---|---|---|---|
1.5b | 0,99 GB | 2,2 GB | 4 GB | ~1 s | zeigt die Schleife, scheitert an mehrstufigen Aufträgen |
3b | 1,93 GB | 3,48 GB | 8 GB | 2–3 s | schreibt brauchbare Programme, verliert aber den Faden und ruft Werkzeuge in falscher Reihenfolge; Rückfall |
7b | 4,68 GB | 6,70 GB | 16 GB | 5–6 s | hält die Kette ein, berichtigt eigene Fehler — Rückfall, wenn kein Coder-Modell da ist |
coder-3bcoder-7b| Sonst | |
|---|---|
| Betriebssystem | Windows 10 oder 11, 64 bit. Keine Adminrechte, außer für einen USB-Treiber |
| Prozessor | vier Kerne aufwärts. Im Prüflauf lagen 500 % Last an — das Modell nimmt, was da ist |
| Platz | 200 MB ohne Modell, 2,2 GB mit dem 3B-, 5,0 GB mit dem 7B-Modell |
| Grafik | keine nötig. Mit Vulkan (AMD, Intel, NVIDIA) wird es schneller, ohne rechnet llama.cpp auf dem Hauptprozessor weiter |
| Netz | einmal zum Füllen des Pakets. Im Kurs nie |
Gemessener Prüflauf (7B-Modell, 20 Kerne, keine Grafik): fünf Werkzeugaufrufe in 2 Minuten 48 Sekunden, davon der größte Teil Wartezeit auf das Modell — rund 15 bis 25 Sekunden je Antwort. Auf vier Kernen ist mit dem Mehrfachen zu rechnen; dann lohnt das 3B-Modell trotz seiner Schwächen.
Diesen Rechner selbst messen lassen:
python pruefe_rechner.py
Es nennt Arbeitsspeicher, Kerne, freien Platz und Grafik, hält sie gegen die Tabelle oben und empfiehlt ein Modell — oder sagt, dass keines passt.
Ohne Sprachmodell läuft weiterhin alles andere: die neun Werkzeuge, der Prüfschritt mit Abnahme, die virtuelle LED, das Flashen, der Nachweis und das Aufräumen. Dafür genügen Windows und 200 MB. Nur die Entscheidung, welches Werkzeug wann läuft, trifft dann ein festes Drehbuch statt eines Modells.
Jedes ist ein eigenständiges Programm mit genau zwei Betriebsarten:
--beschreibung sagt als JSON, was es kann; '<json>' führt es aus.
Mehr Verbindung zwischen Modell und Werkzeug gibt es nicht — deshalb lässt sich jedes ohne
Modell von Hand prüfen, und genau das ist Menüpunkt [2].
| Name | was es tut | Felder |
|---|---|---|
aufraeumen | Loescht alles, was im Lauf angelegt wurde: das eigene Python, die installierten Pakete und die erzeugten Dateien. Zaehlt danach nach, dass nichts zurueckblieb. Am Ende der Arbeit aufrufen. | nur_zeigen |
esp32_firmware | Spielt MicroPython auf den ESP32 am angegebenen Anschluss. Prueft zuerst, ob dort ueberhaupt ein ESP32 antwortet, und schreibt nur dann. Einmal je Geraet noetig, bevor Python-Programme uebertragen werden koennen. Mit nur_pruefen: true sagt es, was auf dem Brett schon ist — fabrikneu, fremdes Programm oder bereits MicroPython — und schreibt nichts. | port, nur_pruefen |
esp32_nachlesen | Liest vom ESP32 zurueck, ob die LED wirklich blinkt: startet das Programm auf dem Geraet und zeichnet dort die Pegel der Anschluesse auf. Takt und Wechsel werden gegen die Erwartung gehalten (ABNAHME) — die Messung am Geraet, unabhaengig von programm_testen. Setzt voraus, dass esp32_uebertragen gelaufen ist. | port, datei, sekunden, pwm, roh, erwartet |
esp32_uebertragen | Kopiert eine Datei aus der Werkstatt auf den ESP32 und startet ihn neu. Standardziel ist main.py, denn MicroPython fuehrt diese Datei nach dem Einschalten selbsttaetig aus. Setzt voraus, dass esp32_firmware bereits gelaufen ist. | port, datei, ziel, erwartet |
nachweis_autark | Nimmt den Zustand der Stellen ausserhalb des Paketordners auf ('vorher') und vergleicht ihn spaeter ('nachher'). Damit laesst sich belegen statt behaupten, dass der Rechner unveraendert bleibt. Vor der Arbeit und vor dem Aufraeumen aufrufen. | wann |
paket_installieren | Installiert ein Python-Paket in die eigene Umgebung in der Ablage. Erlaubt sind nur: esptool, mpremote, pyserial, setuptools, wheel. Fuer den ESP32 wird esptool gebraucht. | paket |
ports_zeigen | Zeigt alle seriellen Anschluesse (COM-Ports) des Rechners und markiert, welcher nach einem USB-Seriell-Wandler eines ESP32 aussieht. Vor dem Flashen aufrufen. | — |
programm_ausfuehren | Fuehrt ein beliebiges Python-Programm aus der Werkstatt mit dem Paket-Python aus — fuer alles, was kein ESP32-Programm ist (Rechner, Skripte, Programme mit Fenster). Berichtet Ausgabe, Fehler und Rueckgabewert; Urteil LAUF BESTANDEN / NICHT BESTANDEN. Mit fenster true wird ein Programm mit grafischer Oberflaeche (tkinter) gestartet und beobachtet, ob es laeuft und ein Fenster zeigt. | datei, sekunden, fenster, offen_lassen, eingabe |
programm_testen | Fuehrt ein Programm aus der Werkstatt ohne Hardware aus und zeichnet auf, was an den Anschluessen geschieht; eine LED auf dem Bildschirm zeigt es an. IMMER aufrufen, nachdem ein Programm geschrieben wurde und BEVOR es auf den ESP32 ueberspielt wird — ein Programm, das hier nicht laeuft, laeuft dort auch nicht. Ersetzt zugleich die Hardware, wenn keine da ist. | datei, sekunden, oeffnen, erwartet |
schreib_datei | Schreibt eine Textdatei in die Werkstatt, zum Beispiel den Quelltext fuer den ESP32. Vorhandene Dateien werden ersetzt. Ausserhalb der Ablage kann nicht geschrieben werden. | name, inhalt |
umgebung_anlegen | Richtet ein eigenes, eingebettetes Python samt pip in der Ablage ein. Installiert nichts im System: es wird nur entpackt und spaeter wieder geloescht. Muss vor paket_installieren und esp32_flashen laufen. | neu |
Diese Tabelle ist nicht abgeschrieben, sondern beim Erzeugen der Seite von den Werkzeugen selbst erfragt. Eine abgeschriebene Tabelle stimmt genau bis zur ersten Änderung.
umgebung_anlegen entpackt Python muss zuerst laufen
└─ paket_installieren esptool, mpremote braucht das Python von oben
├─ ports_zeigen welcher Anschluss? braucht pyserial
└─ esp32_firmware MicroPython aufs Gerät braucht esptool
schreib_datei das Programm entsteht
└─ programm_testen Abnahme ohne Hardware ← hier wird entschieden
└─ esp32_uebertragen dieselbe Datei aufs Gerät braucht mpremote
└─ esp32_nachlesen misst am Gerät, ob es blinkt braucht mpremote
nachweis_autark vorher / nachher
aufraeumen löscht die Ablage, zählt nach
Die Reihenfolge erfindet nicht der Agent, sondern sie ergibt sich: jedes Werkzeug sagt in
seiner Fehlermeldung, was ihm fehlt. Ruft das Modell ports_zeigen zu früh, bekommt
es „Es gibt noch kein eigenes Python. Zuerst umgebung_anlegen aufrufen" — und tut
genau das. So braucht es keinen festen Ablaufplan.
agent\werkzeuge\_muster.py nimmt den Rahmen ab. Eine neue Datei im Ordner
genügt — der Agent findet sie beim nächsten Start, weil er die Liste nicht führt, sondern
erfragt.
from _muster import werkzeug, Abbruch, lauf
def tun(e):
return f"Ergebnis zu {e['feld']}"
werkzeug("mein_werkzeug", "Was es tut und wann man es ruft.",
{"feld": {"type": "string", "description": "wofür"}},
["feld"], {"feld": "Probe"}, tun)
C:\Kurs_Agent. Laufwerksbuchstabe und Name sind beliebig — im ganzen
Paket steht kein fester Pfad.START.bat — auch beim ersten Mal. Ist das Paket
noch leer, sagt das Skript genau das und holt alles selbst: rund 6,8 GB — Python, pip, 25
Pakete, MicroPython, llama.cpp, Treiber und zwei Sprachmodelle (3b und 7b). Zehn bis dreißig
Minuten, je nach Leitung. Danach läuft es weiter, als wäre gerade gestartet worden.
Für diesen einen Schritt — und nur für ihn — wird ein
vorhandenes Python mit pip gebraucht. Der Grund ist einfach: im leeren Paket liegt
noch keines. START.bat sucht eines, prüft ob darin pip läuft, nennt es beim
Namen und fragt nach, bevor etwas geholt wird. Selbst dabei bleibt der Rechner unberührt —
pip-Zwischenspeicher und Benutzerpakete zeigen in den Kursordner, nicht ins Profil.
Danach wird dieses Python nie wieder angefasst: der ganze Kursbetrieb läuft mit dem Python
aus dem Paket.
Wird keines gefunden, nennt das Skript zwei Wege — Python von python.org installieren, oder den gefüllten Ordner von einem anderen Rechner kopieren. Der zweite ist der gedachte: füllen einmal, weitergeben beliebig oft. Auf dem Kursrechner ist nie ein fremdes Python nötig.
START.bat. Es sucht kein
vorhandenes Python — weder im PATH noch dort, wo Windows oder Thonny eines ablegen. Es kopiert
sein eigenes aus paket\python_vorlage\ nach ablage\python\
und arbeitet nur mit diesem. Was auf dem Rechner schon installiert ist, wird nicht gestartet,
nicht gelesen und nicht verändert.[1] Installieren und starten — die Eingabetaste. Mehr fragt
START.bat nicht. Es prüft den Stand des Pakets („Paket: … vollständig"), und
fehlt etwas, holt es das Fehlende von selbst — zuerst aus dem Vorrat (ein
Paket nebenan, ein Stick unter X:\Kurs_Agent, der Download-Ordner), erst dann
aus dem Netz. Liegt irgendwo ein volles Paket, braucht es gar kein Netz.python baue_stick.py E:\Kurs_Agent — nimmt mit, was zum Betrieb gehört, lässt
weg, was beim Entwickeln entsteht, und meldet von selbst, wenn das Modell fehlt.START.bat doppelklicken.| Wahl | was sie bedeutet |
|---|---|
| [1] Installieren und starten | legt das eigene Python bereit, prüft das Paket, holt Fehlendes, öffnet den Agenten im Browser. Das ist der Normalfall — die Eingabetaste genügt. |
| [2] Deinstallieren | zeigt erst den Nachweis, was sich am Rechner verändert hat (nichts), und entfernt dann alles, was der Agent angelegt hat. Das Paket selbst bleibt. |
| [3] Abbrechen | nichts geschieht. |
Wer mehr will — Werkzeuge einzeln prüfen, der Agent ohne Browser,
der Weg ohne Modell, ein Bericht zum Weitergeben —, startet START.bat --menue.
Der Weg „auf die Platte kopieren, danach selbst löschen" heißt START.bat --kopieren.
Paket: … vollständig — jeder Teil ist
da. Und Smart App Control: … — steht dort EIN, lässt dieser Rechner nur
signierte Programme laufen. Der mitgelieferte Modellserver ist signiert (Ollama Inc./DigiCert) und
läuft trotzdem; am 04.10.2026 auf einem solchen Rechner gemessen. Sollte das Modell dennoch nicht
starten, sagt der Agent das im Browser in Worten und läuft ohne Modell weiter:
dieselben Werkzeuge, dieselbe Abnahme, die virtuelle LED — die Entscheidungen trifft ein festes
Drehbuch.Nach [1] öffnet sich der Browser. Oben der Kopf (Ordner, Modell, Zustand), unten
immer das Eingabefeld, dazwischen der Verlauf. Sie sagen dem Agenten, was er tun soll — mit
einem Satz oder einem der Vorschläge —, sehen jeden Schritt mit und geben danach die nächste
Anweisung. Der Agent behält den Zusammenhang: „Nimm jetzt GPIO 4", „ändere auf 10 Hz", „lade es
auf den ESP32 an COM3 und lies nach, ob die LED blinkt" oder ein eigenes Programm in
```-Zeichen zum Prüfen. Im schwarzen Fenster steht derweil, was der Agent tut;
Strg+C dort beendet ihn.
Das ist der häufigere Fall und der eigentlich interessante. Hier der Auszug aus einem
Prüflauf, wörtlich aus dem Protokoll — das Modell schrieb time.sleep(1) für
beide Pausen, was eine Periode von zwei Sekunden ergibt:
[2] programm_testen {"datei": "blink.py", "erwartet": {"pins": [2], "takt_hz": 1.0}}
ABNAHME NICHT BESTANDEN
Anschluesse: erwartet [2], gemessen [2] erfuellt
Takt: erwartet 1.00 Hz, gemessen 0.50 Hz (Spielraum 10 %) NICHT ERFUELLT
Zustandswechsel: erwartet mindestens 6, gemessen 7 erfuellt
NAECHSTER SCHRITT: Rufe schreib_datei mit berichtigtem Quelltext auf. Dasselbe
Programm noch einmal zu pruefen aendert nichts am Ergebnis. [...] Bei einem Takt:
eine Blinkperiode besteht aus zwei Pausen, also ergibt time.sleep(0.5) +
time.sleep(0.5) genau 1 Hz.
[3] schreib_datei {"name": "blink.py", ...}
[4] schreib_datei {"name": "blink.py", ...}
[5] programm_testen {"datei": "blink.py", ...}
ABNAHME BESTANDEN
Takt: erwartet 1.00 Hz, gemessen 1.00 Hz (Spielraum 10 %) erfuellt
=== fertig nach 5 Werkzeugaufrufen ===
Das ist der Kurs in acht Zeilen. Das Modell hat ein plausibles Programm geschrieben, das nicht tat, was verlangt war. Kein Mensch hat den Fehler gefunden, sondern eine Messung gegen eine vorher genannte Zahl. Danach hat das Modell selbst berichtigt.
Ein Agent, der diesen Schritt nicht hat, liefert dasselbe falsche Programm aus — mit der Meldung, alles sei in Ordnung.
[1] Agent starten. Die Eingabetaste nimmt den
vorgegebenen Auftrag. Das Modell lädt beim ersten Mal 10 bis 60 Sekunden.[3] Aufräumen. Zeigt erst den Nachweis — was hat sich
außerhalb des Ordners verändert? — und löscht dann die Ablage, mit Nachzählung.Wenn das Modell klemmt: Menüpunkt
[7] Ohne Modell durchlaufen macht dieselben Schritte in fester Reihenfolge, mit
denselben Werkzeugen und derselben Abnahme. Der Kurs läuft dann weiter; nur die
Entscheidungen trifft das Drehbuch statt des Modells.
Beide Male derselbe Auftrag, dasselbe Modell, dieselben Werkzeuge. Der Unterschied ist nur, ob ein Steckbrett am USB-Anschluss hängt.
Auftrag im Menüpunkt [3]:
Schreibe ein MicroPython-Programm, das die LED an GPIO 2 einmal je Sekunde
blinken lässt. Prüfe es ohne Hardware gegen diese Erwartung, und wenn es
besteht, spiele es auf den ESP32.
Was dann der Reihe nach geschieht — die Zeilen sind die wirklichen Ausgaben der Werkzeuge:
[1] umgebung_anlegen {}
Python-Archiv: mitgeliefert (python-3.12.10-embed-amd64.zip, 11133606 Byte)
entpackt nach ...\ablage\python
python312._pth: 'import site' freigeschaltet
pip eingerichtet
Gegenprobe: pip 25.x from ...\ablage\python\Lib\site-packages\pip
[2] paket_installieren {"paket": "esptool"}
esptool installiert aus mitgelieferten Dateien in ...\paket\pakete
Ziel: ...\ablage\python (nicht das Python des Rechners)
Gegenprobe: import esptool -> Fassung 5.4.0
[3] ports_zeigen {}
2 serielle Anschluesse:
COM3 — Standardmäßige Seriellenschnittstelle
COM5 1A86:7523 USB-SERIAL CH340 <- QinHeng CH340
Nach dem Wandler zu urteilen koennte der ESP32 an COM5 haengen.
Das ist ein Vorschlag, keine Feststellung.
[4] schreib_datei {"name": "blink.py", "inhalt": "from machine import Pin..."}
...\ablage\werkstatt\blink.py geschrieben: 9 Zeilen, 145 Byte.
[5] programm_testen {"datei": "blink.py", "erwartet": {"pins": [2], "takt_hz": 1.0}}
blink.py lief 4.0 s ohne Hardware (nach der Zeitgrenze beendet).
Geschaltet wurde Pin 2, 9 Zustandswechsel.
Takt: 1.000 s zwischen zwei Einschaltvorgaengen (1.00 Hz).
ABNAHME BESTANDEN
Anschluesse: erwartet [2], gemessen [2] erfuellt
Takt: erwartet 1.00 Hz, gemessen 1.00 Hz (Spielraum 10 %) erfuellt
[6] esp32_firmware {"port": "COM5", "nur_pruefen": true}
An COM5: Chip is ESP32-D0WD-V3 (revision v3.1)
Darauf laeuft kein MicroPython — entweder ist das Brett fabrikneu oder es
traegt ein anderes Programm. Beides macht nichts.
[7] esp32_firmware {"port": "COM5"}
Firmware mitgeliefert (ESP32_GENERIC-...-v1.29.0.bin, 1790000 Byte),
der gesamte Speicher wurde geloescht und neu beschrieben.
[8] esp32_uebertragen {"port": "COM5", "datei": "blink.py"}
blink.py (145 Byte) nach COM5:main.py kopiert.
Gegenprobe — Verzeichnis des Geraets: main.py
Geraet neu gestartet.
Die LED blinkt. Der ESP32 braucht ab jetzt keinen Rechner mehr: MicroPython führt
main.py aus, sobald Strom anliegt.
Der ESP32 darf fabrikneu oder schon programmiert sein. Schritt [6] sagt, was darauf ist; Schritt [7] löscht den Speicher vollständig und schreibt MicroPython neu. Was vorher darauf war — ein Arduino-Sketch, ein alter Versuch, nichts — spielt dafür keine Rolle. Es ist danach allerdings weg.
Kein Steckbrett, kein Treiber, kein USB-Anschluss. Derselbe Auftrag, nur der letzte Satz fällt weg:
Schreibe ein MicroPython-Programm, das die LED an GPIO 2 einmal je Sekunde
blinken lässt, und prüfe es ohne Hardware gegen diese Erwartung.
Die Schritte 1, 4 und 5 laufen genau wie oben. Bei Schritt 3 meldet das Werkzeug:
[3] ports_zeigen {}
Es ist kein serieller Anschluss sichtbar.
Zu pruefen: Steckbrett eingesteckt? USB-Kabel mit Datenadern?
Treiber fuer CP2102 oder CH340 vorhanden?
Das ist kein Abbruch — das Modell liest es und arbeitet weiter. Nach der bestandenen Abnahme meldet es FERTIG und sagt dazu, dass das Überspielen aussteht.
Und die LED blinkt trotzdem — auf dem Bildschirm. Der Prüfschritt öffnet eine Seite mit der Aufzeichnung:
Das ist keine Nachahmung. Es ist dieselbe Datei, die
sonst auf den ESP32 geht, ausgeführt mit einem nachgebauten machine-Modul:
Pin schreibt seine Zustandswechsel in die Ausgabe, statt eine Leitung zu
schalten. Wer die Datei später überspielt, bekommt genau dieses Verhalten — dann an echten
Anschlüssen.
Nachgebildet sind Pin, Signal, PWM, ADC,
reset, freq. Alles andere meldet beim Aufruf, dass es nicht
nachgebildet ist — stillschweigend ein Scheinobjekt zu liefern wäre schlimmer als ein
Fehler: das Programm liefe scheinbar durch und versagte erst auf der Hardware.
Vier Fälle, jeder davon im Entwurf dieses Pakets aufgetreten:
| Quelltext | Meldung |
|---|---|
led.valu(1) — Tippfehler | ABGEBROCHEN (Rückgabewert 1), mit der Fehlerzeile. Darf so nicht auf den ESP32. |
time.sleep(0.25) statt 0.5 | ABNAHME NICHT BESTANDEN — Takt: erwartet 1,00 Hz, gemessen 2,00 Hz |
Pin(13, …) statt Pin(2, …) | ABNAHME NICHT BESTANDEN — Anschlüsse: erwartet [2], gemessen [13] |
| Pin gesetzt, aber nie umgeschaltet | ABNAHME NICHT BESTANDEN — nur 1 Einschaltvorgang, Takt nicht prüfbar |
In allen vier Fällen geht das Modell zurück an den Quelltext. Das ist der Grund für den Schritt: nicht, dass etwas blinkt, sondern dass etwas nicht durchgeht.
Für den Kurs ohne Hardware wird nichts davon gebraucht — Beispiel 2 läuft auf jedem Rechner. Dieser Reiter gilt, sobald ein echtes Steckbrett blinken soll.
| Teil | was taugt | woran es scheitert |
|---|---|---|
| ESP32-Brett | jedes gängige mit USB-Buchse: ESP32-DevKitC, NodeMCU-32S, WROOM-32, auch S2/S3/C3 | Bretter ohne USB-Buchse brauchen einen eigenen Programmieradapter |
| USB-Kabel | ein Datenkabel | Der häufigste Fehler im Kurs. Ein reines Ladekabel sieht genauso aus, hat aber nur die Stromadern. Der Rechner zeigt dann gar nichts an |
| LED | die eingebaute an GPIO 2 genügt | manche Bretter haben sie an GPIO 5, 13 oder 22 — dann die Nummer im Auftrag ändern |
| USB-Anschluss | direkt am Rechner | passive Verteiler liefern zu wenig Strom; das Brett meldet sich dann sprunghaft oder gar nicht |
Der ESP32 spricht keine USB-Sprache. Zwischen ihm und der Buchse sitzt ein kleiner
Übersetzer, und für den braucht Windows einen Treiber. Welcher es ist,
steht in winziger Schrift auf dem Chip neben der Buchse — oder ports_zeigen
sagt es:
2 serielle Anschluesse:
COM3 — Standardmäßige Seriellenschnittstelle
COM5 1A86:7523 USB-SERIAL CH340 <- QinHeng CH340
Nach dem Wandler zu urteilen koennte der ESP32 an COM5 haengen.
| Kennung | Wandler | Treiber im Paket |
|---|---|---|
1A86:7523 | QinHeng CH340 — auf den meisten günstigen Brettern | CH341SER.ZIP |
1A86:55D4 | QinHeng CH9102 | CH343SER.ZIP |
10C4:EA60 | Silicon Labs CP2102 / CP2104 | CP210x_Universal_Windows_Driver.zip |
0403:6001 | FTDI FT232R | Windows bringt ihn mit |
303A:… | Espressif selbst (S2/S3 mit eingebautem USB) | kein Treiber nötig |
Erst nachsehen, dann installieren. Windows 10 und 11
bringen CH340 und CP210x oft über Windows Update mit. Rufen Sie zuerst
ports_zeigen auf: erscheint ein COM-Anschluss mit einer der Kennungen oben, ist
nichts zu tun.
paket\treiber\,
„Alle extrahieren".SETUP.EXE, bei
Silicon Labs CP210xVCPInstaller_x64.exe. Windows fragt nach Adminrechten —
das ist das einzige Mal in diesem ganzen Kurs.ports_zeigen noch einmal. Jetzt muss der Anschluss auftauchen.Die Treiber liegen im Paket, unmittelbar von der Herstellerseite über HTTPS geholt, mit
Prüfsummen in paket\treiber\LIESMICH.md. Eine Zwischenquelle kommt nicht in
Frage: ein Treiber läuft im Kern des Betriebssystems. Es liegen nur Archive dort und keine
fertigen Programme — ein .exe auf einem Stick lässt Virenscanner anschlagen.
| Zustand vorher | was der Agent tut |
|---|---|
| fabrikneu, ab Werk meist ein Arduino-Testprogramm | Speicher löschen, MicroPython schreiben |
| ein alter Arduino-Sketch | dasselbe — er ist danach weg |
| bereits MicroPython | die Prüfung meldet das; neu schreiben geht, ist aber nicht nötig |
Der ESP32 wird wirklich verändert, und zwar
vollständig: erase_flash löscht den gesamten Speicher, dann wird MicroPython
geschrieben. Was vorher darauf war, ist weg. Das ist die einzige bleibende Änderung, die
dieses Paket macht — sie trifft das Steckbrett, nicht den Rechner.
Geschrieben wird erst, nachdem sich an diesem Anschluss ein ESP32 gemeldet hat. Antwortet dort nichts oder etwas anderes, bricht das Werkzeug ab, ohne zu schreiben.
| Beobachtung | Ursache und Abhilfe |
|---|---|
| gar kein COM-Anschluss | Ladekabel statt Datenkabel; Treiber fehlt; Brett nicht eingesteckt |
| COM-Anschluss da, aber „meldet sich kein ESP32" | ein anderes Programm hält ihn (Thonny, Arduino-Monitor, PuTTY) — schließen |
| Anschluss erscheint und verschwindet | zu wenig Strom: direkt an den Rechner statt an einen Verteiler |
| „Failed to connect … Wrong boot mode" | bei manchen Brettern BOOT gedrückt halten, während esptool verbindet |
| flasht durch, LED bleibt dunkel | die LED sitzt an einem anderen Anschluss. GPIO 5, 13 oder 22 im Auftrag versuchen |
Das Modell ist eine Datei im Paket, paket\modell\*.gguf, und ein Server, der sie lädt:
llama-server.exe aus paket\llama_signiert. Dieser Server stammt aus dem
Ollama-Archiv und ist signiert (Ollama Inc., DigiCert), deshalb läuft er auch auf Rechnern, deren
Smart App Control nur signierte Programme zulässt. Er antwortet über eine Schnittstelle
(/v1/chat/completions) auf 127.0.0.1:8099; der Agent schickt ihm den Verlauf
und bekommt Text zurück. Mehr Verbindung gibt es nicht.
| Modell | Datei | Rechner | gemessen |
|---|---|---|---|
| Qwen2.5-Coder-3B-Instruct (Q4_K_M) | 1,93 GB | ab 8 GB Arbeitsspeicher — die Wahl | blink.py in 1–2 Anläufen, PWM-Atmen sinusförmig nach 3 Anläufen, Taschenrechner mit tkinter in einem Anlauf; scheitert an 3 Hz und an zwei LEDs mit zwei Takten; erzählt im langen Gespräch erfundene Arbeit; Hardwarefragen falsch |
| Qwen2.5-Coder-7B-Instruct (Q4_K_M) | 4,68 GB | ab 16 GB | siehe Reiter „Stand und Grenzen“, Messreihe 3; schreibt Zeilenumbrüche im JSON doppelt maskiert, der Agent löst das auf |
| Qwen2.5-3B/7B-Instruct | 1,93 / 4,68 GB | Rückfall | 16 Aufrufe statt 4 für dieselbe Karte; nicht mehr die Wahl |
| Qwen3-Coder-30B-A3B | ~18 GB | ab 24 GB | nicht gemessen — der ernsthafteste Kandidat für größere Rechner (3 Mrd. aktive Parameter, 30 Mrd. gesamt) |
Welches Modell läuft, entscheidet sich beim Start am freien Arbeitsspeicher; bei gleicher Größe wird das Coder-Modell vorgezogen, weil die Aufgabe ein Modell „speziell für die Python-Programmierung“ verlangt. Keines der Modelle ist von uns nachtrainiert — kein LoRA, kein Feintuning. Was das Modell über Werkzeuge, Methode und Brett weiß, steht in der Anweisung des Agenten und wirkt nur im Gespräch.
Was ein kleines Modell kann und was nicht — gemessen am 04./05.10.2026: Es schreibt kurze MicroPython- und Python-Programme richtig, hält das Werkzeugformat meist ein, berichtigt nach einer durchgefallenen Abnahme. Es verwechselt die PWM-Trägerfrequenz mit dem Atemtakt, lässt Parameter weg (den Dateinamen), packt mehrere Aufrufe in eine Antwort, und im langen Gespräch rutscht es in Erzählung: „Ich habe das Programm geschrieben, geprüft und übertragen“ — ohne ein Werkzeug. Genau dafür gibt es den Agenten.
Kontextfenster 16384 Zeichenstücke; ist es voll, fasst der Agent ältere Schritte zusammen. Jede Antwort des Modells steht im Protokoll — nichts ist erfunden oder vorgegeben, und nichts gilt, bevor es geprüft ist.
Der Agent ist ein Python-Programm (agent\agent.py, Klasse Sitzung). Er kennt die Werkzeuge
(er fragt jedes beim Start nach seiner Beschreibung), er kennt die Methode (schreiben, prüfen, berichtigen, ausliefern, nachlesen),
und er stellt beides dem Modell bereit — als Anweisung, als Vorschlag im Ergebnis („NÄCHSTER SCHRITT“), als vorgerechnete Zahl
(welche Pause für 10 Hz), als Wissen über das Brett. Das Modell entscheidet frei; der Agent führt aus und wacht.
Ein Vergleich, kein Beweis — aber einer, der die Rollen klärt: Das Sprachmodell ist der Speicher des Erlernten. Es hat Millionen Programme gesehen und gibt auf eine Frage das wieder, was dazu passt — flüssig, plausibel, ohne zu wissen, ob es hier und jetzt stimmt. Erinnerung ohne Gegenwart. Der Agent ist das Bewusstsein. Er weiß, was gerade der Fall ist: welche Datei geschrieben wurde, welche geprüft, was der Mensch wirklich gesagt hat, welcher Anschluss genannt ist. Er hält die Absicht fest (die Erwartung), vergleicht sie mit dem, was geschieht, und lässt eine Erinnerung nicht als Tat gelten. Die Werkzeuge sind Hände und Sinne: Sie greifen in die Welt (Datei schreiben, Gerät beschreiben) und melden zurück, was dort wirklich ist (die LED blinkt mit 2,06 Hz). Und die Werkstatt mit Protokoll ist das Gedächtnis des Tages: was getan wurde, steht da, nicht was erzählt wurde.
Daraus folgt die Arbeitsteilung des Pakets. Wo der Speicher erzählt, es habe geprüft, fragt das Bewusstsein: Welches Werkzeug lief? Wo der Speicher die Erwartung verschiebt, weil das Programm nicht passt, hält das Bewusstsein die Absicht fest. Wo der Speicher in Prosa verfällt, holt das Bewusstsein ihn ohne Vorgeschichte zur Tat zurück. Ein größeres Modell ist ein größerer Speicher — ein besseres Bewusstsein ist ein strengerer Agent. Beides braucht man; das zweite ist hier das Lehrstück.
Eine Sitzung wird beim ersten Satz geöffnet und bleibt, bis der Mensch ein neues Gespräch beginnt. Jede Anweisung
durchläuft dieselben Schritte:
| Schritt | was genau geschieht | |
|---|---|---|
| 1 | Vom Menschen lesen | Die Anweisung wird ins Protokoll geschrieben. Aus ihren Worten kommen die Erwartung (Pins aus „GPIO 4“, Takt aus „10 Hz“ oder „eine Periode pro Sekunde“, Form aus „sinusförmig“), die genannten Dateinamen, die genannten Anschlüsse („com 3“ = COM3). Ändert sich die Erwartung, gilt die betroffene Datei als ungeprüft. |
| 2 | Eigenes Programm | Steht in der Anweisung ein Codeblock, schreibt der Agent ihn selbst wörtlich in die Werkstatt und sagt dem Modell, dass es nur noch prüfen soll. |
| 3 | Modell bereit | Beim ersten Mal wird der Modellserver gestartet (signiert, Kontext 16384); danach bleibt er geladen. Scheitert der Start, läuft dieselbe Kette mit einem festen Drehbuch — der Kurs darf daran nicht enden. |
| 4 | Zwischenrufe | Vor jedem Schritt werden Eingaben aufgenommen, die der Mensch während des Laufs gemacht hat (Anschluss, neue Erwartung, Korrektur); die Warteschlange des Modells verfällt dann. |
| 5 | Das Modell fragen | Der Verlauf geht an den Server. Ist das Kontextfenster voll, werden ältere Schritte zusammengefasst und es wird erneut gefragt. Enthält die Antwort mehrere Werkzeugaufrufe, werden sie der Reihe nach abgearbeitet, ohne das Modell erneut zu fragen. |
| 6 | Antwort in Worten | Kein Werkzeug, kein FERTIG: Die Antwort gilt dem Menschen und beendet die Anweisung. Behauptet sie etwas, das kein Werkzeug der Sitzung belegt, steht eine Anmerkung des Agenten darunter. |
| 7 | FERTIG prüfen | In dieser Reihenfolge: Ist etwas ungeprüft und FERTIG kam schon einmal zurück — der Agent prüft selbst. Wurde Arbeit erzählt, die kein Werkzeug tat — „das ist nicht wahr“, und das Modell wird ohne Vorgeschichte nur nach dem nächsten Aufruf gefragt (Fokus). Verlangte die Anweisung laden oder nachlesen und es lief nicht — Fokus mit dem genannten Anschluss. Nennt der Auftrag eine Datei, die nie geschrieben wurde; ist eine Datei ungeprüft; fiel die letzte Prüfung durch — jeweils Zurückweisung mit dem Grund und der vorgerechneten Zahl. Nach drei Zurückweisungen endet die Anweisung als NICHT ABGENOMMEN. Erst wenn nichts davon zutrifft, gilt FERTIG. |
| 8 | Werkzeug prüfen | Vor dem Ausführen: aufraeumen nie; Geräteaufrufe nur mit einem Anschluss, den der Mensch nannte; esp32_uebertragen nur mit einer Datei, die zuletzt bestanden hat; programm_testen nur mit einer in dieser Sitzung geschriebenen Datei, mit der Erwartung des Menschen (nicht der des Modells), ohne eigenen Browser-Reiter; fehlt der Dateiname, gilt die zuletzt geschriebene; doppelt maskierte Zeilenumbrüche werden aufgelöst. |
| 9 | Ausführen und merken | Das Werkzeug läuft als eigener Prozess. Danach: geschrieben, ungeprüft, abgenommen, letzter Befund werden fortgeschrieben; eine durchgefallene Abnahme bekommt den nächsten Schritt mit der passenden Zahl (bei 10 Hz: 0,05 s je Pause; bei Atmen: Periode geteilt durch Stufen); der dritte gleiche Fehlschlag bekommt den Rat, anders vorzugehen. Ins Protokoll kommt die erste Zeile samt Urteil, in die Oberfläche alles, ins Gedächtnis des Modells eine Kurzfassung. |
| 10 | Ende | Nach höchstens 25 Schritten endet die Anweisung als Abbruch. Bricht der Agent selbst ab, schreibt er ablage\fehlerbericht.txt; das Protokoll endet mit ABBRUCH und ENDE. Der Mensch gibt die nächste Anweisung. |
Eine Sitzung hält über alle Anweisungen hinweg: den Verlauf für das Modell, welche Dateien geschrieben, geprüft und abgenommen
sind, welche Anschlüsse der Mensch genannt hat, die Erwartung. Der Modellserver bleibt geladen. „Nimm GPIO 4“, „ändere auf 3 Hz“,
„lade es an COM3 und lies nach“, ein eigenes Programm in ```-Zeichen — alles bezieht sich auf das Vorige. Während der
Agent arbeitet, bleibt das Eingabefeld offen: ein Zwischenruf wird beim nächsten Schritt aufgenommen.
| Regel | Anlass |
|---|---|
| Die Erwartung setzt der Mensch (Pins, Takt, Form), aus seinen Worten gelesen, auch „eine Periode pro Sekunde“; sie bleibt, bis er sie ändert. Was er nicht festlegt, legt der erste Aufruf des Modells fest — außer unsichtbare Takte über 50 Hz. | das Modell schrieb 1,0 Hz in 0,5 Hz um, damit sein Programm besteht; später 1000 Hz Trägerfrequenz als „Takt“ |
| Geprüft wird nur, was in dieser Sitzung geschrieben wurde; eine Änderung ohne neue Prüfung ist nicht abgenommen; FERTIG wird bis zu dreimal zurückgewiesen, dann endet die Anweisung als NICHT ABGENOMMEN. | Prüfung lief gegen eine alte Datei aus der Nacht; dritte Fassung geschrieben, nie geprüft, FERTIG |
| Sagt das Modell FERTIG, ohne zu prüfen, prüft der Agent selbst — sichtbar als eigener Aufruf. | viermal geschrieben, nie programm_testen gerufen |
| Was im FERTIG steht, muss ein Werkzeug getan haben — in dieser Anweisung. Erzählt das Modell erfundene Arbeit, sagt der Agent, dass es nicht wahr ist, und fragt es ohne Vorgeschichte nur nach dem nächsten Aufruf (Fokus). | „geschrieben, geprüft, übertragen, die LED blinkt“ — kein Werkzeug lief |
| Kein Anschluss wird geraten; nur ein vom Menschen genannter gilt (auch als „com 3“). Auf das Gerät kommt nur, was zuletzt bestanden hat. | das Modell wollte COM5 flashen |
aufraeumen gehört nicht in die Hand des Modells. | es löschte mitten im Auftrag die Ablage samt Protokoll |
| Mehrere Aufrufe in einer Antwort werden der Reihe nach ausgeführt; doppelt maskierte Zeilenumbrüche werden aufgelöst; ein Aufruf ohne JSON gilt als leere Eingabe. | Formmarotten der Modelle |
Bricht der Agent ab, schreibt er ablage\fehlerbericht.txt; das Protokoll endet mit ABBRUCH und ENDE. | auf einem fremden Rechner sieht niemand zu |
Jede dieser Regeln hat eine Gegenprobe im Prüfstand (pruefstand\pruefe_gespraech.py, pruefe_regeln.py,
pruefe_ungeprueft.py), die durchfallen muss, wenn man die Regel ausbaut. Ohne Modell läuft dieselbe Kette mit einem festen Drehbuch.
Jedes Werkzeug ist ein eigenes Programm in agent\werkzeuge\ mit zwei Betriebsarten: --beschreibung
sagt als JSON, was es kann; '{…}' tut es und schreibt das Ergebnis als Text. Ein Fehler wird Text, nie eine Ausnahme;
jedes Schreiben geht in die Ablage. Diese Tabelle ist beim Erzeugen der Seite aus den Programmen gelesen, nicht abgeschrieben:
| Werkzeug | was es tut | Felder |
|---|---|---|
aufraeumen | Loescht alles, was im Lauf angelegt wurde: das eigene Python, die installierten Pakete und die erzeugten Dateien. Zaehlt danach nach, dass nichts zurueckblieb. Am Ende der Arbeit aufrufen. | nur_zeigen |
esp32_firmware | Spielt MicroPython auf den ESP32 am angegebenen Anschluss. Prueft zuerst, ob dort ueberhaupt ein ESP32 antwortet, und schreibt nur dann. Einmal je Geraet noetig, bevor Python-Programme uebertragen werden koennen. Mit nur_pruefen: true sagt es, was auf dem Brett schon ist — fabrikneu, fremdes Programm oder bereits MicroPython — und schreibt nichts. | port, nur_pruefen |
esp32_nachlesen | Liest vom ESP32 zurueck, ob die LED wirklich blinkt: startet das Programm auf dem Geraet und zeichnet dort die Pegel der Anschluesse auf. Takt und Wechsel werden gegen die Erwartung gehalten (ABNAHME) — die Messung am Geraet, unabhaengig von programm_testen. Setzt voraus, dass esp32_uebertragen gelaufen ist. | port, datei, sekunden, pwm, roh, erwartet |
esp32_uebertragen | Kopiert eine Datei aus der Werkstatt auf den ESP32 und startet ihn neu. Standardziel ist main.py, denn MicroPython fuehrt diese Datei nach dem Einschalten selbsttaetig aus. Setzt voraus, dass esp32_firmware bereits gelaufen ist. | port, datei, ziel, erwartet |
nachweis_autark | Nimmt den Zustand der Stellen ausserhalb des Paketordners auf ('vorher') und vergleicht ihn spaeter ('nachher'). Damit laesst sich belegen statt behaupten, dass der Rechner unveraendert bleibt. Vor der Arbeit und vor dem Aufraeumen aufrufen. | wann |
paket_installieren | Installiert ein Python-Paket in die eigene Umgebung in der Ablage. Erlaubt sind nur: esptool, mpremote, pyserial, setuptools, wheel. Fuer den ESP32 wird esptool gebraucht. | paket |
ports_zeigen | Zeigt alle seriellen Anschluesse (COM-Ports) des Rechners und markiert, welcher nach einem USB-Seriell-Wandler eines ESP32 aussieht. Vor dem Flashen aufrufen. | — |
programm_ausfuehren | Fuehrt ein beliebiges Python-Programm aus der Werkstatt mit dem Paket-Python aus — fuer alles, was kein ESP32-Programm ist (Rechner, Skripte, Programme mit Fenster). Berichtet Ausgabe, Fehler und Rueckgabewert; Urteil LAUF BESTANDEN / NICHT BESTANDEN. Mit fenster true wird ein Programm mit grafischer Oberflaeche (tkinter) gestartet und beobachtet, ob es laeuft und ein Fenster zeigt. | datei, sekunden, fenster, offen_lassen, eingabe |
programm_testen | Fuehrt ein Programm aus der Werkstatt ohne Hardware aus und zeichnet auf, was an den Anschluessen geschieht; eine LED auf dem Bildschirm zeigt es an. IMMER aufrufen, nachdem ein Programm geschrieben wurde und BEVOR es auf den ESP32 ueberspielt wird — ein Programm, das hier nicht laeuft, laeuft dort auch nicht. Ersetzt zugleich die Hardware, wenn keine da ist. | datei, sekunden, oeffnen, erwartet |
schreib_datei | Schreibt eine Textdatei in die Werkstatt, zum Beispiel den Quelltext fuer den ESP32. Vorhandene Dateien werden ersetzt. Ausserhalb der Ablage kann nicht geschrieben werden. | name, inhalt |
umgebung_anlegen | Richtet ein eigenes, eingebettetes Python samt pip in der Ablage ein. Installiert nichts im System: es wird nur entpackt und spaeter wieder geloescht. Muss vor paket_installieren und esp32_flashen laufen. | neu |
umgebung_anlegen eigenes Python aus dem Paket, dazu tkinter zuerst
└─ paket_installieren esptool, mpremote aus dem Vorrat (keine Netzverbindung)
├─ ports_zeigen welcher Anschluss? — der Mensch bestätigt
└─ esp32_firmware MicroPython aufs Gerät (löscht das Brett)
schreib_datei das Programm entsteht in der Werkstatt
├─ programm_testen Nachbau ohne Hardware, Abnahme gegen die Erwartung ← hier wird entschieden
│ └─ esp32_uebertragen nur Abgenommenes aufs Gerät; liest danach selbst nach
│ └─ esp32_nachlesen misst am Gerät: Flanken (µs) oder Tastgrad (PWM)
└─ programm_ausfuehren jedes andere Python-Programm: Konsole oder Fenster (tkinter)
nachweis_autark vorher / nachher: der Rechner blieb, wie er war
aufraeumen am Kursende, über START.bat [2]
Der Kern des Lehrbeispiels: Ein Sprachmodell schreibt in Sekunden ein Programm, das plausibel aussieht. Ob es tut, was verlangt war, entscheidet keine Meinung, sondern eine Messung, die durchfallen kann. Es gibt zwei unabhängige Wege, und erst wenn beide übereinstimmen, gilt ein Programm als abgenommen.
programm_testen)Derselbe Quelltext wie für den ESP32 läuft auf dem PC; nur das machine-Modul ist nachgebaut und zeichnet auf, was das
Programm an den Anschlüssen tut. Die Zeit ist eine gedachte Uhr: time.sleep rückt sie vor, statt zu warten,
plus 0,8 ms Rechenzeit je Runde, wie sie MicroPython auf dem ESP32 braucht (kalibriert am 05.10.2026: 11 Atemzüge in 20 s bei 1024 Stufen
zu 1 ms). Grund: Windows hält 10 ms Schlaf nicht ein, der ESP32 schon; ein Lauf dauert so Bruchteile einer Sekunde statt sechs.
Gemessen werden Pins (Wechsel, Takt) und bei PWM die Hüllkurve des Tastgrads: Periode, Takt, Form (sinusförmig oder dreieckig —
„Dreieck ist kein Sinus“). Die Abnahme vergleicht mit der Erwartung des Menschen: Anschlüsse, Takt (10 % Spielraum), Form.
esp32_nachlesen)Das Programm läuft auf dem ESP32, und der ESP32 misst selbst: Flanken per Interrupt mit seinem Mikrosekundenzähler (2,0000 s zwischen zwei Einschaltvorgängen bei einem 1-s/1-s-Programm), bei PWM der Tastgrad direkt aus dem PWM-Kanal, alle 10 ms aus einem Zeitgeber-Interrupt, damit das Programm nicht gebremst wird. Ein meldendes Programm und die Brücke, die nur seriell mitliest, waren der dritte Weg, als Auge und Gerät sich widersprachen — das Gerät hatte recht.
| Programm | Nachbau | Gerät | Auge |
|---|---|---|---|
| blink.py 1 s an / 1 s aus | 0,50 Hz | 0,500 Hz, 2,0000 s | „1 zu 1, subjektiv“ |
| blink.py 2 Hz | 2,00 Hz | 2,06 Hz; seriell „AN“ alle 500 ms | erst „1 Hz“, dann „viel schneller“ — das Auge zählt schlecht |
| atmen.py 1024 Stufen × 1 ms, Kosinus | vor der Rechenzeit 1 Hz, danach 0,55 Hz | 0,49 Hz, sinusförmig | 11 Atemzüge in 20 s = 0,55 Hz |
Der Prüfstand im Arbeitsbereich fährt dieselben Werkzeuge mit einem festen Modell und festen Antworten und hat zu jeder Regel eine
Gegenprobe, die durchfallen muss: pruefe_schleife.py (8), pruefe_regeln.py (28), pruefe_gespraech.py (30),
pruefe_ungeprueft.py (6), pruefe_pwm.py (7), dazu pruefe_alles.py (19) gegen das Anforderungsblatt.
Vermerk der Unvollständigkeit. Dieses Paket ist ein Lehrbeispiel, kein fertiges Produkt. Es zeigt, wie eine lokale KI mit einem Agenten und messenden Werkzeugen Programme schreibt, prüft und auf Hardware bringt — und es zeigt ebenso ehrlich, woran ein kleines Modell scheitert. Alles, was hier als „funktioniert“ steht, ist am 04./05.10.2026 auf einem Windows-Laptop (8 GB frei, Smart App Control EIN) mit einem ESP32 an COM3 gemessen worden; alles andere steht als offen da.
| Anweisung | Qwen2.5-Coder-3B | Qwen2.5-Coder-7B | |||||
|---|---|---|---|---|---|---|---|
| Ende | Aufrufe | Abnahmen | Ende | Aufrufe | Abnahmen | Dauer | |
| hallo bist du bereit? | Antwort in Worten | 0 | — | läuft noch | |||
| Wie testen wir ein Blinkprogramm? Gibt es eine LED? | schrieb und prüfte gleich blink.py; FERTIG | 3 | ✓1 | läuft noch | |||
| blink.py, 1 Hz | FERTIG | 5 | ✓1 ✗1, 1× selbst geprüft | läuft noch | |||
| auf 3 Hz ändern | Abbruch nach 25 Schritten | 15 | ✗5, 5× selbst geprüft | läuft noch | |||
| atmen.py sinusförmig 1 Hz | FERTIG | 9 | ✓1 ✗1, 3× selbst geprüft | läuft noch | |||
| zwei LEDs, zwei Takte | Textantwort („JSON nicht korrekt“), kein Werkzeug | 0 | — | läuft noch | |||
| Taschenrechner tkinter | nicht mehr gemessen (Reihe abgebrochen) | läuft noch | |||||
| Ist nun alles ok? | nicht mehr gemessen | läuft noch | |||||
Lesart: „Ende“ ist, wie die Anweisung ausging; „Abnahmen“ zählt bestandene (✓) und durchgefallene (✗) Prüfungen; „selbst“ heißt, der Agent musste die Prüfung auslösen, weil das Modell FERTIG sagte, ohne zu prüfen. Die 3B-Reihe wurde nach sechs Anweisungen abgebrochen, um dem 7B den Prüfstand freizugeben.
Nichts. Und das wird gemessen, nicht behauptet: beim Start nimmt das Paket den Zustand der gefährdeten Stellen auf, beim Aufräumen vergleicht es ihn und zeigt das Ergebnis, bevor es löscht.
| Stelle | warum sie gefährdet wäre | was dagegen geschieht |
|---|---|---|
Python des Rechners und seine site-packages | hierhin schriebe ein pip install normalerweise | installiert wird nur mit dem eigenen Python in ablage\python |
%APPDATA%\Python | das Benutzer-Paketverzeichnis; pip weicht dorthin aus | PYTHONNOUSERSITE=1 |
%LOCALAPPDATA%\pip | der pip-Zwischenspeicher — wird unbemerkt mehrere hundert MB groß | PIP_CACHE_DIR zeigt in die Ablage |
PATH, PYTHON*, PIP_* | ein halb fremdes Python ist der am schwersten zu findende Fehler | werden für die Unterprozesse entfernt |
Programme werden an fünf Stellen gestartet: die Werkzeuge tun es an genau einer (lauf() in _muster.py), dazu startet der Agent die Werkzeuge, der Modellserver wird gestartet, und einmal startet sich das eigene Python neu. Alle fünf reichen dieselbe abgeschirmte Umgebung weiter. Stünde der Aufruf an neun Stellen, würde die zehnte es vergessen, und zwar unbemerkt: auf dem Rechner des Erbauers ist PYTHONPATH nicht gesetzt und der Zwischenspeicher schon warm; der Fehler zeigte sich erst im Kurs. Deshalb prüft pruefe_alles.py das als B10 und fällt durch, sobald eine Stelle die Umgebung vergisst.
Alles Erzeugte liegt in einem Ordner. Das erzwingt der Werkzeugrahmen: jeder
Schreibpfad wird aufgelöst und gegen die Ablage geprüft, bevor eine Datei entsteht. Deshalb
ist aufraeumen ein Beweis und keine Behauptung — es löscht genau diesen Ordner
und zählt hinterher nach.
Gemessen über drei volle Zyklen: anlegen, nachweisen, aufräumen. Die Prüfsumme über
paket\ war vorher und nachher dieselbe, jedes Mal null Reste. Das Mitgelieferte
wird nur gelesen — darum läuft derselbe Ordner beliebig oft.
Es gibt genau eine Stelle, an der Quelltext ausgeführt wird, den ein Sprachmodell
geschrieben hat: programm_testen. Davor liest ein Prüfer den Syntaxbaum —
erlaubt sind machine und time, verboten sind unter anderem
open, eval, getattr und alle Namen mit doppeltem
Unterstrich, über die der Weg außen herum führt.
Dieser Prüfer ist kein Schutz gegen einen Angreifer — gegen den hilft kein Filter, sondern nur, fremden Quelltext gar nicht auszuführen. Er ist ein Schutz gegen ein Modell, das sich vertut, und das ist der Fall, der wirklich eintritt. Dazu kommen Zeitgrenze, eigenes Python und die abgeschirmte Umgebung.
Zwei Dinge gehören ungeschönt dazu:
Die Registrierung wird nicht gemessen, nur begründet: nichts im Paket ruft ein Installationsprogramm auf. Begründet ist nicht gemessen.
Der ESP32 wird wirklich verändert. Sein Speicher wird gelöscht und mit MicroPython neu beschrieben; was vorher darauf war, ist weg. Das ist der Zweck der Übung — und es ist die einzige bleibende Änderung, die dieses Paket macht. Sie trifft das Steckbrett, nicht den Rechner.
Der USB-Treiber ist das Einzige, was eine echte Installation mit Adminrechten bräuchte — falls Windows den Wandler nicht kennt. Der Agent installiert ihn nicht; das entscheidet ein Mensch.
| Meldung | was zu tun ist |
|---|---|
| „Es ist kein serieller Anschluss sichtbar" | Steckbrett eingesteckt? Datenkabel statt Ladekabel? Sonst Treiber aus paket\treiber\ installieren (Adminrechte) und neu einstecken. Ohne Hardware geht es weiter, siehe Beispiel 2 |
| „An COM5 meldet sich kein ESP32" | anderer Anschluss (ports_zeigen), oder Thonny hält den Anschluss noch belegt. Bei manchen Brettern BOOT beim Einstecken drücken |
| „llama-server hat sich sofort beendet" | zu wenig Arbeitsspeicher. Kleineres Modell: hole_paket.py --modell coder-3b oder 1.5b |
| Modell antwortet, ruft aber kein Werkzeug | kommt bei kleinen Modellen vor. Menüpunkt [7] macht dieselben Schritte mit fester Reihenfolge |
| ABNAHME NICHT BESTANDEN | kein Fehler des Pakets, sondern sein Zweck. Die Befunde sagen, welche Zahl nicht stimmt; das Modell berichtigt den Quelltext und prüft erneut |
| „ist abgebrochen (Rückgabewert 1)" | das erzeugte Programm hat einen Fehler. Die Meldung darunter nennt Datei und Zeile |
| „machine.I2C ist nicht nachgebildet" | das Programm benutzt etwas, das der Lauf ohne Hardware nicht kennt. Dann hilft nur das Gerät selbst |
| „Es blieben N Dateien zurück" | eine Datei ist noch geöffnet (Editor, serieller Monitor). Schließen, Aufräumen wiederholen |
| „pip ließ sich nicht einrichten" | meist ein Virenscanner, der get-pip.py abfängt. Ordner als Ausnahme eintragen |
| Kein Python gefunden | START.bat packt dann das mitgelieferte aus. Für Menüpunkt [4] genügt das nicht — Füllen braucht ein Python mit pip |
Menüpunkt [8] Bericht sammeln schreibt alles, was zur Beurteilung von außen
nötig ist, in eine Datei BERICHT_<Datum>.txt neben
START.bat: dieser Rechner, was im Paket liegt und was fehlt, die Selbstprüfung mit
jedem Punkt, jedes Werkzeug einmal aufgerufen, das Protokoll des letzten Laufs und der Inhalt
der Ablage.
Diese Datei weitergeben genügt — niemand muss danebensitzen und erklären, was er gesehen hat. Benutzer- und Rechnername sind durch Platzhalter ersetzt: der Bericht soll sagen, was das Paket tut, nicht wem der Rechner gehört.
ablage\protokoll.txt hält jeden Werkzeugaufruf mit Uhrzeit fest. Es wird beim
Aufräumen mit gelöscht — wer es behalten will, kopiert es vorher heraus.
python agent\agent.py --werkzeuge was es gibt
python agent\agent.py --probe jedes einmal aufrufen
python agent\pfade.py was im Paket fehlt
python agent\werkzeuge\ports_zeigen.py "{}" ein Werkzeug einzeln