Skip to content

AI & Java Integration

Integrating machine learning and AI in Java: model inference, frameworks, LLM APIs, and production deployment.


ML in Java: Inference vs Training

Training

Building models from data (typically Python/PyTorch/TensorFlow).

Python (ML expert)
├─ Collect data (10M+ samples)
├─ Feature engineering
├─ Train model (hours/days on GPU)
├─ Validate, tune hyperparameters
├─ Export model (PyTorch .pt, TensorFlow .pb)
└─ Save: model.pb, weights.h5

Inference

Using trained models to make predictions (Java/Go/C++).

Java (production)
├─ Load pre-trained model
├─ Preprocess input
├─ Run prediction (milliseconds)
├─ Postprocess output
└─ Return result to API

Workflow:

Data Scientist (Python)
  Train model
    ↓
  Export: model.pb
    ↓
  Java Developer
    Load: model.pb
    Serve: REST API
    Deploy: Production


TensorFlow Java

Google's TensorFlow with Java binding; run pre-trained models.

Installation & Setup

<!-- Maven dependency -->
<dependency>
  <groupId>org.tensorflow</groupId>
  <artifactId>tensorflow</artifactId>
  <version>1.15.0</version>
</dependency>

Loading & Running Model

import org.tensorflow.SavedModelBundle;
import org.tensorflow.Session;
import org.tensorflow.Tensor;

public class MLInference {

    // Load pre-trained model
    SavedModelBundle model = SavedModelBundle.load(
        "path/to/model", 
        "serve"  // Tag (usually "serve" for inference)
    );

    Session session = model.session();

    // Prepare input
    float[][] input = {{1.0f, 2.0f, 3.0f}};
    Tensor inputTensor = Tensor.create(input);

    // Run inference
    Tensor outputTensor = session.runner()
        .feed("input_tensor", inputTensor)  // Input name
        .fetch("output_tensor")              // Output name
        .run()
        .get(0);

    // Extract result
    float[][] predictions = new float[1][10];
    outputTensor.copyTo(predictions);

    // Clean up
    inputTensor.close();
    outputTensor.close();
    session.close();
    model.close();
}

Limitations

  • Inference only (no training in Java)
  • Model must be trained/exported in Python
  • Performance: Slower than Python (JVM overhead)
  • Limited to CPU unless GPU library installed

DeepLearning4J (DL4J)

Native Java deep learning framework; no Python dependency.

Architecture

import org.deeplearning4j.nn.conf.MultiLayerConfiguration;
import org.deeplearning4j.nn.conf.NeuralNetConfiguration;
import org.deeplearning4j.nn.multilayer.MultiLayerNetwork;
import org.deeplearning4j.nn.weights.WeightInit;
import org.nd4j.linalg.activations.Activation;

// Build network configuration
MultiLayerConfiguration config = new NeuralNetConfiguration.Builder()
    .seed(12345)
    .weightInit(WeightInit.XAVIER)
    .activation(Activation.RELU)
    .updater(new Adam(0.001))
    .l2(0.0001)
    .list()
    // Layer 1: Input (784) → Hidden (256)
    .layer(0, new DenseLayer.Builder()
        .nIn(784)
        .nOut(256)
        .build())
    // Layer 2: Hidden (256) → Output (10)
    .layer(1, new OutputLayer.Builder(LossFunctions.LossFunction.NEGATIVELOGLIKELIHOOD)
        .nIn(256)
        .nOut(10)
        .activation(Activation.SOFTMAX)
        .build())
    .build();

// Create network
MultiLayerNetwork network = new MultiLayerNetwork(config);
network.init();

// Train
for (int epoch = 0; epoch < 10; epoch++) {
    network.fit(trainingData);
    double score = network.score();
    System.out.println("Epoch " + epoch + " score: " + score);
}

// Predict
INDArray testData = Nd4j.create(testImages);
INDArray predictions = network.output(testData);

Advantages

  • Pure Java (no Python required)
  • Training & inference
  • GPU support (CUDA)
  • Cluster training (Spark integration)

Disadvantages

  • Smaller ecosystem than PyTorch/TensorFlow
  • Fewer pre-trained models available
  • Learning curve for developers from PyTorch/TensorFlow

Spring AI

High-level abstraction over LLM APIs; unified interface for multiple providers.

Spring AI Features

Abstracts: OpenAI, Anthropic, Google, Hugging Face
Provides: Chat, embeddings, image generation, function calling

Chat API

import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.stereotype.Service;

@Service
public class AIService {

    @Autowired
    private ChatClient chatClient;

    public String askQuestion(String question) {
        Prompt prompt = new Prompt(new UserMessage(question));

        var response = chatClient.call(prompt);

        return response.getResult().getOutput().getContent();
    }
}

Embeddings

@Service
public class EmbeddingService {

    @Autowired
    private EmbeddingClient embeddingClient;

    public List<Double> embed(String text) {
        EmbeddingResponse response = embeddingClient.embedForSingle(text);
        return response.getResult().getOutput();
    }

    // Vector DB integration for RAG
    public void storeEmbedding(String docId, String content) {
        List<Double> embedding = embed(content);
        vectorDB.store(docId, embedding);  // Pinecone, Weaviate, etc.
    }
}

Function Calling

Allow LLM to call Java methods.

@Component
public class Calculator {

