LangChain4j integration for Mistral AI providing chat completion, streaming, embedding, moderation, and code completion capabilities
Query and discover available Mistral AI models and their capabilities dynamically. Useful for applications that need to adapt to new models, display model options to users, or implement dynamic model selection based on capabilities.
Query the Mistral AI API to retrieve all available models and their metadata.
public class MistralAiModels {
/**
* Create a new builder for configuring MistralAiModels.
*
* @return MistralAiModelsBuilder instance
*/
public static MistralAiModelsBuilder builder() { ... }
/**
* Quick initialization with API key.
*
* @param apiKey Your (non-null) Mistral AI API key
* @return MistralAiModels instance
*/
public static MistralAiModels withApiKey(String apiKey) { ... }
/**
* Retrieve list of available models from Mistral AI API.
*
* @return Response containing List of MistralAiModelCard with model metadata
*/
public Response<List<MistralAiModelCard>> availableModels() { ... }
}LangChain4j ModelCatalog implementation for standardized model metadata queries.
public class MistralAiModelCatalog implements ModelCatalog {
/**
* Create a new builder for configuring MistralAiModelCatalog.
*
* @return Builder instance
* @throws IllegalArgumentException if parameter validation fails
*/
public static Builder builder() { ... }
/**
* List all models with standardized descriptions.
*
* @return List of ModelDescription objects
*/
public List<ModelDescription> listModels() { ... }
/**
* Returns the model provider (MISTRAL_AI).
*
* @return ModelProvider enum value
*/
public ModelProvider provider() { ... }
}import dev.langchain4j.model.mistralai.MistralAiModels;
import dev.langchain4j.model.mistralai.internal.api.MistralAiModelCard;
import dev.langchain4j.model.output.Response;
import java.util.List;
// Quick initialization
MistralAiModels models = MistralAiModels.withApiKey(System.getenv("MISTRAL_API_KEY"));
// Retrieve available models
Response<List<MistralAiModelCard>> response = models.availableModels();
List<MistralAiModelCard> modelList = response.content();
// Display models
for (MistralAiModelCard model : modelList) {
System.out.println("Model ID: " + model.getId());
System.out.println("Owned by: " + model.getOwnerBy());
System.out.println("Created: " + new Date(model.getCreated() * 1000L));
System.out.println();
}import dev.langchain4j.model.mistralai.MistralAiModelCatalog;
import dev.langchain4j.model.catalog.ModelDescription;
MistralAiModelCatalog catalog = MistralAiModelCatalog.builder()
.apiKey(System.getenv("MISTRAL_API_KEY"))
.build();
List<ModelDescription> descriptions = catalog.listModels();
for (ModelDescription desc : descriptions) {
System.out.println("Model: " + desc.name());
System.out.println("Provider: " + desc.provider());
System.out.println();
}public class DynamicModelSelector {
private final MistralAiModels models;
public DynamicModelSelector(String apiKey) {
this.models = MistralAiModels.withApiKey(apiKey);
}
public String selectBestModel(String taskType) {
Response<List<MistralAiModelCard>> response = models.availableModels();
List<MistralAiModelCard> availableModels = response.content();
// Filter and select based on task type
return switch (taskType.toLowerCase()) {
case "chat" -> findLatestChatModel(availableModels);
case "code" -> findCodeModel(availableModels);
case "[Moderation Model](./moderation-model.md)" -> findModerationModel(availableModels);
default -> findDefaultModel(availableModels);
};
}
private String findLatestChatModel(List<MistralAiModelCard> models) {
return models.stream()
.filter(m -> m.getId().contains("mistral-large"))
.findFirst()
.map(MistralAiModelCard::getId)
.orElse("mistral-large-latest");
}
private String findCodeModel(List<MistralAiModelCard> models) {
return models.stream()
.filter(m -> m.getId().contains("codestral"))
.findFirst()
.map(MistralAiModelCard::getId)
.orElse("codestral-latest");
}
private String findModerationModel(List<MistralAiModelCard> models) {
return models.stream()
.filter(m -> m.getId().contains("moderation"))
.findFirst()
.map(MistralAiModelCard::getId)
.orElse("mistral-moderation-latest");
}
private String findDefaultModel(List<MistralAiModelCard> models) {
return models.stream()
.findFirst()
.map(MistralAiModelCard::getId)
.orElse("mistral-large-latest");
}
}
// Usage
DynamicModelSelector selector = new DynamicModelSelector(apiKey);
String chatModel = selector.selectBestModel("chat");
String codeModel = selector.selectBestModel("code");
System.out.println("[Chat Models](./chat-models.md): " + chatModel);
System.out.println("Code model: " + codeModel);public class ModelAvailabilityChecker {
private final MistralAiModels models;
public ModelAvailabilityChecker(String apiKey) {
this.models = MistralAiModels.withApiKey(apiKey);
}
public boolean isModelAvailable(String modelName) {
try {
Response<List<MistralAiModelCard>> response = models.availableModels();
return response.content().stream()
.anyMatch(m -> m.getId().equals(modelName));
} catch (Exception e) {
return false;
}
}
public List<String> getAvailableModelNames() {
Response<List<MistralAiModelCard>> response = models.availableModels();
return response.content().stream()
.map(MistralAiModelCard::getId)
.collect(Collectors.toList());
}
}
// Usage
ModelAvailabilityChecker checker = new ModelAvailabilityChecker(apiKey);
if (checker.isModelAvailable("mistral-large-latest")) {
System.out.println("mistral-large-latest is available");
}
System.out.println("All available models:");
checker.getAvailableModelNames().forEach(System.out::println);public class UserModelSelector {
private final MistralAiModels models;
public Map<String, String> getModelOptions() {
Response<List<MistralAiModelCard>> response = models.availableModels();
return response.content().stream()
.collect(Collectors.toMap(
MistralAiModelCard::getId,
this::getDisplayName,
(existing, replacement) -> existing
));
}
private String getDisplayName(MistralAiModelCard model) {
String id = model.getId();
// Create user-friendly display names
if (id.contains("large")) return "Mistral Large (Best Quality)";
if (id.contains("medium")) return "Mistral Medium (Balanced)";
if (id.contains("small")) return "Mistral Small (Fast)";
if (id.contains("codestral")) return "Codestral (Code Specialized)";
if (id.contains("moderation")) return "Moderation Model";
return id;
}
public void displayModelMenu() {
Map<String, String> options = getModelOptions();
System.out.println("Available Models:");
int i = 1;
for (Map.Entry<String, String> entry : options.entrySet()) {
System.out.println(i++ + ". " + entry.getValue() + " (" + entry.getKey() + ")");
}
}
}
// Usage
UserModelSelector selector = new UserModelSelector(models);
selector.displayModelMenu();public class CachedModelDiscovery {
private final MistralAiModels models;
private List<MistralAiModelCard> cachedModels;
private LocalDateTime lastUpdate;
private final Duration cacheDuration;
public CachedModelDiscovery(String apiKey, Duration cacheDuration) {
this.models = MistralAiModels.withApiKey(apiKey);
this.cacheDuration = cacheDuration;
}
public List<MistralAiModelCard> getAvailableModels() {
if (needsRefresh()) {
refreshCache();
}
return new ArrayList<>(cachedModels);
}
private boolean needsRefresh() {
return cachedModels == null ||
lastUpdate == null ||
LocalDateTime.now().isAfter(lastUpdate.plus(cacheDuration));
}
private void refreshCache() {
Response<List<MistralAiModelCard>> response = models.availableModels();
cachedModels = response.content();
lastUpdate = LocalDateTime.now();
}
public void forceRefresh() {
refreshCache();
}
}
// Usage
CachedModelDiscovery discovery = new CachedModelDiscovery(apiKey, Duration.ofHours(24));
List<MistralAiModelCard> models = discovery.getAvailableModels(); // Uses cache
// ... later ...
List<MistralAiModelCard> sameModels = discovery.getAvailableModels(); // Still uses cache
discovery.forceRefresh(); // Force refreshpublic static class MistralAiModelsBuilder {
/**
* Set the Mistral AI API key (required).
*
* @param apiKey Your (non-null) Mistral AI API key
* @return Builder instance
* @throws IllegalArgumentException if parameter validation fails
*/
public MistralAiModelsBuilder apiKey(String apiKey) { ... }
/**
* Set the base URL for the Mistral AI API.
* Default: https://api.mistral.ai/v1
*
* @param baseUrl Custom (non-null) API endpoint URL
* @return Builder instance
* @throws IllegalArgumentException if parameter validation fails
*/
public MistralAiModelsBuilder baseUrl(String baseUrl) { ... }
/**
* Set request timeout.
* Default: 60 seconds
*
* @param timeout Duration (non-null) for request timeout
* @return Builder instance
* @throws IllegalArgumentException if parameter validation fails
*/
public MistralAiModelsBuilder timeout(Duration timeout) { ... }
/**
* Enable request logging.
*
* @param logRequests True (non-null) to log requests
* @return Builder instance
* @throws IllegalArgumentException if parameter validation fails
*/
public MistralAiModelsBuilder logRequests(Boolean logRequests) { ... }
/**
* Enable response logging.
*
* @param logResponses True (non-null) to log responses
* @return Builder instance
* @throws IllegalArgumentException if parameter validation fails
*/
public MistralAiModelsBuilder logResponses(Boolean logResponses) { ... }
/**
* Set custom SLF4J logger for logging.
*
* @param logger SLF (non-null)4J Logger instance
* @return Builder instance
* @throws IllegalArgumentException if parameter validation fails
*/
public MistralAiModelsBuilder logger(Logger logger) { ... }
/**
* Set maximum retry attempts on failure.
* Default: 2
*
* @param maxRetries Maximum (non-null) number of retries
* @return Builder instance
* @throws IllegalArgumentException if parameter validation fails
*/
public MistralAiModelsBuilder maxRetries(Integer maxRetries) { ... }
/**
* Set custom HTTP client builder.
*
* @param httpClientBuilder HttpClientBuilder (non-null) instance
* @return Builder instance
* @throws IllegalArgumentException if parameter validation fails
*/
public MistralAiModelsBuilder httpClientBuilder(HttpClientBuilder httpClientBuilder) { ... }
/**
* Build the MistralAiModels instance.
*
* @return Configured MistralAiModels
*/
public MistralAiModels build() { ... }
}public static class Builder {
/**
* Set the Mistral AI API key (required).
*
* @param apiKey Your (non-null) Mistral AI API key
* @return Builder instance
* @throws IllegalArgumentException if parameter validation fails
*/
public Builder apiKey(String apiKey) { ... }
/**
* Set the base URL for the Mistral AI API.
*
* @param baseUrl Custom (non-null) API endpoint URL
* @return Builder instance
* @throws IllegalArgumentException if parameter validation fails
*/
public Builder baseUrl(String baseUrl) { ... }
/**
* Set request timeout.
*
* @param timeout Duration (non-null) for request timeout
* @return Builder instance
* @throws IllegalArgumentException if parameter validation fails
*/
public Builder timeout(Duration timeout) { ... }
/**
* Enable request logging.
*
* @param logRequests True (non-null) to log requests
* @return Builder instance
* @throws IllegalArgumentException if parameter validation fails
*/
public Builder logRequests(Boolean logRequests) { ... }
/**
* Enable response logging.
*
* @param logResponses True (non-null) to log responses
* @return Builder instance
* @throws IllegalArgumentException if parameter validation fails
*/
public Builder logResponses(Boolean logResponses) { ... }
/**
* Set custom SLF4J logger for logging.
*
* @param logger SLF (non-null)4J Logger instance
* @return Builder instance
* @throws IllegalArgumentException if parameter validation fails
*/
public Builder logger(Logger logger) { ... }
/**
* Set custom HTTP client builder.
*
* @param httpClientBuilder HttpClientBuilder (non-null) instance
* @return Builder instance
* @throws IllegalArgumentException if parameter validation fails
*/
public Builder httpClientBuilder(HttpClientBuilder httpClientBuilder) { ... }
/**
* Build the MistralAiModelCatalog instance.
*
* @return Configured MistralAiModelCatalog
*/
public MistralAiModelCatalog build() { ... }
}public class MistralAiModelCard {
/**
* Get the model identifier.
*
* @return Model ID string (e.g., "mistral-large-latest")
*/
public String getId() { ... }
/**
* Get the object type (always "model").
*
* @return Object type string
*/
public String getObject() { ... }
/**
* Get the creation timestamp (Unix timestamp).
*
* @return Creation time as Unix timestamp (Integer, not Long)
*/
public Integer getCreated() { ... }
/**
* Get the owner/organization.
*
* @return Owner identifier
*/
public String getOwnerBy() { ... }
/**
* Get root model identifier.
*
* @return Root model string
*/
public String getRoot() { ... }
/**
* Get parent model identifier.
*
* @return Parent model string
*/
public String getParent() { ... }
/**
* Get model permissions.
*
* @return List of MistralAiModelPermission objects
*/
public List<MistralAiModelPermission> getPermission() { ... }
/**
* Create a builder for constructing MistralAiModelCard instances.
*
* @return MistralAiModelCardBuilder instance
*/
public static MistralAiModelCardBuilder builder() { ... }
}Query model list once at application startup:
@Component
public class ModelRegistry {
private final List<MistralAiModelCard> availableModels;
@Autowired
public ModelRegistry(@Value("${mistral.api.key}") String apiKey) {
MistralAiModels models = MistralAiModels.withApiKey(apiKey);
Response<List<MistralAiModelCard>> response = models.availableModels();
this.availableModels = response.content();
logger.info("Loaded {} Mistral AI models", availableModels.size());
}
public List<String> getModelIds() {
return availableModels.stream()
.map(MistralAiModelCard::getId)
.collect(Collectors.toList());
}
public boolean isAvailable(String modelId) {
return availableModels.stream()
.anyMatch(m -> m.getId().equals(modelId));
}
}Implement fallback logic for unavailable models:
public class RobustModelSelector {
private final MistralAiModels models;
private final List<String> preferredModels;
public RobustModelSelector(String apiKey, List<String> preferredModels) {
this.models = MistralAiModels.withApiKey(apiKey);
this.preferredModels = preferredModels;
}
public String selectModel() {
Response<List<MistralAiModelCard>> response = models.availableModels();
Set<String> available = response.content().stream()
.map(MistralAiModelCard::getId)
.collect(Collectors.toSet());
// Try preferred models in order
for (String preferred : preferredModels) {
if (available.contains(preferred)) {
return preferred;
}
}
// Fallback to any available model
return available.stream()
.findFirst()
.orElseThrow(() -> new RuntimeException("No models available"));
}
}
// Usage
List<String> preferences = Arrays.asList(
"mistral-large-latest",
"mistral-medium-latest",
"mistral-small-latest"
);
RobustModelSelector selector = new RobustModelSelector(apiKey, preferences);
String selectedModel = selector.selectModel();Refresh model list periodically in long-running applications:
@Service
public class ModelDiscoveryService {
private final MistralAiModels models;
private final ScheduledExecutorService scheduler;
private volatile List<MistralAiModelCard> currentModels;
@Autowired
public ModelDiscoveryService(@Value("${mistral.api.key}") String apiKey) {
this.models = MistralAiModels.withApiKey(apiKey);
this.scheduler = Executors.newScheduledThreadPool(1);
// Initial load
refreshModels();
// Schedule periodic refresh (every 24 hours)
scheduler.scheduleAtFixedRate(
this::refreshModels,
24, 24, TimeUnit.HOURS
);
}
private void refreshModels() {
try {
Response<List<MistralAiModelCard>> response = models.availableModels();
currentModels = response.content();
logger.info("Refreshed model list: {} models available", currentModels.size());
} catch (Exception e) {
logger.error("Failed to refresh model list", e);
}
}
public List<MistralAiModelCard> getCurrentModels() {
return new ArrayList<>(currentModels);
}
@PreDestroy
public void shutdown() {
scheduler.shutdown();
}
}Handle API failures gracefully:
public Optional<List<MistralAiModelCard>> getModelsWithFallback() {
try {
Response<List<MistralAiModelCard>> response = models.availableModels();
return Optional.of(response.content());
} catch (Exception e) {
logger.warn("Failed to fetch models from API: {}", e.getMessage());
return Optional.empty();
}
}
// Usage with default list
List<MistralAiModelCard> modelList = getModelsWithFallback()
.orElse(getDefaultModelList());// Generate UI options from available models
public class ModelConfigurationUI {
public void displayModelOptions(String apiKey) {
MistralAiModels models = MistralAiModels.withApiKey(apiKey);
Response<List<MistralAiModelCard>> response = models.availableModels();
System.out.println("Select a model:");
List<MistralAiModelCard> modelList = response.content();
for (int i = 0; i < modelList.size(); i++) {
MistralAiModelCard model = modelList.get(i);
System.out.println((i + 1) + ". " + model.getId());
}
}
}// Select most cost-effective model for task
public String selectCostEffectiveModel(String taskComplexity) {
Response<List<MistralAiModelCard>> response = models.availableModels();
return switch (taskComplexity) {
case "simple" -> findSmallestModel(response.content());
case "moderate" -> findMediumModel(response.content());
case "complex" -> findLargestModel(response.content());
default -> findDefaultModel(response.content());
};
}// Detect when new models become available
public class ModelUpdateMonitor {
private Set<String> knownModels = new HashSet<>();
public List<String> checkForNewModels(MistralAiModels models) {
Response<List<MistralAiModelCard>> response = models.availableModels();
Set<String> current = response.content().stream()
.map(MistralAiModelCard::getId)
.collect(Collectors.toSet());
List<String> newModels = current.stream()
.filter(id -> !knownModels.contains(id))
.collect(Collectors.toList());
knownModels = current;
return newModels;
}
}Install with Tessl CLI
npx tessl i tessl/maven-dev-langchain4j--langchain4j-mistral-ai@1.11.0