Wie Testcontainers die Entwicklung KI-gestützter Anwendungen optimiert
In der heutigen schnelllebigen und zunehmend wettbewerbsintensiven Geschäftswelt müssen Unternehmen Wege finden, den Abschluss ihrer digitalen Transformationsprojekte zu beschleunigen. Minimieren Sie Verzögerungen bei der Bereitstellung neuer Anwendungen oder Funktionen, und Sie können deren Produktivitäts- und Effizienzvorteile in kürzerer Zeit nutzen – und sich so einen Vorsprung gegenüber Ihren Wettbewerbern verschaffen. Eine Verlängerung der Entwicklung neuer Software oder der Veröffentlichung von Updates kann jedoch Ihren Marktanteil schmälern, da andere Unternehmen in Ihrer Branche schneller innovieren.
Container haben sich als bevorzugte Technologie für Unternehmen etabliert, die ihre Anwendungsentwicklungspraktiken optimieren möchten. Sie ermöglichen Entwicklern, Anwendungen zu erstellen, die sicherer, robuster und skalierbarer sind – in kürzerer Zeit als je zuvor.
In diesem Artikel, inspiriert von diesem Vortrag von Oleg Šelajev bei einem kürzlich von Zilliz veranstalteten Unstructured Data Meetup, untersuchen wir das Konzept der Containerisierung und eines ihrer wesentlichen Tools, Docker, sowie wie sie die Komplexität des Anwendungsentwicklungsprozesses verringern. Anschließend richten wir unsere Aufmerksamkeit auf ein Open-Source-Framework, Testcontainers, das die Fähigkeiten von Docker erheblich erweitert – und Entwicklern ermöglicht, die Entwicklung KI-gestützter Anwendungen zu optimieren.
Was sind Container?
Container sind standardisierte Anwendungscode-Pakete, die alle erforderlichen Komponenten enthalten, einschließlich Binärdateien, Abhängigkeiten, Bibliotheken und Konfigurationsdateien, um in jeder Umgebung ausgeführt zu werden. Traditionell waren Anwendungen monolithisch, mit verschiedenen Komponenten innerhalb einer einzigen Codebasis. Heute teilen Entwickler die Software entsprechend ihrer Funktion oder ihres Dienstes in Komponenten auf, jeweils mit eigener Codebasis und eigenen Abhängigkeiten – Containerisierung oder Microservices-Architektur.
Zu den Vorteilen von Containern gehören:
Erhöhte geschäftliche Agilität: Die Aufteilung von Anwendungen in Dienste ermöglicht es Entwicklern, gleichzeitig an verschiedenen Projektteilen zu arbeiten. Ebenso erlaubt die Modularität von Containern Updates und neue Funktionen, ohne die gesamte Anwendung zu ändern.
Verbesserte Skalierbarkeit: Wenn eine Anwendung in einem Container verpackt werden kann, müssen Sie nur einen zusätzlichen Container bereitstellen, um eine weitere Instanz zu erstellen. Bei modularen Anwendungen können Teams unterdessen einfach neue Container für den Dienst starten, der sich der Kapazitätsgrenze nähert.
Erhöhte Effizienz: Da Container hochgradig portabel und plattformunabhängig sind, müssen Entwickler keine Zeit für das Einrichten und Warten verschiedener Umgebungen aufwenden.
Geringere Kosten: Entwickler von der Verantwortung für die Verwaltung von Servern und Umgebungen zu entlasten, macht sie an anderer Stelle produktiver, d. h. bei der eigentlichen Entwicklung von Anwendungen! Dies reduziert die Arbeitsstunden, die zur Fertigstellung von Projekten erforderlich sind – und senkt deren Kosten.
Anwendungsfälle für Container umfassen:
Entwicklung Cloud-nativer Anwendungen: Containerisierte Architekturen nutzen die Fähigkeiten der Cloud vollständig aus, einschließlich verbesserter Skalierbarkeit, besserem Datenzugriff und stärkerer Cybersicherheit.
Modernisierung von Anwendungen: Container können verwendet werden, um Legacy-Anwendungen zu refaktorisieren, um ihre Kompatibilität mit einer Cloud-Umgebung zu erhöhen, wodurch sie leistungsfähiger, ressourceneffizienter und einfacher zu aktualisieren werden.
Prototyping: Da sie plattformunabhängig sind, vermeiden Container die Notwendigkeit, verschiedene Umgebungen für Entwicklung, Tests, Staging usw. einzurichten – was es Entwicklern erleichtert, mit neuen Funktionen zu experimentieren.
Internet-of-Things-(IoT)-Geräte: Da Container leichtgewichtig und ressourceneffizient sind, bieten sie einen idealen Softwarebereitstellungsmechanismus für eingeschränkte IoT-Hardware.
- DevOps: Container werden verwendet, um konsistente, isolierte Umgebungen zu erstellen und sicherzustellen, dass eine Anwendung unabhängig davon, wo sie bereitgestellt wird, gleich läuft, was zu schnellerer Bereitstellung und verbesserter Zusammenarbeit zwischen Entwicklungs- und Betriebsteams führt.
Was ist Docker?
Docker ist eine Plattform, die es Entwicklern ermöglicht, Container zu erstellen, bereitzustellen, zu konfigurieren und zu verwalten. Docker ist tatsächlich so gleichbedeutend mit Containern, dass sie häufig als „Docker-Container“ bezeichnet werden. In Wirklichkeit beziehen sich Menschen, wenn sie Docker erwähnen, jedoch eigentlich auf die Docker Engine: die Laufzeitumgebung, auf der Container erstellt und ausgeführt werden. Diese Engine befindet sich unterhalb der Container, um das Betriebssystem (OS) des Host-Geräts zu virtualisieren und ihnen die optimale Menge an Ressourcen wie CPU und Arbeitsspeicher zuzuweisen.
Dies steht in deutlichem Gegensatz zu einer ähnlichen Lösung in Form von virtuellen Maschinen (VMs) - die ihr eigenes OS und Rechenressourcen benötigen. Neben der Tatsache, dass Container umgebungsunabhängig werden, macht die Nutzung von Docker sie ressourcenintensiv, schneller beim Starten und Herunterfahren und portabler als VMs.
Weitverbreitete Docker-Tools
So leistungsfähig Docker auch ist, seine Beliebtheit ist zu einem großen Teil auf sein reichhaltiges Ökosystem zugehöriger Tools und Bibliotheken zurückzuführen. Hier sind einige der bemerkenswertesten Docker-Tools.
Docker Enterprise: eine Version von Docker, die für kritische Bereitstellungen entwickelt wurde und erweiterte Sicherheits-, Verwaltungs- und Orchestrierungsfunktionen für zertifizierte, produktionsreife Releases bietet.
Docker Swarm: ein Clustering- und Orchestrierungstool für Docker, das es Benutzern ermöglicht, mehrere Docker-Knoten als ein einziges virtuelles System zu verwalten, und einfachere Skalierung und Lastverteilung ermöglicht.
Docker Compose: ein Tool zur Optimierung der Entwicklung und Verwaltung komplexer Docker-Anwendungen mit mehreren Containern.
Kubernetes: Eine Open-Source-Plattform zur Container-Orchestrierung, die die Bereitstellung, Skalierung und Verwaltung großer containerisierter Anwendungen über Server-Cluster hinweg automatisiert.
Mehr über das Docker-Ökosystem erfahren Sie in diesem Artikel https://middleware.io/blog/understanding-the-docker-ecosystem/
Testcontainers: Vereinfachtes Abhängigkeitsmanagement
Testcontainers ist ein Open-Source-Framework, das leichtgewichtige, modulare Instanzen von Datenbanken, Browsern, Message Brokern und anderen vorkonfigurierten Abhängigkeiten bereitstellt, die in einem Container ausgeführt werden können. Indem Testcontainers dem Benutzer eine Bibliothek programmatischer APIs zur Manipulation von Containern zur Verfügung stellt, abstrahiert es die komplizierten Details jeder Abhängigkeit und erleichtert so die Arbeit damit. Dies reduziert die Betriebskosten von Projekten, fördert gleichzeitig Experimente und ermöglicht eine optimierte Entwicklung.
Eine Auswahl der über 50 modularen Integrationen von Testcontainers
Wie der Name schon vermuten lässt, bietet Testcontainers die größten Produktivitätssteigerungen beim Anwendungstesten, einschließlich Datenzugriffsschicht-, Integrations- und Akzeptanztests.
Zu den Vorteilen der Durchführung von Anwendungstests mit Testcontainers gehören:
Isolation und Konsistenz: Die Containerisierung von Komponenten stellt sicher, dass jeder Test in einem frischen, bekannten Zustand ausgeführt wird. Beispielsweise beseitigt das Testen von Datenbanken in Isolation die Inkonsistenzen, die durch unterschiedliche lokale Datenbank-Setups entstehen, während containerisierte Browser zuverlässigere UI-Tests ermöglichen, indem sie die durch lokale Browser-Setups verursachten Unterschiede beheben.
Umgebungsparität: Entwickler können End-to-End-Tests in einer Umgebung durchführen, die der Produktion stark ähnelt, wodurch die Unterschiede zwischen Umgebungen reduziert und gleichzeitig die Genauigkeit der Testergebnisse erhöht wird.
Ressourcenmanagement: Da Container kurze Laufzeiten haben, können Sie Ressourcen effizienter verwalten und gleichzeitig eine schnelle Testausführung und -bereinigung ermöglichen.
Skalierbarkeit und Zuverlässigkeit: Folglich können Tests problemlos skaliert werden, ohne verfügbare Ressourcen berücksichtigen zu müssen.
Abgesehen davon, dass Testcontainers Anwendungstests einfacher und effektiver macht, kann es Ihnen helfen, umgebungsunabhängige KI-Anwendungen zu entwickeln. Wenden wir uns nun einigen der anderen wichtigen Möglichkeiten zu, wie Testcontainers die Produktivität steigert.
Ausführen einer Milvus-Instanz
Als erstes Beispiel dafür, wie Sie Testcontainers zur Steigerung der Produktivität nutzen können, erstellen wir eine Milvus-Instanz, wie im folgenden Codebeispiel gezeigt (alle Codebeispiele in diesem Artikel sind in Java geschrieben, aber die Testcontainers-Bibliothek ist auch in Python, Node.js, Go, Rust und mehreren anderen Sprachen verfügbar):
import io.milvus.client.MilvusServiceClient;
import io.milvus.param.ConnectParam;
import org.testcontainers.milvus.MilvusContainer;
public class MilvusExample {
public static void main(String[] args) {
MilvusContainer milvus = new MilvusContainer("milvusdb/milvus:v2.3.9");
milvus.start();
MilvusServiceClient milvusClient = new MilvusServiceClient(
ConnectParam.newBuilder().withUri(milvus.getEndpoint()).build());
}
}
Anstatt eine separate Milvus-Instanz installieren und konfigurieren und in Ihre Anwendung integrieren zu müssen, bietet Testcontainers eine benutzerfreundliche Abstraktion, die die Instanz einfach aus dem Code heraus aufruft.
Zuerst erstellen wir eine neue Instanz eines Milvus-Containers und geben die Version an, indem wir das passende Container-Image als Parameter übergeben. Neben der Optimierung der Anwendungsentwicklung erleichtert dies auch die zukünftige Aktualisierung von Anwendungen, da Sie nur das aktualisierte Image angeben müssen. Anschließend führen wir den Container mit der Methode .start() aus und übergeben den Container dann als Parameter an eine neue Instanz eines Milvus Service Client, mit der Sie mit dem Dienst innerhalb des Containers interagieren können.
Neben der Erstellung einer Milvus-Instanz in nur wenigen Codezeilen stellt dieser Ansatz auch sicher, dass die Komponente niemals mit den Anforderungen der Anwendung aus dem Takt gerät – weil sie von der Anwendung selbst aufgerufen wird.
Integration von Ollama und HuggingFace für die LLM-Integration
Eine zweite Möglichkeit, wie Testcontainers die Produktivität steigert, besteht darin, die Integration von KI-Komponenten wie LLMs innerhalb von Anwendungen zu optimieren. Dadurch können Sie problemlos LLM-Aufrufe aus dem Code heraus durchführen, um Anwendungen LLM-Funktionalität hinzuzufügen, und ebenso wichtig: KI-Komponenten zu einem normalen Bestandteil des DevOps-Prozesses machen.
Im folgenden Codeausschnitt erstellen wir eine OllamaHuggingFaceContainer-Klasse, die den vorhandenen OllamaContainer erweitert, um eine Instanz zu starten, die einen Ollama-Container ausführt, der ein von HuggingFace heruntergeladenes Deep-Learning-Modell ausführt.
Ollama ist eine Plattform, mit der Sie Modelle für Inferenz lokal auf Ihrem Gerät bereitstellen können, während HuggingFace ein unverzichtbarer Hub zum Herunterladen von Open-Source-KI-Modellen ist. Durch die Kombination der beiden Ressourcen erhalten Sie Zugriff auf die Dutzenden von Modellen, die von Ollama unterstützt werden, sowie auf jedes Modell im GGUF (GPT-Generated Unified Format)—von denen es 23.000 auf HuggingFace gibt.
package org.testcontainers.huggingface;
import com.github.dockerjava.api.command.InspectContainerResponse;
import org.testcontainers.containers.ContainerLaunchException;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.ollama.OllamaContainer;
import org.testcontainers.utility.DockerImageName;
import java.io.IOException;
public class OllamaHuggingFaceContainer extends OllamaContainer {
private final HuggingFaceModel huggingFaceModel;
public OllamaHuggingFaceContainer(HuggingFaceModel model) {
super(DockerImageName.parse("ollama/ollama:0.1.44"));
this.huggingFaceModel = model;
}
Automatisierte Bereitstellung von KI-Modellen
Da Testcontainers anschließend den Aufruf von KI-Modellen aus der Anwendung heraus ermöglicht, bietet es auch eine bequemere, automatisierte Möglichkeit, diese Modelle zu verteilen. Während Open-Source-Modelle leicht von HuggingFace bezogen werden können, werden sie als eine Reihe von Dateien und Verzeichnissen in Git-Repositories gespeichert. Das ist nicht nur für Uneingeweihte zu kompliziert, sondern auch bei weitem nicht die bequemste Art für erfahrene Entwickler, mit Modellen zu arbeiten.
Ein typisches HuggingFace-Repository
Anstatt ein Modell manuell zu konfigurieren und bereitzustellen, können Sie den Prozess mit einem Skript automatisieren. Dies reduziert wiederum den administrativen Aufwand für Entwickler und fügt gleichzeitig eine weitere Abstraktionsebene für das Modell selbst hinzu. Dies wird im folgenden Code veranschaulicht (der ein Ausschnitt aus einem längeren Testskript ist), der zeigt, wie ein Modell innerhalb des Codes angegeben und konfiguriert werden kann. Neben der Angabe des Verzeichnisses, aus dem das Modell bezogen werden soll, und des genauen zu verwendenden Modells definiert die Variable modelfileeine Prompt-Vorlage.
public class HuggingFaceVisionModelTest {
@Test
public void visionModelWithHuggingFace() throws IOException {
String imageName = "vision-model-from-HuggingFace";
String repository = "xtuner/llava-phi-3-mini-gguf";
String model = "llava-phi-3-mini-int4.gguf";
String visionAdapter = "llava-phi-3-mini-mmproj-f16.gguf";
String modelfile = """
FROM ./llava-phi-3-mini-int4.gguf
FROM ./llava-phi-3-mini-mmproj-f16.gguf
TEMPLATE """{{ if .System }}<|system|>
{{ .System }}<|end|>
{{ end }}{{ if .Prompt }}<|user|>
{{ .Prompt }}<|end|>
{{ end }}<|assistant|>
{{ .Response }}<|end|>
"""
PARAMETER stop "<|user|>"
PARAMETER stop "<|assistant|>"
PARAMETER stop "<|system|>"
PARAMETER stop "<|end|>"
PARAMETER stop "<|endoftext|>"
PARAMETER num_keep 4
PARAMETER num_ctx 4096
""";
try (
OllamaContainer ollama = new OllamaContainer(DockerImageName.parse(imageName).asCompatibleSubstituteFor("ollama/ollama:0.1.44")).withReuse(true)
) {
try {
ollama.start();
} catch (ContainerFetchException ex) {
createImage(imageName, repository, model, modelfile, visionAdapter);
ollama.start();
}
Wie bereits angedeutet, kann dies auf jedes Modell auf Ollama sowie auf die große Anzahl der im GGUF-Format verfügbaren Modelle angewendet werden. Die Bereitstellung eines Modells auf diese Weise erleichtert auch das Upgrade des KI-Modells in zukünftigen Iterationen Ihrer Anwendung, da Sie keine Änderungen an der Umgebung vornehmen müssen – nur an den Verweisen auf das Modell im Code.
Fazit
Zusammenfassend:
Container sind standardisierte Pakete von Anwendungscode, die alle erforderlichen Komponenten enthalten, einschließlich Binärdateien, Abhängigkeiten, Bibliotheken und Konfigurationsdateien, um in jeder Umgebung ausgeführt zu werden.
Zu den Vorteilen von Containern gehören:
Erhöhte geschäftliche Agilität
Verbesserte Skalierbarkeit
Gesteigerte Effizienz
Niedrigere Kosten
Anwendungsfälle für Container umfassen:
Entwicklung cloudnativer Anwendungen
Modernisierung von Anwendungen
Prototyping
IoT-Geräte
DevOps
Docker ist eine Plattform, die es Entwicklern ermöglicht, Container zu erstellen, bereitzustellen, zu konfigurieren und zu verwalten.
Zu den am häufigsten verwendeten Docker-Tools gehören:
Docker Enterprise
Docker Swarm
Docker Compose
Kubernetes
Testcontainers
Testcontainers ist ein Open-Source-Framework, das modulare Instanzen vorkonfigurierter Abhängigkeiten bereitstellt, die in einem Container ausgeführt werden können, wie Datenbanken, Browser und Message Broker.
Testcontainers optimiert Anwendungstests durch die Bereitstellung von:
Isolation und Konsistenz
Umgebungsgleichheit
Ressourcenmanagement
Skalierbarkeit und Zuverlässigkeit
Weitere Produktivitäts- und Effizienzsteigerungen, die Testcontainers bietet, umfassen:
Die Abstraktion von Abhängigkeiten, wodurch sie einfacher zu handhaben sind – ohne zusätzliche Software installieren oder Änderungen an der/den Umgebung(en) der Anwendung vornehmen zu müssen.
Der einfache Aufruf von KI-Komponenten, wodurch sie zu einem normalen Bestandteil von DevOps-Prozessen werden.
Die Abstraktion und automatisierte Bereitstellung von LLMs.
Weiterführende Lektüre
Wir empfehlen Ihnen, sich die untenstehenden Ressourcen anzusehen, um mehr über Container, Docker, DevOps und ihre Rolle bei der Entwicklung der nächsten Generation KI-gestützter Lösungen zu erfahren.
Weiterlesen

Migrating from S3 Vectors to Zilliz Cloud: Unlocking the Power of Tiered Storage
Learn how Zilliz Cloud bridges cost and performance with tiered storage and enterprise-grade features, and how to migrate data from AWS S3 Vectors to Zilliz Cloud.

Zilliz Cloud Update: Smarter Autoscaling for Cost Savings, Stronger Compliance with Audit Logs, and More
What's new in Zilliz Cloud? Smarter autoscaling with scale-down, audit logs GA, enhanced SSO, and Milvus 2.6 in Private Preview.

Selecting the Right ETL Tools for Unstructured Data to Prepare for AI
Learn the right ETL tools for unstructured data to power AI. Explore key challenges, tool comparisons, and integrations with Milvus for vector search.


