from typing import TypedDict, Annotated, Sequence from langchain_core.messages import BaseMessage from langgraph.graph import StateGraph, END from langgraph.graph.message import add_messages from config import llm, client, langsmith_project from pinecone_utilsB import * from typing import TypedDict, Sequence, List, Dict, Optional, Annotated class GraphState(TypedDict): messages: Annotated[Sequence[BaseMessage], add_messages] query: str relevant_docs: List[Dict[str, Optional[Dict[str, float]]]] response: str k: int alpha: float similarity_threshold: float def retrieve_combined(state: GraphState) -> dict: """Récupération hybride : Pinecone (sémantique) + BM25 (mots-clés).""" relevant_docs = hybrid_search( state["query"], alpha=state.get("alpha"), k=state.get("k"), similarity_threshold=state.get("similarity_threshold") ) return {"relevant_docs": relevant_docs} def generate_response(state: GraphState) -> dict: """Génération de réponse en combinant informations sémantiques et mots-clés.""" context = "\n\n".join(doc["text"] for doc in state["relevant_docs"]) prompt = f""" Vous êtes un expert en analyse de texte. Votre tâche consiste à répondre à la question de l'utilisateur en utilisant les informations pertinentes fournies. Intégrez à la fois les éléments sémantiques (contexte, sens) et les mots-clés exacts pour fournir une réponse fluide et cohérente. **Instructions supplémentaires** : - Utilisez les mots-clés pertinents de manière naturelle dans votre réponse. - Expliquez les concepts en vous appuyant sur le contexte sémantique. - Ne mentionnez pas explicitement les termes "recherche sémantique" ou "recherche par mots-clés". - **Si la réponse doit être une liste retournez chaque élément sur **une nouvelle ligne**. - Format correct attendu : 1. Élément 1 2. Élément 2 3. Élément 3 **Informations pertinentes trouvées** : {context} **Question de l'utilisateur** : {state["query"]} **Réponse :** [Fournissez une réponse cohérente qui intègre à la fois les éléments sémantiques et les mots-clés pertinents sans les distinguer explicitement.] """ response = llm.invoke(prompt) return {"response": response.content} def post_process_response(state: GraphState) -> dict: """Nettoie et valide la réponse.""" response = state["response"].strip() # Vérifier si la réponse est pertinente if not response or response.lower() in ["je ne sais pas", "i don't know"]: response = "Désolé, je n'ai pas trouvé d'informations pertinentes pour votre question." return {"response": response} # Construction du graphe graph_builder = StateGraph(GraphState) graph_builder.add_node("retrieve", retrieve_combined) graph_builder.add_node("generate", generate_response) graph_builder.add_node("post_process", post_process_response) graph_builder.set_entry_point("retrieve") graph_builder.add_edge("retrieve", "generate") graph_builder.add_edge("generate", "post_process") graph_builder.add_edge("post_process", END) agent = graph_builder.compile()