    @Description("Adds two numbers")
    public double add(
        @Parameter(description = "First number") double a,
        @Parameter(description = "Second number") double b
    ) {
        return a + b;
    }
}

// LLM can now call this function
// Prompt: "What is 5 + 3?"
// LLM recognizes → calls calculator.add(5, 3) → returns 8

LLM API Integration

Call LLM APIs (OpenAI, Anthropic, etc.) from Java.

OpenAI API

import com.openai.api.OpenAI;
import com.openai.api.models.ChatMessage;
import com.openai.api.models.ChatCompletion;

OpenAI client = new OpenAI(apiKey);

List<ChatMessage> messages = new ArrayList<>();
messages.add(new ChatMessage("user", "Explain quantum computing"));

ChatCompletion response = client.chatCompletions.create(
    ChatCompletionRequest.builder()
        .model("gpt-4")
        .messages(messages)
        .temperature(0.7)
        .build()
);

String answer = response.choices.get(0).message.content;
System.out.println(answer);

Anthropic Claude API

import com.anthropic.api.Anthropic;
import com.anthropic.api.models.Message;

Anthropic client = new Anthropic(apiKey);

Message message = client.messages.create(
    MessageCreateParams.builder()
        .model("claude-3-opus-20240229")
        .maxTokens(1024)
        .messages(MessageParam.builder()
            .role(MessageParam.Role.USER)
            .content("Explain machine learning")
            .build())
        .build()
);

System.out.println(message.content.get(0).asText().text);

Error Handling & Rate Limiting

@Service
public class ResilientAIService {

    @Retryable(maxAttempts = 3, delay = 1000)
    public String callLLM(String prompt) {
        try {
            return llmClient.chat(prompt);
        } catch (RateLimitException e) {
            // Exponential backoff
            Thread.sleep(2000);
            return callLLM(prompt);  // Retry
        } catch (APIException e) {
            logger.error("API error: " + e.getMessage());
            return "Error calling LLM";
        }
    }
}

Model Serving & Deployment

Single Service Instance

┌─────────────┐
│   REST API  │
│  (Spring)   │
├─────────────┤
│ Load Model  │
│ (TensorFlow)│
├─────────────┤
│  Inference  │
│  (CPU/GPU)  │
└─────────────┘

Scaled Deployment

                    ┌─────────────┐
                    │ API Gateway │
                    └────┬────┬───┘
                         │    │
            ┌────────────┘    └──────────┐
            │                            │
       ┌────▼────┐                 ┌────▼────┐
       │ Service1 │                 │ Service2 │
       │ (Model A)│                 │ (Model B)│
       └──────────┘                 └──────────┘

Benefits: Load balancing, failover, A/B testing

Model Serving Frameworks

Framework Type Pros Cons
TensorFlow Serving Dedicated service Production-grade, fast Separate infrastructure
TorchServe PyTorch server Native PyTorch Limited Java support
Triton Inference Server Multi-framework Optimized, batching Complex setup
Spring Boot + TF/DL4J Embedded Simple, single service Less optimized

Docker Deployment

FROM openjdk:11
WORKDIR /app
COPY model.pb .
COPY ai-service.jar .
EXPOSE 8080
CMD ["java", "-jar", "ai-service.jar"]
# Build & push
docker build -t myregistry/ai-service:1.0 .
docker push myregistry/ai-service:1.0

# Deploy to Kubernetes
kubectl apply -f deployment.yaml

Production Considerations

Latency

  • Model inference latency: 50-500ms (depends on model size)
  • API overhead: 10-50ms (network, serialization)
  • Caching: Cache embeddings, frequent queries

Scalability

  • Horizontal: Load balance across instances
  • Vertical: GPU acceleration for complex models
  • Batching: Process multiple requests together (throughput vs latency)

Cost

  • API calls: ~$0.001-0.01 per 1000 tokens (OpenAI)
  • GPU: $0.5-2 per hour (cloud providers)
  • Storage: Vector DB, model files

Monitoring

  • Model performance: Accuracy, latency, throughput
  • System health: CPU, memory, error rates
  • User impact: Query success rate, response quality
@Aspect
@Component
public class AIMetricsAspect {

    @Before("@annotation(AIMetric)")
    public void recordMetric(JoinPoint joinPoint) {
        long startTime = System.currentTimeMillis();
        // ... method execution ...
        long duration = System.currentTimeMillis() - startTime;
        metrics.recordLatency(duration);
        metrics.recordModelInference(modelName, success);
    }
}

Interview Talking Points

  • TensorFlow vs DL4J? TensorFlow: inference only, Python training; DL4J: pure Java, training & inference
  • Training vs Inference? Training: data scientist in Python (slow); Inference: Java app (fast, production)
  • Spring AI benefit? Unified interface over multiple LLM APIs; easier to switch providers
  • LLM API integration? Call OpenAI/Anthropic/Google from Java; handle rate limits, retries
  • Model deployment? Single service (simple), load-balanced instances (scale), or dedicated serving (optimized)
  • Latency considerations? Model inference + network overhead; cache when possible, batch requests
  • Vector DB in Java? Use client libraries (Pinecone SDK, Weaviate Java) for RAG pipelines
  • Cost optimization? Batch inference, cache results, use smaller models, monitor API usage

See also: ML Fundamentals, Deep Learning, RAG & Generative AI