CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-dev-langchain4j--langchain4j-open-ai

LangChain4j OpenAI Integration providing Java access to OpenAI APIs including chat models, embeddings, image generation, audio transcription, and moderation.

Overview
Eval results
Files

model-catalog.mddocs/

Model Catalog

The Model Catalog provides programmatic access to query available OpenAI models and their capabilities through the API. This enables dynamic model selection, capability discovery, and automated configuration based on model availability.

The catalog returns detailed information about each model including its ID, ownership, creation date, and capabilities. This is useful for building adaptive applications that can respond to new model releases or availability changes.

Capabilities

OpenAiModelCatalog

Query the OpenAI API to list available models with their metadata.

public class OpenAiModelCatalog implements ModelCatalog {
    public static Builder builder();

    // Core methods
    public List<ModelDescription> listModels();
    public ModelProvider provider();
}

Builder

public static class Builder {
    // Core configuration
    public Builder apiKey(String apiKey);
    public Builder baseUrl(String baseUrl);
    public Builder organizationId(String organizationId);
    public Builder projectId(String projectId);

    // HTTP configuration
    public Builder httpClientBuilder(HttpClientBuilder httpClientBuilder);
    public Builder connectTimeout(Duration connectTimeout);
    public Builder readTimeout(Duration readTimeout);
    public Builder userAgent(String userAgent);

    // Custom headers and params
    public Builder customHeaders(Map<String, String> customHeaders);
    public Builder customQueryParams(Map<String, String> customQueryParams);

    // Logging
    public Builder logRequests(Boolean logRequests);
    public Builder logResponses(Boolean logResponses);
    public Builder logger(Logger logger);

    public OpenAiModelCatalog build();
}

Basic Usage Example

import dev.langchain4j.model.openai.OpenAiModelCatalog;
import dev.langchain4j.model.catalog.ModelDescription;

// Create model catalog
OpenAiModelCatalog catalog = OpenAiModelCatalog.builder()
    .apiKey(System.getenv("OPENAI_API_KEY"))
    .build();

// List all available models
List<ModelDescription> models = catalog.listModels();

System.out.println("Available models: " + models.size());
for (ModelDescription model : models) {
    System.out.println("- " + model.id());
}

Model Filtering Example

// Find chat models
List<ModelDescription> chatModels = catalog.listModels().stream()
    .filter(model -> model.id().startsWith("gpt-"))
    .collect(Collectors.toList());

System.out.println("Chat models:");
for (ModelDescription model : chatModels) {
    System.out.println("- " + model.id());
}

// Find embedding models
List<ModelDescription> embeddingModels = catalog.listModels().stream()
    .filter(model -> model.id().contains("embedding"))
    .collect(Collectors.toList());

System.out.println("\nEmbedding models:");
for (ModelDescription model : embeddingModels) {
    System.out.println("- " + model.id());
}

Model Selection Example

public class DynamicModelSelector {
    private final OpenAiModelCatalog catalog;

    public DynamicModelSelector(String apiKey) {
        this.catalog = OpenAiModelCatalog.builder()
            .apiKey(apiKey)
            .build();
    }

    public String selectBestChatModel() {
        List<ModelDescription> models = catalog.listModels();

        // Prefer GPT-4o if available
        Optional<ModelDescription> gpt4o = models.stream()
            .filter(m -> m.id().equals("gpt-4o"))
            .findFirst();

        if (gpt4o.isPresent()) {
            return gpt4o.get().id();
        }

        // Fallback to GPT-4 Turbo
        Optional<ModelDescription> gpt4turbo = models.stream()
            .filter(m -> m.id().equals("gpt-4-turbo"))
            .findFirst();

        if (gpt4turbo.isPresent()) {
            return gpt4turbo.get().id();
        }

        // Default to GPT-3.5 Turbo
        return "gpt-3.5-turbo";
    }

    public boolean isModelAvailable(String modelId) {
        return catalog.listModels().stream()
            .anyMatch(m -> m.id().equals(modelId));
    }

    public List<String> getAvailableModelIds() {
        return catalog.listModels().stream()
            .map(ModelDescription::id)
            .sorted()
            .collect(Collectors.toList());
    }
}

// Usage
DynamicModelSelector selector = new DynamicModelSelector(apiKey);

if (selector.isModelAvailable("gpt-4o")) {
    System.out.println("GPT-4o is available");
} else {
    System.out.println("Selecting best alternative...");
    String bestModel = selector.selectBestChatModel();
    System.out.println("Using: " + bestModel);
}

Model Information Display Example

