symfony/ai-store
Experimental Symfony AI Store component: a low-level abstraction to store and retrieve documents in vector stores. Use bridge packages to connect to providers like pgvector, Pinecone, Redis, Elasticsearch, Qdrant, ChromaDB, and more.
composer require symfony/ai-store
pgvector):
composer require symfony/ai-postgres-store
config/services.php:
'ai_store' => [
'default' => env('AI_STORE_DRIVER', 'postgres'),
'stores' => [
'postgres' => [
'dsn' => env('DATABASE_URL'),
'table' => 'vector_documents',
'embedding_dimension' => 384, // Match your model's output
],
],
],
use Symfony\Component\AI\Store\StoreFactory;
use Symfony\Component\AI\Store\Bridge\Postgres\PostgresStore;
public function register()
{
$this->app->singleton(StoreFactory::class, function ($app) {
return new StoreFactory(
$app['config']['services.ai_store.stores']
);
});
}
use Symfony\Component\AI\Store\StoreFactory;
use Symfony\Component\AI\Store\TextDocument;
$storeFactory = app(StoreFactory::class);
$store = $storeFactory->getStore('postgres');
$documents = [
new TextDocument('id1', 'Laravel is a PHP framework...', ['source' => 'docs']),
new TextDocument('id2', 'Symfony AI provides vector stores...', ['source' => 'docs']),
];
$store->add($documents); // Batch add
use Symfony\Component\AI\Store\Query\VectorQuery;
$query = new VectorQuery(
vector: $embedding, // Pre-computed vector (e.g., from symfony/ai-platform)
limit: 3,
distance: 'cosine'
);
$results = $store->query($query);
foreach ($results as $result) {
echo $result->getText(); // Retrieve document text
}
symfony/ai-platform):
$vectorizer = app(Symfony\Component\AI\Vectorizer::class);
$embedding = $vectorizer->vectorize('Your query text');
$query = new VectorQuery($embedding, limit: 5);
$results = $store->query($query);
$context = implode("\n---\n", array_map(fn($r) => $r->getText(), $results));
// app/Providers/AIServiceProvider.php
public function register()
{
$this->app->bind(\Symfony\Component\AI\Store\StoreInterface::class, function ($app) {
return $app->make(StoreFactory::class)->getStore(config('ai_store.default'));
});
}
// app/Console/Commands/IndexDocuments.php
use Symfony\Component\AI\Store\Indexer\Indexer;
use Symfony\Component\AI\Store\Loader\JsonFileLoader;
protected function handle()
{
$loader = new JsonFileLoader('path/to/documents.json');
$indexer = new Indexer($this->store, $loader);
$indexer->index(); // Batch process documents
}
// Listen to query events (e.g., log queries)
use Symfony\Component\AI\Store\Event\PreQueryEvent;
public function boot()
{
event(new PreQueryEvent($query, $store));
}
use Symfony\Component\AI\Store\Transformer\TextSplitTransformer;
$transformer = new TextSplitTransformer(
chunkSize: 1000,
overlap: 200
);
$chunks = $transformer->transform($document);
// Dispatch a job for each document batch
IndexDocumentsJob::dispatch($documents)->onQueue('ai-indexing');
use Symfony\Component\AI\Store\Query\HybridQuery;
$query = new HybridQuery(
vector: $embedding,
text: 'Laravel framework',
limit: 3
);
$results = $store->query($query);
Vector Dimension Mismatch:
embedding_dimension in config matches your model’s output (e.g., 384 for sentence-transformers/all-MiniLM-L6-v2).Memory Leaks with Lazy Iterators:
$store->query() results) in long-lived objects.iterator_to_array() if you need to materialize results immediately.Bridge-Specific Quirks:
pgvector extension. Run:
CREATE EXTENSION vector;
symfony/ai-redis-store but may need Redis 7+ for vector search.Experimental Features:
StoreFactory and Provider abstraction (v0.8+) may change. Pin versions:
"symfony/ai-store": "^0.8.0"
$store = $storeFactory->getStore('postgres');
$store->setLogger($this->app->make(Psr\Log\LoggerInterface::class));
PreQueryEvent to log raw queries before execution:
event(new PreQueryEvent($query, $store));
NaN or infinite values in embeddings:
$vector = $query->getVector();
if (array_key_exists(0, array_filter($vector, fn($v) => !is_finite($v)))) {
throw new \RuntimeException('Invalid vector detected');
}
Batch Size Tuning:
100 documents per batch. Monitor memory usage and adjust.$indexer->setBatchSize(50); // For memory-constrained environments
Indexing Strategies:
ResetInterface to clear the store before bulk indexing:
if ($store instanceof \Symfony\Component\AI\Store\ResetInterface) {
$store->reset();
}
Query Optimization:
distance calculations for large datasets:
$query->setDistance('cosine'); // Faster than 'euclidean' for high-dimensional vectors
filter in VectorQuery to narrow results:
$query->setFilter(['source' => 'docs']);
Custom Bridges:
StoreInterface for unsupported databases (e.g., MongoDB Atlas):
class MongoDbStore implements StoreInterface
{
public function add(iterable $documents): void
{
// Custom MongoDB logic
}
// ...
}
StoreFactory:
$factory->addStore('mongodb', new MongoDbStore($client));
Custom Transformers:
TransformerInterface for domain-specific preprocessing:
class DomainSpecificTransformer implements TransformerInterface
{
public function transform(TextDocument $document): iterable
{
// Custom logic (e.g., extract entities before chunking)
}
}
Event Subscribers:
use Symfony\Component\AI\Store\Event\PreQueryEvent;
$subscriber = new class implements EventSubscriberInterface {
public function onPreQuery(PreQueryEvent $event)
{
$event->getQuery()->setLimit(min($event->getQuery()->getLimit(), 10));
}
};
symfony/ai-cache-store with Laravel’s cache:
How can I help you explore Laravel packages today?