Modell / Datensatz
BoundaryML/baml avatar
BoundaryML/baml

BAML: eine eigene Sprache für LLM-Funktionen, mit Typprüfung zur Laufzeit

The programming language for agents

9.180 Sterne492 ForksRustApache-2.0

Auf einen Blick

Was ist das?
BoundaryMLs BAML ist ein Apache-2.0-lizenziertes Rust-Projekt, das Prompt-Aufrufe in eine deklarative Sprache mit eigenem Typsystem gießt und daraus Client-Bindings für Python, TypeScript, Go, C#, Java und andere erzeugt. Die Nightly-Releases laufen im Tagesrhythmus, der Default-Branch heißt canary. Wer heute auf BAML setzt, setzt auf einen beweglichen Untergrund.
Für wen ist es gedacht?
BAML passt zu Teams, die LLM-Aufrufe als typisierte Funktionen mit Eval-Suite in einer eigenen Datei pflegen und aus mehreren Hostsprachen aufrufen wollen; wer eine stabile, versionsfixierte Abhängigkeit braucht, sollte zuerst prüfen, ob ein Nicht-Nightly-Release von baml-py auf PyPI verfügbar ist, und andernfalls auf eine andere Bibliothek ausweichen.
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 1 Tag.
In welcher Sprache ist es geschrieben?
Hauptsächlich Rust, 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

Welches Problem BAML löst und für wen es gedacht ist

Der Auslöser ist der untypisierte Rand zwischen Anwendungscode und Modellausgabe. In den üblichen Setups steht ein Prompt als String in Python oder TypeScript, das Modell antwortet mit JSON, und die Anwendung parst das Ergebnis ohne Garantie, dass die Felder existieren oder die richtigen Typen haben. BAML verlagert diese Grenze in eine eigene Datei und behandelt sie als Teil des Programms. Die README formuliert den Anspruch so: BAML sehe aus wie TypeScript, aber jedes Feature sei darauf ausgelegt, dass Agenten weniger Fehler machen. Die Zielgruppe sind damit nicht Datenwissenschaftler, die einmalig ein Skript schreiben, sondern Teams, die LLM-Aufrufe über längere Zeit pflegen und aus mehreren Hostsprachen ansprechen. Genau dort liegt der Unterschied zu einer Prompt-Bibliothek: BAML will nicht beim Zusammenbauen des Strings helfen, sondern beim Beschreiben der Schnittstelle zwischen Code und Modell.

Typprüfung zur Laufzeit statt Casting auf gut Glück

Der Kern des Entwurfs ist ein Typsystem, das nicht nur beim Übersetzen existiert. Die README nennt zwei Eigenschaften, die zusammengehören: Typen bleiben zur Laufzeit erhalten, und es gibt kein any und kein gefährliches Casting auf einen beliebigen Typ. In der Praxis heißt das, dass die Antwort des Modells gegen das deklarierte Schema geprüft wird, bevor der Hostsprache ein Wert übergeben wird. Ein Feld, das als Zahl deklariert ist, wird nicht stillschweigend zum String. Die README beschreibt außerdem Fehler als typisiert und statisch analysiert. Das ist der eigentliche Kontrast zu handgeschriebenem Parsing: Dort ist ein fehlendes Feld ein Laufzeitfehler irgendwo im Anwendungscode, hier ist es ein Fehler an der Grenze, an der er entsteht. Ob die Prüfung das Modell zu einem Retry zwingt oder den Aufruf fehlschlagen lässt, geht aus dem vorliegenden Material nicht hervor; das ist ein Punkt, den man in der Dokumentation nachlesen muss, bevor man sich auf das Verhalten verlässt.

Dateien als Module, grüne Threads und farblose Nebenläufigkeit

