MMR Search for Pinecone, Weaviate, Zep and Supabase

This commit is contained in:
vinodkiran
2023-12-22 12:08:48 +05:30
parent 579f66e57e
commit 56b043264a
5 changed files with 98 additions and 109 deletions
@@ -5,6 +5,7 @@ import { Embeddings } from 'langchain/embeddings/base'
import { Document } from 'langchain/document' import { Document } from 'langchain/document'
import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { addMMRInputParams, resolveVectorStoreOrRetriever } from '../VectorStoreUtils'
class Pinecone_VectorStores implements INode { class Pinecone_VectorStores implements INode {
label: string label: string
@@ -23,11 +24,11 @@ class Pinecone_VectorStores implements INode {
constructor() { constructor() {
this.label = 'Pinecone' this.label = 'Pinecone'
this.name = 'pinecone' this.name = 'pinecone'
this.version = 2.0 this.version = 3.0
this.type = 'Pinecone' this.type = 'Pinecone'
this.icon = 'pinecone.svg' this.icon = 'pinecone.svg'
this.category = 'Vector Stores' this.category = 'Vector Stores'
this.description = `Upsert embedded data and perform search upon query using Pinecone, a leading fully managed hosted vector database` this.description = `Upsert embedded data and perform similarity or mmr search using Pinecone, a leading fully managed hosted vector database`
this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever']
this.badge = 'NEW' this.badge = 'NEW'
this.credential = { this.credential = {
@@ -77,45 +78,9 @@ class Pinecone_VectorStores implements INode {
type: 'number', type: 'number',
additionalParams: true, additionalParams: true,
optional: true optional: true
},
{
label: 'Search Type',
name: 'searchType',
type: 'options',
default: 'similarity',
options: [
{
label: 'Similarity',
name: 'similarity'
},
{
label: 'Max Marginal Relevance',
name: 'mmr'
}
],
additionalParams: true,
optional: true
},
{
label: 'Fetch K (for MMR Search)',
name: 'fetchK',
description: 'Number of initial documents to fetch for MMR reranking. Default to 20. Used only when the search type is MMR',
placeholder: '20',
type: 'number',
additionalParams: true,
optional: true
},
{
label: 'Lambda (for MMR Search)',
name: 'lambda',
description:
'Number between 0 and 1 that determines the degree of diversity among the results, where 0 corresponds to maximum diversity and 1 to minimum diversity. Used only when the search type is MMR',
placeholder: '0.5',
type: 'number',
additionalParams: true,
optional: true
} }
] ]
addMMRInputParams(this.inputs)
this.outputs = [ this.outputs = [
{ {
label: 'Pinecone Retriever', label: 'Pinecone Retriever',
@@ -177,10 +142,6 @@ class Pinecone_VectorStores implements INode {
const pineconeMetadataFilter = nodeData.inputs?.pineconeMetadataFilter const pineconeMetadataFilter = nodeData.inputs?.pineconeMetadataFilter
const docs = nodeData.inputs?.document as Document[] const docs = nodeData.inputs?.document as Document[]
const embeddings = nodeData.inputs?.embeddings as Embeddings const embeddings = nodeData.inputs?.embeddings as Embeddings
const output = nodeData.outputs?.output as string
const searchType = nodeData.outputs?.searchType as string
const topK = nodeData.inputs?.topK as string
const k = topK ? parseFloat(topK) : 4
const credentialData = await getCredentialData(nodeData.credential ?? '', options) const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const pineconeApiKey = getCredentialParam('pineconeApiKey', credentialData, nodeData) const pineconeApiKey = getCredentialParam('pineconeApiKey', credentialData, nodeData)
@@ -213,31 +174,7 @@ class Pinecone_VectorStores implements INode {
const vectorStore = await PineconeStore.fromExistingIndex(embeddings, obj) const vectorStore = await PineconeStore.fromExistingIndex(embeddings, obj)
if (output === 'retriever') { return resolveVectorStoreOrRetriever(nodeData, vectorStore)
if ('mmr' === searchType) {
const fetchK = nodeData.inputs?.fetchK as string
const lambda = nodeData.inputs?.lambda as string
const f = fetchK ? parseInt(fetchK) : 20
const l = lambda ? parseFloat(lambda) : 0.5
const retriever = vectorStore.asRetriever({
searchType: 'mmr',
k: 5,
searchKwargs: {
fetchK: f,
lambda: l
}
})
return retriever
} else {
// "searchType" is "similarity"
const retriever = vectorStore.asRetriever(k)
return retriever
}
} else if (output === 'vectorStore') {
;(vectorStore as any).k = k
return vectorStore
}
return vectorStore
} }
} }
@@ -5,6 +5,7 @@ import { Embeddings } from 'langchain/embeddings/base'
import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { SupabaseLibArgs, SupabaseVectorStore } from 'langchain/vectorstores/supabase' import { SupabaseLibArgs, SupabaseVectorStore } from 'langchain/vectorstores/supabase'
import { addMMRInputParams, resolveVectorStoreOrRetriever } from '../VectorStoreUtils'
class Supabase_VectorStores implements INode { class Supabase_VectorStores implements INode {
label: string label: string
@@ -23,11 +24,11 @@ class Supabase_VectorStores implements INode {
constructor() { constructor() {
this.label = 'Supabase' this.label = 'Supabase'
this.name = 'supabase' this.name = 'supabase'
this.version = 1.0 this.version = 2.0
this.type = 'Supabase' this.type = 'Supabase'
this.icon = 'supabase.svg' this.icon = 'supabase.svg'
this.category = 'Vector Stores' this.category = 'Vector Stores'
this.description = 'Upsert embedded data and perform similarity search upon query using Supabase via pgvector extension' this.description = 'Upsert embedded data and perform similarity or mmr search upon query using Supabase via pgvector extension'
this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever']
this.badge = 'NEW' this.badge = 'NEW'
this.credential = { this.credential = {
@@ -81,6 +82,7 @@ class Supabase_VectorStores implements INode {
optional: true optional: true
} }
] ]
addMMRInputParams(this.inputs)
this.outputs = [ this.outputs = [
{ {
label: 'Supabase Retriever', label: 'Supabase Retriever',
@@ -135,9 +137,6 @@ class Supabase_VectorStores implements INode {
const queryName = nodeData.inputs?.queryName as string const queryName = nodeData.inputs?.queryName as string
const embeddings = nodeData.inputs?.embeddings as Embeddings const embeddings = nodeData.inputs?.embeddings as Embeddings
const supabaseMetadataFilter = nodeData.inputs?.supabaseMetadataFilter const supabaseMetadataFilter = nodeData.inputs?.supabaseMetadataFilter
const output = nodeData.outputs?.output as string
const topK = nodeData.inputs?.topK as string
const k = topK ? parseFloat(topK) : 4
const credentialData = await getCredentialData(nodeData.credential ?? '', options) const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const supabaseApiKey = getCredentialParam('supabaseApiKey', credentialData, nodeData) const supabaseApiKey = getCredentialParam('supabaseApiKey', credentialData, nodeData)
@@ -157,14 +156,7 @@ class Supabase_VectorStores implements INode {
const vectorStore = await SupabaseVectorStore.fromExistingIndex(embeddings, obj) const vectorStore = await SupabaseVectorStore.fromExistingIndex(embeddings, obj)
if (output === 'retriever') { return resolveVectorStoreOrRetriever(nodeData, vectorStore)
const retriever = vectorStore.asRetriever(k)
return retriever
} else if (output === 'vectorStore') {
;(vectorStore as any).k = k
return vectorStore
}
return vectorStore
} }
} }
@@ -0,0 +1,76 @@
import { INodeData } from '../../src'
export const resolveVectorStoreOrRetriever = (nodeData: INodeData, vectorStore: any) => {
const output = nodeData.outputs?.output as string
const searchType = nodeData.outputs?.searchType as string
const topK = nodeData.inputs?.topK as string
const k = topK ? parseFloat(topK) : 4
if (output === 'retriever') {
if ('mmr' === searchType) {
const fetchK = nodeData.inputs?.fetchK as string
const lambda = nodeData.inputs?.lambda as string
const f = fetchK ? parseInt(fetchK) : 20
const l = lambda ? parseFloat(lambda) : 0.5
const retriever = vectorStore.asRetriever({
searchType: 'mmr',
k: k,
searchKwargs: {
fetchK: f,
lambda: l
}
})
return retriever
} else {
// "searchType" is "similarity"
return vectorStore.asRetriever(k)
}
} else if (output === 'vectorStore') {
;(vectorStore as any).k = k
return vectorStore
}
}
export const addMMRInputParams = (inputs: any[]) => {
const mmrInputParams = [
{
label: 'Search Type',
name: 'searchType',
type: 'options',
default: 'similarity',
options: [
{
label: 'Similarity',
name: 'similarity'
},
{
label: 'Max Marginal Relevance',
name: 'mmr'
}
],
additionalParams: true,
optional: true
},
{
label: 'Fetch K (for MMR Search)',
name: 'fetchK',
description: 'Number of initial documents to fetch for MMR reranking. Default to 20. Used only when the search type is MMR',
placeholder: '20',
type: 'number',
additionalParams: true,
optional: true
},
{
label: 'Lambda (for MMR Search)',
name: 'lambda',
description:
'Number between 0 and 1 that determines the degree of diversity among the results, where 0 corresponds to maximum diversity and 1 to minimum diversity. Used only when the search type is MMR',
placeholder: '0.5',
type: 'number',
additionalParams: true,
optional: true
}
]
inputs.push(...mmrInputParams)
}
@@ -5,6 +5,7 @@ import { Document } from 'langchain/document'
import { Embeddings } from 'langchain/embeddings/base' import { Embeddings } from 'langchain/embeddings/base'
import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { addMMRInputParams, resolveVectorStoreOrRetriever } from '../VectorStoreUtils'
class Weaviate_VectorStores implements INode { class Weaviate_VectorStores implements INode {
label: string label: string
@@ -23,12 +24,12 @@ class Weaviate_VectorStores implements INode {
constructor() { constructor() {
this.label = 'Weaviate' this.label = 'Weaviate'
this.name = 'weaviate' this.name = 'weaviate'
this.version = 1.0 this.version = 2.0
this.type = 'Weaviate' this.type = 'Weaviate'
this.icon = 'weaviate.png' this.icon = 'weaviate.png'
this.category = 'Vector Stores' this.category = 'Vector Stores'
this.description = this.description =
'Upsert embedded data and perform similarity search upon query using Weaviate, a scalable open-source vector database' 'Upsert embedded data and perform similarity or mmr search using Weaviate, a scalable open-source vector database'
this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever']
this.badge = 'NEW' this.badge = 'NEW'
this.credential = { this.credential = {
@@ -107,6 +108,7 @@ class Weaviate_VectorStores implements INode {
optional: true optional: true
} }
] ]
addMMRInputParams(this.inputs)
this.outputs = [ this.outputs = [
{ {
label: 'Weaviate Retriever', label: 'Weaviate Retriever',
@@ -174,9 +176,6 @@ class Weaviate_VectorStores implements INode {
const weaviateTextKey = nodeData.inputs?.weaviateTextKey as string const weaviateTextKey = nodeData.inputs?.weaviateTextKey as string
const weaviateMetadataKeys = nodeData.inputs?.weaviateMetadataKeys as string const weaviateMetadataKeys = nodeData.inputs?.weaviateMetadataKeys as string
const embeddings = nodeData.inputs?.embeddings as Embeddings const embeddings = nodeData.inputs?.embeddings as Embeddings
const output = nodeData.outputs?.output as string
const topK = nodeData.inputs?.topK as string
const k = topK ? parseFloat(topK) : 4
const credentialData = await getCredentialData(nodeData.credential ?? '', options) const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const weaviateApiKey = getCredentialParam('weaviateApiKey', credentialData, nodeData) const weaviateApiKey = getCredentialParam('weaviateApiKey', credentialData, nodeData)
@@ -199,14 +198,7 @@ class Weaviate_VectorStores implements INode {
const vectorStore = await WeaviateStore.fromExistingIndex(embeddings, obj) const vectorStore = await WeaviateStore.fromExistingIndex(embeddings, obj)
if (output === 'retriever') { return resolveVectorStoreOrRetriever(nodeData, vectorStore)
const retriever = vectorStore.asRetriever(k)
return retriever
} else if (output === 'vectorStore') {
;(vectorStore as any).k = k
return vectorStore
}
return vectorStore
} }
} }
@@ -5,6 +5,7 @@ import { Embeddings } from 'langchain/embeddings/base'
import { Document } from 'langchain/document' import { Document } from 'langchain/document'
import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { addMMRInputParams, resolveVectorStoreOrRetriever } from '../VectorStoreUtils'
class Zep_VectorStores implements INode { class Zep_VectorStores implements INode {
label: string label: string
@@ -23,12 +24,12 @@ class Zep_VectorStores implements INode {
constructor() { constructor() {
this.label = 'Zep' this.label = 'Zep'
this.name = 'zep' this.name = 'zep'
this.version = 1.0 this.version = 2.0
this.type = 'Zep' this.type = 'Zep'
this.icon = 'zep.svg' this.icon = 'zep.svg'
this.category = 'Vector Stores' this.category = 'Vector Stores'
this.description = this.description =
'Upsert embedded data and perform similarity search upon query using Zep, a fast and scalable building block for LLM apps' 'Upsert embedded data and perform similarity or mmr search upon query using Zep, a fast and scalable building block for LLM apps'
this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever']
this.badge = 'NEW' this.badge = 'NEW'
this.credential = { this.credential = {
@@ -88,6 +89,7 @@ class Zep_VectorStores implements INode {
optional: true optional: true
} }
] ]
addMMRInputParams(this.inputs)
this.outputs = [ this.outputs = [
{ {
label: 'Zep Retriever', label: 'Zep Retriever',
@@ -144,9 +146,6 @@ class Zep_VectorStores implements INode {
const zepMetadataFilter = nodeData.inputs?.zepMetadataFilter const zepMetadataFilter = nodeData.inputs?.zepMetadataFilter
const dimension = nodeData.inputs?.dimension as number const dimension = nodeData.inputs?.dimension as number
const embeddings = nodeData.inputs?.embeddings as Embeddings const embeddings = nodeData.inputs?.embeddings as Embeddings
const output = nodeData.outputs?.output as string
const topK = nodeData.inputs?.topK as string
const k = topK ? parseFloat(topK) : 4
const credentialData = await getCredentialData(nodeData.credential ?? '', options) const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const apiKey = getCredentialParam('apiKey', credentialData, nodeData) const apiKey = getCredentialParam('apiKey', credentialData, nodeData)
@@ -165,14 +164,7 @@ class Zep_VectorStores implements INode {
const vectorStore = await ZepExistingVS.fromExistingIndex(embeddings, zepConfig) const vectorStore = await ZepExistingVS.fromExistingIndex(embeddings, zepConfig)
if (output === 'retriever') { return resolveVectorStoreOrRetriever(nodeData, vectorStore)
const retriever = vectorStore.asRetriever(k)
return retriever
} else if (output === 'vectorStore') {
;(vectorStore as any).k = k
return vectorStore
}
return vectorStore
} }
} }
@@ -210,7 +202,7 @@ class ZepExistingVS extends ZepVectorStore {
this.args = args this.args = args
} }
async initalizeCollection(args: IZepConfig & Partial<ZepFilter>) { async initializeCollection(args: IZepConfig & Partial<ZepFilter>) {
this.client = await ZepClient.init(args.apiUrl, args.apiKey) this.client = await ZepClient.init(args.apiUrl, args.apiKey)
try { try {
this.collection = await this.client.document.getCollection(args.collectionName) this.collection = await this.client.document.getCollection(args.collectionName)
@@ -259,7 +251,7 @@ class ZepExistingVS extends ZepVectorStore {
const newfilter = { const newfilter = {
where: { and: ANDFilters } where: { and: ANDFilters }
} }
await this.initalizeCollection(this.args!).catch((err) => { await this.initializeCollection(this.args!).catch((err) => {
console.error('Error initializing collection:', err) console.error('Error initializing collection:', err)
throw err throw err
}) })