diff --git a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts index 19e28752e70..2233ebf9486 100644 --- a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts +++ b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts @@ -56,7 +56,8 @@ class ConversationChain_Chains implements INode { const obj: any = { llm: model, - memory + memory, + verbose: process.env.DEBUG === 'true' ? true : false } const chatPrompt = ChatPromptTemplate.fromPromptMessages([ diff --git a/packages/components/nodes/chains/MultiPromptChain/MultiPromptChain.ts b/packages/components/nodes/chains/MultiPromptChain/MultiPromptChain.ts new file mode 100644 index 00000000000..a7b00f4636a --- /dev/null +++ b/packages/components/nodes/chains/MultiPromptChain/MultiPromptChain.ts @@ -0,0 +1,68 @@ +import { BaseLanguageModel } from 'langchain/base_language' +import { INode, INodeData, INodeParams, PromptRetriever } from '../../../src/Interface' +import { getBaseClasses } from '../../../src/utils' +import { MultiPromptChain } from 'langchain/chains' + +class MultiPromptChain_Chains implements INode { + label: string + name: string + type: string + icon: string + category: string + baseClasses: string[] + description: string + inputs: INodeParams[] + + constructor() { + this.label = 'Multi Prompt Chain' + this.name = 'multiPromptChain' + this.type = 'MultiPromptChain' + this.icon = 'chain.svg' + this.category = 'Chains' + this.description = 'Chain automatically picks an appropriate prompt from multiple prompt templates' + this.baseClasses = [this.type, ...getBaseClasses(MultiPromptChain)] + this.inputs = [ + { + label: 'Language Model', + name: 'model', + type: 'BaseLanguageModel' + }, + { + label: 'Prompt Retriever', + name: 'promptRetriever', + type: 'PromptRetriever', + list: true + } + ] + } + + async init(nodeData: INodeData): Promise { + const model = nodeData.inputs?.model as BaseLanguageModel + const promptRetriever = nodeData.inputs?.promptRetriever as PromptRetriever[] + const promptNames = [] + const promptDescriptions = [] + const promptTemplates = [] + + for (const prompt of promptRetriever) { + promptNames.push(prompt.name) + promptDescriptions.push(prompt.description) + promptTemplates.push(prompt.systemMessage) + } + + const chain = MultiPromptChain.fromPrompts(model, promptNames, promptDescriptions, promptTemplates, undefined, { + verbose: process.env.DEBUG === 'true' ? true : false + } as any) + + return chain + } + + async run(nodeData: INodeData, input: string): Promise { + const chain = nodeData.instance as MultiPromptChain + + const res = await chain.call({ input }) + + return res?.text + } +} + +module.exports = { nodeClass: MultiPromptChain_Chains } diff --git a/packages/components/nodes/chains/MultiPromptChain/chain.svg b/packages/components/nodes/chains/MultiPromptChain/chain.svg new file mode 100644 index 00000000000..a5b32f90aa3 --- /dev/null +++ b/packages/components/nodes/chains/MultiPromptChain/chain.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/packages/components/nodes/retrievers/PromptRetriever/PromptRetriever.ts b/packages/components/nodes/retrievers/PromptRetriever/PromptRetriever.ts new file mode 100644 index 00000000000..e3b9a4acbd0 --- /dev/null +++ b/packages/components/nodes/retrievers/PromptRetriever/PromptRetriever.ts @@ -0,0 +1,62 @@ +import { INode, INodeData, INodeParams, PromptRetriever, PromptRetrieverInput } from '../../../src/Interface' + +class PromptRetriever_Retrievers implements INode { + label: string + name: string + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'Prompt Retriever' + this.name = 'promptRetriever' + this.type = 'PromptRetriever' + this.icon = 'promptretriever.svg' + this.category = 'Retrievers' + this.description = 'Store prompt template with name & description to be later queried by MultiPromptChain' + this.baseClasses = [this.type] + this.inputs = [ + { + label: 'Prompt Name', + name: 'name', + type: 'string', + placeholder: 'physics-qa' + }, + { + label: 'Prompt Description', + name: 'description', + type: 'string', + rows: 3, + description: 'Description of what the prompt does and when it should be used', + placeholder: 'Good for answering questions about physics' + }, + { + label: 'Prompt System Message', + name: 'systemMessage', + type: 'string', + rows: 4, + placeholder: `You are a very smart physics professor. You are great at answering questions about physics in a concise and easy to understand manner. When you don't know the answer to a question you admit that you don't know.` + } + ] + } + + async init(nodeData: INodeData): Promise { + const name = nodeData.inputs?.name as string + const description = nodeData.inputs?.description as string + const systemMessage = nodeData.inputs?.systemMessage as string + + const obj = { + name, + description, + systemMessage + } as PromptRetrieverInput + + const retriever = new PromptRetriever(obj) + return retriever + } +} + +module.exports = { nodeClass: PromptRetriever_Retrievers } diff --git a/packages/components/nodes/retrievers/PromptRetriever/promptretriever.svg b/packages/components/nodes/retrievers/PromptRetriever/promptretriever.svg new file mode 100644 index 00000000000..db48e8a519c --- /dev/null +++ b/packages/components/nodes/retrievers/PromptRetriever/promptretriever.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/packages/components/src/Interface.ts b/packages/components/src/Interface.ts index 181cc206e11..ea3d1f0d4aa 100644 --- a/packages/components/src/Interface.ts +++ b/packages/components/src/Interface.ts @@ -103,3 +103,24 @@ export class PromptTemplate extends LangchainPromptTemplate { super(input) } } + +export interface PromptRetrieverInput { + name: string + description: string + systemMessage: string +} + +const fixedTemplate = `Here is a question: +{input} +` +export class PromptRetriever { + name: string + description: string + systemMessage: string + + constructor(fields: PromptRetrieverInput) { + this.name = fields.name + this.description = fields.description + this.systemMessage = `${fields.systemMessage}\n${fixedTemplate}` + } +} diff --git a/packages/server/marketplaces/Multi Prompt Chain.json b/packages/server/marketplaces/Multi Prompt Chain.json new file mode 100644 index 00000000000..fa99cd91615 --- /dev/null +++ b/packages/server/marketplaces/Multi Prompt Chain.json @@ -0,0 +1,442 @@ +{ + "description": "A chain that automatically picks an appropriate prompt from multiple prompts", + "nodes": [ + { + "width": 300, + "height": 632, + "id": "promptRetriever_0", + "position": { + "x": 197.46642699727397, + "y": 25.945621297410923 + }, + "type": "customNode", + "data": { + "id": "promptRetriever_0", + "label": "Prompt Retriever", + "name": "promptRetriever", + "type": "PromptRetriever", + "baseClasses": ["PromptRetriever"], + "category": "Retrievers", + "description": "Store prompt template with name & description to be later queried by MultiPromptChain", + "inputParams": [ + { + "label": "Prompt Name", + "name": "name", + "type": "string", + "placeholder": "physics-qa", + "id": "promptRetriever_0-input-name-string" + }, + { + "label": "Prompt Description", + "name": "description", + "type": "string", + "rows": 3, + "description": "Description of what the prompt does and when it should be used", + "placeholder": "Good for answering questions about physics", + "id": "promptRetriever_0-input-description-string" + }, + { + "label": "Prompt System Message", + "name": "systemMessage", + "type": "string", + "rows": 4, + "placeholder": "You are a very smart physics professor. You are great at answering questions about physics in a concise and easy to understand manner. When you don't know the answer to a question you admit that you don't know.", + "id": "promptRetriever_0-input-systemMessage-string" + } + ], + "inputAnchors": [], + "inputs": { + "name": "physics", + "description": "Good for answering questions about physics", + "systemMessage": "You are a very smart physics professor. You are great at answering questions about physics in a concise and easy to understand manner. When you don't know the answer to a question you admit that you don't know." + }, + "outputAnchors": [ + { + "id": "promptRetriever_0-output-promptRetriever-PromptRetriever", + "name": "promptRetriever", + "label": "PromptRetriever", + "type": "PromptRetriever" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 197.46642699727397, + "y": 25.945621297410923 + }, + "dragging": false + }, + { + "width": 300, + "height": 280, + "id": "multiPromptChain_0", + "position": { + "x": 1619.1305522575494, + "y": 210.28103293821243 + }, + "type": "customNode", + "data": { + "id": "multiPromptChain_0", + "label": "Multi Prompt Chain", + "name": "multiPromptChain", + "type": "MultiPromptChain", + "baseClasses": ["MultiPromptChain", "MultiRouteChain", "BaseChain", "BaseLangChain"], + "category": "Chains", + "description": "Chain automatically picks an appropriate prompt from multiple prompt templates", + "inputParams": [], + "inputAnchors": [ + { + "label": "Language Model", + "name": "model", + "type": "BaseLanguageModel", + "id": "multiPromptChain_0-input-model-BaseLanguageModel" + }, + { + "label": "Prompt Retriever", + "name": "promptRetriever", + "type": "PromptRetriever", + "list": true, + "id": "multiPromptChain_0-input-promptRetriever-PromptRetriever" + } + ], + "inputs": { + "model": "{{chatOpenAI_0.data.instance}}", + "promptRetriever": [ + "{{promptRetriever_0.data.instance}}", + "{{promptRetriever_2.data.instance}}", + "{{promptRetriever_1.data.instance}}" + ] + }, + "outputAnchors": [ + { + "id": "multiPromptChain_0-output-multiPromptChain-MultiPromptChain|MultiRouteChain|BaseChain|BaseLangChain", + "name": "multiPromptChain", + "label": "MultiPromptChain", + "type": "MultiPromptChain | MultiRouteChain | BaseChain | BaseLangChain" + } + ], + "outputs": {}, + "selected": false + }, + "positionAbsolute": { + "x": 1619.1305522575494, + "y": 210.28103293821243 + }, + "selected": false, + "dragging": false + }, + { + "width": 300, + "height": 632, + "id": "promptRetriever_1", + "position": { + "x": 539.1322780233141, + "y": -250.72967142925938 + }, + "type": "customNode", + "data": { + "id": "promptRetriever_1", + "label": "Prompt Retriever", + "name": "promptRetriever", + "type": "PromptRetriever", + "baseClasses": ["PromptRetriever"], + "category": "Retrievers", + "description": "Store prompt template with name & description to be later queried by MultiPromptChain", + "inputParams": [ + { + "label": "Prompt Name", + "name": "name", + "type": "string", + "placeholder": "physics-qa", + "id": "promptRetriever_1-input-name-string" + }, + { + "label": "Prompt Description", + "name": "description", + "type": "string", + "rows": 3, + "description": "Description of what the prompt does and when it should be used", + "placeholder": "Good for answering questions about physics", + "id": "promptRetriever_1-input-description-string" + }, + { + "label": "Prompt System Message", + "name": "systemMessage", + "type": "string", + "rows": 4, + "placeholder": "You are a very smart physics professor. You are great at answering questions about physics in a concise and easy to understand manner. When you don't know the answer to a question you admit that you don't know.", + "id": "promptRetriever_1-input-systemMessage-string" + } + ], + "inputAnchors": [], + "inputs": { + "name": "math", + "description": "Good for answering math questions", + "systemMessage": "You are a very good mathematician. You are great at answering math questions. You are so good because you are able to break down hard problems into their component parts, answer the component parts, and then put them together to answer the broader question." + }, + "outputAnchors": [ + { + "id": "promptRetriever_1-output-promptRetriever-PromptRetriever", + "name": "promptRetriever", + "label": "PromptRetriever", + "type": "PromptRetriever" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 539.1322780233141, + "y": -250.72967142925938 + }, + "dragging": false + }, + { + "width": 300, + "height": 632, + "id": "promptRetriever_2", + "position": { + "x": 872.6184534864304, + "y": -366.9443140594265 + }, + "type": "customNode", + "data": { + "id": "promptRetriever_2", + "label": "Prompt Retriever", + "name": "promptRetriever", + "type": "PromptRetriever", + "baseClasses": ["PromptRetriever"], + "category": "Retrievers", + "description": "Store prompt template with name & description to be later queried by MultiPromptChain", + "inputParams": [ + { + "label": "Prompt Name", + "name": "name", + "type": "string", + "placeholder": "physics-qa", + "id": "promptRetriever_2-input-name-string" + }, + { + "label": "Prompt Description", + "name": "description", + "type": "string", + "rows": 3, + "description": "Description of what the prompt does and when it should be used", + "placeholder": "Good for answering questions about physics", + "id": "promptRetriever_2-input-description-string" + }, + { + "label": "Prompt System Message", + "name": "systemMessage", + "type": "string", + "rows": 4, + "placeholder": "You are a very smart physics professor. You are great at answering questions about physics in a concise and easy to understand manner. When you don't know the answer to a question you admit that you don't know.", + "id": "promptRetriever_2-input-systemMessage-string" + } + ], + "inputAnchors": [], + "inputs": { + "name": "history", + "description": "Good for answering questions about history", + "systemMessage": "You are a very smart history professor. You are great at answering questions about history in a concise and easy to understand manner. When you don't know the answer to a question you admit that you don't know." + }, + "outputAnchors": [ + { + "id": "promptRetriever_2-output-promptRetriever-PromptRetriever", + "name": "promptRetriever", + "label": "PromptRetriever", + "type": "PromptRetriever" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 872.6184534864304, + "y": -366.9443140594265 + }, + "dragging": false + }, + { + "width": 300, + "height": 524, + "id": "chatOpenAI_0", + "position": { + "x": 1230.07368145571, + "y": -296.44522826934826 + }, + "type": "customNode", + "data": { + "id": "chatOpenAI_0", + "label": "ChatOpenAI", + "name": "chatOpenAI", + "type": "ChatOpenAI", + "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "BaseLangChain"], + "category": "Chat Models", + "description": "Wrapper around OpenAI large language models that use the Chat endpoint", + "inputParams": [ + { + "label": "OpenAI Api Key", + "name": "openAIApiKey", + "type": "password", + "id": "chatOpenAI_0-input-openAIApiKey-password" + }, + { + "label": "Model Name", + "name": "modelName", + "type": "options", + "options": [ + { + "label": "gpt-4", + "name": "gpt-4" + }, + { + "label": "gpt-4-0314", + "name": "gpt-4-0314" + }, + { + "label": "gpt-4-32k-0314", + "name": "gpt-4-32k-0314" + }, + { + "label": "gpt-3.5-turbo", + "name": "gpt-3.5-turbo" + }, + { + "label": "gpt-3.5-turbo-0301", + "name": "gpt-3.5-turbo-0301" + } + ], + "default": "gpt-3.5-turbo", + "optional": true, + "id": "chatOpenAI_0-input-modelName-options" + }, + { + "label": "Temperature", + "name": "temperature", + "type": "number", + "default": 0.9, + "optional": true, + "id": "chatOpenAI_0-input-temperature-number" + }, + { + "label": "Max Tokens", + "name": "maxTokens", + "type": "number", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-maxTokens-number" + }, + { + "label": "Top Probability", + "name": "topP", + "type": "number", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-topP-number" + }, + { + "label": "Frequency Penalty", + "name": "frequencyPenalty", + "type": "number", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-frequencyPenalty-number" + }, + { + "label": "Presence Penalty", + "name": "presencePenalty", + "type": "number", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-presencePenalty-number" + }, + { + "label": "Timeout", + "name": "timeout", + "type": "number", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-timeout-number" + } + ], + "inputAnchors": [], + "inputs": { + "modelName": "gpt-3.5-turbo", + "temperature": 0.9, + "maxTokens": "", + "topP": "", + "frequencyPenalty": "", + "presencePenalty": "", + "timeout": "" + }, + "outputAnchors": [ + { + "id": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|BaseLangChain", + "name": "chatOpenAI", + "label": "ChatOpenAI", + "type": "ChatOpenAI | BaseChatModel | BaseLanguageModel | BaseLangChain" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 1230.07368145571, + "y": -296.44522826934826 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "promptRetriever_0", + "sourceHandle": "promptRetriever_0-output-promptRetriever-PromptRetriever", + "target": "multiPromptChain_0", + "targetHandle": "multiPromptChain_0-input-promptRetriever-PromptRetriever", + "type": "buttonedge", + "id": "promptRetriever_0-promptRetriever_0-output-promptRetriever-PromptRetriever-multiPromptChain_0-multiPromptChain_0-input-promptRetriever-PromptRetriever", + "data": { + "label": "" + } + }, + { + "source": "promptRetriever_2", + "sourceHandle": "promptRetriever_2-output-promptRetriever-PromptRetriever", + "target": "multiPromptChain_0", + "targetHandle": "multiPromptChain_0-input-promptRetriever-PromptRetriever", + "type": "buttonedge", + "id": "promptRetriever_2-promptRetriever_2-output-promptRetriever-PromptRetriever-multiPromptChain_0-multiPromptChain_0-input-promptRetriever-PromptRetriever", + "data": { + "label": "" + } + }, + { + "source": "promptRetriever_1", + "sourceHandle": "promptRetriever_1-output-promptRetriever-PromptRetriever", + "target": "multiPromptChain_0", + "targetHandle": "multiPromptChain_0-input-promptRetriever-PromptRetriever", + "type": "buttonedge", + "id": "promptRetriever_1-promptRetriever_1-output-promptRetriever-PromptRetriever-multiPromptChain_0-multiPromptChain_0-input-promptRetriever-PromptRetriever", + "data": { + "label": "" + } + }, + { + "source": "chatOpenAI_0", + "sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|BaseLangChain", + "target": "multiPromptChain_0", + "targetHandle": "multiPromptChain_0-input-model-BaseLanguageModel", + "type": "buttonedge", + "id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|BaseLangChain-multiPromptChain_0-multiPromptChain_0-input-model-BaseLanguageModel", + "data": { + "label": "" + } + } + ] +}