Microsoft Agent Framework: Detaillierte Erklärung mit Beispielen

Zu diesem Artikel gibt es ein kurzes Video:TikTok

1. Übersicht

Microsoft hat offiziell ein einheitliches Framework zur Erstellung, Orchestrierung und zum Betrieb von AI-Agenten veröffentlicht (GA – General Availability), indem die beiden bisherigen Produkte Semantic Kernel und AutoGen zusammengeführt wurden. Das ist nicht nur eine Produktankündigung – es zeichnet eine neue Richtung vor, wie Sie ein System mit LLMs, die “eigenständig entscheiden, welche Maßnahmen zu ergreifen sind”, statt nur eine Frage zu beantworten, gestalten sollten.

Dieser Artikel erklärt, worin sich ein AI-Agent von einem normalen Chatbot unterscheidet, was Microsoft konkret bereitgestellt hat, und dann werden Sie selbst einen minimalen Agent mit Java 21 + Spring Boot 3 + Spring AI (mit Azure OpenAI integriert) bauen, um die zugrunde liegende Mechanik zu verstehen – auch wenn Microsofts ursprüngliches Framework auf .NET und Python läuft.

2. Was ist ein AI-Agent?

Ein normaler Chatbot empfängt eine Frage, ruft das LLM einmal auf und gibt eine Antwort zurück. Ein Agent unterscheidet sich darin, dass er die Denk-Handlungs-Schleife mehrmals wiederholt und eigenständig entscheidet, ob er ein Tool (API, Datenbank, Datei…) aufrufen muss oder nicht, bevor er eine endgültige Antwort gibt.

Merkmal Chatbot AI Agent
Anzahl der LLM-Aufrufe 1x pro Frage Mehrmals, selbstschleifend
Tool-Nutzung Typischerweise nein Ja, vom Modell selbst ausgewählt
Status Statuslos oder Chat-Verlauf gespeichert Mit Memory, kann Checkpoints setzen
Latenz Niedrig Höher (viele Round-Trips)
Zuverlässigkeit Leicht zu kontrollieren Guardrails erforderlich, Human-in-the-Loop

2.1. Reason-Act-Schleife (ReAct)

Der Kernmechanismus, den die meisten Agent-Frameworks heute verwenden, ist ReAct: das Modell “denkt” (Thought), wählt eine Aktion (Action) – einen Tool-Aufruf – aus, erhält ein Ergebnis (Observation) und wiederholt dies, bis es genug Informationen für eine Antwort hat (Final Answer).

Thought: Der Benutzer fragt nach dem Status der Bestellung ORD-001, ich muss sie nachschlagen.
Action: lookupOrder("ORD-001")
Observation: Bestellung ORD-001: Status SHIPPED, Gesamtbetrag 450000 VND
Thought: Ich habe genug Informationen.
Final Answer: Ihre Bestellung ORD-001 wird gerade geliefert, Gesamtbetrag 450.000đ.

Das ist der Teil, den das Microsoft Agent Framework (und das Spring AI, das Sie unten verwenden werden) automatisiert – Sie müssen diese Schleife nicht von Hand schreiben, Sie müssen nur das Tool und den System-Prompt deklarieren.

3. Was hat Microsoft für AI-Agenten bereitgestellt?

Vor der Zusammenführung verfolgte Microsoft zwei parallele Entwicklungsrichtungen:

  • Semantic Kernel: Production-gerichtetes SDK mit Fokus auf typsichere Plugins, Enterprise-Integration (Azure, .NET), geeignet für stabile Bereitstellung.
  • AutoGen: Forschungsorientiert, stark bei Multi-Agent-Kommunikation – mehrere Agenten “chatten” miteinander, um komplexe Aufgaben zu lösen.

Das neue Framework kombiniert beide Stärken und umfasst die folgenden Hauptfunktionen:

  • Vorgefertigte Orchestrierungsmuster: sequenziell (Agent A fertig, dann B), parallel (mehrere Agenten laufen gleichzeitig, dann Zusammenfassung), Hand-off (Agent übergeben an einen spezialisierteren Agent), Gruppenchat (mehrere Agenten diskutieren vor der Antwort).
  • Langlebige/zustandsbehaftete Ausführung: Agenten können Checkpoints setzen, bei einem Crash fortsetzen – wichtig für lange laufende Aufgaben (Minuten bis Stunden).
  • Beobachtbarkeit als Standard: Tracing nach OpenTelemetry-Standard, Sie können jeden Thought/Action/Observation-Schritt in der Produktion sehen.
  • Human-in-the-Loop: Agent pausiert, wartet auf menschliche Überprüfung vor sensiblen Aktionen (Rückerstattung, Löschung von Daten…).
  • Azure AI Foundry Agent Service: gehostete Runtime zur Agent-Bereitstellung, vordefinierter Tool-Katalog (Bing-Suche, Code-Interpreter, Datei-Abruf) und Unterstützung für Model Context Protocol (MCP), um externe Tools nach offenen Standards anzubinden, ohne Vendor-Lock-in.

