Modell / Datensatz
ax-llm/ax avatar
ax-llm/ax

ax-llm/ax: DSPy-Modell für TypeScript mit generierten Bindings für fünf weitere Sprachen

The pretty much "official" DSPy framework for Typescript

2.924 Sterne194 ForksTypeScriptApache-2.0

Auf einen Blick

Was ist das?
Ax beschreibt LLM-Programme über Signaturen, Agents, Flows und Optimierer und kompiliert dieselbe Semantik nach Python, Java, C++, Go und Rust. Der interessante Teil ist weniger die Prompt-Abstraktion als die Frage, ob man den generierten Paketen in einer Nicht-TypeScript-Umgebung traut.
Für wen ist es gedacht?
Wer eine TypeScript-Codebasis hat und strukturierte LLM-Ausgaben mit Zod, Valibot oder ArkType validieren will, findet in @ax-llm/ax ein Paket, dessen Kernpfad laut README bewusst dünn bleibt. Wer Python, Java, C++, Go oder Rust als primäre Laufzeit braucht, sollte vor dem Einsatz prüfen, wie die generierten Quellen unter packages/<language> gepflegt werden und ob der eigene Anwendungsfall dort abgedeckt ist.
Darf ich es kommerziell nutzen?
Ja. Apache-2.0 ist eine freizügige Lizenz: Sie dürfen darauf aufbauende Software nutzen, verändern und verkaufen, solange Sie die Urheberrechts- und Lizenzhinweise beibehalten.
Wird es noch gepflegt?
Ja. Die letzten Commits kamen vor 6 Tagen.
In welcher Sprache ist es geschrieben?
Hauptsächlich TypeScript, laut der Sprachstatistik von GitHub.

Die Antworten beruhen auf den GitHub-Daten des Projekts (zuletzt abgeglichen am 15. September 2026) und auf unserer Analyse. Sie sind keine Rechtsberatung.

TIEFGEHENDE OPEN-SOURCE-ANALYSE

Das Problem: Prompt-Strings sind keine Schnittstellen

Wer heute mit einem LLM arbeitet, schreibt meist einen Prompt als Zeichenkette, hängt Nutzereingaben an, bekommt JSON zurück und parst es mit einem try/catch. Das funktioniert, bis sich das Modell anders verhält, ein Feld fehlt oder ein Provider die Antwort anders verpackt. Ax setzt an dieser Stelle an und macht die Beschreibung des Modellaufrufs zum typisierten Objekt. Eine Signatur wie 'review:string -> sentiment:class "positive, negative, neutral"' legt Eingabefeld, Ausgabefeld und die erlaubte Wertemenge fest. Der Rückgabewert ist laut README als literale Union typisiert, nicht als beliebiges Objekt. Adressat sind TypeScript-Teams, die LLM-Aufrufe in bestehenden Anwendungscode einbetten und dabei die Typprüfung des Compilers behalten wollen. Genau das ist der Unterschied zu einem Wrapper, der nur den HTTP-Aufruf kapselt: Ax verschiebt die Zusicherung über die Ausgabe in das Typsystem.

Signaturen, Deployment-Profile und der aufgelöste Modellname

Der Mechanismus lässt sich am Beispiel aus dem README ablesen. Der Aufruf ai({ name: "openai", apiKey: ... }) erzeugt einen Client, ax(...) erzeugt aus der Signatur einen Generator, und classify.forward(llm, { review: ... }) führt den Aufruf aus. Bemerkenswert ist, was der Parameter name bedeutet. Laut README ist er ein Deployment-Profil, keine Modellkennung. Das Profil bestimmt das Wire-Verhalten, also Endpunkt, Reasoning-Regeln und Antwortformat, während die Modell-ID erst innerhalb des Profils aufgelöst wird. Das README nennt ein Beispiel: Ein DeepSeek-Modell, das über Together gehostet wird, läuft über den Together-Endpunkt und dessen Regeln, nicht über das native DeepSeek-Format. Diese Trennung ist der Grund, warum derselbe Signaturcode mit name: "anthropic", "google-gemini", "grok", "ollama" und weiteren funktionieren kann. Für Anwendungen, die mehrere Anbieter parallel betreiben, ist das der eigentliche Nutzen. Die Kehrseite: Wer das Verhalten eines Aufrufs verstehen will, muss zwei Dinge nachschlagen, das Profil und die Modell-ID darin.

Streaming als Standardpfad und die Abbruchlogik

