< BACK Prompt Engineering für Produktionscode: Hard Lessons – Strichzeichnung

Prompt Engineering für Produktionscode: Lehren aus echten Fehlschlägen

Es war 23:43 Uhr an einem Donnerstag und ich starrte auf 340 Zeilen React-Code, den GPT-4 mit absoluter Sicherheit generiert hatte. Sauber. Gut kommentiert. Völlig kaputt in der Production. Der Custom Hook verwaltete den State auf eine Weise, die stille Re-Render-Schleifen verursachte – die Art, die keine Fehler wirft, sondern einfach leise deine Performance erledigt, bis ein Kunde dich Freitag morgens anruft und fragt, warum ihre Checkout-Seite neun Sekunden zum Laden braucht.

Diese Nacht hat mir mehr über Prompt Engineering beigebracht als jedes YouTube-Tutorial oder Twitter-Thread je könnte. Und ich hatte seitdem viele solcher Nächte.

Ich baue im Web seit neun Jahren. Bei Seahawk Media haben wir über 12.000 Websites versendet – WordPress, Headless Builds, maßgeschneiderte React Apps, WooCommerce Stores mit ernstem Transaktionsvolumen. KI-Code-Assistenten sind Anfang 2023 richtig in meinen Workflow eingestiegen, und ich bin zwischen dem Gedanken, dass sie wunderbar sind, und dem Wunsch, meinen Laptop in die Themse zu werfen, hin und her geschwungen.

Hier ist, was ich wirklich gelernt habe. Auf die harte Tour.

---

Das Modell kennt deine Codebase nicht. Du musst es ihr sagen.

Das klingt offensichtlich. In der Praxis ist es das nicht.

Der größte einzelne Fehler, den ich Entwickler machen sehe – mich selbst die ersten sechs Monate lang eingeschlossen – ist, ein LLM wie einen Senior Engineer zu behandeln, der deinen Code bereits gelesen hat. Du fragst „schreib eine Funktion zur Authentifizierung des Benutzers" und es schreibt etwas technisch Korrektes im Vakuum. Aber dein Projekt nutzt Supabase, nicht Firebase. Deine Tokens sind in httpOnly Cookies, nicht in localStorage. Dein Error-Format ist { status, message, data }, nicht das, worauf das Modell ausfiel.

Das Modell liegt nicht falsch. Es kennt dich nur nicht.

Gib Ihm jedes Mal einen Project Preamble

Ich starte jede bedeutsame Coding-Session jetzt mit dem, was ich einen „Context Block" nenne. Dauert etwa 90 Sekunden zu schreiben. Sieht ungefähr so aus:

  • Stack: Next.js 14 (App Router), TypeScript, Supabase, Tailwind CSS 3.4
  • State: Zustand, nirgendwo Redux
  • Auth: Supabase Auth mit httpOnly Cookies über Middleware
  • Error shape: { success: boolean, error?: string, data?: unknown }
  • Stilkonvention: Utility-first, keine Custom-CSS-Dateien außer wenn absolut notwendig

Paste das vor jede nicht-triviale Anfrage. Ich mache das in Cursor, indem ich eine _context.md Datei im Projekt-Root halte. Zwei Tastenanschläge zum Einfügen. Die Output-Qualität springt merklich nach oben, weniger Annahmen, weniger Dinge, die ich rausreißen muss.

---

Präzision ist das ganze Spiel

Zurück in 2022, bevor ich AI intensiv nutzte, gab mir ein Client ein Briefing, das buchstäblich zwei Sätze waren: „Baue uns ein Buchungssystem. Mach es gut." Wir verbrachten drei Wochen damit, hin und her über den Umfang zu diskutieren. Diese Erfahrung ist mir geblieben und prägt direkt, wie ich jetzt Prompts schreibe.

Vage Anfrage → vager Code. Jedes Mal.