Das ursprüngliche Framework läuft auf .NET/Python, aber das Muster ist universell. Im nächsten Abschnitt werde ich dieses Muster in Java nachbilden, damit Sie sehen, wie es auf Code-Ebene funktioniert.

4. Kernarchitektur eines AI-Agenten

Ein minimaler Agent benötigt 4 Komponenten: Planner (das ist das LLM), Tool (Funktionen, die der Agent aufrufen kann), Memory (Gesprächsverlauf/Tool-Ergebnisse), Executor (Orchestrierungsschleife). Spring AI kapselt bereits Executor und Planner über ChatClient, Sie müssen nur das Tool deklarieren.

4.1. Maven-Abhängigkeit

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-azure-openai-spring-boot-starter</artifactId>
    <version>1.0.0</version>
</dependency>

Konfiguration der Azure-OpenAI-Verbindung (Microsofts GPT-Dienst, bereitgestellt über Azure):

spring.ai.azure.openai.api-key=${AZURE_OPENAI_KEY}
spring.ai.azure.openai.endpoint=${AZURE_OPENAI_ENDPOINT}
spring.ai.azure.openai.chat.options.deployment-name=gpt-4o-mini

4.2. Tool-Definition für einen Agent

Ein Tool ist eine normale Java-Methode, die mit @Tool gekennzeichnet wird, damit das Modell weiß, dass es aufgerufen werden kann und mit welchen Parametern.

public record Order(String id, String status, BigDecimal total) {}

public interface OrderService {
    Order findById(String orderId);
}

@Service
public class OrderTools {

    private final OrderService orderService;

    public OrderTools(OrderService orderService) {
        this.orderService = orderService;
    }

    @Tool(description = "Abfrage des Status und der Gesamtsumme einer Bestellung anhand der Bestellnummer")
    public String lookupOrder(String orderId) {
        Order order = orderService.findById(orderId);
        return "Bestellung %s: Status %s, Gesamtbetrag %s VND"
            .formatted(order.id(), order.status(), order.total());
    }
}

Das description in @Tool ist das, was das Modell liest, um zu entscheiden, ob lookupOrder aufgerufen werden soll – klare, präzise Beschreibungen helfen dem Agent, das richtige Tool auszuwählen.

4.3. Agent ruft Tool automatisch über ChatClient auf

@Service
public class SupportAgentService {

    private final ChatClient chatClient;

    public SupportAgentService(ChatClient.Builder builder, OrderTools orderTools) {
        this.chatClient = builder
            .defaultSystem("""
                Sie sind ein Kundenservice-Assistent eines Online-Shops.
                Verwenden Sie das lookupOrder-Tool, wenn die Frage mit Bestellungen zu tun hat.
                Antworten Sie kurz und freundlich auf Vietnamesisch.
                """)
            .defaultTools(orderTools)
            .build();
    }

    public String handle(String userMessage) {
        return chatClient.prompt()
            .user(userMessage)
            .call()
            .content();
    }
}

Die Zeile .defaultTools(orderTools) registriert das Tool-Set. ChatClient führt die ReAct-Schleife intern aus: sendet den Prompt mit der Werkzeugliste an das Modell. Falls das Modell einen Aufruf von lookupOrder anfordert, führt Spring AI automatisch die entsprechende Java-Methode aus, gibt das Ergebnis (Observation) an das Modell zurück und erhält dann die endgültige Antwort. Sie schreiben die Schleife nicht von Hand – dies ist genau der Teil, in dem sich das Microsoft Agent Framework und Spring AI vom Wesen her gleichen.

> handle("Wo ist meine Bestellung ORD-001?")
Ihre Bestellung ORD-001 wird gerade geliefert (SHIPPED), Gesamtbetrag 450.000đ!

Hinweis: Das Modell ruft ein Tool nur auf, wenn es “entscheidet”, dass es nötig ist – nicht jede Frage aktiviert ein Tool. Wenn der Benutzer fragt “Versendet der Shop international?”, antwortet das Modell direkt, ohne lookupOrder aufzurufen.

5. Multi-Agent: wenn ein Agent nicht ausreicht

Eine der herausragenden Funktionen, die Microsoft bereitgestellt hat, ist Hand-off – das Übergeben des Gesprächs zwischen spezialisierten Agenten. Für kleine Probleme können Sie es mit einem einfachen Router simulieren, ohne ein komplexes Multi-Agent-Framework zu benötigen:

@Service
public class AgentRouter {

    private final SupportAgentService orderAgent;
    private final RefundAgentService refundAgent;

    public AgentRouter(SupportAgentService orderAgent, RefundAgentService refundAgent) {
        this.orderAgent = orderAgent;
        this.refundAgent = refundAgent;
    }

    public String route(String userMessage) {
        String lower = userMessage.toLowerCase();
        if (lower.contains("rückerstattung") || lower.contains("refund")) {
            return refundAgent.handle(userMessage);
        }
        return orderAgent.handle(userMessage);
    }
}

Dieser Router spielt eine minimale “Orchestrator”-Rolle. In größerem Maßstab sollte auch die Auswahl, welcher Agent verarbeitet, vom LLM selbst entschieden werden (Intent-Klassifizierung durch das Modell), anstatt es hart zu codieren .contains() – das manuelle Schreiben eignet sich nur für Demos oder sehr kleine, stabile Intent-Sets.

