LarAI Kit supports multiple vector store backends. Switch between them via .env — no code changes.
| Store | Best for | Requires |
|---|---|---|
| Pinecone (default) | Most users, any database, managed service | Pinecone account (free tier available) |
| pgvector | Self-hosted, no external services | PostgreSQL + pgvector extension |
| none | Chat-only mode, no RAG | Nothing |
Works with MySQL or PostgreSQL. Vectors stored in Pinecone's cloud.
1536, Metric cosine.env:LARAI_VECTOR_STORE=pinecone
PINECONE_API_KEY=pcsk_your-key
PINECONE_INDEX_HOST=https://your-index-abc123.svc.pinecone.io
upsertMany()$eq filters for multi-tenant isolationHttp facade100K vectors, 1 index — enough for development and small production apps.
Self-hosted vector search using PostgreSQL's pgvector extension.
DB_CONNECTION=pgsql
LARAI_VECTOR_STORE=pgvector
Scope parameters translate to WHERE source_meta->key = value JSON queries.
LARAI_VECTOR_STORE=none
Chat still works but without document context. The NullVectorStore silently no-ops all operations.
Both Pinecone and pgvector support scoped queries to prevent data leaks between tenants:
// Ingest with scope
$ingestion->ingestText($content, scope: ['chatbot_id' => 42]);
// Retrieve with same scope — only returns that tenant's documents
$retrieval->retrieve($query, scope: ['chatbot_id' => 42]);
// ChatService with scope
$chat->sendMessage($message, scope: ['chatbot_id' => 42]);
Without scope, queries are global. Always pass scope in multi-tenant applications.
Implement the VectorStore contract:
use LarAIgent\AiKit\Contracts\VectorStore;
use Illuminate\Support\Collection;
class WeaviateVectorStore implements VectorStore
{
public function upsert(int $chunkId, array $embedding, array $metadata = []): void { ... }
public function upsertMany(array $items): void { ... }
public function search(array $embedding, int $limit = 5, float $threshold = 0.4, array $scope = []): Collection { ... }
public function delete(array $chunkIds): void { ... }
}
Bind in a service provider:
$this->app->singleton(VectorStore::class, WeaviateVectorStore::class);
Both upsertMany() and embedMany() support batched operations:
// Embedding: batch all texts in one API call
$embedder->embedMany(['text 1', 'text 2', 'text 3']);
// Vector store: batch upsert (Pinecone does 100/request)
$store->upsertMany([
['chunk_id' => 1, 'embedding' => [...], 'metadata' => [...]],
['chunk_id' => 2, 'embedding' => [...], 'metadata' => [...]],
]);
The ingestion pipeline uses both automatically — you don't need to call these directly.
How can I help you explore Laravel packages today?