Skip to content
Zum Inhalt springen

Ist dein KI-Agent „temporalisierbar“? Robuste Workflows mit Quarkus und LangChain4j

mit Les Jackson

Les Jackson von Temporal war live dabei, als wir einen Urlaubsgenehmigungs-Agenten in Quarkus bauten. Wir haben das LLM und die App selbst mitten im Workflow abgeschossen, um zu sehen, ob Temporals Durable Execution ihn ohne handgeschriebenen Recovery-Code zurückholt. Hat sie, und dabei ist ein neues Wort entstanden.

Veröffentlicht: 30. Juli 2026Lesezeit: 6 Min. Lesezeit
Ist dein KI-Agent „temporalisierbar“? Robuste Workflows mit Quarkus und LangChain4j

YouTube

Ist dein KI-Agent „temporalisierbar“? Robuste Workflows mit Quarkus und LangChain4j

YouTube-Video laden

Dieses Video wird von YouTube eingebettet und erst nach Ihrer Einwilligung geladen. Beim Laden können personenbezogene Daten an YouTube oder Google übermittelt und Cookies gesetzt werden.

Auf YouTube öffnen

Mehr dazu in der Datenschutzerklärung.

Projektquelle

Arbeits-Repository

Hier findest du Prompts, Instructions und Beispiele aus dem gezeigten Modernisierungs-Workflow.

Repository öffnen
Timestamps der Session

Les Jackson, Staff Developer Advocate bei Temporal, kam direkt von einer Dienstreise, um mit mir ein Urlaubsgenehmigungssystem in Quarkus und LangChain4j zu bauen und es anschließend auf Temporals Plattform für Durable Execution umzustellen. Die Frage, zu der wir immer wieder zurückkamen: Wenn der LLM-Aufruf eines KI-Agenten fehlschlägt oder die ganze App mitten in einer Anfrage abstürzt, was übersteht das eigentlich?

Les Jackson

Co-Speaker

Les Jackson

Staff Developer Advocate bei Temporal

Les war dabei, um einen Quarkus- und LangChain4j-Agenten auf Temporal umzustellen, und führte dabei durch Workflows, Activities, durable Retries und Human-in-the-Loop-Signale.

Was ist Temporal?

Temporal bezeichnet sich selbst als „Durable Execution"-Plattform. Les brachte das Versprechen auf den Punkt und relativierte es im gleichen Atemzug:

Code wird immer irgendwann fehlschlagen. Temporal hilft deinem Code, sich davon wirklich elegant zu erholen, ohne dass du als Entwickler viel dafür tun musst.

Les Jackson, Staff Developer Advocate, Temporal

Unter der Haube ist Temporal ein Event-Sourcing-System. Es speichert jedes Ereignis, das ein Workflow auslöst. Stürzt ein Service ab, spielen diese Ereignisse den genauen Stand vor dem Absturz zurück. Dein Code muss nie selbst wissen, wie er weitermacht.

Zwei Bausteine machen das möglich. Ein Workflow ist deine Businesslogik: die Schleife, die entscheidet, was als Nächstes passiert, und sie muss deterministisch sein, damit Temporal sie sicher wiederholen kann. Eine Activity ruft etwas anderes auf, ein LLM, eine REST-API, eine Datenbank, und darf dabei beliebig nicht-deterministisch sein.

Genau hier entsteht ein verbreitetes Missverständnis. Wer „der Workflow muss deterministisch sein" hört, schließt daraus oft, dass sich KI-Agenten-Loops damit gar nicht bauen lassen. Das stimmt nicht. Der Loop orchestriert nur. Die unberechenbaren Teile, die, die zu lange brauchen oder bei jeder Anfrage anders antworten, stecken in den Activities, die er aufruft.

Für eine kleine App ohne externe Aufrufe, die schnell antwortet, ist Temporal übertrieben. Es lohnt sich, sobald du andere Services aufrufst, etwas Langlaufendes betreibst oder etwas absichern musst, das wirklich nicht scheitern darf, Les' Beispiel war Banking-Workloads. Cron oder Job-Queues ersetzt Temporal nicht eins zu eins, aber es setzt sich darüber: Alles, wofür du sonst Cron einplanen würdest, kann Temporal auch orchestrieren, dazu die Absturzerholung, die Cron nie mitgeliefert hat.

Wie die Session lief

Die Ausgangslage hatte kein Sicherheitsnetz. Die Demo: eine Urlaubsantrag-App aus Quarkus, LangChain4j und einem lokalen Llama-3.2-Modell in Ollama. Ein Mitarbeiter stellt einen Antrag, die App prüft ihn gegen die Urlaubstermine aller anderen, LangChain4j lässt das LLM den Antrag bewerten, und die Entscheidung einer Führungskraft löst eine von LangChain4j entworfene Benachrichtigungsmail aus. Der gesamte Zustand lag in einer ConcurrentHashMap, nur im Arbeitsspeicher, wie bei 20:22 zu sehen.

Ollama mitten im Aufruf zu killen bewies genau das. Bei 39:23 lieferte die App einen schlichten internen Serverfehler. Der Antrag war einfach weg: kein Retry, keine Erinnerung, dass er je existierte.