„Schreib eine Funktion, die Orders abruft" wird dir etwas geben. „Schreib eine TypeScript async Funktion namens fetchOrdersByUser, die userId: string akzeptiert, die orders Tabelle in Supabase abfragt, wo user_id passt und status nicht cancelled ist, sortiert Ergebnisse nach created_at absteigend und gibt Order[] zurück oder wirft einen typisierten Error" wird dir etwas geben, das du tatsächlich ausliefern kannst.

Der Unterschied liegt nicht in der Fähigkeit des Modells. Es ist die Präzision der Anfrage.

Was in eine Code-Anfrage gehört

  1. Funktionsname und Signatur, lass das Modell keine Namenskonventionen erfinden
  2. Input-Typen und Output-Typen, TypeScript Generics falls relevant
  3. Die Datenquelle, welche Tabelle, welcher API Endpoint, welche Cache Layer
  4. Edge Cases, die du bereits kennst, „handle den Fall, wenn das Array leer ist"
  5. Was NICHT zu tun: „useEffect dafür nicht nutzen, verwende stattdessen eine Server Action"

Diese letzte Punkt ist wichtiger, als die meisten realisieren. Dem Modell zu sagen, was man vermeiden sollte, spart enorme Zeit. Ich habe angefangen, pro Projekt eine kleine „Anti-Patterns"-Notiz zu führen, Dinge wie „keine Client Components, es sei denn, die Benutzerinteraktion erfordert es", und ich beziehe relevante Zeilen in Prompts für dieses Projekt ein.

---

Verkette deine Prompts. Frag nicht nach allem auf einmal.

Seahawk hatte Ende 2023 einen Fintech-Kunden, ich werde nicht sagen, wer, bei dem wir einen mehrstufigen KYC-Flow aufgebaut haben. Komplexe Angelegenheit. Dokument-Upload, Liveness-Check-Integration, Status-Polling. Ich habe früh den Fehler gemacht, GPT-4 zu bitten, „baue die vollständige KYC-Flow-Komponente". Es produzierte 600 Zeilen heroisch aussehender Müll. Verstrickte Logik, vermischte Concerns, keine echte Trennung zwischen UI-State und Business Logic.

Also habe ich es verworfen und mit einer Chain neu angefangen.

Erster Prompt: „Design the state machine for a 4-step KYC flow. Steps: identity, document upload, liveness, review. Give me the state type and transitions only, no UI."

Zweite Aufforderung: „Gegeben diese State Machine [einfügen], schreibe den Zustand Store."

Dritte Aufforderung: „Gegeben dieser Store [einfügen], schreibe die StepIdentity Komponente. Nur dieser Schritt."

Die Ausgabe aus dem verketteten Ansatz war verwendbar. Nicht perfekt, ich habe immer noch etwa 30% umgeschrieben, aber verwendbar. Der monolithische Ansatz brachte mir nichts.

Anthropics eigene Anleitung zum Prompting spricht davon, komplexe Aufgaben in Teilaufgaben zu unterteilen, und ehrlich gesagt, das entspricht genau dem, was ich durch Versuch und Irrtum herausgefunden habe. Zerlege das Problem, bevor du deine Codebase zerlegi.

---

Lass Es Mit Sich Selbst Argumentieren

Das ist eine, über die ich völlig zufällig gestolpert bin. Ich habe eine generierte Utility-Funktion überprüft und statt sie einfach auszuführen, habe ich eine Folgefrage hinzugefügt: „Welche potenziellen Bugs oder Grenzfälle hat der Code, den du gerade geschrieben hast?"

Das Modell fand drei Probleme, die es nicht berücksichtigt hatte. Eines davon war ein echtes Problem, eine Race Condition in einer Async-Schleife, die in der Produktion ein Albtraum zum Debuggen gewesen wäre.

Jetzt mache ich das routinemäßig. Schreibe den Code, dann bitte ich es, den Code zu kritisieren. Dann bitte ich es, die Kritik zu beheben. Es fühlt sich leicht absurd an, das Modell aufzufordern, seine eigene Arbeit zu überprüfen, aber es deckt konsequent Dinge auf, die ich nur nach einer schmerzhaften Debugging-Sitzung gefangen hätte.

