From f3271589a88da1a95c20e0a36c74613037db0a5d Mon Sep 17 00:00:00 2001 From: falkor Date: Wed, 28 Aug 2024 13:47:20 +0300 Subject: [PATCH] feature/introducting-conversational-retrieval-tool-agent (#2430) * introducting openai-conversational-retriever-agent * fix lint * fix build * rename + update description * changing agent base from openai to tool agent * adding author for community agent --- .../ConversationalRetrievalToolAgent.ts | 286 ++++++++++++++++++ .../toolAgent.png | Bin 0 -> 17519 bytes packages/server/src/utils/index.ts | 1 + 3 files changed, 287 insertions(+) create mode 100644 packages/components/nodes/agents/ConversationalRetrievalToolAgent/ConversationalRetrievalToolAgent.ts create mode 100644 packages/components/nodes/agents/ConversationalRetrievalToolAgent/toolAgent.png diff --git a/packages/components/nodes/agents/ConversationalRetrievalToolAgent/ConversationalRetrievalToolAgent.ts b/packages/components/nodes/agents/ConversationalRetrievalToolAgent/ConversationalRetrievalToolAgent.ts new file mode 100644 index 000000000..54013ac55 --- /dev/null +++ b/packages/components/nodes/agents/ConversationalRetrievalToolAgent/ConversationalRetrievalToolAgent.ts @@ -0,0 +1,286 @@ +import { flatten } from 'lodash' +import { BaseMessage } from '@langchain/core/messages' +import { ChainValues } from '@langchain/core/utils/types' +import { RunnableSequence } from '@langchain/core/runnables' +import { BaseChatModel } from '@langchain/core/language_models/chat_models' +import { ChatPromptTemplate, MessagesPlaceholder, HumanMessagePromptTemplate, PromptTemplate } from '@langchain/core/prompts' +import { formatToOpenAIToolMessages } from 'langchain/agents/format_scratchpad/openai_tools' +import { getBaseClasses } from '../../../src/utils' +import { type ToolsAgentStep } from 'langchain/agents/openai/output_parser' +import { FlowiseMemory, ICommonObject, INode, INodeData, INodeParams, IUsedTool, IVisionChatModal } from '../../../src/Interface' +import { ConsoleCallbackHandler, CustomChainHandler, additionalCallbacks } from '../../../src/handler' +import { AgentExecutor, ToolCallingAgentOutputParser } from '../../../src/agents' +import { Moderation, checkInputs, streamResponse } from '../../moderation/Moderation' +import { formatResponse } from '../../outputparsers/OutputParserHelpers' +import type { Document } from '@langchain/core/documents' +import { BaseRetriever } from '@langchain/core/retrievers' +import { RESPONSE_TEMPLATE } from '../../chains/ConversationalRetrievalQAChain/prompts' +import { addImagesToMessages, llmSupportsVision } from '../../../src/multiModalUtils' + +class ConversationalRetrievalToolAgent_Agents implements INode { + label: string + name: string + author: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + sessionId?: string + badge?: string + + constructor(fields?: { sessionId?: string }) { + this.label = 'Conversational Retrieval Tool Agent' + this.name = 'conversationalRetrievalToolAgent' + this.author = 'niztal(falkor)' + this.version = 1.0 + this.type = 'AgentExecutor' + this.category = 'Agents' + this.icon = 'toolAgent.png' + this.description = `Agent that calls a vector store retrieval and uses Function Calling to pick the tools and args to call` + this.baseClasses = [this.type, ...getBaseClasses(AgentExecutor)] + this.badge = 'NEW' + this.inputs = [ + { + label: 'Tools', + name: 'tools', + type: 'Tool', + list: true + }, + { + label: 'Memory', + name: 'memory', + type: 'BaseChatMemory' + }, + { + label: 'Tool Calling Chat Model', + name: 'model', + type: 'BaseChatModel', + description: + 'Only compatible with models that are capable of function calling. ChatOpenAI, ChatMistral, ChatAnthropic, ChatVertexAI' + }, + { + label: 'System Message', + name: 'systemMessage', + type: 'string', + description: 'Taking the rephrased question, search for answer from the provided context', + warning: 'Prompt must include input variable: {context}', + rows: 4, + additionalParams: true, + optional: true, + default: RESPONSE_TEMPLATE + }, + { + label: 'Input Moderation', + description: 'Detect text that could generate harmful output and prevent it from being sent to the language model', + name: 'inputModeration', + type: 'Moderation', + optional: true, + list: true + }, + { + label: 'Max Iterations', + name: 'maxIterations', + type: 'number', + optional: true, + additionalParams: true + }, + { + label: 'Vector Store Retriever', + name: 'vectorStoreRetriever', + type: 'BaseRetriever' + } + ] + this.sessionId = fields?.sessionId + } + + async init(nodeData: INodeData, input: string, options: ICommonObject): Promise { + return prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input }) + } + + async run(nodeData: INodeData, input: string, options: ICommonObject): Promise { + const memory = nodeData.inputs?.memory as FlowiseMemory + const moderations = nodeData.inputs?.inputModeration as Moderation[] + + const isStreamable = options.socketIO && options.socketIOClientId + + if (moderations && moderations.length > 0) { + try { + // Use the output of the moderation chain as input for the OpenAI Function Agent + input = await checkInputs(moderations, input) + } catch (e) { + await new Promise((resolve) => setTimeout(resolve, 500)) + if (isStreamable) + streamResponse(options.socketIO && options.socketIOClientId, e.message, options.socketIO, options.socketIOClientId) + return formatResponse(e.message) + } + } + + const executor = await prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input }) + + const loggerHandler = new ConsoleCallbackHandler(options.logger) + const callbacks = await additionalCallbacks(nodeData, options) + + let res: ChainValues = {} + let sourceDocuments: ICommonObject[] = [] + let usedTools: IUsedTool[] = [] + + if (isStreamable) { + const handler = new CustomChainHandler(options.socketIO, options.socketIOClientId) + res = await executor.invoke({ input }, { callbacks: [loggerHandler, handler, ...callbacks] }) + if (res.sourceDocuments) { + options.socketIO.to(options.socketIOClientId).emit('sourceDocuments', flatten(res.sourceDocuments)) + sourceDocuments = res.sourceDocuments + } + if (res.usedTools) { + options.socketIO.to(options.socketIOClientId).emit('usedTools', res.usedTools) + usedTools = res.usedTools + } + } else { + res = await executor.invoke({ input }, { callbacks: [loggerHandler, ...callbacks] }) + if (res.sourceDocuments) { + sourceDocuments = res.sourceDocuments + } + if (res.usedTools) { + usedTools = res.usedTools + } + } + + let output = res?.output as string + + // Claude 3 Opus tends to spit out .. as well, discard that in final output + const regexPattern: RegExp = /[\s\S]*?<\/thinking>/ + const matches: RegExpMatchArray | null = output.match(regexPattern) + if (matches) { + for (const match of matches) { + output = output.replace(match, '') + } + } + + await memory.addChatMessages( + [ + { + text: input, + type: 'userMessage' + }, + { + text: output, + type: 'apiMessage' + } + ], + this.sessionId + ) + + let finalRes = res?.output + + if (sourceDocuments.length || usedTools.length) { + const finalRes: ICommonObject = { text: output } + if (sourceDocuments.length) { + finalRes.sourceDocuments = flatten(sourceDocuments) + } + if (usedTools.length) { + finalRes.usedTools = usedTools + } + return finalRes + } + + return finalRes + } +} + +const formatDocs = (docs: Document[]) => { + return docs.map((doc, i) => `${doc.pageContent}`).join('\n') +} + +const prepareAgent = async ( + nodeData: INodeData, + options: ICommonObject, + flowObj: { sessionId?: string; chatId?: string; input?: string } +) => { + const model = nodeData.inputs?.model as BaseChatModel + const maxIterations = nodeData.inputs?.maxIterations as string + const memory = nodeData.inputs?.memory as FlowiseMemory + const systemMessage = nodeData.inputs?.systemMessage as string + let tools = nodeData.inputs?.tools + tools = flatten(tools) + const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history' + const inputKey = memory.inputKey ? memory.inputKey : 'input' + const vectorStoreRetriever = nodeData.inputs?.vectorStoreRetriever as BaseRetriever + + const prompt = ChatPromptTemplate.fromMessages([ + ['system', systemMessage ? systemMessage : `You are a helpful AI assistant.`], + new MessagesPlaceholder(memoryKey), + ['human', `{${inputKey}}`], + new MessagesPlaceholder('agent_scratchpad') + ]) + + if (llmSupportsVision(model)) { + const visionChatModel = model as IVisionChatModal + const messageContent = await addImagesToMessages(nodeData, options, model.multiModalOption) + + if (messageContent?.length) { + visionChatModel.setVisionModel() + + // Pop the `agent_scratchpad` MessagePlaceHolder + let messagePlaceholder = prompt.promptMessages.pop() as MessagesPlaceholder + if (prompt.promptMessages.at(-1) instanceof HumanMessagePromptTemplate) { + const lastMessage = prompt.promptMessages.pop() as HumanMessagePromptTemplate + const template = (lastMessage.prompt as PromptTemplate).template as string + const msg = HumanMessagePromptTemplate.fromTemplate([ + ...messageContent, + { + text: template + } + ]) + msg.inputVariables = lastMessage.inputVariables + prompt.promptMessages.push(msg) + } + + // Add the `agent_scratchpad` MessagePlaceHolder back + prompt.promptMessages.push(messagePlaceholder) + } else { + visionChatModel.revertToOriginalModel() + } + } + + if (model.bindTools === undefined) { + throw new Error(`This agent requires that the "bindTools()" method be implemented on the input model.`) + } + + const modelWithTools = model.bindTools(tools) + + const runnableAgent = RunnableSequence.from([ + { + [inputKey]: (i: { input: string; steps: ToolsAgentStep[] }) => i.input, + agent_scratchpad: (i: { input: string; steps: ToolsAgentStep[] }) => formatToOpenAIToolMessages(i.steps), + [memoryKey]: async (_: { input: string; steps: ToolsAgentStep[] }) => { + const messages = (await memory.getChatMessages(flowObj?.sessionId, true)) as BaseMessage[] + return messages ?? [] + }, + context: async (i: { input: string; chatHistory?: string }) => { + const relevantDocs = await vectorStoreRetriever.invoke(i.input) + const formattedDocs = formatDocs(relevantDocs) + return formattedDocs + } + }, + prompt, + modelWithTools, + new ToolCallingAgentOutputParser() + ]) + + const executor = AgentExecutor.fromAgentAndTools({ + agent: runnableAgent, + tools, + sessionId: flowObj?.sessionId, + chatId: flowObj?.chatId, + input: flowObj?.input, + verbose: process.env.DEBUG === 'true' ? true : false, + maxIterations: maxIterations ? parseFloat(maxIterations) : undefined + }) + + return executor +} + +module.exports = { nodeClass: ConversationalRetrievalToolAgent_Agents } diff --git a/packages/components/nodes/agents/ConversationalRetrievalToolAgent/toolAgent.png b/packages/components/nodes/agents/ConversationalRetrievalToolAgent/toolAgent.png new file mode 100644 index 0000000000000000000000000000000000000000..7bf44339bcb68396d8acc5709280507439abc901 GIT binary patch literal 17519 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 literal 0 HcmV?d00001 diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index 2aa430f00..1fc3be602 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -1228,6 +1228,7 @@ export const isFlowValidForStream = (reactFlowNodes: IReactFlowNode[], endingNod 'conversationalRetrievalAgent', 'openAIToolAgent', 'toolAgent', + 'conversationalRetrievalToolAgent', 'openAIToolAgentLlamaIndex' ] isValidChainOrAgent = whitelistAgents.includes(endingNodeData.name)