Wednesday, 25 June 2025

Understanding ChatMessage Types in Langchain4j: The Core of LLM Communication

Langchain4j defines five types of ChatMessages, each representing a distinct communication role or purpose in a conversation pipeline with LLM. Understanding these is key to designing robust, context-aware LLM integrations.

1. Types of Chat messages

1.1. UserMessage

This message originates from the end user (a person or your application logic). It represents a direct query or command.

 

Example

UserMessage userMessage = new UserMessage("What's the weather in London today?");

1.2. AiMessage

This message is the LLM’s response to a UserMessage. It can either be a text reply or a structured command to invoke a tool.

 

Example

AiMessage aiTextResponse = new AiMessage("It looks sunny in London with a high of 22°C.");

 

This is what you usually get back from the LLM.

 

1.3. ToolExecutionResultMessage

This message is used to return the result of executing a tool that the AI requested in a previous ToolExecutionRequest.

 

Example

ToolExecutionResultMessage resultMessage = new ToolExecutionResultMessage("toolId1", "temp_prediction_tool", "Current temperature in London is 22°C.");

ToolExecutionResultMessage is used in AI-to-tool roundtrips in tool-augmented LLM systems.

 

1.4. SystemMessage

This is a message from the developer or system that sets up rules, behaviors, tone, or context for the AI model.

 

Example

SystemMessage systemMessage = new SystemMessage("You are a helpful assistant that predicts Wather conditions");

SystemMessages are explicit instructions to the model about:

 

·      What role it should take (e.g., “You are a medical assistant”)

·      How it should respond (e.g., “Always reply formally”)

·      What it should or should not do (e.g., “Do not answer questions about politics”)

 

LLMs are trained to pay more attention to instructions in system prompts, so even if a UserMessage contradicts it, the model will often follow the SystemMessage instead.

 

1.5. CustomMessage (For Advanced Use)

A message type that allows arbitrary attributes. Only supported by specific chat models (like Ollama).

 

Example

Map<String, Object> attributes = Map.of("type", "meta", "value", "some extra context");
CustomMessage customMessage = new CustomMessage(attributes);

2. What’s happening in the simplest LLM chat scenario?

When you want to talk to the AI using Langchain4j, you can send just one message like this:

UserMessage message = new UserMessage("Hi");
ChatResponse response = chatModel.chat(message);

 

This is similar to how you might send just a string like "Hi" to a chat method, but there's a big difference. Instead of just getting the AI’s reply as a plain string, now you get a full ChatResponse object.

public class ChatResponse {

    private final AiMessage aiMessage;
    private final ChatResponseMetadata metadata;

}

2.1 AiMessage

The ChatResponse contains an AiMessage, which represents the actual reply generated by the AI. Here’s how you can extract the AI’s response text and any tool execution requests from it.

AiMessage aiMessage = response.aiMessage();

// Get the AI's text response
String responseFromLLM = aiMessage.text();

// Get any tool execution requests made by the AI
List<ToolExecutionRequest> toolsToExecute = aiMessage.toolExecutionRequests();

// Print the response
System.out.println("AI Response: " + responseFromLLM);

// Print tool execution details (if any)
for (ToolExecutionRequest toolExecutionRequest : toolsToExecute) {
    System.out.println(
        "Tool ID: " + toolExecutionRequest.id() +
        ", Name: " + toolExecutionRequest.name() +
        ", Arguments: " + toolExecutionRequest.arguments()
    );
}

 

2.2 ChatResponseMetadata

This contains additional details about the model’s response, including:

 

TokenUsage:

Indicates how many tokens were used:

·      In the input messages

·      In the AI’s response

·      Total tokens used in the entire interaction

 

This is especially useful for tracking usage costs, as LLM providers typically charge based on the number of tokens processed.

 

FinishReason:

·      Explains why the model stopped generating a response.

·      In most cases, the reason will be FinishReason.STOP, which means, the AI completed its response naturally.

 

Here’s how you can extract and log this metadata

ChatResponseMetadata chatResponseMetadata = response.metadata();

FinishReason finishReason = chatResponseMetadata.finishReason();
String modelName = chatResponseMetadata.modelName();
TokenUsage tokenUsage = chatResponseMetadata.tokenUsage();

System.out.println("Model stopped because: " + finishReason);
System.out.println("Model used: " + modelName);
System.out.println("Input tokens: " + tokenUsage.inputTokenCount());
System.out.println("Output tokens: " + tokenUsage.outputTokenCount());
System.out.println("Total tokens: " + tokenUsage.totalTokenCount());

 

Find the below working application.

 

ChatMessagesDemo.java

 

package com.sample.app.chatmodels;

import java.util.List;

import dev.langchain4j.agent.tool.ToolExecutionRequest;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.chat.response.ChatResponseMetadata;
import dev.langchain4j.model.ollama.OllamaChatModel;
import dev.langchain4j.model.output.FinishReason;
import dev.langchain4j.model.output.TokenUsage;

public class ChatMessagesDemo {

        public static void main(String[] args) {

                // Create the Ollama language model
                ChatModel chatModel = OllamaChatModel.builder().baseUrl("http://localhost:11434").modelName("llama3.2").build();
                UserMessage userMessage = new UserMessage("Hi");

                ChatResponse response = chatModel.chat(userMessage);

                AiMessage aiMessage = response.aiMessage();
                String responseFromLLM = aiMessage.text();
                List<ToolExecutionRequest> toolsToExecute = aiMessage.toolExecutionRequests();

                System.out.println("responseFromLLM : " + responseFromLLM);
                for (ToolExecutionRequest toolExecutionRequest : toolsToExecute) {
                        System.out.println(toolExecutionRequest.id() + " " + toolExecutionRequest.name() + " "
                                        + toolExecutionRequest.arguments());
                }

                ChatResponseMetadata chatResponseMetadata = response.metadata();
                FinishReason finishReason = chatResponseMetadata.finishReason();
                String modelName = chatResponseMetadata.modelName();
                TokenUsage tokenUsage = chatResponseMetadata.tokenUsage();

                System.out.println("The reason why a model call finished : " + finishReason);
                System.out.println("modelName : " + modelName);
                System.out.println("inputTokenCount : " + tokenUsage.inputTokenCount());
                System.out.println("outputTokenCount : " + tokenUsage.outputTokenCount());
                System.out.println("totalTokenCount : " + tokenUsage.totalTokenCount());

        }

}

 

Output

responseFromLLM : How can I assist you today?
The reason why a model call finished : STOP
modelName : llama3.2
inputTokenCount : 26
outputTokenCount : 8
totalTokenCount : 34

 


  

Previous                                                    Next                                                    Home

No comments:

Post a Comment