← Zurück zum Blog

Anatomie eines lynox-Agent-Laufs

Die häufigste Reaktion von Entwicklern auf lynox ist die richtige: „Ist das nur Claude mit ein bisschen mehr Prompting?” Berechtigte Frage. Genau das sind viele Produkte. Für lynox lautet die ehrliche Antwort: Nein — aber das zu erklären, heißt dir die beweglichen Teile zu zeigen.

Also gehen wir Schritt für Schritt durch, was zwischen deinem Senden im Web-UI und der Antwort von lynox passiert. Keine Marketing-Behauptungen — nur die vier beteiligten Systeme und wo jedes davon hingehört.

Die vier Systeme

Jeder lynox-Lauf nutzt diese vier. Sie sind unabhängige Prozesse (zumindest unabhängig testbare Einheiten), die sich über klar definierte Schnittstellen koordinieren:

┌─────────────────────────────────────────────────────────────┐
│                          Engine                             │
│  Prozessweiter Singleton. Verwaltet Config, Provider,       │
│  Tools, den Knowledge Graph und die HTTP-API.               │
└──────────────────┬──────────────────────────────────────────┘
                   │ erzeugt pro Konversation

┌─────────────────────────────────────────────────────────────┐
│                         Session                             │
│  Kontext pro Konversation. Enthält Agent-Loop, LLM-Client,  │
│  Streaming-Zustand, Tool-Permission-Zustand.                │
└──────────────────┬──────────────────────────────────────────┘
                   │ persistiert via

┌─────────────────────────────────────────────────────────────┐
│                       ThreadStore                           │
│  SQLite. Threads, Nachrichten, Tool-Call-Audit, Anhänge.    │
│  Die dauerhafte Schicht. Alles andere ist wiederherstellbar.│
└─────────────────────────────────────────────────────────────┘

                          (orthogonal)

┌─────────────────────────────────────────────────────────────┐
│                       WorkerLoop                            │
│  Hintergrund. Wiederkehrende Aufgaben, geplante Workflows,  │
│  alles, was der Agent „für später" entschieden hat. Läuft   │
│  unabhängig von jeder offenen Session.                      │
└─────────────────────────────────────────────────────────────┘

Die Engine ist mit Absicht single-tenant. Pro Benutzer beziehungsweise pro Geschäft läuft genau ein lynox-Prozess. Multi-Tenant lebt eine Schicht darüber — in der Control Plane des Managed Hostings, wo jeder Mandant einen isolierten Container bekommt. Genau diese Trennung hält die Engine selbst schlank: keine Autorisierungs-Akrobatik pro Request, keine Row-Level-Security, die sich quer durch jede Query zieht. Als einzelner Nutzer fährst du eine Engine — Punkt.

Schritt 1 — deine Nachricht trifft die Engine

Du schickst „Was ist diese Woche bei Acme offen?”. Die HTTP-API (ein SSE-Endpoint) nimmt sie entgegen. Die Engine sucht oder erzeugt eine Session, geschlüsselt über die Thread-ID. Die Session re-hydriert aus dem ThreadStore — sie zieht die vorherigen Nachrichten, den partiellen Tool-Call-Zustand, falls der vorige Lauf mitten in einem Tool abgebrochen ist, sowie die Thread-spezifische State-Machine.

Schon hier ein Unterschied zu den meisten Agent-Frameworks: Der dauerhafte Zustand liegt in SQLite, nicht im Context Window des LLM. Ein Thread mit 10 000 Nachrichten ist kein Problem. Der Agent re-hydriert nur, was für den aktuellen Turn nötig ist — nicht den gesamten Verlauf.

Schritt 2 — der Knowledge Graph hängt Kontext an

Bevor der Prompt zum LLM geht, läuft eine Entity-Extraction über deine Nachricht — auf der Suche nach bekannten Entitäten im Knowledge Graph, die zu „Acme”, „diese Woche” und weiteren Handles passen. Der Graph ist ein typisierter In-Process-Store: Entitäten sind Knoten (Firmen, Kontakte, Deals, Projekte, Threads), Kanten sind typisierte Beziehungen („arbeitet bei”, „Owner von”, „erwähnt in”), und die Entity-Resolution ist ihr eigenes Subsystem — „Acme Inc.”, „acme corp” und das nackte „Acme” in einer E-Mail lösen sich zum selben Knoten auf.

Die extrahierten Entitäten und ihre direkte Nachbarschaft werden dem Prompt als strukturierter Kontext beigefügt. Nicht als Chatlog-Dump — als benannte Fakten. Das Modell fasst keine Konversationshistorie zusammen; es liest einen kleinen, typisierten Graph-Ausschnitt, der zu deiner Frage passt.

Schritt 3 — der Agent-Loop dreht

