| """Chat agent node producing replies using system + RAG contexts + history.""" |
| from typing import Callable, List |
|
|
| from langchain_core.messages import BaseMessage, SystemMessage, AIMessage |
| from langchain_core.language_models.chat_models import BaseChatModel |
|
|
| from graphs.state import AgentState |
| from graphs.prompts import SYSTEM_PROMPT_TEMPLATE |
|
|
|
|
| def chat_node(llm: BaseChatModel) -> Callable[[AgentState], AgentState]: |
| """Factory returning a node that generates a reply with RAG context.""" |
|
|
| def _run(state: AgentState) -> AgentState: |
| messages = list(state.get("messages", [])) |
| sys_msgs: List[BaseMessage] = [SystemMessage(content=SYSTEM_PROMPT_TEMPLATE)] |
|
|
| formation_context = state.get("formation_context", "") |
| prestation_context = state.get("prestation_context", "") |
| project_context = state.get("project_context", "") |
|
|
| |
| if project_context: |
| sys_msgs.append( |
| SystemMessage( |
| content=( |
| "CONTEXTE PROJET (extraits des documents du projet; n'utilise rien d'autre):\n\n" |
| f"{project_context}\n\n" |
| "Consignes projet: Ce contenu indique des informations complémentaires à prendre en compte pour répondre à la question. " |
| ) |
| ) |
| ) |
|
|
| if formation_context: |
| sys_msgs.append( |
| SystemMessage( |
| content=( |
| "CONTEXTE FORMATIONS (extraits du catalogue formations; n'utilise rien d'autre):\n\n" |
| f"{formation_context}\n\n" |
| "Consignes formations: Utilise exclusivement ce contexte pour recommander les formations. " |
| "Cite la page et la source pour chaque recommandation. " |
| "Une formation = un document." |
| ) |
| ) |
| ) |
|
|
| if prestation_context: |
| sys_msgs.append( |
| SystemMessage( |
| content=( |
| "CONTEXTE PRESTATIONS (extraits du catalogue services; n'utilise rien d'autre):\n\n" |
| f"{prestation_context}\n\n" |
| "Consignes prestations: Utilise exclusivement ce contexte pour recommander les prestations. " |
| "Cite la page et la source pour chaque recommandation. " |
| "Un document peut contenir plusieurs prestations." |
| ) |
| ) |
| ) |
|
|
| if state.get("voice_mode"): |
| sys_msgs.append(SystemMessage(content=( |
| "IMPORTANT - MODE VOCAL: Ta réponse sera lue à voix haute. " |
| "Réponds de manière concise et naturelle, comme dans une conversation orale. " |
| "N'utilise PAS de markdown, pas de listes à puces, pas de tableaux, pas de gras/italique. " |
| "Pas de numéros de page ni de références documentaires détaillées. " |
| "Limite ta réponse à quelques phrases claires et directes. " |
| "Si la question nécessite des détails, propose de les envoyer par écrit." |
| ))) |
|
|
| response = llm.invoke(sys_msgs + messages) |
| return {"messages": messages + [AIMessage(content=response.content)]} |
|
|
| return _run |
|
|
|
|
|
|