Copilot erledigte den Umbau mit einem einzigen Prompt. Nach der Installation des offiziellen skill-temporal-developer-Skills, damit Copilot mit Temporals echten Konventionen arbeitet statt zu raten, erzeugte ein Prompt bei 44:58 einen Workflow, verpackte beide LangChain4j-Aufrufe als Activities und trug in application.properties Temporal-Ziel, Namespace und Task-Queue ein.

Es scheiterte beim ersten Versuch, und genau das war der nützliche Teil. Bei 1:03:51 nannte die Event-Historie der Temporal-UI das genaue Problem: eine ContextNotActiveException, weil die LangChain4j-Aufrufe jetzt auf einem Activity-Thread außerhalb jeder HTTP-Anfrage liefen, wo Quarkus' CDI-Request-Scope gar nicht existiert. Der Fix war eine einzige Annotation, @ActivateRequestContext. Les' größerer Punkt: eine App nicht in einem einzigen Big-Bang-Prompt „temporalisieren" lassen. Erst einen Migrationsplan anfordern, dann Schritt für Schritt umsetzen.

Der eigentliche Test war Überleben, nicht Erfolg. Mit dem Fix zeigte die Temporal-UI einen Workflow im Status „läuft" bei 1:11:24, wartend auf ein Signal mit der Entscheidung der Führungskraft. Den kompletten Worker-Prozess bei 1:12:27 zu killen und neu zu starten änderte nichts: Die spätere Genehmigung über die UI ließ den Workflow genau dort weitermachen, wo er aufgehört hatte, und rief LangChain4j nur noch für die Benachrichtigung auf, nicht für die bereits abgeschlossene Prüfung.

Retries haben Grenzen, und die Demo traf genau darauf, ganz ehrlich. Ollama während einer laufenden Wiederholung der Benachrichtigungs-Activity erneut zu killen, bei 1:17:28, zeigte die Retries live in der Temporal-UI. Nachdem die Versuche der Standard-Retry-Policy aufgebraucht waren, scheiterte der Workflow, und der Antrag verschwand, weil die App diesen Fehlerfall selbst nie behandelt hatte. Temporal wiederholt einen Aufruf für dich. Es repariert nicht die Annahme deiner UI, dass immer alles klappt.

Drei Dinge, die hängen geblieben sind

1. Retries merken sich, wo sie waren

Temporals Retries sind durable, nicht in-process. Les' Vergleich: Eine In-Process-Retry-Bibliothek in .NET, die mitten im Retry abstürzt, fängt nach dem Neustart wieder bei Versuch eins an. Temporal nicht. Ein Aufruf, der beim Absturz gerade beim fünften von zehn Versuchen war, macht bei Versuch fünf weiter.

Das hat einen echten Preis: Ein von vorn gestarteter Retry verschwendet einen LLM-Aufruf, nicht nur Zeit.

Ein Zuschauer im Live-Chat ergänzte einen Punkt, den man sich merken sollte: Lässt man LangChain4js eigene Chat-Modell-Retries zusätzlich zu Temporals Retries aktiv, stapeln sich beide übereinander. Die Retries des Chat-Modells auf null setzen. Retries allein Temporal überlassen.

2. Warten kostet nichts

Ein Workflow, der auf ein Signal wartet, kostet nichts, solange er wartet, und braucht niemanden, der ihn beobachtet. Das machte aus dem Urlaubsgenehmigungs-Szenario mehr als ein Spielzeugbeispiel: Echte Genehmigungen warten auf echte Menschen, manchmal tagelang, und der Workflow muss diese Lücke genauso überstehen wie einen Absturz.

3. Ein echtes Skill brachte Copilot weiter als erwartet

Dass wir das offizielle Temporal-Skill geladen hatten, bevor Copilot den Code anfasste, machte einen Unterschied. Es fand die richtigen Annotationen, die Form der Retry-Optionen und die Workflow- und Activity-Interfaces, ohne dass wir auf Dokumentation zeigen mussten.

Es hat dabei auch einen echten Bug eingebaut, den CDI-Context-Fehler von oben. Ein Skill macht den Agenten kompetent in den Konventionen eines Frameworks. Es macht seine Ausgabe nicht automatisch richtig.

Abschließender Gedanke

Temporal hat das LLM nicht klüger gemacht und die Genehmigungslogik nicht ausgefeilter. Umsonst ist es auch nicht: Man betreibt weiterhin einen Server und eine Datenbank und denkt in Workflows und Activities statt in einfachen Funktionen.

Was es uns für vergleichsweise wenig Code gebracht hat, war ein Agent, der nach einem Absturz zurückkam, ohne dass einer von uns eine einzige Zeile Recovery-Logik geschrieben hätte. Ruft ein Teil deines eigenen Codes etwas Unzuverlässiges auf, und würde der Verlust seines Zustands etwas ausmachen, stell dir die Frage, die wir uns an diesem Abend ständig gestellt haben: Ist es temporalisierbar?

Kommentare

Kommentare optional von GitHub laden

Die Kommentarfunktion wird über Giscus und GitHub Discussions bereitgestellt. Sie wird erst nach Ihrer ausdrücklichen Einwilligung geladen. Beim Laden können personenbezogene Daten wie Ihre IP-Adresse und technische Metadaten an GitHub übermittelt sowie Cookies oder ähnliche Technologien gesetzt werden.

Bitte bestätigen Sie zuerst Ihre Einwilligung, bevor die Kommentare geladen werden.

Mehr dazu in der Datenschutzerklärung.