Du kannst das noch weiter treiben. Nachdem du eine funktionierende Funktion hast, versuche: „Schreibe das mit Fokus auf Performance um" oder „Wie würde sich das unter hoher Concurrency verhalten?" Die Antworten sind nicht immer anwendbar, aber etwa 40 % der Zeit decken sie etwas auf, das es wert ist, danach zu handeln.

---

Der „Role + Constraint"-Rahmen

Es gibt ein Prompt-Muster, das ich ständig nutze und das ich mir schon im ersten Jahr hätte überlegen sollen. Es funktioniert so: „Du bist ein [spezifischer Typ von Engineer]. Deine Einschränkung ist [harte Regel]. Jetzt [Aufgabe]."

Beispiel: „Du bist ein Backend-Engineer, der sich intensiv um Datenbankabfrage-Effizienz kümmert. Deine Einschränkung ist, dass du nicht mehr abrufen kannst, als für dieses Rendering erforderlich ist, kein Over-Fetching. Schreibe eine Supabase-Abfrage für das Admin-Dashboard, die Bestellanzahl, Gesamtumsatz und die fünf neuesten Bestellungen zurückgibt."

Diese Formulierung macht zwei Dinge. Sie richtet die „Persona" des Modells an dem aus, was ich wirklich brauche. Und die Einschränkung fungiert als Leitplanke, etwas, das das Modell beim Generieren explizit gegen sich selbst überprüft.

OpenAIs Prompting-Best-Practices beschreiben eine ähnliche Idee zum Geben einer Persona mit expliziten Anweisungen. Lesenswert, wenn du das noch nicht getan hast, aber ich würde sagen, der Constraint-Teil wird in ihrer Dokumentation unterbewertet.

Vergleiche die Ausgabe dieses gerahmten Prompts mit „schreib eine Supabase-Query für das Admin-Dashboard." Tag und Nacht. Wirklich.

---

Wann du mit Prompting aufhören und einfach den Code schreiben solltest

Das ist der Teil, den niemand laut aussprechen will.

KI-Codierungstools sind brillant bei: Boilerplate-Code, CRUD-Operationen, Utility-Funktionen, dem Schreiben von Tests für bereits vorhandenen Code, der Übersetzung zwischen Formaten (JSON-Schema zu TypeScript-Typ, SQL zu Supabase-Abfrage, etc.) und ersten Entwürfen von Dingen, die du später umfassend modifizieren wirst.

Sie sind wirklich schlecht darin: die tatsächliche Architektur deiner App zu verstehen, zu wissen, welcher Trade-off bei deiner spezifischen Skalierung wichtig ist, etwas zu schreiben, das eine knifflige zustandsbehaftete Interaktion berührt, ohne intensive Anleitung, und alles, wo die Spezifikation grundlegend mehrdeutig ist.

Ich habe mir jetzt eine persönliche Regel gesetzt: Wenn ich mehr als vier Folgeprompts gesendet habe, um ein Code-Stück richtig hinzubekommen, schließe ich den Chat und schreibe es selbst. Die Zeitkosten des Prompt-Debuggings können die Zeitkosten des reinen Schreibens übersteigen, besonders bei allem unter etwa 50 Zeilen.

Die Stack Overflow Developer Survey 2024 zeigte, dass 76% der Entwickler KI-Tools nutzen oder planen zu nutzen, aber dieselben Daten zeigten relativ geringes Vertrauen in die Genauigkeit. Diese Lücke zwischen Nutzung und Vertrauen ist genau dort, wo gutes Prompt Engineering lebt.

---

Versioniere deine Prompts wie du deinen Code versionierst

