Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/components/store.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ You can find more advanced usage in combination with an Agent using the store fo
* `Similarity Search with Symfony Cache (RAG)`_
* `Similarity Search with Typesense (RAG)`_
* `Similarity Search with Weaviate (RAG)`_
* `Similarity Search with Supabase (RAG)`_

.. note::

Expand All @@ -70,6 +71,7 @@ Supported Stores
* `Pinecone`_ (requires `probots-io/pinecone-php` as additional dependency)
* `Postgres`_ (requires `ext-pdo`)
* `Qdrant`_
* `Supabase`_ (requires manual database setup)
* `SurrealDB`_
* `Symfony Cache`_ (requires `symfony/cache` as additional dependency)
* `Typesense`_
Expand Down Expand Up @@ -137,6 +139,7 @@ This leads to a store implementing two methods::
.. _`Similarity Search with Qdrant (RAG)`: https://github.com/symfony/ai/blob/main/examples/rag/qdrant.php
.. _`Similarity Search with SurrealDB (RAG)`: https://github.com/symfony/ai/blob/main/examples/rag/surrealdb.php
.. _`Similarity Search with Typesense (RAG)`: https://github.com/symfony/ai/blob/main/examples/rag/typesense.php
.. _`Similarity Search with Supabase (RAG)`: https://github.com/symfony/ai/blob/main/examples/rag/supabase.php
.. _`Similarity Search with Weaviate (RAG)`: https://github.com/symfony/ai/blob/main/examples/rag/weaviate.php
.. _`Azure AI Search`: https://azure.microsoft.com/products/ai-services/ai-search
.. _`Chroma`: https://www.trychroma.com/
Expand All @@ -154,3 +157,4 @@ This leads to a store implementing two methods::
.. _`Typesense`: https://typesense.org/
.. _`Symfony Cache`: https://symfony.com/doc/current/components/cache.html
.. _`Weaviate`: https://weaviate.io/
.. _`Supabase`: https://https://supabase.com/
226 changes: 226 additions & 0 deletions docs/components/store/supabase.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
Supabase Bridge
===============

The Supabase bridge provides vector storage capabilities using `pgvector`_ extension through the REST API.

.. note::

Unlike the Postgres Store, the Supabase Store requires manual setup of the database schema because Supabase doesn't
allow arbitrary SQL execution via REST API.

Requirements
~~~~~~~~~~~~

* Enable `pgvector extension`_ in the relevant schema of your Supabase project for using `vector`_ column types.
* Add columns for embedding (type `vector`) and metadata (type `jsonb`) to your table
* Pre-configured RPC `function`_ for similarity search

See section below for detailed SQL commands.

Database Setup
--------------

Execute the following SQL commands in your Supabase SQL Editor:

Enable ``pgvector`` extension
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: sql

CREATE EXTENSION IF NOT EXISTS vector;

Create the `documents` table
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: sql

CREATE TABLE IF NOT EXISTS documents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
embedding vector(768) NOT NULL,
metadata JSONB
);

Create the similarity search function
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: sql

CREATE OR REPLACE FUNCTION match_documents(
query_embedding vector(768),
match_count int DEFAULT 10,
match_threshold float DEFAULT 0.0
)
RETURNS TABLE (
id UUID,
embedding vector,
metadata JSONB,
score float
)
LANGUAGE sql
AS $$
SELECT
documents.id,
documents.embedding,
documents.metadata,
1- (documents.embedding <=> query_embedding) AS score
FROM documents
WHERE 1- (documents.embedding <=> query_embedding) >= match_threshold
ORDER BY documents.embedding <=> query_embedding ASC
LIMIT match_count;
$$;

Create an index for better performance
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: sql

CREATE INDEX IF NOT EXISTS documents_embedding_idx
ON documents USING ivfflat (embedding vector_cosine_ops);

Configuration
-------------

Basic Configuration
~~~~~~~~~~~~~~~~~~~

