rembrembdocs

LangChain


LangChain is a popular framework for working with AI, Vectors, and embeddings. LangChain supports using Supabase as a vector store, using the pgvector extension.

Initializing your database#

Prepare you database with the relevant tables:

  1. Go to the SQL Editor page in the Dashboard.
  2. Click LangChain in the Quick start section.
  3. Click Run.

Usage#

You can now search your documents using any Node.js application. This is intended to be run on a secure server route.

1import { SupabaseVectorStore } from '@langchain/community/vectorstores/supabase'2import { OpenAIEmbeddings } from '@langchain/openai'3import { createClient } from '@supabase/supabase-js'45const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY6if (!supabaseKey) throw new Error(`Expected SUPABASE_SERVICE_ROLE_KEY`)78const url = process.env.SUPABASE_URL9if (!url) throw new Error(`Expected env var SUPABASE_URL`)1011export const run = async () => {12  const client = createClient(url, supabaseKey)1314  const vectorStore = await SupabaseVectorStore.fromTexts(15    ['Hello world', 'Bye bye', "What's this?"],16    [{ id: 2 }, { id: 1 }, { id: 3 }],17    new OpenAIEmbeddings(),18    {19      client,20      tableName: 'documents',21      queryName: 'match_documents',22    }23  )2425  const resultOne = await vectorStore.similaritySearch('Hello world', 1)2627  console.log(resultOne)28}

Simple metadata filtering#

Given the above match_documents Postgres function, you can also pass a filter parameter to only return documents with a specific metadata field value. This filter parameter is a JSON object, and the match_documents function will use the Postgres JSONB Containment operator @> to filter documents by the metadata field values you specify. See details on the Postgres JSONB Containment operator for more information.

1import { SupabaseVectorStore } from '@langchain/community/vectorstores/supabase'2import { OpenAIEmbeddings } from '@langchain/openai'3import { createClient } from '@supabase/supabase-js'45// First, follow set-up instructions above67const privateKey = process.env.SUPABASE_SERVICE_ROLE_KEY8if (!privateKey) throw new Error(`Expected env var SUPABASE_SERVICE_ROLE_KEY`)910const url = process.env.SUPABASE_URL11if (!url) throw new Error(`Expected env var SUPABASE_URL`)1213export const run = async () => {14  const client = createClient(url, privateKey)1516  const vectorStore = await SupabaseVectorStore.fromTexts(17    ['Hello world', 'Hello world', 'Hello world'],18    [{ user_id: 2 }, { user_id: 1 }, { user_id: 3 }],19    new OpenAIEmbeddings(),20    {21      client,22      tableName: 'documents',23      queryName: 'match_documents',24    }25  )2627  const result = await vectorStore.similaritySearch('Hello world', 1, {28    user_id: 3,29  })3031  console.log(result)32}

Advanced metadata filtering#

You can also use query builder-style filtering (similar to how the Supabase JavaScript library works) instead of passing an object. Note that since the filter properties will be in the metadata column, you need to use arrow operators (-> for integer or ->> for text) as defined in PostgREST API documentation and specify the data type of the property (e.g. the column should look something like metadata->some_int_value::int).

1import { SupabaseFilterRPCCall, SupabaseVectorStore } from '@langchain/community/vectorstores/supabase'2import { OpenAIEmbeddings } from '@langchain/openai'3import { createClient } from '@supabase/supabase-js'45// First, follow set-up instructions above67const privateKey = process.env.SUPABASE_SERVICE_ROLE_KEY8if (!privateKey) throw new Error(`Expected env var SUPABASE_SERVICE_ROLE_KEY`)910const url = process.env.SUPABASE_URL11if (!url) throw new Error(`Expected env var SUPABASE_URL`)1213export const run = async () => {14  const client = createClient(url, privateKey)1516  const embeddings = new OpenAIEmbeddings()1718  const store = new SupabaseVectorStore(embeddings, {19    client,20    tableName: 'documents',21  })2223  const docs = [24    {25      pageContent:26        'This is a long text, but it actually means something because vector database does not understand Lorem Ipsum. So I would need to expand upon the notion of quantum fluff, a theoretical concept where subatomic particles coalesce to form transient multidimensional spaces. Yet, this abstraction holds no real-world application or comprehensible meaning, reflecting a cosmic puzzle.',27      metadata: { b: 1, c: 10, stuff: 'right' },28    },29    {30      pageContent:31        'This is a long text, but it actually means something because vector database does not understand Lorem Ipsum. So I would need to proceed by discussing the echo of virtual tweets in the binary corridors of the digital universe. Each tweet, like a pixelated canary, hums in an unseen frequency, a fascinatingly perplexing phenomenon that, while conjuring vivid imagery, lacks any concrete implication or real-world relevance, portraying a paradox of multidimensional spaces in the age of cyber folklore.',32      metadata: { b: 2, c: 9, stuff: 'right' },33    },34    { pageContent: 'hello', metadata: { b: 1, c: 9, stuff: 'right' } },35    { pageContent: 'hello', metadata: { b: 1, c: 9, stuff: 'wrong' } },36    { pageContent: 'hi', metadata: { b: 2, c: 8, stuff: 'right' } },37    { pageContent: 'bye', metadata: { b: 3, c: 7, stuff: 'right' } },38    { pageContent: "what's this", metadata: { b: 4, c: 6, stuff: 'right' } },39  ]4041  await store.addDocuments(docs)4243  const funcFilterA: SupabaseFilterRPCCall = (rpc) =>44    rpc45      .filter('metadata->b::int', 'lt', 3)46      .filter('metadata->c::int', 'gt', 7)47      .textSearch('content', `'multidimensional' & 'spaces'`, {48        config: 'english',49      })5051  const resultA = await store.similaritySearch('quantum', 4, funcFilterA)5253  const funcFilterB: SupabaseFilterRPCCall = (rpc) =>54    rpc55      .filter('metadata->b::int', 'lt', 3)56      .filter('metadata->c::int', 'gt', 7)57      .filter('metadata->>stuff', 'eq', 'right')5859  const resultB = await store.similaritySearch('hello', 2, funcFilterB)6061  console.log(resultA, resultB)62}

Hybrid search#

LangChain supports the concept of a hybrid search, which combines Similarity Search with Full Text Search. Read the official docs to get started: Supabase Hybrid Search.

You can install the LangChain Hybrid Search function though our database.dev package manager.

Resources#