Letztes Jahr habe ich angefangen, einen prompts/-Ordner in Projekten zu führen, bei denen KI-Unterstützung erheblich ist. Markdown-Dateien. Eine pro Hauptfeaturebereich. Wenn ein Prompt besonders gute Ausgabe produziert, speichere ich ihn. Wenn ich eine bessere Version finde, aktualisiere ich die Datei.

Klingt obsessiv. Es hat mir wahrscheinlich sechs Stunden beim letzten großen Projekt allein gespart, ein Headless-WooCommerce-Build für einen Einzelhandelskunden, der von Shopify umzieht. Ich habe einen Product-Query-Prompt (mit kleineren Änderungen) über vier verschiedene Komponenten hinweg wiederverwendet, statt den Kontext von Grund auf erneut zu entwickeln.

Git-Track es. Ernsthaft. Prompt-Qualität ist reproduzierbar, wenn du Prompts als Artefakte behandelst, nicht als Wegwerf-Input. LangChain formalisiert diese Idee in einem Framework-Kontext, aber du brauchst kein Framework – ein Ordner mit Markdown-Dateien reicht für die meisten Agency-Workflows aus.

---

FAQ

Ist Prompt Engineering wirklich eine übertragbare Fähigkeit oder nur modellspezifisch?

Größtenteils übertragbar. Die Kernprinzipien – Spezifität, Kontext-Setting, Chaining, Critique Loops – gelten über GPT-4, Claude 3.5 Sonnet, Gemini und was auch immer kommt. Die Syntax variiert ein wenig und einige Modelle reagieren besser auf bestimmtes Framing, aber die zugrundeliegende Logik hält. Ich habe festgestellt, dass Claude gut auf explizite Constraints reagiert; GPT-4 reagiert gut auf Beispiele. Kleine Unterschiede, gleiche Grundlagen.

Wie gehst du mit von KI generiertem Code in Code Reviews um?

Wie jeder andere Code auch. Wenn es in Production geht, wird es reviewed. Punkt. Ich habe bei Seahawk aufgehört, "das wurde von KI generiert" in PRs zu markieren, weil es zu einem Red Herring wurde – Reviewer haben es anders scrutinisiert, manchmal unfair, manchmal nicht gründlich genug. Der Code besteht oder fällt auf seinen eigenen Meriten. Was ich markiere: jeder Abschnitt, wo die Logik nicht offensichtlich ist und ich keine Inline-Kommentare hinzugefügt habe, die die Überlegung erklären.

Verwendest du System Prompts oder nur Chat Prompts?

Beides. In Cursor verlasse ich mich auf die .cursorrules-Datei für persistente Project-Level-Instruktionen, Dinge, die ich sonst jedes Mal einfügen würde. Für One-Off-Tasks in der ChatGPT- oder Claude Web UI ist alles im Chat. Der .cursorrules-Ansatz hat Wiederholungen signifikant reduziert und das Modell bleibt über längere Sessions konsistenter.

Wie ist deine ehrliche Einschätzung: Ersetzen KI-Systeme Developer?

Es ersetzt bestimmte Tasks, nicht Entwickler. Die Judgment Calls – was gebaut werden soll, wie man es architektiert, welcher Trade-Off in diese Klien-Situation passt – sind nirgends automatisiert. Falls überhaupt, sind es die Entwickler, die unter Druck geraten, die rein execution-orientiert waren, nicht design- oder architecture-orientiert. Schärfe die Judgment Layer. Das ist der verteidigbare Teil.

---

Neun Jahre im Web-Entwicklung, und die grundlegende Lektion wiederholt sich immer wieder: Die Qualität deines Outputs wird durch die Qualität deiner Inputs bestimmt. Das galt, als es noch um Kundenbriefs ging. Es gilt jetzt mit Prompts.

Das Modell ist ein schneller, gelegentlich brillanter, häufig überselbstbewusster Junior-Developer. Behandle es entsprechend.

Empfohlene Lektüre: Building a Real-Time Auction Site with Next.js & Supabase, How to Cost Custom Software in 2026: A Working Estimator for und maßgeschneiderte Webentwicklung.

< BACK