public void displayModelInfo() {
    OpenAiModelCatalog catalog = OpenAiModelCatalog.builder()
        .apiKey(apiKey)
        .build();

    List<ModelDescription> models = catalog.listModels();

    System.out.println("=== OpenAI Models ===\n");

    // Group by type
    Map<String, List<ModelDescription>> byType = models.stream()
        .collect(Collectors.groupingBy(this::getModelType));

    for (Map.Entry<String, List<ModelDescription>> entry : byType.entrySet()) {
        System.out.println(entry.getKey() + ":");
        for (ModelDescription model : entry.getValue()) {
            System.out.println("  - " + model.id());
            System.out.println("    Owner: " + model.ownedBy());
            System.out.println("    Created: " + formatDate(model.created()));
        }
        System.out.println();
    }
}

private String getModelType(ModelDescription model) {
    String id = model.id();
    if (id.contains("gpt")) return "Chat Models";
    if (id.contains("embedding")) return "Embedding Models";
    if (id.contains("dall-e")) return "Image Models";
    if (id.contains("whisper")) return "Audio Models";
    if (id.contains("moderation")) return "Moderation Models";
    return "Other";
}

private String formatDate(Long timestamp) {
    if (timestamp == null) return "Unknown";
    return new SimpleDateFormat("yyyy-MM-dd").format(new Date(timestamp * 1000));
}

Caching Example

public class CachedModelCatalog {
    private final OpenAiModelCatalog catalog;
    private List<ModelDescription> cachedModels;
    private long lastFetch;
    private final long cacheValidityMs;

    public CachedModelCatalog(String apiKey, long cacheValidityMs) {
        this.catalog = OpenAiModelCatalog.builder()
            .apiKey(apiKey)
            .build();
        this.cacheValidityMs = cacheValidityMs;
    }

    public synchronized List<ModelDescription> listModels() {
        long now = System.currentTimeMillis();

        if (cachedModels == null || (now - lastFetch) > cacheValidityMs) {
            cachedModels = catalog.listModels();
            lastFetch = now;
        }

        return new ArrayList<>(cachedModels);
    }

    public synchronized void invalidateCache() {
        cachedModels = null;
    }
}

// Usage with 1 hour cache
CachedModelCatalog cachedCatalog = new CachedModelCatalog(
    apiKey,
    TimeUnit.HOURS.toMillis(1)
);

// Fast subsequent calls
List<ModelDescription> models = cachedCatalog.listModels();

Version Checking Example

public class ModelVersionChecker {
    private final OpenAiModelCatalog catalog;
    private final Map<String, Long> knownVersions = new ConcurrentHashMap<>();

    public ModelVersionChecker(String apiKey) {
        this.catalog = OpenAiModelCatalog.builder()
            .apiKey(apiKey)
            .build();
        initializeKnownVersions();
    }

    private void initializeKnownVersions() {
        for (ModelDescription model : catalog.listModels()) {
            knownVersions.put(model.id(), model.created());
        }
    }

    public boolean hasNewVersion(String modelId) {
        List<ModelDescription> models = catalog.listModels();

        Optional<ModelDescription> current = models.stream()
            .filter(m -> m.id().equals(modelId))
            .findFirst();

        if (!current.isPresent()) {
            return false;
        }

        Long previousVersion = knownVersions.get(modelId);
        Long currentVersion = current.get().created();

        if (previousVersion == null) {
            knownVersions.put(modelId, currentVersion);
            return false;
        }

        if (!previousVersion.equals(currentVersion)) {
            knownVersions.put(modelId, currentVersion);
            return true;
        }

        return false;
    }

    public List<String> checkForUpdates() {
        List<String> updated = new ArrayList<>();

        for (String modelId : knownVersions.keySet()) {
            if (hasNewVersion(modelId)) {
                updated.add(modelId);
            }
        }

        return updated;
    }
}

Types

ModelDescription

public class ModelDescription {
    public String id();
    public String object();
    public Long created();
    public String ownedBy();
}

ModelCatalog Interface

public interface ModelCatalog {
    List<ModelDescription> listModels();
    ModelProvider provider();
}

Model Information

Model ID

Unique identifier for the model:

  • Examples: gpt-4o, gpt-3.5-turbo, text-embedding-3-small
  • Use for model selection and configuration
  • May include version snapshots

Object Type

Type of object returned:

  • Usually "model"
  • Part of OpenAI API structure

Created

Unix timestamp when model was created:

  • Seconds since epoch
  • Indicates model version/release date
  • Use for tracking updates

Owned By

Organization that owns the model:

  • Usually "openai" or "openai-internal"
  • May show "system" for internal models
  • Indicates model source

Best Practices

Periodic Updates

// Check for new models periodically
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

scheduler.scheduleAtFixedRate(() -> {
    try {
        List<ModelDescription> models = catalog.listModels();
        System.out.println("Model count: " + models.size());

        // Check for new models
        List<String> modelIds = models.stream()
            .map(ModelDescription::id)
            .collect(Collectors.toList());

        // Store or compare with previous list
        checkForNewModels(modelIds);
    } catch (Exception e) {
        logger.error("Failed to update model catalog", e);
    }
}, 0, 1, TimeUnit.HOURS);

Error Handling

