symfony/ai-azure-search-store
Azure AI Search vector store integration for Symfony AI Store. Index and query embeddings using Azure’s vector search capabilities, enabling semantic retrieval for RAG and AI apps. Links to official docs plus Symfony AI contribution and issue resources.
composer require symfony/ai-azure-search-store
// config/services.php
'azure_search' => [
'endpoint' => env('AZURE_SEARCH_ENDPOINT'),
'key' => env('AZURE_SEARCH_KEY'),
'index_name' => env('AZURE_SEARCH_INDEX', 'vectors'),
],
// app/Providers/AppServiceProvider.php
use Symfony\AI\AzureSearchStore\AzureSearchStore;
use Symfony\Contracts\HttpClient\HttpClientInterface;
public function register()
{
$this->app->singleton(\Symfony\AI\Store\StoreInterface::class, function ($app) {
return new AzureSearchStore(
$app->make(HttpClientInterface::class),
config('services.azure_search.endpoint'),
config('services.azure_search.key'),
config('services.azure_search.index_name')
);
});
}
// Store embeddings
$store->upsert('doc1', [1.2, 3.4, ...], ['metadata' => ['category' => 'tech']]);
// Query similar vectors
$results = $store->findNearest('query_embedding', 3, ['$filter' => 'metadata/category eq \'tech\'']);
upsert, findNearest, remove).// Generate embeddings (e.g., with OpenAI)
$embeddings = $embeddingService->generate(['text' => $document]);
// Store with metadata
$store->upsert(
'doc_id_' . uniqid(),
$embeddings,
['metadata' => ['source' => 'user_guide', 'language' => 'en']]
);
// Retrieve for LLM context
$nearest = $store->findNearest($queryEmbedding, 5, [
'$filter' => 'metadata/language eq \'en\' AND metadata/source eq \'user_guide\''
]);
// Combine vector similarity with metadata filters
$results = $store->findNearest($queryEmbedding, 10, [
'$filter' => 'metadata/category eq \'electronics\' AND price lt 1000',
'$select' => 'id,metadata/name,metadata/price' // Project only needed fields
]);
// Batch insert (Azure Search supports bulk API)
$batch = [];
foreach ($documents as $doc) {
$batch[] = [
'id' => $doc['id'],
'embedding' => $doc['embedding'],
'metadata' => $doc['metadata']
];
}
$store->bulkUpsert($batch);
// Delete by filter
$store->remove(['$filter' => 'metadata/createdDate lt datetime\'2023-01-01T00:00:00\'']);
$cacheKey = "azure_search:{$queryHash}";
$results = Cache::remember($cacheKey, now()->addHours(1), function () use ($store, $queryEmbedding) {
return $store->findNearest($queryEmbedding, 3);
});
language = 'en').try {
$results = $store->findNearest(...);
} catch (AzureSearchException $e) {
if ($e->getCode() === 429) {
sleep(2); // Retry after delay
retry();
}
throw $e;
}
$httpClient = \Symfony\Contracts\HttpClient\HttpClientInterface::create([
'base_uri' => config('services.azure_search.endpoint'),
'auth_bearer' => config('services.azure_search.key'),
'timeout' => 30,
'max_duration' => 60,
]);
$store = new AzureSearchStore($httpClient, ...);
$this->app->bind(\Symfony\AI\Store\StoreInterface::class, function ($app) {
return new AzureSearchStore(
$app->makeWith(HttpClientInterface::class, [
'base_uri' => config('services.azure_search.endpoint'),
'auth_bearer' => config('services.azure_search.key'),
]),
config('services.azure_search.index_name')
);
});
use Symfony\AI\AzureSearchStore\AzureSearchStore;
class SyncEmbeddingsCommand extends Command
{
protected $signature = 'ai:sync-embeddings';
protected $description = 'Sync embeddings to Azure Search';
public function handle()
{
$store = app(AzureSearchStore::class);
foreach (Model::all() as $model) {
$store->upsert($model->id, $model->embedding, $model->metadata);
}
}
}
saved):
Model::saved(function ($model) {
$store = app(AzureSearchStore::class);
$store->upsert($model->id, $model->embedding, $model->metadata);
});
Index Schema Mismatches:
400 Bad Request errors.vector field with the correct dimensions (e.g., 1536 for OpenAI embeddings). Use the Azure Portal to check or update the schema.Filter Syntax Errors:
$filter syntax (e.g., metadata/category = 'tech' instead of metadata/category eq 'tech') returns empty results or errors.Rate Limiting:
ScopedHttpClient:
$httpClient = HttpClient::create([
'on_options' => function (Options $options) {
$options->setRetryOptions([
'max_retries' => 3,
'delay_factor' => 2,
'delay_multiplier' => 100,
]);
},
]);
Metadata Field Limits:
Vector Field Precision:
float for vectors, which may lose precision for high-dimensional embeddings (e.g., 1536D).Laravel Service Container Conflicts:
HttpClientInterface may conflict with Laravel’s HttpClient.How can I help you explore Laravel packages today?