Update metaSearchAgent.ts
memory + sources -> OK
This commit is contained in:
parent
c22df4ba66
commit
3e53bab9b4
1 changed files with 120 additions and 33 deletions
|
@ -36,6 +36,7 @@ import { EventEmitter } from 'events';
|
||||||
import { MemoryVectorStore } from "langchain/vectorstores/memory";
|
import { MemoryVectorStore } from "langchain/vectorstores/memory";
|
||||||
|
|
||||||
export interface MetaSearchAgentType {
|
export interface MetaSearchAgentType {
|
||||||
|
initialize: (embeddings: Embeddings) => Promise<void>;
|
||||||
searchAndAnswer: (
|
searchAndAnswer: (
|
||||||
message: string,
|
message: string,
|
||||||
history: BaseMessage[],
|
history: BaseMessage[],
|
||||||
|
@ -106,7 +107,20 @@ export class MetaSearchAgent implements MetaSearchAgentType {
|
||||||
}
|
}
|
||||||
|
|
||||||
async initialize(embeddings: Embeddings) {
|
async initialize(embeddings: Embeddings) {
|
||||||
this.memoryStore = new MemoryVectorStore(embeddings);
|
try {
|
||||||
|
if (!this.memoryStore) {
|
||||||
|
console.log("🔄 Initialisation du memory store...");
|
||||||
|
this.memoryStore = new MemoryVectorStore(embeddings);
|
||||||
|
await this.memoryStore.addDocuments([{
|
||||||
|
pageContent: "Initialisation du memory store",
|
||||||
|
metadata: { timestamp: Date.now() }
|
||||||
|
}]);
|
||||||
|
console.log("✅ Memory store initialisé avec succès");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("❌ Erreur lors de l'initialisation du memory store:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async enrichWithMemory(message: string, embeddings: Embeddings): Promise<string> {
|
private async enrichWithMemory(message: string, embeddings: Embeddings): Promise<string> {
|
||||||
|
@ -296,33 +310,43 @@ export class MetaSearchAgent implements MetaSearchAgentType {
|
||||||
query: (input: BasicChainInput) => input.query,
|
query: (input: BasicChainInput) => input.query,
|
||||||
chat_history: (input: BasicChainInput) => input.chat_history,
|
chat_history: (input: BasicChainInput) => input.chat_history,
|
||||||
docs: RunnableLambda.from(async (input: BasicChainInput) => {
|
docs: RunnableLambda.from(async (input: BasicChainInput) => {
|
||||||
console.log("Début de la recherche...");
|
console.log("Début de la recherche avec contexte enrichi...");
|
||||||
let docs: Document[] = [];
|
let docs: Document[] = [];
|
||||||
|
|
||||||
// 1. D'abord chercher dans les documents uploadés
|
// Récupérer le contexte historique
|
||||||
|
const memoryContext = await this.getRelevantContext(input.query);
|
||||||
|
console.log("💭 Contexte historique pour la recherche:", memoryContext);
|
||||||
|
|
||||||
|
// Enrichir la requête avec le contexte
|
||||||
|
const enrichedQuery = `
|
||||||
|
Contexte précédent:
|
||||||
|
${memoryContext}
|
||||||
|
|
||||||
|
Question actuelle:
|
||||||
|
${input.query}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// 1. D'abord chercher dans les documents uploadés avec le contexte enrichi
|
||||||
if (fileIds.length > 0) {
|
if (fileIds.length > 0) {
|
||||||
try {
|
try {
|
||||||
const uploadedDocs = await this.loadUploadedDocuments(fileIds);
|
const uploadedDocs = await this.loadUploadedDocuments(fileIds);
|
||||||
console.log("📚 Documents uploadés chargés:", uploadedDocs.length);
|
console.log("📚 Documents uploadés chargés:", uploadedDocs.length);
|
||||||
|
|
||||||
// Utiliser RAGDocumentChain pour la recherche dans les documents
|
|
||||||
const ragChain = new RAGDocumentChain();
|
const ragChain = new RAGDocumentChain();
|
||||||
await ragChain.initializeVectorStoreFromDocuments(uploadedDocs, embeddings);
|
await ragChain.initializeVectorStoreFromDocuments(uploadedDocs, embeddings);
|
||||||
|
|
||||||
// Utiliser le type 'specific' pour une recherche précise
|
|
||||||
const searchChain = ragChain.createSearchChain(llm);
|
const searchChain = ragChain.createSearchChain(llm);
|
||||||
const relevantDocs = await searchChain.invoke({
|
const relevantDocs = await searchChain.invoke({
|
||||||
query: input.query,
|
query: enrichedQuery,
|
||||||
chat_history: input.chat_history,
|
chat_history: input.chat_history,
|
||||||
type: 'specific'
|
type: 'specific'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Ajouter les documents pertinents avec un score élevé
|
|
||||||
docs = uploadedDocs.map(doc => ({
|
docs = uploadedDocs.map(doc => ({
|
||||||
...doc,
|
...doc,
|
||||||
metadata: {
|
metadata: {
|
||||||
...doc.metadata,
|
...doc.metadata,
|
||||||
score: 0.8 // Score élevé pour les documents uploadés
|
score: 0.8
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -367,7 +391,7 @@ export class MetaSearchAgent implements MetaSearchAgentType {
|
||||||
|
|
||||||
console.log("🔍 DEBUG - Avant appel rerankDocs - Mode:", optimizationMode, "Query:", input.query);
|
console.log("🔍 DEBUG - Avant appel rerankDocs - Mode:", optimizationMode, "Query:", input.query);
|
||||||
return this.rerankDocs(
|
return this.rerankDocs(
|
||||||
input.query,
|
enrichedQuery,
|
||||||
docs,
|
docs,
|
||||||
fileIds,
|
fileIds,
|
||||||
embeddings,
|
embeddings,
|
||||||
|
@ -673,11 +697,16 @@ export class MetaSearchAgent implements MetaSearchAgentType {
|
||||||
if (!this.memoryStore) {
|
if (!this.memoryStore) {
|
||||||
throw new Error("Memory store not initialized");
|
throw new Error("Memory store not initialized");
|
||||||
}
|
}
|
||||||
// Créer un document avec le contexte actuel
|
|
||||||
|
// Créer un document avec le contexte actuel et sa structure
|
||||||
const contextDoc = {
|
const contextDoc = {
|
||||||
pageContent: `Question: ${message}\nContext: ${history.map(m =>
|
pageContent: `Question: ${message}\nContext: ${history.map(m =>
|
||||||
`${m._getType()}: ${m.content}`).join('\n')}`,
|
`${m._getType()}: ${m.content}`).join('\n')}`,
|
||||||
metadata: { timestamp: Date.now() }
|
metadata: {
|
||||||
|
timestamp: Date.now(),
|
||||||
|
themes: this.extractThemes(message + ' ' + history.map(m => m.content).join(' ')),
|
||||||
|
type: 'conversation'
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log("💾 Ajout à la mémoire:", contextDoc);
|
console.log("💾 Ajout à la mémoire:", contextDoc);
|
||||||
|
@ -694,7 +723,8 @@ export class MetaSearchAgent implements MetaSearchAgentType {
|
||||||
throw new Error("Memory store not initialized");
|
throw new Error("Memory store not initialized");
|
||||||
}
|
}
|
||||||
console.log("🔍 Recherche dans la mémoire pour:", message);
|
console.log("🔍 Recherche dans la mémoire pour:", message);
|
||||||
const results = await this.memoryStore.similaritySearch(message, 2);
|
|
||||||
|
const results = await this.memoryStore.similaritySearch(message, 3);
|
||||||
console.log("📚 Contexte trouvé dans la mémoire:", results);
|
console.log("📚 Contexte trouvé dans la mémoire:", results);
|
||||||
return results.map(doc => doc.pageContent).join('\n');
|
return results.map(doc => doc.pageContent).join('\n');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -703,6 +733,13 @@ export class MetaSearchAgent implements MetaSearchAgentType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private extractThemes(context: string): string[] {
|
||||||
|
const commonThemes = ['sas', 'entreprise', 'création', 'chomage', 'juridique', 'financement'];
|
||||||
|
return commonThemes.filter(theme =>
|
||||||
|
context.toLowerCase().includes(theme.toLowerCase())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private async analyzeConversationContext(
|
private async analyzeConversationContext(
|
||||||
message: string,
|
message: string,
|
||||||
history: BaseMessage[],
|
history: BaseMessage[],
|
||||||
|
@ -712,17 +749,27 @@ export class MetaSearchAgent implements MetaSearchAgentType {
|
||||||
const formattedHistory = formatChatHistoryAsString(history);
|
const formattedHistory = formatChatHistoryAsString(history);
|
||||||
|
|
||||||
const analysis = await llm.invoke(`
|
const analysis = await llm.invoke(`
|
||||||
Analysez cette conversation en profondeur pour établir les liens entre les différents sujets et leur impact mutuel.
|
Analysez cette conversation en profondeur en donnant une importance particulière aux 3 derniers échanges.
|
||||||
|
Assurez-vous de maintenir la cohérence du contexte entre les questions.
|
||||||
|
|
||||||
Historique de la conversation:
|
Historique de la conversation:
|
||||||
${formattedHistory}
|
${formattedHistory}
|
||||||
|
|
||||||
Nouvelle question: "${message}"
|
Nouvelle question: "${message}"
|
||||||
|
|
||||||
|
Instructions spécifiques:
|
||||||
|
1. Identifiez les thèmes récurrents des 3 derniers échanges
|
||||||
|
2. Notez les contraintes ou conditions mentionnées précédemment qui restent pertinentes
|
||||||
|
3. Évaluez comment la nouvelle question s'inscrit dans la continuité des échanges
|
||||||
|
|
||||||
Répondez au format JSON:
|
Répondez au format JSON:
|
||||||
{
|
{
|
||||||
"mainTopic": "sujet principal actuel",
|
"mainTopic": "sujet principal actuel",
|
||||||
"relatedTopics": ["sujets connexes"],
|
"recentContext": {
|
||||||
|
"lastThemes": ["thèmes des 3 derniers échanges"],
|
||||||
|
"activeConstraints": ["contraintes toujours actives"],
|
||||||
|
"continuityScore": <0.0 à 1.0>
|
||||||
|
},
|
||||||
"contextualFactors": {
|
"contextualFactors": {
|
||||||
"financial": ["facteurs financiers"],
|
"financial": ["facteurs financiers"],
|
||||||
"legal": ["aspects juridiques"],
|
"legal": ["aspects juridiques"],
|
||||||
|
@ -739,18 +786,23 @@ export class MetaSearchAgent implements MetaSearchAgentType {
|
||||||
|
|
||||||
const result = JSON.parse(String(analysis.content));
|
const result = JSON.parse(String(analysis.content));
|
||||||
|
|
||||||
// Construire un contexte enrichi qui prend en compte les relations et impacts
|
// Construction d'un contexte enrichi qui met l'accent sur la continuité
|
||||||
const enrichedContext = `
|
const enrichedContext = `
|
||||||
Contexte principal: ${result.mainTopic}
|
Contexte principal: ${result.mainTopic}
|
||||||
|
Thèmes récents: ${result.recentContext.lastThemes.join(', ')}
|
||||||
|
Contraintes actives: ${result.recentContext.activeConstraints.join(', ')}
|
||||||
Facteurs impactants: ${result.contextualFactors.financial.join(', ')}
|
Facteurs impactants: ${result.contextualFactors.financial.join(', ')}
|
||||||
Implications légales: ${result.contextualFactors.legal.join(', ')}
|
Implications légales: ${result.contextualFactors.legal.join(', ')}
|
||||||
Impact global: ${result.impactAnalysis.primary}
|
Impact global: ${result.impactAnalysis.primary}
|
||||||
Contraintes à considérer: ${result.impactAnalysis.constraints.join(', ')}
|
Contraintes à considérer: ${result.impactAnalysis.constraints.join(', ')}
|
||||||
`.trim();
|
`.trim();
|
||||||
|
|
||||||
|
// Ajuster le score de pertinence en fonction de la continuité
|
||||||
|
const adjustedRelevance = (result.relevanceScore + result.recentContext.continuityScore) / 2;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
context: enrichedContext,
|
context: enrichedContext,
|
||||||
relevance: result.relevanceScore
|
relevance: adjustedRelevance
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Erreur lors de l'analyse du contexte:", error);
|
console.error("Erreur lors de l'analyse du contexte:", error);
|
||||||
|
@ -770,6 +822,20 @@ export class MetaSearchAgent implements MetaSearchAgentType {
|
||||||
const emitter = new EventEmitter();
|
const emitter = new EventEmitter();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// S'assurer que le memoryStore est initialisé
|
||||||
|
if (!this.memoryStore) {
|
||||||
|
console.log("🔄 Initialisation du memory store dans searchAndAnswer...");
|
||||||
|
try {
|
||||||
|
await this.initialize(embeddings);
|
||||||
|
if (!this.memoryStore) {
|
||||||
|
throw new Error("Memory store initialization failed");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("❌ Erreur lors de l'initialisation du memory store:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Analyser le contexte de la conversation
|
// Analyser le contexte de la conversation
|
||||||
const conversationContext = await this.analyzeConversationContext(message, history, llm);
|
const conversationContext = await this.analyzeConversationContext(message, history, llm);
|
||||||
console.log("🧠 Analyse du contexte:", conversationContext);
|
console.log("🧠 Analyse du contexte:", conversationContext);
|
||||||
|
@ -779,29 +845,41 @@ export class MetaSearchAgent implements MetaSearchAgentType {
|
||||||
|
|
||||||
// Récupérer le contexte pertinent de la mémoire
|
// Récupérer le contexte pertinent de la mémoire
|
||||||
const memoryContext = await this.getRelevantContext(message);
|
const memoryContext = await this.getRelevantContext(message);
|
||||||
|
console.log("💭 Contexte mémoire récupéré:", memoryContext);
|
||||||
|
|
||||||
|
// Enrichir le message avec le contexte historique
|
||||||
|
const enrichedMessage = `
|
||||||
|
Contexte précédent:
|
||||||
|
${memoryContext}
|
||||||
|
|
||||||
|
Contexte actuel:
|
||||||
|
${conversationContext.context}
|
||||||
|
|
||||||
|
Question actuelle:
|
||||||
|
${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 dans son contexte complet.
|
||||||
|
|
||||||
Question/Requête: "${message}"
|
${enrichedMessage}
|
||||||
${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"}
|
||||||
|
|
||||||
Analyse et réponds au format JSON:
|
Analyse et réponds au format JSON:
|
||||||
{
|
{
|
||||||
"primaryIntent": "DOCUMENT_QUERY" | "WEB_SEARCH" | "EXPERT_ADVICE" | "HYBRID",
|
"primaryIntent": "DOCUMENT_QUERY" | "WEB_SEARCH" | "EXPERT_ADVICE" | "HYBRID",
|
||||||
"requiresDocumentSearch": <boolean>,
|
"requiresDocumentSearch": <boolean>,
|
||||||
"requiresWebSearch": <boolean>,
|
"requiresWebSearch": <boolean>,
|
||||||
"requiresExpertSearch": <boolean>,
|
"requiresExpertSearch": <boolean>,
|
||||||
"documentRelevance": <0.0 à 1.0>,
|
"documentRelevance": <0.0 à 1.0>,
|
||||||
"contextRelevance": ${conversationContext.relevance},
|
"contextRelevance": ${conversationContext.relevance},
|
||||||
"reasoning": "<courte explication>"
|
"reasoning": "<courte explication>"
|
||||||
}`);
|
}`);
|
||||||
|
|
||||||
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 enrichie:", analysis);
|
||||||
|
|
||||||
// 1. Analyse des documents uploadés avec RAG
|
// 1. Analyse des documents uploadés avec RAG
|
||||||
const uploadedDocs = await this.loadUploadedDocuments(fileIds);
|
const uploadedDocs = await this.loadUploadedDocuments(fileIds);
|
||||||
|
@ -940,6 +1018,9 @@ Analyse et réponds au format JSON:
|
||||||
export const searchHandlers: Record<string, MetaSearchAgentType> = {
|
export const searchHandlers: Record<string, MetaSearchAgentType> = {
|
||||||
// ... existing handlers ...
|
// ... existing handlers ...
|
||||||
legal: {
|
legal: {
|
||||||
|
initialize: async (embeddings: Embeddings) => {
|
||||||
|
// Pas besoin d'initialisation spécifique pour le handler legal
|
||||||
|
},
|
||||||
searchAndAnswer: async (
|
searchAndAnswer: async (
|
||||||
message,
|
message,
|
||||||
history,
|
history,
|
||||||
|
@ -994,6 +1075,9 @@ export const searchHandlers: Record<string, MetaSearchAgentType> = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
documents: {
|
documents: {
|
||||||
|
initialize: async (embeddings: Embeddings) => {
|
||||||
|
// Pas besoin d'initialisation spécifique pour le handler documents
|
||||||
|
},
|
||||||
searchAndAnswer: async (
|
searchAndAnswer: async (
|
||||||
message,
|
message,
|
||||||
history,
|
history,
|
||||||
|
@ -1059,6 +1143,9 @@ export const searchHandlers: Record<string, MetaSearchAgentType> = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
uploads: {
|
uploads: {
|
||||||
|
initialize: async (embeddings: Embeddings) => {
|
||||||
|
// Pas besoin d'initialisation spécifique pour le handler uploads
|
||||||
|
},
|
||||||
searchAndAnswer: async (
|
searchAndAnswer: async (
|
||||||
message,
|
message,
|
||||||
history,
|
history,
|
||||||
|
|
Loading…
Add table
Reference in a new issue