diff --git a/packages/components/nodes/chains/VectaraChain/VectaraChain.ts b/packages/components/nodes/chains/VectaraChain/VectaraChain.ts index 3799d062..7d65c9cd 100644 --- a/packages/components/nodes/chains/VectaraChain/VectaraChain.ts +++ b/packages/components/nodes/chains/VectaraChain/VectaraChain.ts @@ -69,22 +69,23 @@ class VectaraChain_Chains implements INode { options: [ { label: 'vectara-summary-ext-v1.2.0 (gpt-3.5-turbo)', - name: 'vectara-summary-ext-v1.2.0' + name: 'vectara-summary-ext-v1.2.0', + description: 'base summarizer, available to all Vectara users' }, { label: 'vectara-experimental-summary-ext-2023-10-23-small (gpt-3.5-turbo)', name: 'vectara-experimental-summary-ext-2023-10-23-small', - description: 'In beta, available to both Growth and Scale Vectara users' + description: `In beta, available to both Growth and Scale Vectara users` }, { label: 'vectara-summary-ext-v1.3.0 (gpt-4.0)', name: 'vectara-summary-ext-v1.3.0', - description: 'Only available to paying Scale Vectara users' + description: 'Only available to Scale Vectara users' }, { label: 'vectara-experimental-summary-ext-2023-10-23-med (gpt-4.0)', name: 'vectara-experimental-summary-ext-2023-10-23-med', - description: 'In beta, only available to paying Scale Vectara users' + description: `In beta, only available to Scale Vectara users` } ], default: 'vectara-summary-ext-v1.2.0' @@ -228,7 +229,7 @@ class VectaraChain_Chains implements INode { async run(nodeData: INodeData, input: string): Promise { const vectorStore = nodeData.inputs?.vectaraStore as VectaraStore - const responseLang = (nodeData.inputs?.responseLang as string) ?? 'auto' + const responseLang = (nodeData.inputs?.responseLang as string) ?? 'eng' const summarizerPromptName = nodeData.inputs?.summarizerPromptName as string const maxSummarizedResultsStr = nodeData.inputs?.maxSummarizedResults as string const maxSummarizedResults = maxSummarizedResultsStr ? parseInt(maxSummarizedResultsStr, 10) : 7 @@ -247,17 +248,31 @@ class VectaraChain_Chains implements INode { lexicalInterpolationConfig: { lambda: vectaraFilter?.lambda ?? 0.025 } })) + // Vectara reranker ID for MMR (https://docs.vectara.com/docs/api-reference/search-apis/reranking#maximal-marginal-relevance-mmr-reranker) + const mmrRerankerId = 272725718 + const mmrEnabled = vectaraFilter?.mmrConfig?.enabled + const data = { query: [ { query: input, start: 0, - numResults: topK, + numResults: mmrEnabled ? vectaraFilter?.mmrTopK : topK, + corpusKey: corpusKeys, contextConfig: { sentencesAfter: vectaraFilter?.contextConfig?.sentencesAfter ?? 2, sentencesBefore: vectaraFilter?.contextConfig?.sentencesBefore ?? 2 }, - corpusKey: corpusKeys, + ...(mmrEnabled + ? { + rerankingConfig: { + rerankerId: mmrRerankerId, + mmrConfig: { + diversityBias: vectaraFilter?.mmrConfig.diversityBias + } + } + } + : {}), summary: [ { summarizerPromptName, @@ -285,6 +300,14 @@ class VectaraChain_Chains implements INode { const documents = result.responseSet[0].document let rawSummarizedText = '' + // remove responses that are not in the topK (in case of MMR) + // Note that this does not really matter functionally due to the reorder citations, but it is more efficient + const maxResponses = mmrEnabled ? Math.min(responses.length, topK) : responses.length + if (responses.length > maxResponses) { + responses.splice(0, maxResponses) + } + + // Add metadata to each text response given its corresponding document metadata for (let i = 0; i < responses.length; i += 1) { const responseMetadata = responses[i].metadata const documentMetadata = documents[responses[i].documentIndex].metadata @@ -301,13 +324,13 @@ class VectaraChain_Chains implements INode { responses[i].metadata = combinedMetadata } + // Create the summarization response const summaryStatus = result.responseSet[0].summary[0].status if (summaryStatus.length > 0 && summaryStatus[0].code === 'BAD_REQUEST') { throw new Error( `BAD REQUEST: Too much text for the summarizer to summarize. Please try reducing the number of search results to summarize, or the context of each result by adjusting the 'summary_num_sentences', and 'summary_num_results' parameters respectively.` ) } - if ( summaryStatus.length > 0 && summaryStatus[0].code === 'NOT_FOUND' && @@ -316,8 +339,8 @@ class VectaraChain_Chains implements INode { throw new Error(`BAD REQUEST: summarizer ${summarizerPromptName} is invalid for this account.`) } + // Reorder citations in summary and create the list of returned source documents rawSummarizedText = result.responseSet[0].summary[0]?.text - let summarizedText = reorderCitations(rawSummarizedText) let summaryResponses = applyCitationOrder(responses, rawSummarizedText) diff --git a/packages/components/nodes/vectorstores/Vectara/Vectara.ts b/packages/components/nodes/vectorstores/Vectara/Vectara.ts index 7460c586..939a4ac3 100644 --- a/packages/components/nodes/vectorstores/Vectara/Vectara.ts +++ b/packages/components/nodes/vectorstores/Vectara/Vectara.ts @@ -1,5 +1,5 @@ import { flatten } from 'lodash' -import { VectaraStore, VectaraLibArgs, VectaraFilter, VectaraContextConfig, VectaraFile } from 'langchain/vectorstores/vectara' +import { VectaraStore, VectaraLibArgs, VectaraFilter, VectaraContextConfig, VectaraFile, MMRConfig } from 'langchain/vectorstores/vectara' import { Document } from 'langchain/document' import { Embeddings } from 'langchain/embeddings/base' import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' @@ -22,7 +22,7 @@ class Vectara_VectorStores implements INode { constructor() { this.label = 'Vectara' this.name = 'vectara' - this.version = 1.0 + this.version = 2.0 this.type = 'Vectara' this.icon = 'vectara.png' this.category = 'Vector Stores' @@ -82,7 +82,9 @@ class Vectara_VectorStores implements INode { label: 'Lambda', name: 'lambda', description: - 'Improves retrieval accuracy by adjusting the balance (from 0 to 1) between neural search and keyword-based search factors.', + 'Enable hybrid search to improve retrieval accuracy by adjusting the balance (from 0 to 1) between neural search and keyword-based search factors.' + + 'A value of 0.0 means that only neural search is used, while a value of 1.0 means that only keyword-based search is used. Defaults to 0.0 (neural only).', + default: 0.0, type: 'number', additionalParams: true, optional: true @@ -90,8 +92,30 @@ class Vectara_VectorStores implements INode { { label: 'Top K', name: 'topK', - description: 'Number of top results to fetch. Defaults to 4', - placeholder: '4', + description: 'Number of top results to fetch. Defaults to 5', + placeholder: '5', + type: 'number', + additionalParams: true, + optional: true + }, + { + label: 'MMR K', + name: 'mmrK', + description: 'Number of top results to fetch for MMR. Defaults to 50', + placeholder: '50', + type: 'number', + additionalParams: true, + optional: true + }, + { + label: 'MMR diversity bias', + name: 'mmrDiversityBias', + step: 0.1, + description: + 'The diversity bias to use for MMR. This is a value between 0.0 and 1.0' + + 'Values closer to 1.0 optimize for the most diverse results.' + + 'Defaults to 0 (MMR disabled)', + placeholder: '0.0', type: 'number', additionalParams: true, optional: true @@ -191,7 +215,9 @@ class Vectara_VectorStores implements INode { const lambda = nodeData.inputs?.lambda as number const output = nodeData.outputs?.output as string const topK = nodeData.inputs?.topK as string - const k = topK ? parseFloat(topK) : 4 + const k = topK ? parseFloat(topK) : 5 + const mmrK = nodeData.inputs?.mmrK as number + const mmrDiversityBias = nodeData.inputs?.mmrDiversityBias as number const vectaraArgs: VectaraLibArgs = { apiKey: apiKey, @@ -208,6 +234,11 @@ class Vectara_VectorStores implements INode { if (sentencesBefore) vectaraContextConfig.sentencesBefore = sentencesBefore if (sentencesAfter) vectaraContextConfig.sentencesAfter = sentencesAfter vectaraFilter.contextConfig = vectaraContextConfig + const mmrConfig: MMRConfig = {} + mmrConfig.enabled = mmrDiversityBias > 0 + mmrConfig.mmrTopK = mmrK + mmrConfig.diversityBias = mmrDiversityBias + vectaraFilter.mmrConfig = mmrConfig const vectorStore = new VectaraStore(vectaraArgs) diff --git a/packages/components/package.json b/packages/components/package.json index 07b2c3df..c179a4cc 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -49,7 +49,7 @@ "express": "^4.17.3", "faiss-node": "^0.2.2", "form-data": "^4.0.0", - "google-auth-library": "^9.0.0", + "google-auth-library": "^9.4.0", "graphql": "^16.6.0", "html-to-text": "^9.0.5", "husky": "^8.0.3", diff --git a/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json b/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json index d9f9fb49..33b93578 100644 --- a/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json +++ b/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json @@ -361,12 +361,33 @@ { "label": "Top K", "name": "topK", - "description": "Number of top results to fetch. Defaults to 4", - "placeholder": "4", + "description": "Number of top results to fetch. Defaults to 5", + "placeholder": "5", "type": "number", "additionalParams": true, "optional": true, "id": "vectara_0-input-topK-number" + }, + { + "label": "MMR K", + "name": "mmrK", + "description": "The number of results to rerank if MMR is enabled.", + "placeholder": "50", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "vectara_0-input-mmrK-number" + }, + { + "label": "MMR Diversity Bias", + "name": "mmrDiversityBias", + "step": 0.1, + "description": "Diversity Bias parameter for MMR, if enabled. 0.0 means no diversiry bias, 1.0 means maximum diversity bias. Defaults to 0.0 (MMR disabled).", + "placeholder": "0.0", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "vectara_0-input-mmrDiversityBias-number" } ], "inputAnchors": [ @@ -385,7 +406,9 @@ "sentencesBefore": "", "sentencesAfter": "", "lambda": "", - "topK": "" + "topK": "", + "mmrK": "", + "mmrDiversityBias": "" }, "outputAnchors": [ {