diff --git a/AgentReact/agent.py b/AgentReact/agent.py index 86b28ff..c6479e4 100644 --- a/AgentReact/agent.py +++ b/AgentReact/agent.py @@ -22,21 +22,28 @@ def getGraph()->CompiledStateGraph: workflow.add_node(inject_preparation_prompt) workflow.add_node("tool_node", tool_node)# BasicToolNode(tools=getTools())) # N'est pas une fonction, mais une classe instanciée, je dois précisier le nom du node workflow.add_node("weekly_report_tools", weekly_report_tools) + workflow.add_node(context_shortener) # Réduit la taille du contexte + workflow.add_node("context_shortener_2", context_shortener) # Le même, sous un autre nom pour le différencier dans le graphe # Arrêtes workflow.set_conditional_entry_point(is_resumes_reports_already_initialised, { - "résumés non disponibles": "inject_preparation_prompt", - "résumés déjà générés": "user_prompt" + "résumés non disponibles": "inject_preparation_prompt", # Résumés non générés + "résumés déjà générés": "user_prompt" # Résumés déjà prêts, je peux aller direct à la partie principale }) workflow.add_edge("inject_preparation_prompt", "preparation_docs") workflow.add_conditional_edges("preparation_docs", should_continue, { "tools":"weekly_report_tools", - "no_tools":"user_prompt" + "no_tools":"context_shortener" # FIN de la préparation, on réduit le contexte avant de passer à la suite }) + workflow.add_edge("context_shortener", "user_prompt") # Et ici, je rejoins la partie principale qui rédigera le rapport workflow.add_edge("user_prompt", "LLM_central") workflow.add_edge("weekly_report_tools", "preparation_docs") - workflow.add_edge("tool_node", "LLM_central") + workflow.add_conditional_edges("tool_node", should_shorten, { + 'sous la limite': "LLM_central", + 'réduire contexte': "context_shortener_2" + }) + workflow.add_edge("context_shortener_2", "LLM_central") workflow.add_conditional_edges("LLM_central", should_continue, { "tools":"tool_node", "no_tools":END diff --git a/AgentReact/utils/nodes.py b/AgentReact/utils/nodes.py index 0d1bb23..76c50cd 100644 --- a/AgentReact/utils/nodes.py +++ b/AgentReact/utils/nodes.py @@ -3,11 +3,12 @@ from langgraph.graph import MessagesState from langgraph.prebuilt import ToolNode from langchain.chat_models import init_chat_model from langgraph.graph import START, END -from langchain.messages import HumanMessage, AIMessage, SystemMessage +from langchain.messages import HumanMessage, AIMessage, SystemMessage, ToolMessage from langgraph.types import interrupt import os import sys from pathlib import Path +import json from .tools import getTools, getWeeklyReportTools from .state import CustomState @@ -66,6 +67,30 @@ def LLM_central(state: MessagesState): # Appel du LLM return {"messages": [model.invoke(state["messages"])]} +def context_shortener(state: CustomState): + """ Noeud visant à réduire la taille du contexte pour éviter une explosion de la taille de la mémoire court-terme/contexte """ + raise NotImplementedError('TODO, faut que je le fasse') + +# fonction de routage +def should_shorten(state: CustomState)->str: + """ + Fonction de routage, permet de savoir s'il est temps de résumer la contexte de la conversation + + Args: + state (CustomState): Le State actuel + + Returns: + str: Faut-il réduire le contexte ? + """ + TAILLE_CONTEXTE_MAX = 20000 #charactères + count = 0 + for msg in state['messages']: count += len(msg.content) # Compter le nombre total de caractères dans le contexte + + if count < TAILLE_CONTEXTE_MAX: + # OK + return 'sous la limite' + return 'réduire contexte' + # fonction de routage : Après reponse_question, si le LLM veut appeler un outil, on va au tool_node def should_continue(state: MessagesState): """ @@ -82,21 +107,6 @@ def should_continue(state: MessagesState): return "tools" return "no_tools" -def task_ended(state: MessagesState): - """ - Vérifier si l'agent a terminé son cycle, ou s'il faut le relancer - """ - if isinstance(state, list): - ai_message = state[-1] - elif messages := state.get("messages", []): - ai_message = messages[-1] - else: - raise ValueError(f"No messages found in input state to tool_edge: {state}") - - if "terminé" in ai_message.content.lower(): - return END - return "continue" - weekly_report_tools = ToolNode(tools=getWeeklyReportTools()) tool_node = ToolNode(tools=getTools()) @@ -127,8 +137,7 @@ class BasicToolNode: # De mon ancien projet, https://github.com/LJ5O/Assistant/b ) return {"messages": outputs} -# UTILS - +# fonction de routage def is_resumes_reports_already_initialised(state: CustomState)->str: """Permet de savoirr si les résumés de comptes-rendu ont déjà été générés. S'ils le sont, inutile de recréer ce dossier. diff --git a/imgs/agent.png b/imgs/agent.png index d4c44c0..804d7f1 100644 Binary files a/imgs/agent.png and b/imgs/agent.png differ diff --git a/roadmap.md b/roadmap.md index 48fefee..f5ce0d4 100644 --- a/roadmap.md +++ b/roadmap.md @@ -22,6 +22,7 @@ ## Amélioration de l'agent - [ ] Cross-encoding sur la sortie du **RAG** - [ ] Sauvegarde de l'état de l'agent +- [ ] Lecture d'un `skills.md` - [ ] Système de redémarrage après un arrêt - [ ] Détection de *prompt injection* - [ ] Génération d'un PDF en sortie du système