Ax streamt standardmäßig. Das README begründet das nicht mit gefühlter Geschwindigkeit, sondern mit Fehlerbehandlung: Felder lassen sich beim Eintreffen parsen, Streaming-Assertions laufen mit, und wenn eine Ausgabe bereits ungültig ist, kann der laufende Stream abgebrochen werden, bevor weitere Tokens bezahlt werden. forward() liefert trotzdem ein fertiges Objekt, streamingForward() gibt den Strom direkt heraus. Das ist ein anderer Entwurf als bei SDK-Aufrufen, die erst am Ende validieren. Ob sich das in der eigenen Anwendung rechnet, hängt davon ab, wie teuer ein ungültiger Lauf ist. Das Repository enthält ein Benchmark-Skript, das man gegen die eigenen Provider laufen lassen kann: AX_STREAM_BENCH_PROVIDER, AX_STREAM_BENCH_MODEL, AX_STREAM_BENCH_RUNS und AX_STREAM_BENCH_WARMUP_RUNS werden als Umgebungsvariablen gesetzt, gestartet wird es über npm run tsx src/examples/streaming-latency.ts. Das README berichtet von Läufen mit Claude Haiku/Sonnet und Gemini Flash/Flash Lite und hält fest, dass Warteschlangen beim Anbieter und die Generierung selbst die Gesamtlatenz dominieren, während AxGen nahe am direkten ai.chat()-Pfad bleibt. Das sind Angaben des Projekts, keine unabhängige Messung, und sie hängen stark am gewählten Anbieter.

Agents, Flows und GEPA: drei Ebenen über der Generierung

Über der einzelnen Generierung liegen drei Bausteine, die im Repository als eigene Konzepte geführt werden. AxAgent bietet Ausführung zur Laufzeit, Kontextbudgets, Checkpoints, Wiederholung aus einem Aktionsprotokoll, Discovery, Memory, Skills und Delegation. AxFlow beschreibt Programme als typisierte Graphen mit Verzweigungen, Schleifen, Rückkopplung, Cache-Verhalten, paralleler Ausführung und einer Projektion über .returns(...). Dazu kommen Optimierer, darunter GEPA, Few-Shot-Bootstrapping und portable Optimierer-Artefakte mit Auswertungs- und Anwendungsschritten. Das ist ein deutlich größerer Umfang als das 30-Sekunden-Beispiel vermuten lässt. Wer nur eine Klassifikation braucht, zahlt für diese Ebenen nichts, muss sich aber auch nicht mit ihnen beschäftigen. Wer Agents mit Checkpoints und Wiederaufnahme baut, sollte wissen, dass die Zustandsverwaltung dann Teil der eigenen Betriebsfragen wird: Wo liegen die Checkpoints, wie lange werden Aktionsprotokolle aufbewahrt. Das Material beantwortet das nicht.

Sechs Sprachen, ein Compiler, und die Frage nach dem Vertrauen

Der ungewöhnlichste Teil des Projekts ist die Sprachmatrix. TypeScript ist die Quellimplementierung und das veröffentlichte npm-Paket @ax-llm/ax. Daneben gibt es axllm auf PyPI, dev.axllm:ax auf Maven Central, axllm auf crates.io, ein Go-Modul unter github.com/ax-llm/ax/packages/go und C++ über CMake FetchContent, also als Quellbau. Laut README wird derselbe semantische Kern in diese Bibliotheksformen kompiliert, und der generierte Quellcode liegt unter packages/<language> eingecheckt, damit die unterstützten APIs einsehbar sind. Wenn sich AxIR ändert, erzeugt npm run axir:generate-packages die Pakete neu. Hier liegt die offene Flanke. Generierter Code, der neben der Quelle im Repository liegt, kann von der Quelle abweichen, und das README liefert keine Aussage darüber, wie diese Abweichung geprüft wird. Wer in Go oder Rust produktiv geht, sollte vorher die generierten Quellen lesen, nicht nur die Beispiele laufen lassen. Dass die Beispiele über einen einheitlichen Runner starten (npm run example -- python src/examples/python/generation/axgen-openai.py und entsprechend für java, cpp, go, rust), senkt die Einstiegshürde, sagt aber nichts über die Vollständigkeit der Bindings.

Wann Ax das falsche Werkzeug ist