.. code-block:: php

use Symfony\AI\Store\Bridge\Supabase\Store;
use Symfony\Component\HttpClient\HttpClient;

$store = new Store(
HttpClient::create(),
'https://your-project.supabase.co',
'your-anon-key',
'documents', // table name
'embedding', // vector field name
768, // vector dimension (depending on your embedding model)
'match_documents' // function name
);

Bundle Configuration
~~~~~~~~~~~~~~~~~~~~

.. code-block:: yaml

# config/packages/ai.yaml
ai:
store:
supabase:
my_supabase_store:
url: 'https://your-project.supabase.co'
api_key: '%env(SUPABASE_API_KEY)%'
table: 'documents'
vector_field: 'embedding'
vector_dimension: 768
function_name: 'match_documents'

Environment Variables
~~~~~~~~~~~~~~~~~~~~~

.. code-block:: bash

# .env.local
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_API_KEY=your-supabase-anon-key

Usage
-----

Adding Documents
~~~~~~~~~~~~~~~~

.. code-block:: php

use Symfony\AI\Platform\Vector\Vector;
use Symfony\AI\Store\Document\Metadata;
use Symfony\AI\Store\Document\VectorDocument;
use Symfony\Component\Uid\Uuid;

$document = new VectorDocument(
Uuid::v4(),
new Vector([0.1, 0.2, 0.3, /* ... 768 dimensions */]),
new Metadata(['title' => 'My Document', 'category' => 'example'])
);

$store->add($document);

Querying Documents
~~~~~~~~~~~~~~~~~~

.. code-block:: php

$queryVector = new Vector([0.1, 0.2, 0.3, /* ... 768 dimensions */]);

$results = $store->query($queryVector, [
'max_items' => 10,
'min_score' => 0.7
]);

foreach ($results as $document) {
echo "ID: " . $document->id . "\n";
echo "Score: " . $document->score . "\n";
echo "Metadata: " . json_encode($document->metadata->getArrayCopy()) . "\n";
}

Customization
-------------

You can customize the Supabase setup for different requirements:

Table Name
~~~~~~~~~~

Change ``documents`` to your preferred table name in both the SQL setup and configuration.

Vector Field Name
~~~~~~~~~~~~~~~~~

Change ``embedding`` to your preferred field name in both the SQL setup and configuration.

Vector Dimension
~~~~~~~~~~~~~~~~

Change ``768`` to match your embedding model's dimensions in both the SQL setup and configuration.

Distance Metric
~~~~~~~~~~~~~~~

* Cosine: ``<=>`` (default, recommended for most embeddings)
* Euclidean: ``<->``
* Inner Product: ``<#>``

Index Type
~~~~~~~~~~

* ``ivfflat``: Good balance of speed and accuracy
* ``hnsw``: Better for high-dimensional vectors (requires PostgreSQL 14+)

Limitations
-----------

* Manual schema setup required (no automatic table creation)
* Limited to Supabase's REST API capabilities
* Requires pre-configured RPC functions for complex queries
* Vector dimension must be consistent across all documents

Performance Considerations
--------------------------

* Use appropriate index types based on your vector dimensions
* Consider using ``hnsw`` indexes for high-dimensional vectors
* Batch document insertions when possible (up to 200 documents per request)
* Monitor your Supabase usage limits and quotas

Security Considerations
-----------------------

* Use row-level security (RLS) policies if needed
* Consider using service role keys for server-side operations
* Validate vector dimensions in your application code
* Implement proper error handling for API failures

.. _`pgvector`: https://github.com/pgvector/pgvector
.. _`pgvector extension`: https://supabase.com/docs/guides/database/extensions/pgvector
.. _`vector`: https://supabase.com/docs/guides/ai/vector-columns
.. _`function`: https://supabase.com/docs/guides/database/functions
8 changes: 8 additions & 0 deletions examples/.env
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,11 @@ SCALEWAY_SECRET_KEY=

