CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-dev-langchain4j--langchain4j-core

Core classes and interfaces of LangChain4j providing foundational abstractions for LLM interaction, RAG, embeddings, agents, and observability

Overview
Eval results
Files

messages.mddocs/data/

Chat Messages

Package: dev.langchain4j.data.message Thread-Safety: All message types are immutable and thread-safe Multimodal: Supports text, images, audio, video, and PDF content

Chat messages represent the fundamental building blocks of conversations in LangChain4j, supporting both simple text and rich multimodal content.

Message Types

ChatMessage Interface

package dev.langchain4j.data.message;

/**
 * Base interface for all message types
 * Immutability: All implementations are immutable and thread-safe
 */
public interface ChatMessage {
    /**
     * Get message type
     * @return Message type enum
     */
    ChatMessageType type();

    /**
     * Get message text content
     * For multimodal messages, returns text portion only
     * @return Text content (may be null for some message types)
     */
    String text();
}

ChatMessageType Enum

package dev.langchain4j.data.message;

public enum ChatMessageType {
    SYSTEM,              // System instructions to model
    USER,                // User input to model
    AI,                  // Model response to user
    TOOL_EXECUTION_RESULT  // Result of tool execution
}

Message Type Classes

SystemMessage

package dev.langchain4j.data.message;

/**
 * System instructions that guide model behavior
 * Typically placed at start of conversation
 * Immutability: Immutable, thread-safe
 */
public class SystemMessage implements ChatMessage {
    private final String text;

    public static SystemMessage from(String text) { /* ... */ }
    public static SystemMessage systemMessage(String text) { /* ... */ }

    @Override
    public ChatMessageType type() { return ChatMessageType.SYSTEM; }

    @Override
    public String text() { return text; }
}

UserMessage

package dev.langchain4j.data.message;

/**
 * User input to the model
 * Supports multimodal content (text, images, audio, video, PDFs)
 * Immutability: Immutable, thread-safe
 */
public class UserMessage implements ChatMessage {
    private final List<Content> contents;  // Can contain text, images, etc.
    private final String name;             // Optional user identifier

    // Text-only constructors
    public static UserMessage from(String text) { /* ... */ }
    public static UserMessage userMessage(String text) { /* ... */ }

    // Multimodal constructors
    public static UserMessage from(Content... contents) { /* ... */ }
    public static UserMessage from(List<Content> contents) { /* ... */ }

    // With user name
    public static UserMessage from(String name, String text) { /* ... */ }
    public static UserMessage from(String name, Content... contents) { /* ... */ }

    @Override
    public ChatMessageType type() { return ChatMessageType.USER; }

    @Override
    public String text() { /* Returns text from TextContent */ }

    public List<Content> contents() { return contents; }
    public String name() { return name; }
}

AiMessage

package dev.langchain4j.data.message;

import dev.langchain4j.agent.tool.ToolExecutionRequest;

/**
 * Model response to user
 * Can contain text and/or tool execution requests
 * Immutability: Immutable, thread-safe
 */
public class AiMessage implements ChatMessage {
    private final String text;
    private final List<ToolExecutionRequest> toolExecutionRequests;

    public static AiMessage from(String text) { /* ... */ }
    public static AiMessage aiMessage(String text) { /* ... */ }

    // With tool requests
    public static AiMessage from(ToolExecutionRequest... requests) { /* ... */ }
    public static AiMessage from(String text, List<ToolExecutionRequest> requests) { /* ... */ }

    @Override
    public ChatMessageType type() { return ChatMessageType.AI; }

    @Override
    public String text() { return text; }

    public List<ToolExecutionRequest> toolExecutionRequests() { return toolExecutionRequests; }

    public boolean hasToolExecutionRequests() {
        return toolExecutionRequests != null && !toolExecutionRequests.isEmpty();
    }
}

ToolExecutionResultMessage

package dev.langchain4j.data.message;

/**
 * Result of tool execution, sent back to model
 * Links to original tool request via ID
 * Immutability: Immutable, thread-safe
 */
public class ToolExecutionResultMessage implements ChatMessage {
    private final String id;           // Matches ToolExecutionRequest.id()
    private final String toolName;
    private final String text;         // Tool result as text

    public static ToolExecutionResultMessage from(
        String id,
        String toolName,
        String result
    ) { /* ... */ }