public List<ModelDescription> safeListModels() {
    try {
        return catalog.listModels();
    } catch (Exception e) {
        logger.error("Failed to fetch models", e);
        // Return cached or default list
        return getDefaultModels();
    }
}

private List<ModelDescription> getDefaultModels() {
    // Return known stable models as fallback
    return List.of(
        createModelDescription("gpt-4o"),
        createModelDescription("gpt-3.5-turbo"),
        createModelDescription("text-embedding-3-small")
    );
}

Model Capabilities Detection

public class ModelCapabilitiesDetector {
    public enum Capability {
        CHAT,
        COMPLETION,
        EMBEDDING,
        IMAGE_GENERATION,
        AUDIO_TRANSCRIPTION,
        MODERATION,
        FUNCTION_CALLING,
        VISION,
        JSON_MODE
    }

    public Set<Capability> detectCapabilities(String modelId) {
        Set<Capability> capabilities = new HashSet<>();

        if (modelId.startsWith("gpt-")) {
            capabilities.add(Capability.CHAT);
            capabilities.add(Capability.FUNCTION_CALLING);

            if (modelId.contains("gpt-4") || modelId.contains("gpt-3.5-turbo")) {
                capabilities.add(Capability.JSON_MODE);
            }

            if (modelId.contains("vision") || modelId.contains("gpt-4")) {
                capabilities.add(Capability.VISION);
            }
        }

        if (modelId.contains("embedding")) {
            capabilities.add(Capability.EMBEDDING);
        }

        if (modelId.contains("dall-e")) {
            capabilities.add(Capability.IMAGE_GENERATION);
        }

        if (modelId.contains("whisper") || modelId.contains("transcribe")) {
            capabilities.add(Capability.AUDIO_TRANSCRIPTION);
        }

        if (modelId.contains("moderation")) {
            capabilities.add(Capability.MODERATION);
        }

        return capabilities;
    }

    public boolean supportsFeature(String modelId, Capability capability) {
        return detectCapabilities(modelId).contains(capability);
    }
}

Configuration Management

public class ModelConfiguration {
    private final OpenAiModelCatalog catalog;
    private final Map<String, ModelConfig> configurations;

    public ModelConfiguration(String apiKey) {
        this.catalog = OpenAiModelCatalog.builder()
            .apiKey(apiKey)
            .build();
        this.configurations = new HashMap<>();
        loadConfigurations();
    }

    private void loadConfigurations() {
        List<ModelDescription> models = catalog.listModels();

        for (ModelDescription model : models) {
            ModelConfig config = createDefaultConfig(model);
            configurations.put(model.id(), config);
        }
    }

    private ModelConfig createDefaultConfig(ModelDescription model) {
        String id = model.id();

        if (id.contains("gpt-4o")) {
            return new ModelConfig(0.7, 2000, true);
        } else if (id.contains("gpt-4")) {
            return new ModelConfig(0.7, 1000, true);
        } else if (id.contains("gpt-3.5")) {
            return new ModelConfig(0.7, 500, false);
        }

        return new ModelConfig(0.7, 1000, false);
    }

    public ModelConfig getConfig(String modelId) {
        return configurations.getOrDefault(
            modelId,
            new ModelConfig(0.7, 1000, false)
        );
    }

    private static class ModelConfig {
        final double defaultTemperature;
        final int defaultMaxTokens;
        final boolean supportsVision;

        ModelConfig(double temperature, int maxTokens, boolean vision) {
            this.defaultTemperature = temperature;
            this.defaultMaxTokens = maxTokens;
            this.supportsVision = vision;
        }
    }
}

Common Use Cases

Dynamic Model Selection

Choose the best available model based on current availability and requirements.

Availability Monitoring

Track when models become available or are deprecated.

Feature Detection

Determine which features are supported by available models.

Cost Optimization

Select models based on cost and capability trade-offs.

Graceful Degradation

Fall back to alternative models when preferred models are unavailable.

Documentation Generation

Generate up-to-date documentation of available models.

Testing

Verify model availability before running test suites.

Performance Considerations

API Call Cost

  • Model listing is a separate API call
  • Cache results when possible
  • Typically very fast (<100ms)
  • Free or very low cost

Rate Limits

  • Subject to standard API rate limits
  • Typically generous for catalog endpoints
  • Consider caching to reduce calls

Response Size

  • Returns metadata for all models
  • Typically small (few KB)
  • Fast to parse and process

Caching Strategy

  • Cache for 1-24 hours depending on needs
  • Invalidate on errors or manual refresh
  • Balance freshness vs API calls

Install with Tessl CLI

npx tessl i tessl/maven-dev-langchain4j--langchain4j-open-ai

docs

advanced-features.md

audio-transcription-models.md

chat-models.md

embedding-models.md

image-models.md

index.md

language-models.md

model-catalog.md

moderation-models.md

request-response.md

token-management.md

README.md

tile.json