Skip to content

Building an Agent with LangChain4j

LangChain4j is a powerful and idiomatic Java library for building applications with Large Language Models. It provides high-level APIs that make creating complex agents with tools simple and elegant. It fully supports any OpenAI-compatible API, including Voidon.

This tutorial demonstrates how to build a weather agent using the AiServices feature of LangChain4j, which automatically creates an agent implementation from a simple Java interface.

Why use a framework like LangChain4j?

LangChain4j handles the entire tool-use lifecycle automatically. You simply annotate your Java methods with @Tool, and the AiService will make them available to the language model, execute them when requested, and use the results to formulate a final answer.


Prerequisites

You need to add the LangChain4j dependencies to your project. If you are using Maven, add the following to your pom.xml:

XML
<dependencies>
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j</artifactId>
        <version>0.30.0</version> <!-- Use the latest version -->
    </dependency>
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-open-ai</artifactId>
        <version>0.30.0</version> <!-- Use the same version -->
    </dependency>

    <!-- Add a logger to see LangChain4j's output -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>2.0.12</version>
    </dependency>
</dependencies>

Implementation

Step 1: Define a Class with Tools

A tool is just a method in a class annotated with @Tool. LangChain4j will automatically parse the method signature and Javadoc to create a description for the language model.

src/main/java/com/voidon/agent/WeatherTools.java

Java
package com.voidon.agent;

import dev.langchain4j.agent.tool.Tool;

public class WeatherTools {

    @Tool("Gets the current weather for a specific location")
    public String getCurrentWeather(String location, String unit) {
        System.out.printf("--- Executing tool: getCurrentWeather(location=%s, unit=%s) ---\n", location, unit);

        if (location.toLowerCase().contains("tokyo")) {
            return String.format("{\"location\": \"%s\", \"temperature\": 10, \"unit\": \"%s\"}", location, unit);
        } else if (location.toLowerCase().contains("paris")) {
            return String.format("{\"location\": \"%s\", \"temperature\": 22, \"unit\": \"%s\"}", location, unit);
        } else {
            return String.format("{\"location\": \"%s\", \"temperature\": \"unknown\"}", location);
        }
    }
}

Step 2: Configure the Language Model

Next, we create an OpenAiChatModel instance, configuring it to point to the Voidon API endpoint with your API key.

src/main/java/com/voidon/agent/AgentExample.java

Java
package com.voidon.agent;

import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;

public class AgentExample {

    public static void main(String[] args) {
        // Configure the model to use the Voidon API
        ChatLanguageModel model = OpenAiChatModel.builder()
                .baseUrl("https://api.voidon.astramind.ai/v1")
                .apiKey("your-voidon-api-key")
                .modelName("auto")
                .build();
    }
}

Step 3: Define an Agent Interface

With AiServices, you don't write the agent logic yourself. Instead, you define an interface that represents the agent. LangChain4j will create the implementation for you.

src/main/java/com/voidon/agent/WeatherAssistant.java

Java
1
2
3
4
5
6
package com.voidon.agent;

// This is the interface for our agent
public interface WeatherAssistant {
    String chat(String userMessage);
}

Step 4: Build and Use the Agent

Now, we use the AiServices.builder to assemble our agent. We provide the agent interface, the language model, and the class containing our tools.

src/main/java/com/voidon/agent/AgentExample.java (updated)

Java
package com.voidon.agent;

import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;

public class AgentExample {

    public static void main(String[] args) {
        // 1. Configure the model to use the Voidon API
        ChatLanguageModel model = OpenAiChatModel.builder()
                .baseUrl("https://api.voidon.astramind.ai/v1")
                .apiKey("your-voidon-api-key")
                .modelName("auto")
                .build();

        // 2. Create an instance of the class containing the tools
        WeatherTools weatherTools = new WeatherTools();

        // 3. Define chat memory to hold the conversation history
        ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10);

        // 4. Build the AiService (our agent)
        WeatherAssistant assistant = AiServices.builder(WeatherAssistant.class)
                .chatLanguageModel(model)
                .tools(weatherTools)
                .chatMemory(chatMemory)
                .build();

        // 5. Interact with the agent
        String question = "What is the weather in Tokyo in celsius?";
        System.out.println("User: " + question);

        String answer = assistant.chat(question);

        System.out.println("Agent: " + answer);
    }
}

What's Happening Under the Hood?

  1. When you call assistant.chat(question), LangChain4j sends the user's message and the descriptions of all @Tool-annotated methods to the Voidon API.
  2. The language model analyzes the request and determines that it needs to call the getCurrentWeather function with location="Tokyo" and unit="celsius".
  3. The model responds with a special tool_calls message.
  4. LangChain4j intercepts this response, parses it, and executes the getCurrentWeather method in your WeatherTools class with the specified arguments.
  5. LangChain4j takes the return value of your Java method and sends it back to the model as a "tool result."
  6. The model receives the weather data ("temperature is 10") and formulates a final, natural language response (e.g., "The current weather in Tokyo is 10°C.").
  7. This final response is returned from the assistant.chat() method call.