Nicht jede LLM-Nutzung braucht eine Signaturschicht. Ein einzelner Chat-Aufruf, ein Freitext-Zusammenfasser ohne feste Felder oder ein Prototyp, bei dem der Prompt ohnehin täglich umgeschrieben wird, gewinnt nichts durch typisierte Signaturen. Auch wer volle Kontrolle über das exakte Wire-Format eines Anbieters braucht, verliert durch die Profil-Abstraktion eine Ebene: Das README beschreibt ausdrücklich, dass das Deployment-Profil das Verhalten bestimmt und die Modell-ID erst darin aufgelöst wird. Wer einen anbieterspezifischen Parameter setzen will, der in keinem Profil abgebildet ist, muss prüfen, ob das überhaupt vorgesehen ist. Und wer einen sehr kleinen Ausschnitt braucht, trägt mit Ax eine Abhängigkeit ein, deren Umfang Agents, Flows und Optimierer umfasst, auch wenn nur ax() und forward() verwendet werden. Das ist keine Schwäche des Entwurfs, aber eine Entscheidung, die man bewusst treffen sollte.

Alternative: DSPy selbst, und was sich dadurch ändert

Der naheliegende Vergleich ist DSPy, auf das die Projektbeschreibung im Repository selbst verweist ("the pretty much official DSPy framework for Typescript"). DSPy ist in Python beheimatet und arbeitet ebenfalls mit Signaturen und Modulen, die Prompts beschreiben statt sie zu schreiben. Der Unterschied liegt weniger in der Idee als im Ort der Ausführung. Mit DSPy bleibt die Pipeline in Python, und eine TypeScript-Anwendung ruft sie über eine Prozessgrenze oder einen Dienst auf. Mit Ax bleibt die Pipeline im Node-Prozess, teilt Typen mit dem restlichen Anwendungscode und kann Standard-Schema-Validatoren wie Zod, Valibot oder ArkType direkt verwenden. Umgekehrt gilt: Wer bereits eine Python-Umgebung mit DSPy betreibt und dessen Optimierer und Ökosystem nutzt, hat wenig Grund zu wechseln, nur um TypeScript zu bekommen. Die generierten axllm-Bindings für Python sind laut README aus demselben Kern erzeugt, nicht mit dem Python-Ökosystem verwachsen. Das ist ein anderer Ansatz als eine handgeschriebene Python-Bibliothek.

Release-Kadenz, Lizenz und was vor dem Upgrade zu prüfen ist

Die veröffentlichten Versionen liegen dicht beieinander: 24.0.16 am 31. August 2026, 24.0.17 am 1. September 2026, 24.0.18 am 9. September 2026. Die Hauptversionsnummer steht bei 24, und die Patch-Schritte folgen in kurzen Abständen. Für Betreiber bedeutet das zweierlei. Erstens ist das Projekt aktiv, was für die Wartung spricht. Zweitens ist die Wahrscheinlichkeit höher, dass eine Aktualisierung Verhalten anfasst, das die eigene Anwendung nutzt. Das README verweist für die Paket- und Release-Struktur auf docs/RELEASE.md und für die Migration von Deployment-Profilen und Klassen auf docs/AI_PROFILES.md. Genau diese beiden Dokumente sind vor einem Sprung über mehrere Patch-Versionen die richtige Stelle, weil das Profil das Wire-Verhalten steuert und eine Signatur die Ausgabestruktur festlegt. Zur Lizenz: Das Projekt steht unter Apache-2.0, einer permissiven Lizenz mit einer ausdrücklichen Patentgewährung. Sie erlaubt kommerzielle Nutzung und Änderungen, verlangt aber, dass Lizenzhinweise und Änderungshinweise weitergegeben werden. Das ist eine Einordnung, keine Rechtsberatung; wer Ax in ein Produkt einbettet, sollte die Weitergabepflichten mit der eigenen Rechtsabteilung klären. Zu den generierten Paketen in fünf Sprachen sagt das Material nichts über deren Lizenzstatus im Einzelnen, und das ist eine der Fragen, die man vor einem produktiven Einsatz in Go, Rust, Java oder C++ beantworten sollte.

Redaktionelles Fazit

Wer eine TypeScript-Codebasis hat und strukturierte LLM-Ausgaben mit Zod, Valibot oder ArkType validieren will, findet in @ax-llm/ax ein Paket, dessen Kernpfad laut README bewusst dünn bleibt. Wer Python, Java, C++, Go oder Rust als primäre Laufzeit braucht, sollte vor dem Einsatz prüfen, wie die generierten Quellen unter packages/<language> gepflegt werden und ob der eigene Anwendungsfall dort abgedeckt ist. Vor jedem Upgrade ist zu klären, ob die eigene Programmversion an einer Signatur oder einem Deployment-Profil hängt, das die Release Notes als geändert ausweisen, denn genau diese beiden Ebenen bestimmen das Verhalten.

Offizielle Quellen

  1. ax-llm/ax on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Community-Notizen

Community-Notizen