    public static ToolExecutionResultMessage from(
        ToolExecutionRequest request,
        String result
    ) { /* ... */ }

    @Override
    public ChatMessageType type() { return ChatMessageType.TOOL_EXECUTION_RESULT; }

    @Override
    public String text() { return text; }

    public String id() { return id; }
    public String toolName() { return toolName; }
}

Content Types (Multimodal)

Content Interface

package dev.langchain4j.data.message;

/**
 * Base interface for message content
 * Immutability: All implementations are immutable
 */
public interface Content {
    /**
     * Get content type
     * @return Content type enum
     */
    ContentType type();
}

public enum ContentType {
    TEXT,
    IMAGE,
    AUDIO,
    VIDEO,
    PDF
}

TextContent

package dev.langchain4j.data.message;

public class TextContent implements Content {
    private final String text;

    public static TextContent from(String text) { /* ... */ }

    @Override
    public ContentType type() { return ContentType.TEXT; }

    public String text() { return text; }
}

ImageContent

package dev.langchain4j.data.message;

import java.net.URI;

public class ImageContent implements Content {
    private final URI imageUrl;       // OR
    private final String base64Data;  // Base64-encoded image
    private final String mimeType;    // e.g., "image/png"

    // From URL
    public static ImageContent from(String imageUrl) { /* ... */ }
    public static ImageContent from(URI imageUrl) { /* ... */ }

    // From base64 data
    public static ImageContent from(String base64Data, String mimeType) { /* ... */ }

    @Override
    public ContentType type() { return ContentType.IMAGE; }

    public URI imageUrl() { return imageUrl; }
    public String base64Data() { return base64Data; }
    public String mimeType() { return mimeType; }
}

AudioContent

package dev.langchain4j.data.message;

public class AudioContent implements Content {
    private final URI audioUrl;       // OR
    private final String base64Data;  // Base64-encoded audio
    private final String mimeType;    // e.g., "audio/mp3"

    public static AudioContent from(String audioUrl) { /* ... */ }
    public static AudioContent from(String base64Data, String mimeType) { /* ... */ }

    @Override
    public ContentType type() { return ContentType.AUDIO; }
}

VideoContent

package dev.langchain4j.data.message;

public class VideoContent implements Content {
    private final URI videoUrl;
    private final String base64Data;
    private final String mimeType;    // e.g., "video/mp4"

    public static VideoContent from(String videoUrl) { /* ... */ }
    public static VideoContent from(String base64Data, String mimeType) { /* ... */ }

    @Override
    public ContentType type() { return ContentType.VIDEO; }
}

PdfFileContent

package dev.langchain4j.data.message;

public class PdfFileContent implements Content {
    private final URI pdfUrl;
    private final String base64Data;

    public static PdfFileContent from(String pdfUrl) { /* ... */ }
    public static PdfFileContent from(String base64Data) { /* ... */ }

    @Override
    public ContentType type() { return ContentType.PDF; }
}

Usage Examples

Simple Text Messages

import dev.langchain4j.data.message.*;
import java.util.List;
import java.util.ArrayList;

// Build conversation
List<ChatMessage> messages = new ArrayList<>();

// System instruction
messages.add(SystemMessage.from("You are a helpful assistant."));

// User message
messages.add(UserMessage.from("What is the capital of France?"));

// AI response
messages.add(AiMessage.from("The capital of France is Paris."));

// Next user turn
messages.add(UserMessage.from("What about Spain?"));

// Send to model
ChatResponse response = chatModel.chat(messages);

Multimodal User Messages

import dev.langchain4j.data.message.*;

// Text + Image
UserMessage multimodal = UserMessage.from(
    TextContent.from("What's in this image?"),
    ImageContent.from("https://example.com/image.jpg")
);

// Multiple images
UserMessage compareImages = UserMessage.from(
    TextContent.from("Compare these two images:"),
    ImageContent.from("https://example.com/image1.jpg"),
    ImageContent.from("https://example.com/image2.jpg")
);

// Image from file (base64)
byte[] imageData = Files.readAllBytes(Path.of("photo.jpg"));
String base64 = Base64.getEncoder().encodeToString(imageData);

UserMessage localImage = UserMessage.from(
    TextContent.from("Describe this photo"),
    ImageContent.from(base64, "image/jpeg")
);

