Update metaSearchAgent.ts
memory update
This commit is contained in:
parent
6e82bb54eb
commit
377bf937bf
1 changed files with 128 additions and 16 deletions
|
@ -33,6 +33,7 @@ import { SearxngSearchOptions } from '../lib/searxng';
|
||||||
import { ChromaClient } from 'chromadb';
|
import { ChromaClient } from 'chromadb';
|
||||||
import { OpenAIEmbeddings } from '@langchain/openai';
|
import { OpenAIEmbeddings } from '@langchain/openai';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
|
import { MemoryVectorStore } from "langchain/vectorstores/memory";
|
||||||
|
|
||||||
export interface MetaSearchAgentType {
|
export interface MetaSearchAgentType {
|
||||||
searchAndAnswer: (
|
searchAndAnswer: (
|
||||||
|
@ -97,12 +98,34 @@ export class MetaSearchAgent implements MetaSearchAgentType {
|
||||||
private config: Config;
|
private config: Config;
|
||||||
private strParser = new StringOutputParser();
|
private strParser = new StringOutputParser();
|
||||||
private fileIds: string[];
|
private fileIds: string[];
|
||||||
|
private memoryStore: MemoryVectorStore;
|
||||||
|
|
||||||
constructor(config: Config) {
|
constructor(config: Config) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.fileIds = [];
|
this.fileIds = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async initialize(embeddings: Embeddings) {
|
||||||
|
this.memoryStore = new MemoryVectorStore(embeddings);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async enrichWithMemory(message: string, embeddings: Embeddings): Promise<string> {
|
||||||
|
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) {
|
private async createSearchRetrieverChain(llm: BaseChatModel) {
|
||||||
(llm as unknown as ChatOpenAI).temperature = 0;
|
(llm as unknown as ChatOpenAI).temperature = 0;
|
||||||
|
|
||||||
|
@ -645,6 +668,96 @@ export class MetaSearchAgent implements MetaSearchAgentType {
|
||||||
return docs.slice(0, 15);
|
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<string> {
|
||||||
|
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(
|
async searchAndAnswer(
|
||||||
message: string,
|
message: string,
|
||||||
history: BaseMessage[],
|
history: BaseMessage[],
|
||||||
|
@ -654,14 +767,25 @@ export class MetaSearchAgent implements MetaSearchAgentType {
|
||||||
fileIds: string[],
|
fileIds: string[],
|
||||||
) {
|
) {
|
||||||
const effectiveMode = 'balanced';
|
const effectiveMode = 'balanced';
|
||||||
|
const emitter = new EventEmitter();
|
||||||
const emitter = new eventEmitter();
|
|
||||||
|
|
||||||
try {
|
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
|
// 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.
|
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}"
|
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"}
|
Documents disponibles: ${fileIds.length > 0 ? "Oui" : "Non"}
|
||||||
|
|
||||||
|
@ -672,20 +796,9 @@ Analyse et réponds au format JSON:
|
||||||
"requiresWebSearch": <boolean>,
|
"requiresWebSearch": <boolean>,
|
||||||
"requiresExpertSearch": <boolean>,
|
"requiresExpertSearch": <boolean>,
|
||||||
"documentRelevance": <0.0 à 1.0>,
|
"documentRelevance": <0.0 à 1.0>,
|
||||||
|
"contextRelevance": ${conversationContext.relevance},
|
||||||
"reasoning": "<courte explication>"
|
"reasoning": "<courte explication>"
|
||||||
}
|
}`);
|
||||||
|
|
||||||
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));
|
const analysis = JSON.parse(String(queryAnalysis.content));
|
||||||
console.log("🎯 Analyse de la requête:", analysis);
|
console.log("🎯 Analyse de la requête:", analysis);
|
||||||
|
@ -1115,4 +1228,3 @@ export const searchHandlers: Record<string, MetaSearchAgentType> = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MetaSearchAgent;
|
export default MetaSearchAgent;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue