mirror of
				https://github.com/ItzCrazyKns/Perplexica.git
				synced 2025-10-31 19:38:13 +00:00 
			
		
		
		
	feat(metaSearchAgent): eliminate runnables
This commit is contained in:
		| @@ -6,11 +6,6 @@ import { | |||||||
|   MessagesPlaceholder, |   MessagesPlaceholder, | ||||||
|   PromptTemplate, |   PromptTemplate, | ||||||
| } from '@langchain/core/prompts'; | } from '@langchain/core/prompts'; | ||||||
| import { |  | ||||||
|   RunnableLambda, |  | ||||||
|   RunnableMap, |  | ||||||
|   RunnableSequence, |  | ||||||
| } from '@langchain/core/runnables'; |  | ||||||
| import { BaseMessage } from '@langchain/core/messages'; | import { BaseMessage } from '@langchain/core/messages'; | ||||||
| import { StringOutputParser } from '@langchain/core/output_parsers'; | import { StringOutputParser } from '@langchain/core/output_parsers'; | ||||||
| import LineListOutputParser from '../outputParsers/listLineOutputParser'; | import LineListOutputParser from '../outputParsers/listLineOutputParser'; | ||||||
| @@ -24,6 +19,7 @@ import computeSimilarity from '../utils/computeSimilarity'; | |||||||
| import formatChatHistoryAsString from '../utils/formatHistory'; | import formatChatHistoryAsString from '../utils/formatHistory'; | ||||||
| import eventEmitter from 'events'; | import eventEmitter from 'events'; | ||||||
| import { StreamEvent } from '@langchain/core/tracers/log_stream'; | import { StreamEvent } from '@langchain/core/tracers/log_stream'; | ||||||
|  | import { EventEmitter } from 'node:stream'; | ||||||
|  |  | ||||||
| export interface MetaSearchAgentType { | export interface MetaSearchAgentType { | ||||||
|   searchAndAnswer: ( |   searchAndAnswer: ( | ||||||
| @@ -46,7 +42,7 @@ interface Config { | |||||||
|   activeEngines: string[]; |   activeEngines: string[]; | ||||||
| } | } | ||||||
|  |  | ||||||
| type BasicChainInput = { | type SearchInput = { | ||||||
|   chat_history: BaseMessage[]; |   chat_history: BaseMessage[]; | ||||||
|   query: string; |   query: string; | ||||||
| }; | }; | ||||||
| @@ -59,14 +55,25 @@ class MetaSearchAgent implements MetaSearchAgentType { | |||||||
|     this.config = config; |     this.config = config; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private async createSearchRetrieverChain(llm: BaseChatModel) { |   private async searchSources( | ||||||
|  |     llm: BaseChatModel, | ||||||
|  |     input: SearchInput, | ||||||
|  |     emitter: EventEmitter, | ||||||
|  |   ) { | ||||||
|     (llm as unknown as ChatOpenAI).temperature = 0; |     (llm as unknown as ChatOpenAI).temperature = 0; | ||||||
|  |  | ||||||
|     return RunnableSequence.from([ |     const chatPrompt = PromptTemplate.fromTemplate( | ||||||
|       PromptTemplate.fromTemplate(this.config.queryGeneratorPrompt), |       this.config.queryGeneratorPrompt, | ||||||
|       llm, |     ); | ||||||
|       this.strParser, |  | ||||||
|       RunnableLambda.from(async (input: string) => { |     const processedChatPrompt = await chatPrompt.invoke({ | ||||||
|  |       chat_history: formatChatHistoryAsString(input.chat_history), | ||||||
|  |       query: input.query, | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     const llmRes = await llm.invoke(processedChatPrompt); | ||||||
|  |     const messageStr = await this.strParser.invoke(llmRes); | ||||||
|  |  | ||||||
|     const linksOutputParser = new LineListOutputParser({ |     const linksOutputParser = new LineListOutputParser({ | ||||||
|       key: 'links', |       key: 'links', | ||||||
|     }); |     }); | ||||||
| @@ -75,10 +82,10 @@ class MetaSearchAgent implements MetaSearchAgentType { | |||||||
|       key: 'question', |       key: 'question', | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|         const links = await linksOutputParser.parse(input); |     const links = await linksOutputParser.parse(messageStr); | ||||||
|     let question = this.config.summarizer |     let question = this.config.summarizer | ||||||
|           ? await questionOutputParser.parse(input) |       ? await questionOutputParser.parse(messageStr) | ||||||
|           : input; |       : messageStr; | ||||||
|  |  | ||||||
|     if (question === 'not_needed') { |     if (question === 'not_needed') { | ||||||
|       return { query: '', docs: [] }; |       return { query: '', docs: [] }; | ||||||
| @@ -98,8 +105,7 @@ class MetaSearchAgent implements MetaSearchAgentType { | |||||||
|       linkDocs.map((doc) => { |       linkDocs.map((doc) => { | ||||||
|         const URLDocExists = docGroups.find( |         const URLDocExists = docGroups.find( | ||||||
|           (d) => |           (d) => | ||||||
|                 d.metadata.url === doc.metadata.url && |             d.metadata.url === doc.metadata.url && d.metadata.totalDocs < 10, | ||||||
|                 d.metadata.totalDocs < 10, |  | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|         if (!URLDocExists) { |         if (!URLDocExists) { | ||||||
| @@ -114,8 +120,7 @@ class MetaSearchAgent implements MetaSearchAgentType { | |||||||
|  |  | ||||||
|         const docIndex = docGroups.findIndex( |         const docIndex = docGroups.findIndex( | ||||||
|           (d) => |           (d) => | ||||||
|                 d.metadata.url === doc.metadata.url && |             d.metadata.url === doc.metadata.url && d.metadata.totalDocs < 10, | ||||||
|                 d.metadata.totalDocs < 10, |  | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|         if (docIndex !== -1) { |         if (docIndex !== -1) { | ||||||
| @@ -227,40 +232,30 @@ class MetaSearchAgent implements MetaSearchAgentType { | |||||||
|  |  | ||||||
|       return { query: question, docs: documents }; |       return { query: question, docs: documents }; | ||||||
|     } |     } | ||||||
|       }), |  | ||||||
|     ]); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private async createAnsweringChain( |   private async streamAnswer( | ||||||
|     llm: BaseChatModel, |     llm: BaseChatModel, | ||||||
|     fileIds: string[], |     fileIds: string[], | ||||||
|     embeddings: Embeddings, |     embeddings: Embeddings, | ||||||
|     optimizationMode: 'speed' | 'balanced' | 'quality', |     optimizationMode: 'speed' | 'balanced' | 'quality', | ||||||
|  |     input: SearchInput, | ||||||
|  |     emitter: EventEmitter, | ||||||
|   ) { |   ) { | ||||||
|     return RunnableSequence.from([ |     const chatPrompt = ChatPromptTemplate.fromMessages([ | ||||||
|       RunnableMap.from({ |       ['system', this.config.responsePrompt], | ||||||
|         query: (input: BasicChainInput) => input.query, |       new MessagesPlaceholder('chat_history'), | ||||||
|         chat_history: (input: BasicChainInput) => input.chat_history, |       ['user', '{query}'], | ||||||
|         date: () => new Date().toISOString(), |     ]); | ||||||
|         context: RunnableLambda.from(async (input: BasicChainInput) => { |  | ||||||
|           const processedHistory = formatChatHistoryAsString( |  | ||||||
|             input.chat_history, |  | ||||||
|           ); |  | ||||||
|  |  | ||||||
|     let docs: Document[] | null = null; |     let docs: Document[] | null = null; | ||||||
|     let query = input.query; |     let query = input.query; | ||||||
|  |  | ||||||
|     if (this.config.searchWeb) { |     if (this.config.searchWeb) { | ||||||
|             const searchRetrieverChain = |       const searchResults = await this.searchSources(llm, input, emitter); | ||||||
|               await this.createSearchRetrieverChain(llm); |  | ||||||
|  |  | ||||||
|             const searchRetrieverResult = await searchRetrieverChain.invoke({ |       query = searchResults.query; | ||||||
|               chat_history: processedHistory, |       docs = searchResults.docs; | ||||||
|               query, |  | ||||||
|             }); |  | ||||||
|  |  | ||||||
|             query = searchRetrieverResult.query; |  | ||||||
|             docs = searchRetrieverResult.docs; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const sortedDocs = await this.rerankDocs( |     const sortedDocs = await this.rerankDocs( | ||||||
| @@ -271,23 +266,29 @@ class MetaSearchAgent implements MetaSearchAgentType { | |||||||
|       optimizationMode, |       optimizationMode, | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|           return sortedDocs; |     emitter.emit('data', JSON.stringify({ type: 'sources', data: sortedDocs })); | ||||||
|         }) |  | ||||||
|           .withConfig({ |     const context = this.processDocs(sortedDocs); | ||||||
|             runName: 'FinalSourceRetriever', |  | ||||||
|           }) |     const formattedChatPrompt = await chatPrompt.invoke({ | ||||||
|           .pipe(this.processDocs), |       query: input.query, | ||||||
|       }), |       chat_history: input.chat_history, | ||||||
|       ChatPromptTemplate.fromMessages([ |       date: new Date().toISOString(), | ||||||
|         ['system', this.config.responsePrompt], |       context: context, | ||||||
|         new MessagesPlaceholder('chat_history'), |  | ||||||
|         ['user', '{query}'], |  | ||||||
|       ]), |  | ||||||
|       llm, |  | ||||||
|       this.strParser, |  | ||||||
|     ]).withConfig({ |  | ||||||
|       runName: 'FinalResponseGenerator', |  | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  |     const llmRes = await llm.stream(formattedChatPrompt); | ||||||
|  |  | ||||||
|  |     for await (const data of llmRes) { | ||||||
|  |       const messageStr = await this.strParser.invoke(data); | ||||||
|  |  | ||||||
|  |       emitter.emit( | ||||||
|  |         'data', | ||||||
|  |         JSON.stringify({ type: 'response', data: messageStr }), | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     emitter.emit('end'); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private async rerankDocs( |   private async rerankDocs( | ||||||
| @@ -428,39 +429,6 @@ class MetaSearchAgent implements MetaSearchAgentType { | |||||||
|       .join('\n'); |       .join('\n'); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private async handleStream( |  | ||||||
|     stream: AsyncGenerator<StreamEvent, any, any>, |  | ||||||
|     emitter: eventEmitter, |  | ||||||
|   ) { |  | ||||||
|     for await (const event of stream) { |  | ||||||
|       if ( |  | ||||||
|         event.event === 'on_chain_end' && |  | ||||||
|         event.name === 'FinalSourceRetriever' |  | ||||||
|       ) { |  | ||||||
|         ``; |  | ||||||
|         emitter.emit( |  | ||||||
|           'data', |  | ||||||
|           JSON.stringify({ type: 'sources', data: event.data.output }), |  | ||||||
|         ); |  | ||||||
|       } |  | ||||||
|       if ( |  | ||||||
|         event.event === 'on_chain_stream' && |  | ||||||
|         event.name === 'FinalResponseGenerator' |  | ||||||
|       ) { |  | ||||||
|         emitter.emit( |  | ||||||
|           'data', |  | ||||||
|           JSON.stringify({ type: 'response', data: event.data.chunk }), |  | ||||||
|         ); |  | ||||||
|       } |  | ||||||
|       if ( |  | ||||||
|         event.event === 'on_chain_end' && |  | ||||||
|         event.name === 'FinalResponseGenerator' |  | ||||||
|       ) { |  | ||||||
|         emitter.emit('end'); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   async searchAndAnswer( |   async searchAndAnswer( | ||||||
|     message: string, |     message: string, | ||||||
|     history: BaseMessage[], |     history: BaseMessage[], | ||||||
| @@ -471,25 +439,18 @@ class MetaSearchAgent implements MetaSearchAgentType { | |||||||
|   ) { |   ) { | ||||||
|     const emitter = new eventEmitter(); |     const emitter = new eventEmitter(); | ||||||
|  |  | ||||||
|     const answeringChain = await this.createAnsweringChain( |     this.streamAnswer( | ||||||
|       llm, |       llm, | ||||||
|       fileIds, |       fileIds, | ||||||
|       embeddings, |       embeddings, | ||||||
|       optimizationMode, |       optimizationMode, | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     const stream = answeringChain.streamEvents( |  | ||||||
|       { |       { | ||||||
|         chat_history: history, |         chat_history: history, | ||||||
|         query: message, |         query: message, | ||||||
|       }, |       }, | ||||||
|       { |       emitter, | ||||||
|         version: 'v1', |  | ||||||
|       }, |  | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|     this.handleStream(stream, emitter); |  | ||||||
|  |  | ||||||
|     return emitter; |     return emitter; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user