From 377bf937bfbd7088f4a8d5d46613b7ddfc94456e Mon Sep 17 00:00:00 2001 From: Lucas Date: Thu, 2 Jan 2025 13:01:07 +0100 Subject: [PATCH] Update metaSearchAgent.ts memory update --- src/search/metaSearchAgent.ts | 144 ++++++++++++++++++++++++++++++---- 1 file changed, 128 insertions(+), 16 deletions(-) diff --git a/src/search/metaSearchAgent.ts b/src/search/metaSearchAgent.ts index eef8295..1a32fca 100644 --- a/src/search/metaSearchAgent.ts +++ b/src/search/metaSearchAgent.ts @@ -33,6 +33,7 @@ import { SearxngSearchOptions } from '../lib/searxng'; import { ChromaClient } from 'chromadb'; import { OpenAIEmbeddings } from '@langchain/openai'; import { EventEmitter } from 'events'; +import { MemoryVectorStore } from "langchain/vectorstores/memory"; export interface MetaSearchAgentType { searchAndAnswer: ( @@ -97,12 +98,34 @@ export class MetaSearchAgent implements MetaSearchAgentType { private config: Config; private strParser = new StringOutputParser(); private fileIds: string[]; + private memoryStore: MemoryVectorStore; constructor(config: Config) { this.config = config; this.fileIds = []; } + async initialize(embeddings: Embeddings) { + this.memoryStore = new MemoryVectorStore(embeddings); + } + + private async enrichWithMemory(message: string, embeddings: Embeddings): Promise { + try { + if (!this.memoryStore) { + await this.initialize(embeddings); + } + await this.memoryStore.addDocuments([{ + pageContent: message, + metadata: { timestamp: Date.now() } + }]); + const results = await this.memoryStore.similaritySearch(message, 2); + return results.map(doc => doc.pageContent).join('\n'); + } catch (error) { + console.error("Erreur mémoire:", error); + return ''; + } + } + private async createSearchRetrieverChain(llm: BaseChatModel) { (llm as unknown as ChatOpenAI).temperature = 0; @@ -645,6 +668,96 @@ export class MetaSearchAgent implements MetaSearchAgentType { return docs.slice(0, 15); } + private async updateMemoryStore(message: string, history: BaseMessage[]) { + try { + if (!this.memoryStore) { + throw new Error("Memory store not initialized"); + } + // Créer un document avec le contexte actuel + const contextDoc = { + pageContent: `Question: ${message}\nContext: ${history.map(m => + `${m._getType()}: ${m.content}`).join('\n')}`, + metadata: { timestamp: Date.now() } + }; + + console.log("💾 Ajout à la mémoire:", contextDoc); + await this.memoryStore.addDocuments([contextDoc]); + console.log("✅ Mémoire mise à jour avec succès"); + } catch (error) { + console.error("❌ Erreur lors de la mise à jour de la mémoire:", error); + } + } + + private async getRelevantContext(message: string): Promise { + try { + if (!this.memoryStore) { + throw new Error("Memory store not initialized"); + } + console.log("🔍 Recherche dans la mémoire pour:", message); + const results = await this.memoryStore.similaritySearch(message, 2); + console.log("📚 Contexte trouvé dans la mémoire:", results); + return results.map(doc => doc.pageContent).join('\n'); + } catch (error) { + console.error("❌ Erreur lors de la récupération du contexte:", error); + return ''; + } + } + + private async analyzeConversationContext( + message: string, + history: BaseMessage[], + llm: BaseChatModel + ): Promise<{ context: string; relevance: number }> { + try { + const formattedHistory = formatChatHistoryAsString(history); + + const analysis = await llm.invoke(` + Analysez cette conversation en profondeur pour établir les liens entre les différents sujets et leur impact mutuel. + + Historique de la conversation: + ${formattedHistory} + + Nouvelle question: "${message}" + + Répondez au format JSON: + { + "mainTopic": "sujet principal actuel", + "relatedTopics": ["sujets connexes"], + "contextualFactors": { + "financial": ["facteurs financiers"], + "legal": ["aspects juridiques"], + "administrative": ["aspects administratifs"] + }, + "impactAnalysis": { + "primary": "impact principal", + "secondary": ["impacts secondaires"], + "constraints": ["contraintes identifiées"] + }, + "relevanceScore": <0.0 à 1.0> + } + `); + + const result = JSON.parse(String(analysis.content)); + + // Construire un contexte enrichi qui prend en compte les relations et impacts + const enrichedContext = ` + Contexte principal: ${result.mainTopic} + Facteurs impactants: ${result.contextualFactors.financial.join(', ')} + Implications légales: ${result.contextualFactors.legal.join(', ')} + Impact global: ${result.impactAnalysis.primary} + Contraintes à considérer: ${result.impactAnalysis.constraints.join(', ')} + `.trim(); + + return { + context: enrichedContext, + relevance: result.relevanceScore + }; + } catch (error) { + console.error("Erreur lors de l'analyse du contexte:", error); + return { context: '', relevance: 0 }; + } + } + async searchAndAnswer( message: string, history: BaseMessage[], @@ -654,14 +767,25 @@ export class MetaSearchAgent implements MetaSearchAgentType { fileIds: string[], ) { const effectiveMode = 'balanced'; - - const emitter = new eventEmitter(); + const emitter = new EventEmitter(); try { + // Analyser le contexte de la conversation + const conversationContext = await this.analyzeConversationContext(message, history, llm); + console.log("🧠 Analyse du contexte:", conversationContext); + + // Mettre à jour la mémoire avec le contexte actuel + await this.updateMemoryStore(message, history); + + // Récupérer le contexte pertinent de la mémoire + const memoryContext = await this.getRelevantContext(message); + // Analyse sophistiquée de la requête avec LLM const queryAnalysis = await llm.invoke(`En tant qu'expert en analyse de requêtes, examine cette demande et détermine la stratégie de recherche optimale. Question/Requête: "${message}" +${memoryContext ? `\nContexte mémorisé:\n${memoryContext}` : ''} +${conversationContext.context ? `\nContexte de la conversation:\n${conversationContext.context}` : ''} Documents disponibles: ${fileIds.length > 0 ? "Oui" : "Non"} @@ -672,20 +796,9 @@ Analyse et réponds au format JSON: "requiresWebSearch": , "requiresExpertSearch": , "documentRelevance": <0.0 à 1.0>, + "contextRelevance": ${conversationContext.relevance}, "reasoning": "" -} - -Critères d'analyse: -- DOCUMENT_QUERY: La question porte spécifiquement sur le contenu des documents -- WEB_SEARCH: Recherche d'informations générales ou actuelles -- EXPERT_ADVICE: Demande nécessitant une expertise spécifique -- HYBRID: Combinaison de plusieurs sources - -Prends en compte: -- La présence ou non de documents uploadés -- La spécificité de la question -- Le besoin d'expertise externe -- L'actualité du sujet`); +}`); const analysis = JSON.parse(String(queryAnalysis.content)); console.log("🎯 Analyse de la requête:", analysis); @@ -1115,4 +1228,3 @@ export const searchHandlers: Record = { }; export default MetaSearchAgent; -