# For using DeepSeek
DEEPSEEK_API_KEY=

# Supabase (store)
SUPABASE_URL=
SUPABASE_API_KEY=
SUPABASE_TABLE=documents
SUPABASE_VECTOR_FIELD=embedding
SUPABASE_VECTOR_DIMENSION=768 # when using Ollama with nomic-embed-text
SUPABASE_MATCH_FUNCTION=match_documents
69 changes: 69 additions & 0 deletions examples/rag/supabase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

use Symfony\AI\Agent\Agent;
use Symfony\AI\Agent\Toolbox\AgentProcessor;
use Symfony\AI\Agent\Toolbox\Tool\SimilaritySearch;
use Symfony\AI\Agent\Toolbox\Toolbox;
use Symfony\AI\Fixtures\Movies;
use Symfony\AI\Platform\Bridge\Ollama\PlatformFactory;
use Symfony\AI\Platform\Message\Message;
use Symfony\AI\Platform\Message\MessageBag;
use Symfony\AI\Store\Bridge\Supabase\Store;
use Symfony\AI\Store\Document\Loader\InMemoryLoader;
use Symfony\AI\Store\Document\Metadata;
use Symfony\AI\Store\Document\TextDocument;
use Symfony\AI\Store\Document\Vectorizer;
use Symfony\AI\Store\Indexer;
use Symfony\Component\Uid\Uuid;

require_once dirname(__DIR__).'/bootstrap.php';

$store = new Store(
httpClient: http_client(),
url: env('SUPABASE_URL'),
apiKey: env('SUPABASE_API_KEY'),
table: env('SUPABASE_TABLE'),
vectorFieldName: env('SUPABASE_VECTOR_FIELD'),
vectorDimension: (int) env('SUPABASE_VECTOR_DIMENSION'),
functionName: env('SUPABASE_MATCH_FUNCTION'),
);

$documents = [];

foreach (Movies::all() as $movie) {
$documents[] = new TextDocument(
id: Uuid::v4(),
content: 'Title: '.$movie['title'].\PHP_EOL.'Director: '.$movie['director'].\PHP_EOL.'Description: '.$movie['description'],
metadata: new Metadata($movie),
);
}

$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), http_client());

$vectorizer = new Vectorizer($platform, env('OLLAMA_EMBEDDINGS'));
$loader = new InMemoryLoader($documents);
$indexer = new Indexer($loader, $vectorizer, $store, logger: logger());
$indexer->index();

$similaritySearch = new SimilaritySearch($vectorizer, $store);
$toolbox = new Toolbox([$similaritySearch], logger: logger());
$processor = new AgentProcessor($toolbox);
$agent = new Agent($platform, env('OLLAMA_LLM'), [$processor], [$processor]);

$messages = new MessageBag(
Message::forSystem('Please answer all user questions only using SimilaritySearch function.'),
Message::ofUser('Which movie fits the theme of technology?')
);

$result = $agent->call($messages);

echo $result->getContent().\PHP_EOL;
18 changes: 18 additions & 0 deletions src/ai-bundle/config/options.php
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,24 @@
->end()
->end()
->end()
->arrayNode('supabase')
->useAttributeAsKey('name')
->arrayPrototype()
->children()
->stringNode('http_client')
->cannotBeEmpty()
->defaultValue('http_client')
->info('Service ID of the HTTP client to use')
->end()
->stringNode('url')->isRequired()->cannotBeEmpty()->end()
->stringNode('api_key')->isRequired()->cannotBeEmpty()->end()
->stringNode('table')->end()
->stringNode('vector_field')->end()
->integerNode('vector_dimension')->end()
->stringNode('function_name')->end()
->end()
->end()
->end()
->arrayNode('typesense')
->useAttributeAsKey('name')
->arrayPrototype()
Expand Down
Loading