symfony/ai-sqlite-store
SQLite vector store integration for Symfony AI Store. Supports full-text search via SQLite FTS5 and computes vector similarity distances in PHP. Compatible with sqlite-vec (vec0) extension for embedding storage and retrieval.
Install Dependencies:
composer require symfony/ai symfony/ai-sqlite-store
pecl install sqlite-vec # Requires PHP 8.1+ and SQLite 3.35+
Add to php.ini:
extension=sqlite-vec.so
Configure Database:
Add an SQLite connection to config/database.php:
'sqlite' => [
'driver' => 'sqlite',
'database' => database_path('ai_store.sqlite'),
'prefix' => '',
],
Register Store Service:
In AppServiceProvider:
use Symfony\AI\Store\SQLiteStore;
use Doctrine\DBAL\Connection;
public function register()
{
$this->app->singleton('ai.store', function ($app) {
$connection = $app->make(Connection::class);
return new SQLiteStore(
$connection->getWrappedConnection()->getNativeConnection()
);
});
}
First Use Case: Inject the store and perform a vector search:
use Symfony\AI\Store\StoreInterface;
public function __construct(private StoreInterface $store) {}
public function findSimilarDocuments(array $embedding)
{
return $this->store->findNearest($embedding, limit: 5);
}
sqlite-vec extension docs.vec0 and FTS5 tables via:
SELECT name FROM sqlite_master WHERE type='table';
// Store embeddings with metadata
$this->store->save(
id: 'doc_123',
embedding: $vectorArray,
data: ['title' => 'Laravel AI', 'content' => '...']
);
// Retrieve nearest neighbors
$results = $this->store->findNearest(
$queryEmbedding,
limit: 3,
distance: 'cosine' // or 'euclidean'
);
// Hybrid search (FTS5 + vectors via RRF)
$results = $this->store->findNearest(
$queryEmbedding,
query: 'laravel ai', // FTS5 query
limit: 5
);
Service Container: Bind the store to Laravel’s container with a facade for convenience:
// app/Providers/AppServiceProvider.php
use Illuminate\Support\Facades\AI;
AI::extend('sqlite', function ($app) {
return $app->make('ai.store');
});
Usage:
$results = AI::store('sqlite')->findNearest($embedding);
Artisan Commands: Create a command to manage the store:
use Illuminate\Console\Command;
use Symfony\AI\Store\StoreInterface;
class AiStoreCommand extends Command
{
protected $signature = 'ai:store {action : clear|optimize}';
protected $description = 'Manage the SQLite AI store';
public function handle(StoreInterface $store)
{
if ($this->argument('action') === 'clear') {
$store->clear();
$this->info('Store cleared!');
}
}
}
Leverage SQLite’s FTS5 for keyword search combined with vectors:
// Store documents with FTS5 metadata
$this->store->save(
id: 'doc_456',
embedding: $vector,
data: ['title' => 'Hybrid Search', 'content' => '...']
);
// Query with both vector and text
$results = $this->store->findNearest(
$queryVector,
query: 'hybrid search laravel',
limit: 4
);
Note: RRF (Reciprocal Rank Fusion) is handled automatically by the store.
// Bulk insert
$batch = [];
foreach ($documents as $doc) {
$batch[] = [
'id' => $doc['id'],
'embedding' => $doc['embedding'],
'data' => $doc['metadata']
];
}
$this->store->saveMany($batch);
// Bulk delete
$this->store->deleteMany(['doc_1', 'doc_2', 'doc_3']);
Use Scout for indexing and this store for vector search:
// In your Scout searchable model
public function toSearchableArray()
{
return [
'title' => $this->title,
'content' => $this->content,
// Vector embedding stored separately
];
}
// Custom search method
public function semanticSearch($query, $limit = 5)
{
$scoutResults = $this->search($query)->get();
$vectorResults = AI::store('sqlite')->findNearest(
$this->generateEmbedding($query),
limit: $limit
);
return $this->mergeResults($scoutResults, $vectorResults);
}
Cache frequent queries to reduce SQLite load:
$cacheKey = 'ai_search_' . md5($query);
$results = Cache::remember($cacheKey, now()->addMinutes(10), function () use ($query) {
return AI::store('sqlite')->findNearest($this->generateEmbedding($query));
});
Offload heavy vector operations to queues:
// Dispatch a job
SearchVectorsJob::dispatch($queryEmbedding, $userId);
// Job class
public function handle()
{
$results = AI::store('sqlite')->findNearest($this->embedding);
// Process results (e.g., send notifications)
}
Extension Dependency:
sqlite-vec is not bundled with PHP and may fail to install on shared hosting or CI/CD pipelines.docker-php-ext-install sqlite-vec
if (!extension_loaded('sqlite-vec')) {
throw new \RuntimeException('sqlite-vec extension required for vector search');
}
Performance Degradation:
sqlite-vec falls back to PHP-side calculations, which are O(n) and slow for >10K vectors.'ai' => [
'sqlite_store' => [
'max_vectors_for_php_calc' => 5000, // Disable PHP-side search beyond this
],
],
Concurrency Conflicts:
Hybrid Search Limitations:
if (empty($query) && empty($embedding)) {
throw new \InvalidArgumentException('Provide either a query, embedding, or both');
}
Schema Migrations:
DB::statement('ALTER TABLE vec0 ADD COLUMN custom_data JSON');
Query Inspection: Enable SQLite logging to debug queries:
DB::connection('sqlite')->enableQueryLog();
$results = $this->store->findNearest($embedding);
dd(DB::connection('sqlite')->getQueryLog());
Vector Distance Calculation: Verify distance metrics (e.g., cosine vs. Euclidean):
$config = $this->store->getConfig();
$config['distance'] = 'cosine'; // or 'euclidean'
$this->store->setConfig($config);
FTS5 Tokenizer: Customize FTS5 tokenization for better keyword search:
-- Create a custom tokenizer
How can I help you explore Laravel packages today?