In Rust entwickelte KI-Anwendungen bewegen sich laut einer von JetBrains gemeinsam mit der Rust Foundation veranstalteten Live-Präsentation allmählich von ersten Experimenten zu praktischeren Modellen. Die erste Sitzung konzentrierte sich auf die Open-Source-Bibliothek Rig und darauf, wie sie zum Bau von Anwendungen verwendet werden kann, die auf großen Sprachmodellen und Agenten basieren, die Tools aufrufen und Aufgaben innerhalb der Anwendung ausführen können.
Orhun Parmaksız, Developer Advocate, zeigte einen kleinen Software-Agenten, den er mit Rig und Ratatui gebaut hatte, während Stephen Korzeniewski, der Hauptbetreuer von Rig bei 0xPlaygrounds, die interne Struktur des Projekts und die Entscheidungen hinter seinen Programmierschnittstellen erläuterte.
Eine einheitliche Schnittstelle für Modellanbieter
Rig löst ein häufiges praktisches Problem in Anwendungen für Sprachmodelle: OpenAI, Anthropic, Gemini und andere Anbieter verfügen über unterschiedliche Programmierschnittstellen, selbst wenn einige Dienste ihre Kompatibilität mit der OpenAI-Schnittstelle erklären. Anstatt Anwendungsteile direkt an die Schnittstelle eines einzelnen Anbieters zu binden, bietet Rig eine einheitliche Rust-Schnittstelle, über die der Anbieter gewechselt werden kann, ohne die modellbezogenen Teile neu schreiben zu müssen.
Die Bibliothek strukturiert die Anwendung um mehrere grundlegende Komponenten, darunter den Client des Anbieters, das Completion-Modell, den Agenten und die ihm verfügbaren Tools. Der Agent arbeitet als übergeordnete Schicht über einer direkten Modellanfrage: Er ergänzt die Anweisungen, die Token-Grenzen und die Fähigkeiten, die für Aufgaben erforderlich sind, die über den Fluss von Eingabetext und Ausgabetext hinausgehen.
Die Anweisungen des Agenten werden in Rig als Preamble bezeichnet. Dabei handelt es sich um Anweisungen, die die Rolle eines System-Prompts übernehmen und am Anfang jeder Anfrage eingefügt werden. Die Netzwerkverbindungen zu den Modellanbietern werden über asynchrone Schnittstellen verwaltet, wobei viele Details der asynchronen Verarbeitung innerhalb der Bibliothek verborgen bleiben, damit sich der Anwendungscode auf die erforderliche Konfiguration und das gewünschte Verhalten konzentrieren kann.
Tools machen den Agenten zu einem Teil der Anwendung
Rig definiert ein Tool über das Tool trait in Rust. Die Definition des Tools umfasst seinen Namen, die Typen der Eingaben, Ausgaben und Fehler sowie die Funktion, die beim Aufruf ausgeführt wird. Außerdem beschreibt die Definition die erwarteten Argumente mithilfe eines JSON-Schemas, sodass das Modell eine strukturierte Beschreibung der Daten erhält, die es bereitstellen kann.
Nachdem das Tool beim Agenten registriert wurde, kann ein Modell, das Tool-Aufrufe unterstützt, bestimmen, wann es das Tool verwendet, und sein Ergebnis in die Antwort integrieren. Die Funktion kann eine Berechnung ausführen, eine Datenbank abfragen, Informationen abrufen oder eine Verbindung zu einem anderen Dienst herstellen. Ein Tool kann außerdem Kontext empfangen, der Zustände wie die Anzahl der Aufrufe oder zwischengespeicherte Ergebnisse bewahrt. Das Konzept lässt sich auch auf Agenten übertragen: Ein Agent kann einem anderen Agenten als Tool zur Verfügung gestellt werden, um Aufgaben zwischen ihnen zu delegieren.
Von der Demo zu einer testbaren Anwendung
Das Projekt Rat Code vereinte diese Komponenten in einem kleinen Software-Agenten, der mithilfe von Rig und Ratatui im Terminal ausgeführt wird. Die Datei main.rs initialisiert den Anbieter-Client, das Modell und den Agenten, während die Fähigkeiten zum Lesen und Schreiben von Dateien sowie zum Ausführen von Shell-Befehlen separat definiert und anschließend über die Tool-Schnittstelle von Rig beim Agenten registriert werden.
Die Anwendung verwendet außerdem die Streaming-Schnittstelle von Rig, um die Antwort in Abschnitten zu verarbeiten und die Terminaloberfläche zu aktualisieren, während das Modell die Antwort generiert. In der Präsentation wurden auch das Hook-System, die Wiederherstellung nach Tool-Aufrufen und die Designentscheidungen hinter den von der Bibliothek bereitgestellten Abstraktionen behandelt. Die vollständige Codevorführung beginnt in der Aufzeichnung bei Minute 27:28.
RAG, lokale Modelle und Tests
Rig beschränkt sich nicht auf gehostete Modellanbieter. Die Bibliothek unterstützt Anwendungen mit Retrieval-Augmented Generation, bei denen Dokumente und Benutzeranfragen in Vektoreinbettungen umgewandelt werden. Anschließend werden die semantisch ähnlichsten Dokumente gesucht, um sie dem Kontext des Modells hinzuzufügen. Die Bibliothek bietet Integrationen für Datenbanken und Abstraktionen für Vektorspeicher. Bei Verwendung einer Datenbank, die nicht direkt unterstützt wird, kann die Schnittstelle für den Vektorspeicher selbst implementiert werden.
Lokale Modelle können außerdem über Ollama und llama.cpp ausgeführt werden. Alternativ lässt sich die Integration rig-candle verwenden, um die Inferenz direkt innerhalb einer Rust-Anwendung auszuführen. Diese Option ermöglicht es, Modellgewichte in die Anwendung einzubetten und unterstützte Modelle über WebAssembly auszuführen, ohne auf eine gehostete Modellschnittstelle oder einen separaten lokalen Inferenzserver angewiesen zu sein.
Die Bedeutung dieser Optionen zeigt sich darin, wo Modelle und Daten ausgeführt werden. Gleichzeitig stellen sie eine Herausforderung für das Testen der Integrationen dar. Rig stützt sich im Wesentlichen auf ein Aufzeichnungssystem: Tests werden mit den echten Anbietern ausgeführt, der HTTP-Datenverkehr wird in YAML-Dateien gespeichert, und anschließend werden Anfragen und Antworten innerhalb der Tests der kontinuierlichen Integration von einem Mock-Server wiedergegeben. Das Projekt umfasst etwa 1.700 aufgezeichnete Interaktionen, die bei jeder Pull-Anfrage innerhalb weniger Sekunden erneut ausgeführt werden.
Diese Tests überprüfen, ob die Softwareintegration weiterhin funktioniert. Sie messen jedoch nicht die Qualität der Modellausgaben, die sich ändern kann, wenn der Anbieter sein Modell aktualisiert. Daher verwies die Präsentation auf geplante Tests mit Live-Modellen als separate Methode für Anwendungen, die von der Qualität der Antwort abhängen.
Redaktionelle Einordnung: Was ist für Entwickler wichtig?
Der praktische Wert von Rig besteht nicht nur darin, einen neuen Anbieter hinzuzufügen, sondern darin, die Anwendungsschicht von den Details der Modellschnittstellen zu trennen und zugleich Tools, Retrieval und lokale Inferenz in einer gemeinsamen Rust-Struktur zu halten. Dies kann die Kosten eines Wechsels des Anbieters oder der Ausführungsmethode senken. Die Verhaltensunterschiede zwischen den Modellen werden dadurch jedoch nicht beseitigt, und auch das Problem der Bewertung der Ausgabequalität wird dadurch allein nicht gelöst. Der Testmechanismus des Projekts verdeutlicht, dass die Sicherstellung einer funktionierenden Verbindung etwas anderes ist als die Überprüfung, ob das Modell das gewünschte Ergebnis erzeugt – dafür sind Live-Tests und unabhängige Bewertungskriterien erforderlich.