Tool Execution Flow

import dev.langchain4j.agent.tool.ToolExecutionRequest;

// 1. User asks a question
messages.add(UserMessage.from("What's the weather in Paris?"));

// 2. Model responds with tool call
ChatResponse response = chatModel.chat(messages);
AiMessage aiMessage = response.aiMessage();
messages.add(aiMessage);

if (aiMessage.hasToolExecutionRequests()) {
    for (ToolExecutionRequest request : aiMessage.toolExecutionRequests()) {
        // 3. Execute tool
        String result = executeTool(request);

        // 4. Add tool result to conversation
        ToolExecutionResultMessage toolResult = ToolExecutionResultMessage.from(
            request,
            result
        );
        messages.add(toolResult);
    }

    // 5. Send back to model for final response
    ChatResponse finalResponse = chatModel.chat(messages);
    System.out.println(finalResponse.aiMessage().text());
}

Named Users (Multi-User Scenarios)

// Distinguish between users in group chat
messages.add(UserMessage.from("Alice", "I think we should use React"));
messages.add(UserMessage.from("Bob", "I prefer Vue.js"));

ChatResponse response = chatModel.chat(messages);
// Model can reference users by name in response

Best Practices

1. System Message Placement

// ✅ GOOD: System message at the start
List<ChatMessage> messages = new ArrayList<>();
messages.add(SystemMessage.from("You are a helpful coding assistant."));
messages.add(UserMessage.from("Help me debug this code"));

// ❌ BAD: System message in the middle (model may ignore it)
messages.add(UserMessage.from("Question 1"));
messages.add(SystemMessage.from("Be concise"));  // Too late!

2. Conversation History Management

// Keep history within context window limits
private static final int MAX_MESSAGES = 20;

if (messages.size() > MAX_MESSAGES) {
    // Keep system message + recent history
    ChatMessage systemMsg = messages.get(0);
    List<ChatMessage> recentMsgs = messages.subList(
        messages.size() - MAX_MESSAGES + 1,
        messages.size()
    );

    messages.clear();
    messages.add(systemMsg);
    messages.addAll(recentMsgs);
}

3. Immutability Benefits

// Messages are immutable - safe to share across threads
UserMessage userMsg = UserMessage.from("Hello");

// Both threads use same message instance safely
executor.submit(() -> chatModel1.chat(List.of(userMsg)));
executor.submit(() -> chatModel2.chat(List.of(userMsg)));

4. Content Type Checking

for (Content content : userMessage.contents()) {
    switch (content.type()) {
        case TEXT:
            TextContent text = (TextContent) content;
            processText(text.text());
            break;
        case IMAGE:
            ImageContent image = (ImageContent) content;
            processImage(image);
            break;
        case AUDIO:
            AudioContent audio = (AudioContent) content;
            processAudio(audio);
            break;
    }
}

Provider Support for Multimodal

Content TypeOpenAIAnthropicGoogleAzure
Text
Images✅ GPT-4V✅ Claude 3+✅ Gemini
Audio✅ GPT-4o✅ Gemini
Video✅ Gemini
PDF✅ Claude 3+✅ Gemini

Common Pitfalls

PitfallSolution
Modifying message list during iterationCreate new list or use iterator.remove()
System message not at startPlace system message first
Forgetting to add AI response to historyAlways append AI message before next user turn
Not handling null textCheck text() != null for messages
Exceeding context windowImplement message pruning strategy

Message Serialization

// Messages are serializable for persistence
import com.fasterxml.jackson.databind.ObjectMapper;

ObjectMapper mapper = new ObjectMapper();

// Serialize
String json = mapper.writeValueAsString(messages);

// Deserialize
List<ChatMessage> loaded = mapper.readValue(
    json,
    new TypeReference<List<ChatMessage>>() {}
);

See Also

  • Chat Models - Using messages with chat models
  • Tools - Tool execution with messages
  • Chat Memory - Persisting conversation history
  • Guardrails - Validating message content

Install with Tessl CLI

npx tessl i tessl/maven-dev-langchain4j--langchain4j-core@1.11.0

docs

data

documents.md

embeddings.md

messages.md

guardrails.md

index.md

memory.md

observability.md

tools.md

tile.json