Ein Detail, das in der README auffällt: Das Dateisystem beschreibt die Module und Namespaces. Es gibt also keine Registrierungsdatei, in der man Funktionen manuell anmeldet; die Verzeichnisstruktur ist die Struktur des Programms. Wer aus anderen Sprachen kommt, kennt dieses Modell von Go oder von Python-Paketen, und es macht den Einstieg flach, weil man keine zweite Wahrheit pflegen muss. Dazu kommen grüne Threads und farblose Nebenläufigkeit, also das Modell, bei dem asynchrone und synchrone Aufrufe nicht durch unterschiedliche Funktionsfarben getrennt sind. In Sprachen wie JavaScript oder Python ist das ein wiederkehrender Reibungspunkt, weil eine async-Funktion nur aus einer async-Funktion aufgerufen werden kann. BAML verspricht hier, dass die Färbung wegfällt. Ob das in der generierten Hostsprache tatsächlich so ankommt oder ob die Binding-Schicht die Unterscheidung wieder einführt, lässt sich aus der README nicht belegen. Das ist eine der Stellen, an denen die Selbstdarstellung mehr verspricht, als das Material zeigt.

Installation und der erste Lauf

Der Einstieg ist kurz und in der README als Abfolge dokumentiert. Zuerst die Installation über Homebrew, dann die Agent-Installation, dann die Projektinitialisierung, dann die IDE-Anbindung:

brew install baml baml agent install baml init baml ide install --code

Der Befehl baml init legt die Projektstruktur an, baml ide install --code bindet den Editor an. Wer nicht über Homebrew installiert, findet das Python-Paket unter dem Namen baml-py auf PyPI, wie das Versionsbadge in der README zeigt. Ein Konfigurationsbeispiel für eine Funktion, ein Modell oder einen Client ist im vorliegenden README-Ausschnitt nicht enthalten; die README verweist dafür auf die Quickstart-Seite und auf die Explore-Seite mit Beispielen. Wer die tatsächlichen Schlüsselnamen für Provider, Modelle oder Retry-Verhalten braucht, muss dort nachsehen. Das ist keine Kleinigkeit: Ohne diese Namen lässt sich kein Projekt aufsetzen, und die README allein reicht dafür nicht.

Einbettung in bestehende Codebasen

BAML muss nicht das ganze Projekt übernehmen. Die README nennt zwei Betriebsarten: eigenständig lauffähig oder inkrementell adoptierbar, indem man eine BAML-Funktion aus TypeScript, Python, Go, C#, Java und weiteren Sprachen aufruft. Für Bestandssysteme ist das der entscheidende Punkt, weil die Migration auf eine einzelne Funktion beschränkt bleiben kann. Der Preis dafür ist eine zusätzliche Schicht: Es gibt jetzt BAML-Dateien, generierte Bindings und den Hostcode, und alle drei müssen zusammenpassen. Wer die Bindings nicht versioniert oder den Generierungsschritt aus der Build-Pipeline heraushält, bekommt Fehler, die auf den ersten Blick nichts mit dem Prompt zu tun haben. Die README beschreibt außerdem ein eingebautes Test- und Eval-Framework sowie eine Standardbibliothek für Agenten. Das Eval-Framework ist der Teil, der in typischen Prompt-Setups fehlt: Änderungen an einem Prompt lassen sich damit gegen eine Sammlung von Fällen prüfen, statt sie per Sichtprüfung freizugeben.

Nightly-Releases als Betriebsrisiko

