llm-speak / mistral-ai
A Laravel package for integrating MistralAI into LLMSpeak
Requires
- php: ^8.2
README
LLMSpeak Mistral AI is a Laravel package that provides a fluent, Laravel-native interface for integrating with Mistral AI's powerful language models. Built as part of the LLMSpeak ecosystem, it offers seamless access to Mistral's cutting-edge models including Mistral Large, Mistral Medium, and specialized models like Codestral for code generation.
Note: This package is part of the larger LLMSpeak ecosystem. For universal provider switching and standardized interfaces, check out the LLMSpeak Core package.
Table of Contents
Features
- 🧠 Advanced Models: Access to Mistral Large, Medium, Small, and specialized models like Codestral
- 🚀 Laravel Native: Full Laravel integration with automatic service discovery
- 🔧 Fluent Interface: Expressive request builders with method chaining
- 📊 Laravel Data: Powered by Spatie Laravel Data for robust data validation
- 🛠️ Tool Support: Complete function calling capabilities with flexible tool choice
- 📝 Embeddings: Advanced embedding generation with multiple output formats
- 🎛️ Output Control: Precise control over embedding dimensions and data types
- 💨 Streaming: Real-time streaming responses for chat completions
- 🎯 JSON Mode: Structured output generation for reliable data extraction
- 🎯 Type Safety: Full PHP 8.2+ type declarations and IDE support
- 🔐 Secure: Built-in API key management and request validation
Get Started
Requires PHP 8.2+ and Laravel 10.x/11.x/12.x
Install the package via Composer:
composer require llm-speak/mistral-ai
The package will automatically register itself via Laravel's package discovery.
Environment Configuration
Add your Mistral AI API key to your .env
file:
MISTRAL_API_KEY=your_mistral_api_key_here
Get your API key from Mistral AI Console.
Usage
Chat Completions
The simplest way to chat with Mistral AI models:
use LLMSpeak\Mistral\MistralCompletionsRequest; $request = new MistralCompletionsRequest( model: 'mistral-large-latest', messages: [ ['role' => 'user', 'content' => 'Explain quantum computing in simple terms'] ] ); $response = $request->post(); echo $response->getTextContent(); // "Quantum computing is..."
Model Selection
Choose the right Mistral model for your use case:
// Most capable model for complex reasoning $request = new MistralCompletionsRequest( model: 'mistral-large-latest', messages: $messages ); // Balanced performance and speed $request = new MistralCompletionsRequest( model: 'mistral-medium-latest', messages: $messages ); // Fast and efficient for simple tasks $request = new MistralCompletionsRequest( model: 'mistral-small-latest', messages: $messages ); // Specialized for code generation $request = new MistralCompletionsRequest( model: 'codestral-latest', messages: $messages );
Embeddings
Generate embeddings with advanced output control:
use LLMSpeak\Mistral\MistralEmbeddingsRequest; // Simple text embedding $request = new MistralEmbeddingsRequest( model: 'mistral-embed', input: 'Generate embeddings for this text' ); $response = $request->post(); $embeddings = $response->getEmbeddings(); $dimensions = $response->getDimensions();
Advanced Embedding Configuration
Control output format and dimensions:
// High-precision embeddings $request = new MistralEmbeddingsRequest( model: 'mistral-embed', input: 'Research paper abstract content' ) ->setOutputDimension(1024) // Custom dimensions ->setOutputDtype('float'); // High precision // Memory-efficient embeddings $request = new MistralEmbeddingsRequest( model: 'mistral-embed', input: ['Text 1', 'Text 2', 'Text 3'] // Batch processing ) ->setOutputDimension(512) // Reduced dimensions ->setOutputDtype('int8'); // Quantized format // Ultra-compact embeddings $request = new MistralEmbeddingsRequest( model: 'mistral-embed', input: $documentTexts ) ->setOutputDimension(256) ->setOutputDtype('binary'); // Maximum compression $response = $request->post(); // Access different embedding formats $embeddings = $response->getEmbeddings(); // Raw embeddings $firstEmbedding = $response->getFirstEmbedding(); // Single vector $count = $response->getEmbeddingCount(); // Number of embeddings
Universal LLMSpeak Interface
For provider-agnostic embeddings that work across Mistral, Gemini, Ollama, and other providers, use the universal LLMSpeak interface:
use LLMSpeak\Core\Support\Facades\LLMSpeak; use LLMSpeak\Core\Support\Requests\LLMSpeakEmbeddingsRequest; // Universal request works with ANY provider $request = new LLMSpeakEmbeddingsRequest( model: 'mistral-embed', input: 'Generate embeddings for this text', encoding_format: 'float', // Maps to Mistral's outputDtype dimensions: 1024, // Maps to Mistral's outputDimension task_type: null // Not applicable for Mistral ); // Execute with Mistral - same code works with other providers! $response = LLMSpeak::embeddingsFrom('mistral', $request); // Universal response methods $embeddings = $response->getAllEmbeddings(); $firstVector = $response->getFirstEmbedding(); $dimensions = $response->getDimensions(); $tokenUsage = $response->getTotalTokens();
Universal Format Mapping
The universal interface automatically maps encoding formats to Mistral's native types:
// Float precision (maps to Mistral's outputDtype: 'float') $floatRequest = new LLMSpeakEmbeddingsRequest( model: 'mistral-embed', input: 'High precision embeddings', encoding_format: 'float', // → outputDtype: 'float' dimensions: 1024, // → outputDimension: 1024 task_type: null ); $floatResponse = LLMSpeak::embeddingsFrom('mistral', $floatRequest); // Quantized format (maps to Mistral's outputDtype: 'int8') $quantizedRequest = new LLMSpeakEmbeddingsRequest( model: 'mistral-embed', input: 'Memory-efficient embeddings', encoding_format: 'base64', // → outputDtype: 'int8' (quantized) dimensions: 512, // → outputDimension: 512 task_type: null ); $quantizedResponse = LLMSpeak::embeddingsFrom('mistral', $quantizedRequest); // Batch processing with universal interface $batchRequest = new LLMSpeakEmbeddingsRequest( model: 'mistral-embed', input: [ 'Document one for embeddings', 'Document two for embeddings', 'Document three for embeddings' ], encoding_format: 'float', dimensions: null, // Use model default task_type: null ); $batchResponse = LLMSpeak::embeddingsFrom('mistral', $batchRequest); echo "Generated {$batchResponse->getEmbeddingCount()} embeddings"; echo "Vector dimensions: {$batchResponse->getDimensions()}";
Advanced Universal Configuration
Access Mistral's advanced features through the universal interface:
// Ultra-compact embeddings with automatic format mapping $compactRequest = new LLMSpeakEmbeddingsRequest( model: 'mistral-embed', input: 'Large document corpus for storage', encoding_format: 'base64', // Automatically maps to binary/int8 dimensions: 256, // Reduced dimensions for storage task_type: null ); $compactResponse = LLMSpeak::embeddingsFrom('mistral', $compactRequest); // Different models with same interface $models = ['mistral-embed', 'codestral-embed']; foreach ($models as $model) { $request = new LLMSpeakEmbeddingsRequest( model: $model, input: 'Code snippet for analysis', encoding_format: 'float', dimensions: 1024, task_type: null ); $response = LLMSpeak::embeddingsFrom('mistral', $request); echo "Model {$model}: {$response->getDimensions()} dimensions"; }
Why Use Universal Interface?
✅ Provider Independence: Switch between Mistral, Gemini, Ollama with zero code changes
✅ Automatic Mapping: Encoding formats automatically mapped to provider-specific types
✅ Future Proof: New providers automatically supported
✅ Consistent API: Same methods across all providers
✅ Type Safety: Full PHP type declarations and IDE support
// Same request works with different providers! $request = new LLMSpeakEmbeddingsRequest( model: 'embedding-model', input: 'Universal text input', encoding_format: 'float', dimensions: 512, task_type: null ); $mistralResponse = LLMSpeak::embeddingsFrom('mistral', $request); // Mistral AI $geminiResponse = LLMSpeak::embeddingsFrom('gemini', $request); // Google AI $ollamaResponse = LLMSpeak::embeddingsFrom('ollama', $request); // Local models
Fluent Request Building
Build complex requests using the fluent interface:
use LLMSpeak\Mistral\MistralCompletionsRequest; $request = new MistralCompletionsRequest( model: 'mistral-large-latest', messages: [ ['role' => 'user', 'content' => 'Write a creative story about AI'] ] ) ->setMaxTokens(2000) ->setTemperature(0.8) ->setPresencePenalty(0.1) ->setFrequencyPenalty(0.1) ->setStop(['THE END', '---']); $response = $request->post(); // Access response properties echo $response->id; // chatcmpl-abc123 echo $response->model; // mistral-large-latest echo $response->getTotalTokens(); // 1850 echo $response->getTextContent(); // Generated story
Batch Configuration
Set multiple parameters at once:
$request = new MistralCompletionsRequest( model: 'mistral-medium-latest', messages: $conversation )->setMultiple([ 'maxTokens' => 1500, 'temperature' => 0.7, 'presencePenalty' => 0.2, 'frequencyPenalty' => 0.1, 'stop' => ['Human:', 'Assistant:'], 'n' => 3 // Generate 3 different responses ]);
Tool Calling
Enable Mistral models to use external functions:
$tools = [ [ 'type' => 'function', 'function' => [ 'name' => 'get_weather_forecast', 'description' => 'Get weather forecast for a specific location', 'parameters' => [ 'type' => 'object', 'properties' => [ 'location' => [ 'type' => 'string', 'description' => 'City and country (e.g., "Paris, France")' ], 'days' => [ 'type' => 'integer', 'description' => 'Number of days to forecast (1-7)', 'minimum' => 1, 'maximum' => 7 ] ], 'required' => ['location'] ] ] ] ]; $request = new MistralCompletionsRequest( model: 'mistral-large-latest', messages: [ ['role' => 'user', 'content' => 'What\'s the weather forecast for London this week?'] ] ) ->setTools($tools) ->setToolChoice('auto'); // Let model decide when to use tools $response = $request->post(); // Check for tool usage if ($response->usedTools()) { $toolCalls = $response->getToolCalls(); foreach ($toolCalls as $call) { echo "Function: {$call['function']['name']}\n"; echo "Arguments: " . json_encode($call['function']['arguments']) . "\n"; } }
Multiple Choices
Generate multiple response alternatives:
$request = new MistralCompletionsRequest( model: 'mistral-large-latest', messages: [ ['role' => 'user', 'content' => 'Give me three different marketing slogans for an eco-friendly product'] ] ) ->setN(3) // Generate 3 different responses ->setTemperature(0.9); // Higher creativity for variety $response = $request->post(); // Access all choices $allChoices = $response->getAllChoices(); foreach ($allChoices as $index => $choice) { echo "Option " . ($index + 1) . ": " . $choice['message']['content'] . "\n\n"; } // Or get a specific choice $firstChoice = $response->getChoice(0); $secondChoice = $response->getChoice(1);
Response Formatting
Control output format for structured data:
$request = new MistralCompletionsRequest( model: 'mistral-large-latest', messages: [ [ 'role' => 'user', 'content' => 'Extract the following information from this text as JSON: name, age, occupation. Text: "John Smith is a 35-year-old software engineer."' ] ] ) ->setResponseFormat(['type' => 'json_object']) ->setMaxTokens(200); $response = $request->post(); $jsonContent = $response->getTextContent(); $data = json_decode($jsonContent, true); echo "Name: " . $data['name']; // John Smith echo "Age: " . $data['age']; // 35 echo "Occupation: " . $data['occupation']; // software engineer
Streaming Responses
Enable real-time streaming for long responses:
$request = new MistralCompletionsRequest( model: 'mistral-large-latest', messages: [ ['role' => 'user', 'content' => 'Write a detailed technical article about machine learning'] ] ) ->setStream(true) ->setMaxTokens(4000); $response = $request->post(); // Stream handling will be processed by the CompletionsEndpoint // Response contains streaming data format
Advanced Configuration
Configure advanced parameters for optimal performance:
$request = new MistralCompletionsRequest( model: 'mistral-large-latest', messages: $conversationHistory ) ->setMaxTokens(4000) ->setTemperature(0.7) ->setPresencePenalty(0.3) // Encourage topic diversity ->setFrequencyPenalty(0.2) // Reduce repetition ->setStop(['[END]', '###']) // Custom stop sequences ->setN(2) // Generate 2 alternatives ->setResponseFormat(['type' => 'json_object']); $response = $request->post();
Response Handling
Access comprehensive response data:
$response = $request->post(); // Basic response info $responseId = $response->id; $modelUsed = $response->model; $timestamp = $response->created; $responseObject = $response->object; // Content access $textContent = $response->getTextContent(); $allChoices = $response->getAllChoices(); $firstChoice = $response->getChoice(0); // Token usage analysis $totalTokens = $response->getTotalTokens(); $promptTokens = $response->getPromptTokens(); $completionTokens = $response->getCompletionTokens(); // Completion analysis $finishReason = $response->getFinishReason(); $completedNaturally = $response->completedNaturally(); $hitTokenLimit = $response->reachedTokenLimit(); $stoppedBySequence = $response->stoppedBySequence(); // Tool usage analysis $usedTools = $response->usedTools(); $toolCalls = $response->getToolCalls(); $hasAnyToolCalls = $response->hasAnyToolCalls(); // Quality metrics $responseQuality = $response->calculateQualityScore(); $isHighQuality = $response->isHighQuality(); // System information $systemFingerprint = $response->system_fingerprint; // Convert to array for storage $responseArray = $response->toArray(); // Embeddings Response Handling $embeddingResponse = $embeddingRequest->post(); $embeddings = $embeddingResponse->getEmbeddings(); $firstVector = $embeddingResponse->getFirstEmbedding(); $dimensions = $embeddingResponse->getDimensions(); $embeddingCount = $embeddingResponse->getEmbeddingCount(); $tokenUsage = $embeddingResponse->getTotalTokens();
Testing
The package provides testing utilities for mocking Mistral responses:
use LLMSpeak\Mistral\MistralCompletionsRequest; use LLMSpeak\Mistral\MistralCompletionsResponse; use LLMSpeak\Mistral\MistralEmbeddingsResponse; // Create a mock chat completion response $mockResponse = new MistralCompletionsResponse( id: 'chatcmpl-test123', object: 'chat.completion', created: time(), model: 'mistral-large-latest', choices: [ [ 'index' => 0, 'message' => [ 'role' => 'assistant', 'content' => 'Mock response content' ], 'finish_reason' => 'stop' ] ], usage: [ 'prompt_tokens' => 15, 'completion_tokens' => 20, 'total_tokens' => 35 ] ); // Test your application logic $this->assertEquals('Mock response content', $mockResponse->getTextContent()); $this->assertEquals(35, $mockResponse->getTotalTokens()); $this->assertTrue($mockResponse->completedNaturally()); // Create a mock embeddings response $mockEmbeddingResponse = new MistralEmbeddingsResponse( id: 'emb-test123', object: 'list', data: [ [ 'object' => 'embedding', 'embedding' => array_fill(0, 1024, 0.1), 'index' => 0 ] ], model: 'mistral-embed', usage: [ 'prompt_tokens' => 5, 'total_tokens' => 5 ], status_code: 200, headers: [] ); // Test embedding functionality $this->assertEquals(1024, $mockEmbeddingResponse->getDimensions()); $this->assertEquals(1, $mockEmbeddingResponse->getEmbeddingCount());
Credits
- Project Saturn Studios
- Mistral AI for providing advanced language models
License
The MIT License (MIT). Please see License File for more information.
Part of the LLMSpeak Ecosystem - Built with ❤️ by Project Saturn Studios