>_ DevTrendsnl

Taal

Home

Talen

Secties

Frontend Backend Mobiel DevOps AI / ML GameDev Blockchain Embedded Beveiliging
Java

Hoe cyclische AI-agents uit te voeren in Java

De meeste tutorials over multi-agent systemen met LLMs zijn geschreven in Python. Als je een backend in Java schrijft en iets complexers wilt bouwen dan een lineaire keten van aanroepen, moest je voorheen je eigen finite state machines verzinnen of branching bovenop LangChain4j hacken.

In het Python-ecosysteem is LangGraph van het LangChain-team de standaard geworden voor dergelijke taken. Het lost een eenvoudig probleem op: echte conversationele agents werken bijna nooit in een rechte lijn (DAG). Een agent moet een tool aanroepen, naar een fout kijken, de gebruiker om verduidelijking vragen, of een subtask opnieuw starten. Dit zijn cycli.

Het LangGraph4j-project brengt dit concept naar de Java-wereld. De library werkt goed samen met Spring AI en LangChain4j, ondersteunt state-persistentie naar echte databases, en biedt de mogelijkheid om complexe uitvoeringsgrafen te bouwen.

Wat zit erin en hoe het werkt

De kern van de library is de StateGraph-klasse. Je beschrijft een graaf als een set van nodes, edges en gedeelde state die tussen stappen wordt doorgegeven.

Elke node ontvangt de huidige state, voert een stukje logica uit (bijvoorbeeld roept een LLM aan of opent een database) en retourneert een dictionary met updates. Deze updates worden samengevoegd met de gedeelde state via zogenaamde reducers. Nieuwe berichten kunnen bijvoorbeeld aan het einde van een lijst worden toegevoegd, terwijl een statusvlag simpelweg kan worden overschreven.

Basisvoorbeeld

Je hebt Java 17 of nieuwer nodig om hiermee te werken. Voeg de dependency toe:

<dependency>
    <groupId>org.bsc.langgraph4j</groupId>
    <artifactId>langgraph4j-core</artifactId>
    <version>1.8.24</version>
</dependency>

Laten we de eenvoudigste graaf beschrijven met twee nodes en gedeelde state voor berichten:

import org.bsc.langgraph4j.StateGraph;
import org.bsc.langgraph4j.state.AgentState;
import org.bsc.langgraph4j.state.Channels;
import org.bsc.langgraph4j.state.Channel;
import static org.bsc.langgraph4j.action.AsyncNodeAction.node_async;
import static org.bsc.langgraph4j.StateGraph.START;
import static org.bsc.langgraph4j.StateGraph.END;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

// 1. Описываем структуру состояния
class SimpleState extends AgentState {
    public static final String MESSAGES_KEY = "messages";
    public static final Map<String, Channel<?>> SCHEMA = Map.of(
            MESSAGES_KEY, Channels.appender(ArrayList::new)
    );

    public SimpleState(Map<String, Object> initData) {
        super(initData);
    }

    public List<String> messages() {
        return this.<List<String>>value("messages").orElse(List.of());
    }
}

public class SimpleApp {
    public static void main(String[] args) throws Exception {
        // 2. Собираем граф
        var graph = new StateGraph<>(SimpleState.SCHEMA, SimpleState::new)
            .addNode("greeter", node_async(state -> 
                Map.of(SimpleState.MESSAGES_KEY, "Привет от первого узла!")))
            .addNode("responder", node_async(state -> 
                Map.of(SimpleState.MESSAGES_KEY, "Ответ получен.")))
            .addEdge(START, "greeter")
            .addEdge("greeter", "responder")
            .addEdge("responder", END)
            .compile();

        // 3. Запускаем стриминг шагов
        for (var step : graph.stream(Map.of(SimpleState.MESSAGES_KEY, "Старт"))) {
            System.out.println("Шаг выполнен: " + step);
        }
    }
}

Hier retourneert de graaf een async generator. Je krijgt de graaf-state na elke node-uitvoering, wat handig is voor het streamen van voortgangsupdates naar de client in real time.

Wat dit project interessant maakt in de praktijk

1. Conditionele overgangen en cycli

Lineaire ketens zijn eenvoudig te bouwen met reguliere code. De kracht van grafen komt naar voren wanneer je conditionele edges toevoegt. Je koppelt een functie aan een edge die naar het resultaat van het werk van de LLM kijkt en beslist waar als volgende naartoe te gaan: naar een tool-calling node, naar regeneratie, of naar het voltooien van het gesprek.

2. State-persistentie en Time Travel

Als een agent over meerdere iteraties communiceert met een gebruiker of een proces uren duurt, is alles in JVM-geheugen houden niet haalbaar.

LangGraph4j bevat een checkpoint-module. Kant-en-klare adapters zijn beschikbaar voor PostgreSQL, Redis, MySQL, SQLite, OracleDB, Hazelcast en DynamoDB. Je kunt:

  • State opslaan na elke stap;
  • Uitvoering hervatten vanaf een specifiek punt na een service restart;
  • Human-in-the-loop implementeren, waarbij de graaf wacht op menselijke bevestiging van een actie en dan doorgaat;
  • De graaf terug "spoelen" naar een vorige state-snapshot.

3. Native integratie met Spring AI en LangChain4j

Je hoeft modelaanroepen niet te herschrijven voor een aparte API. De repository bevat al integratiemodules.

Zo voer je een ReAct-agent uit met LangGraph4j en LangChain4j:

var model = OllamaChatModel.builder()
        .modelName("qwen2.5:7b")
        .baseUrl("http://localhost:11434")
        .build();

var agent = AgentExecutor.builder()
        .chatModel(model)
        .toolsFromObject(new TestTool())
        .build()
        .compile();

for (var item : agent.stream(Map.of("messages", "Проверь статус и верни число потоков"))) {
    System.out.println(item);
}

Voor Spring AI is de syntax vrijwel identiek, met annotaties en Spring beans.

4. LangGraph Studio en visualisatie

Complexe grafen debuggen zonder zichtbaarheid is moeilijk. LangGraph4j kan graafdiagrammen genereren in PlantUML- en Mermaid-formaten.

De auteurs hebben ook een webinterface gebouwd genaamd LangGraph4j Studio, die je direct kunt inbedden in je Spring Boot-, Quarkus- of Jetty-applicatie om graafnodes visueel uit te voeren en te inspecteren in de browser.

Valkuilen

De library ontwikkelt zich actief (versie 1.8.x ten tijde van deze review), dus sommige zeldzame APIs kunnen veranderen tussen minor releases.

Sommige tutorials in de examples-map zijn opgemaakt als Jupyter-notebooks voor Java. Om deze voorbeelden uit te voeren, vereisen de auteurs Java 22, hoewel de library-kern prima werkt op stabiel Java 17+.

Voor wie is dit

Als je enterprise services bouwt op Spring Boot of Quarkus en agentic-scenario's wilt implementeren (technische ondersteuning, CI/CD-automatisering, meerfasige documentverwerking), verwijdert LangGraph4j de noodzaak om je eigen task scheduler voor LLMs te schrijven.

De library biedt een volwassen architecturale fundering zonder het team te dwingen over te schakelen naar een Python-stack alleen voor agent-orchestratie. Je kunt beginnen met experimenteren met een lokaal model via Ollama en een eenvoudige graaf van twee of drie nodes.

Gerelateerde projecten