Die Release-Liste zeigt drei Einträge im Abstand weniger Tage, alle mit dem Muster baml-language-0.18.1-nightly.DATUM.a. Der Default-Branch heißt canary. Das ist eine klare Ansage über den Reifegrad: Die veröffentlichten Artefakte sind Nightly-Builds, keine stabilen Versionen, und der Entwicklungszweig ist der Vorabzweig. Für ein Projekt, das produktiv LLM-Aufrufe abwickelt, bedeutet das, dass ein Update der Abhängigkeit das Verhalten ändern kann, ohne dass sich die Versionsnummer an der Stelle ändert, an der man hinsieht. Wer auf Reproduzierbarkeit angewiesen ist, muss die Version exakt pinnen und den Generierungsschritt der Bindings im Build reproduzieren. Die Lizenz ist Apache-2.0, also permissiv, mit den üblichen Pflichten: Beibehaltung der Copyright- und Lizenzhinweise, Kennzeichnung geänderter Dateien und eine Patenthilfe-Klausel. Das ist keine Rechtsberatung, aber es ist der Rahmen, in dem die Weitergabe stattfindet. Wer BAML in ein Produkt einbettet, sollte die NOTICE-Anforderungen prüfen, bevor er Binärartefakte ausliefert.

Wann BAML das falsche Werkzeug ist

BAML lohnt sich, wenn es mehrere Aufrufe, mehrere Modelle oder mehrere Hostsprachen gibt. Bei einem einzelnen Prompt in einem einzelnen Python-Skript ist der Aufwand für eine eigene Sprache, einen Generierungsschritt und eine Binding-Schicht größer als der Nutzen. Ebenso ungeeignet ist es, wenn das Team ausdrücklich keine neue DSL einführen will: BAML ist kein Wrapper um eine bestehende Bibliothek, sondern eine Sprache mit eigener Syntax, eigenem Typsystem und eigener Toolchain. Wer bereits ein stabiles Schema mit einer etablierten Validierungsbibliothek pflegt, tauscht funktionierenden Code gegen eine Abhängigkeit, deren Releases im Nightly-Takt erscheinen. Und wer Modelle einsetzt, deren Ausgabe sich nicht sinnvoll in ein Schema pressen lässt, etwa bei freien Texten mit offenem Ende, gewinnt durch die Typprüfung wenig. Die README behauptet, BAML kompiliere schneller als Go; das ist eine Aussage des Projekts, kein unabhängig gemessener Wert, und sie sagt nichts über die Laufzeit der generierten Bindings.

Alternative: Instructor oder Pydantic AI statt eigener Sprache

Der naheliegende Vergleich ist eine Bibliothek, die dasselbe Problem in der Hostsprache löst, statt eine neue Sprache einzuführen. Instructor für Python und TypeScript arbeitet mit Pydantic-Modellen und einem Patch über den Client: Man definiert eine Klasse, übergibt sie an den Aufruf, und die Bibliothek validiert die Antwort und startet bei Bedarf einen Retry mit der Fehlermeldung. Der Unterschied liegt nicht in der Validierung, sondern im Ort der Definition. Bei Instructor bleibt das Schema eine Klasse in der Hostsprache, und die Toolchain ist der normale Paketmanager. Bei BAML wandert das Schema in eine .baml-Datei, und der Hostcode sieht nur die generierte Funktion. Daraus folgen die trade-offs: Instructor braucht keinen Codegenerierungsschritt und keine zusätzliche Sprache, ist aber an eine Hostsprache gebunden. BAML kann aus mehreren Sprachen aufgerufen werden, verlangt dafür aber, dass das Team eine zweite Syntax lernt und den Generierungsschritt in die Pipeline aufnimmt. Pydantic AI geht in eine ähnliche Richtung und bindet Agenten enger an das Python-Ökosystem. Wer nur Python schreibt, hat mit Instructor oder Pydantic AI weniger bewegliche Teile; wer Python, TypeScript und Go parallel bedient, zahlt den Preis für BAML möglicherweise gern.

Redaktionelles Fazit

BAML passt zu Teams, die LLM-Aufrufe als typisierte Funktionen mit Eval-Suite in einer eigenen Datei pflegen und aus mehreren Hostsprachen aufrufen wollen; wer eine stabile, versionsfixierte Abhängigkeit braucht, sollte zuerst prüfen, ob ein Nicht-Nightly-Release von baml-py auf PyPI verfügbar ist, und andernfalls auf eine andere Bibliothek ausweichen.

Offizielle Quellen

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

Community-Notizen