6. Testen von Tools und Agenten

Die einfachste Komponente zum Testen in einem Agent-System ist das Tool – weil es eine reine Java-Methode ist, die nicht vom LLM abhängt. Sie sollten diesen Teil gründlich testen, da der Agent nur so “intelligent” ist wie die Qualität der Tools, die er aufruft.

class OrderToolsTest {

    @Test
    void shouldReturnOrderSummaryWithStatusAndTotal() {
        OrderService fakeOrderService = orderId ->
            new Order(orderId, "SHIPPED", new BigDecimal("450000"));

        OrderTools tools = new OrderTools(fakeOrderService);

        String result = tools.lookupOrder("ORD-001");

        assertThat(result)
            .contains("ORD-001")
            .contains("SHIPPED")
            .contains("450000");
    }
}

Da OrderService nur eine Methode findById hat, verwende ich ein Lambda für eine Fake-Implementierung, anstatt ein Mock-Framework-Dependency hinzuzufügen – prägnant und ausreichend für diesen Unit-Test.

class AgentRouterTest {

    @Test
    void shouldRouteRefundKeywordToRefundAgent() {
        SupportAgentService orderAgent = mock(SupportAgentService.class);
        RefundAgentService refundAgent = mock(RefundAgentService.class);
        when(refundAgent.handle(anyString())).thenReturn("Rückerstattungsanfrage empfangen");

        AgentRouter router = new AgentRouter(orderAgent, refundAgent);

        String result = router.route("Ich möchte eine Rückerstattung für Bestellung ORD-002");

        assertThat(result).isEqualTo("Rückerstattungsanfrage empfangen");
        verify(refundAgent).handle(anyString());
        verify(orderAgent, never()).handle(anyString());
    }
}

Hinweis: Schreiben Sie keine “End-to-End-Tests, die das LLM aufrufen” in Unit-Tests – die Ergebnisse sind nicht deterministisch (das Modell kann jedes Mal anders antworten), API-Aufrufe kosten Geld und machen CI langsam/fragil. Mocken Sie ChatClient oder testen Sie Tool/Router separat wie oben; führen Sie eine separate Integration-Test-Suite aus (manuell oder nächtlich) durch, um zu überprüfen, ob der Agent das richtige Tool in echten Szenarien auswählt.

7. Häufige Fehler und wann Sie keinen Agent verwenden sollten

  • Agent für Probleme verwenden, die mit if-else gelöst werden können: Wenn die Aktionsauswahllogik im Voraus bekannt und fest ist (z. B. immer die Bestellung nachschlagen, wenn die Bestellnummer im Format ORD-\d+ vorliegt), ist das Schreiben von Code normalerweise billiger, schneller und viel einfacher zu testen, als das LLM jedes Mal “denken” zu lassen.
  • Guardrails für sensible Maßnahmen ignorieren: Der Agent kann Tools zum Löschen von Daten, zur Rückerstattung und zum Senden von E-Mails an Kunden aufrufen – ohne einen Bestätigungsschritt (Human-in-the-Loop) oder Tool-Berechtigungsbeschränkungen können ein Prompt-Injection oder ein Schlussfolgerungsfehler des Modells echte Konsequenzen haben.
  • Schleifenanzahl nicht begrenzen: Wenn das Modell ständig das falsche Tool auswählt oder nicht genug Daten zum Schlussfolgern hat, kann die ReAct-Schleife endlos laufen, Token und Geld verschwenden. Setzen Sie immer eine maximale Schrittanzahl und Timeout.
  • Mangelnde Beobachtbarkeit: Wenn der Agent falsch antwortet, müssen Sie die gesamte Kette von Thought/Action/Observation überprüfen, um das Problem zu debuggen – ohne detaillierte Logs/Traces ist es fast unmöglich, herauszufinden, was das Modell “gedacht” hat, das zu falschen Ergebnissen führte.
  • Latenz und Kosten: Jeder Schritt in der Schleife ist ein LLM-Aufruf. Eine einfache Frage kann 2-3 Modellaufrufe kosten (und jeder Aufruf dauert mehrere hundert Millisekunden bis Sekunden). Für APIs, die sofortige Antworten erfordern (z. B. unter 200 ms), eignet sich dieser Agent-Typ nicht.

8. Fazit

Microsofts Zusammenführung von Semantic Kernel und AutoGen zu einem einzigen Framework zeigt einen klaren Trend: AI-Agenten werden von “interessanten Demos” zu Production-Infrastruktur, die Orchestrierung, Zustand, Beobachtbarkeit und strenge Zugriffskontrolle wie jedes andere Enterprise-System erfordert. Ob Sie .NET, Python oder Java/Spring AI wie in diesem Beispiel verwenden, die Kernarchitektur dreht sich immer um vier Blöcke: Planner, Tool, Memory, Executor – wenn Sie diese vier Blöcke beherrschen, können Sie jedes zukünftig erscheinende Agent-Framework verstehen und anwenden.

AI AgentMicrosoftSpring AIAzure OpenAILLM