Der Agent-Loop der Session ist ein Standard-Tool-Use-Loop, mit zwei Details, die wichtig sind:

  1. Streaming ist verschränkt, nicht sequenziell. Das LLM emittiert eine teilweise Assistant-Nachricht, dann einen tool_use-Block, dann wieder Assistant-Text, dann ein weiteres tool_use. Das Web-UI rendert das in chronologischer Reihenfolge — du siehst das „Ich schaue erst in die Inbox” und den Inbox-Tool-Call und das Ergebnis und die anschließende Argumentation in genau der Reihenfolge, in der es passiert ist. Das ist das Rendering, das der Chat-Store ContentBlock[] nennt.

  2. Tools gehen durch ein Permission-Gate. Jeder Tool-Call landet vor der Ausführung beim permissionGuard. Der prüft (a) liegt dieses Tool im erlaubten Set für diese Session, (b) braucht diese spezifische Operation eine Bestätigung vom Nutzer, (c) ist das Kostenlimit pro Session beziehungsweise pro Tag noch eingehalten. Das Kostenlimit ist die tragende Prüfung: Wenn die Session ihr konfiguriertes Maximum erreicht hat, hält der Loop sauber an.

Der Loop endet, sobald das LLM eine finale Assistant-Nachricht ohne weiteren Tool-Call sendet. Die komplette Konversation — jede Assistant-Nachricht, jeder Tool-Call, jedes Tool-Ergebnis — wird in einer einzigen Transaktion in den ThreadStore committet.

Schritt 4 — was sich gemerkt wird

Wenn der Lauf abschließt, passieren zwei Dinge:

  • Entity-Extraction (der zweite Pass). Neu erwähnte Entitäten in diesem Lauf — eine Person, die zum ersten Mal auftaucht, ein Deal, der die Stage wechselt, ein Thread-Verweis — werden in den Knowledge Graph reconciled. Die Entity-Resolution ist konservativ; mehrdeutige Matches werden markiert, nicht stillschweigend zusammengeführt.
  • Pattern-Detection. Die Pattern-Engine merkt, wenn du etwas mehr als einmal machst („du hast in den letzten drei Läufen Support-E-Mails beantwortet”). Sie schlägt dann gegebenenfalls einen Workflow-Capture vor — das Muster wird zu einem wiederverwendbaren, parametrisierten Template, das du wie ein Rezept bearbeiten kannst.

Keines von beidem musst du anstoßen. Beides läuft am Ende jedes erfolgreich beendeten Laufs.

Schritt 5 — was der Worker ohne dich tut

Manche Läufe planen etwas für später. „Bei Acme am Freitag nachfassen, falls bis dahin keine Antwort kommt” ist zweierlei: ein Tool-Call, der die Absicht festhält, plus ein Worker-Eintrag, der am Freitagmorgen feuert. Der WorkerLoop ist ein eigener Prozess — er teilt mit keiner offenen Session Zustand — der per Cron aufwacht, fällige Work-Items aufnimmt und pro Item eine neue Session aufmacht, um die Sache zu erledigen. Aus Sicht des Loops sind eine wiederkehrende Aufgabe und eine interaktive Nachricht derselbe Codepfad; der einzige Unterschied ist, wer den Trigger ausgelöst hat.

Warum diese Form

Ein paar Alternativen, die ich verworfen habe und warum:

  • Ein einfacher LLM-Call-Wrapper. Funktioniert für Chatbots; fällt auseinander, sobald der Agent über mehr als einen Turn hinweg etwas tun oder über mehr als eine Konversation hinweg etwas behalten soll.
  • Vektor-Suche über Markdown. Funktioniert für Dokumente. Reicht nicht für das Relationale: „Welche Deals sind diese Woche offen?” braucht einen Join, keinen Ähnlichkeits-Score.
  • Eine Library, die du selbst verdrahtest. Eine Library lässt dir das Integrationsproblem: ThreadStore, Knowledge Graph, Permission-Gate, Worker — jeder Consumer würde sie schlecht nachbauen. lynox liefert das System mit, damit sie konsistent bleiben.

Den Split „single-tenant Engine + multi-tenant Control Plane” halte ich für am meisten unterschätzt. Die Runtime bleibt schlank, die Persistenz ist eine SQLite-Datei, und „auf einen anderen Server umziehen” heißt scp ~/.lynox/. Cloud-Hosting ist ein Service obendrauf — kein anderes Produkt.

Was noch ruckelt

  • Voice ist mies. Die Latenz auf dem Round-Trip macht’s kaputt; der Launch-Stack ist text-only.
  • Echtzeit-Kalender-Reads/-Writes fehlen noch. CalDAV ist das nächste große PRD.
  • Die Engine ist single-tenant by design. Wenn dein Team gemeinsamen Zustand braucht, ist das Aufgabe der Managed-Hosting-Schicht, nicht der Engine.
  • LLM-Outputs sind nicht deterministisch. Zwei Läufe mit demselben Prompt können divergieren. Das System hält das, wo’s drauf ankommt (Tool-Auswahl, Entity-Resolution), in Schach — aber nicht im reinen Antworttext.

Lies den Code

Alles oben steht im Source. ELv2-lizenziert — kostenlos für Produktion und Kundeneinsatz, ausgenommen ist das Anbieten von lynox als konkurrierender Hosted-Dienst (gleiche Lizenz wie Elasticsearch und Kibana). Einstiegspunkte:

Wer lieber über das Warum statt über die Architektur liest: Warum wir lynox gebaut haben deckt das ab.