| from langchain_groq import ChatGroq |
| from langchain_core.messages import HumanMessage, AIMessage, SystemMessage |
| from langgraph.graph import StateGraph, END |
| from typing import TypedDict, Sequence, Annotated, Union |
| from langchain_core.messages import BaseMessage |
| from dotenv import load_dotenv |
| from langchain_core.tools import tool |
| import os |
| from langgraph.graph.message import add_messages |
| from langgraph.prebuilt import ToolNode |
| import asyncio |
|
|
| from src.agents.researcher_agent import ResearcherAgent |
| from src.agents.content_extractor_agent import ContentExtractorAgent |
| from src.agents.summarizer_agent import SummarizerAgent |
| from src.agents.global_synthesizer_agent import GlobalSynthesizerAgent |
| from src.models.research_models import ResearchQuery |
|
|
| |
| |
| |
| researcher_agent = ResearcherAgent() |
| content_extractor_agent = ContentExtractorAgent() |
| summarizer_agent = SummarizerAgent() |
| global_synthesizer_agent = GlobalSynthesizerAgent() |
|
|
| |
| |
| |
| @tool |
| def research_complete_pipeline(topic: str, max_results: Union[int, str] = 2) -> str: |
| """Exécute un pipeline de recherche complet sur un sujet donné. |
| |
| Ce tool encapsule 4 agents qui travaillent ensemble : |
| 1. ResearcherAgent : recherche web et extraction de mots-clés |
| 2. ContentExtractorAgent : extraction du contenu des pages |
| 3. SummarizerAgent : création de résumés détaillés |
| 4. GlobalSynthesizerAgent : synthèse globale finale |
| |
| Args: |
| topic: Le sujet de recherche (ex: "impact de l'IA sur l'emploi") |
| max_results: Nombre de sources à analyser (2-10, défaut: 2) |
| |
| Returns: |
| Un rapport complet au format texte avec résumé exécutif et analyse détaillée |
| """ |
| |
| if isinstance(max_results, str): |
| try: |
| max_results = int(max_results) |
| except ValueError: |
| max_results = 2 |
| max_results = max(2, min(max_results, 10)) |
| |
| async def run_pipeline(): |
| print(f"\n{'='*60}") |
| print(f"🚀 DÉMARRAGE DU PIPELINE DE RECHERCHE") |
| print(f"📋 Sujet: {topic}") |
| print(f"📊 Sources à analyser: {max_results}") |
| print(f"{'='*60}\n") |
| |
| |
| print("🔍 [1/4] Recherche web en cours...") |
| query = ResearchQuery( |
| topic=topic, |
| keywords=await researcher_agent.extract_keywords_with_llm(topic), |
| max_results=max_results, |
| search_depth="basic" |
| ) |
| research_data = await researcher_agent.process(query) |
| print(f"✅ Trouvé {research_data.total_found} sources") |
| |
| |
| print("\n📄 [2/4] Extraction du contenu...") |
| extraction_data = await content_extractor_agent.process_from_research_output( |
| research_output=research_data |
| ) |
| print(f"✅ Extrait {extraction_data.successful_extractions} documents") |
| |
| |
| print("\n📝 [3/4] Création des résumés...") |
| summarization_data = await summarizer_agent.process_from_extraction_result( |
| extraction_result=extraction_data |
| ) |
| print(f"✅ Généré {summarization_data.total_documents} résumés") |
| |
| |
| print("\n🎯 [4/4] Synthèse globale...") |
| global_synthesis = await global_synthesizer_agent.process_from_summarization_output( |
| summarization_output=summarization_data |
| ) |
| print(f"✅ Rapport final généré ({global_synthesis.final_report.word_count} mots)") |
| |
| print(f"\n{'='*60}") |
| print("✨ PIPELINE TERMINÉ AVEC SUCCÈS") |
| print(f"{'='*60}\n") |
| |
| |
| return global_synthesis.formatted_outputs.get('markdown', |
| global_synthesis.formatted_outputs.get('text', |
| str(global_synthesis)) |
| ) |
| |
| return asyncio.run(run_pipeline()) |
|
|
| |
| |
| |
|
|
| |
| class AgentState(TypedDict): |
| messages: Annotated[Sequence[BaseMessage], add_messages] |
|
|
| |
| load_dotenv() |
| api_key = os.getenv("GROQ_API_KEY") |
| if not api_key: |
| raise ValueError("GROQ_API_KEY non définie dans .env") |
|
|
| |
| tools = [research_complete_pipeline] |
| model = ChatGroq( |
| model="llama-3.1-8b-instant", |
| temperature=0.3, |
| max_tokens=2048*2, |
| api_key=api_key |
| ).bind_tools(tools) |
|
|
| |
| |
| |
|
|
| def model_call(state: AgentState) -> AgentState: |
| """Nœud qui appelle le LLM pour décider quoi faire""" |
| |
| system_prompt = SystemMessage(content="""Tu es un assistant de recherche intelligent. |
| |
| 🎯 TON RÔLE: |
| Tu aides les utilisateurs à obtenir des résumés et analyses sur n'importe quel sujet. |
| |
| 🔧 TON OUTIL: |
| Tu as accès à un outil puissant appelé 'research_complete_pipeline' qui : |
| - Effectue des recherches web automatiques |
| - Extrait et analyse le contenu |
| - Génère des résumés détaillés |
| - Produit une synthèse globale complète |
| |
| 📋 QUAND L'UTILISER: |
| Utilise cet outil quand l'utilisateur demande : |
| - Un résumé sur un sujet |
| - Des informations sur un topic |
| - Une analyse d'un domaine |
| - Une recherche documentée |
| |
| 💡 COMMENT L'UTILISER: |
| - Identifie le sujet principal de la demande |
| - Appelle research_complete_pipeline avec le sujet en français clair |
| - Utilise max_results=2 pour une recherche standard |
| |
| ✅ EXEMPLES: |
| User: "Résume l'impact de l'IA sur l'emploi" |
| → Appelle: research_complete_pipeline(topic="impact de l'intelligence artificielle sur le marché de l'emploi", max_results=2) |
| User: "Fais-moi une analyse complète sur le changement climatique" |
| → Appelle: research_complete_pipeline(topic="changement climatique", max_results=3) |
| |
| ⚠️ IMPORTANT: |
| - N'essaie PAS de faire la recherche toi-même |
| - Utilise TOUJOURS l'outil pour les demandes de recherche |
| - Le résultat de l'outil est déjà un rapport complet formaté |
| - Tu peux présenter le résultat directement à l'utilisateur |
| """ |
| |
| ) |
| |
| messages = state["messages"] |
| response = model.invoke([system_prompt] + messages) |
| return {"messages": [response]} |
|
|
| def should_continue(state: AgentState) -> str: |
| """Décide si on continue avec des outils ou si on termine""" |
| messages = state["messages"] |
| last_message = messages[-1] |
| |
| |
| if hasattr(last_message, 'tool_calls') and last_message.tool_calls: |
| return "continue" |
| else: |
| return "end" |
|
|
| |
| |
| |
|
|
| |
| graph = StateGraph(AgentState) |
|
|
| |
| graph.add_node("llm", model_call) |
| tool_node = ToolNode(tools=tools) |
| graph.add_node("tools", tool_node) |
|
|
| |
| graph.set_entry_point("llm") |
|
|
| |
| graph.add_conditional_edges( |
| "llm", |
| should_continue, |
| { |
| "continue": "tools", |
| "end": END, |
| }, |
| ) |
|
|
| |
| graph.add_edge("tools", "llm") |
|
|
| |
| app = graph.compile() |