File size: 3,147 Bytes
f810b2f
 
 
 
 
 
 
 
 
 
66febf2
f810b2f
 
66febf2
f810b2f
 
 
 
 
 
 
 
 
66febf2
 
 
 
f810b2f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66febf2
f810b2f
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
from typing import TypedDict, Annotated, List, Dict, Any
from langgraph.graph.message import add_messages
from langchain_core.messages import AnyMessage, SystemMessage
from langgraph.prebuilt import ToolNode
from langgraph.graph import START, StateGraph
from langgraph.prebuilt import tools_condition
from langchain_openai import ChatOpenAI
from langchain.tools import Tool

from utils.logger import log_info, log_warn, log_error, log_debug
from pathlib import Path

class RestaurantAgent:
    def __init__(self, llm: ChatOpenAI, tools: List[Tool]):
        """
        Inicializa el agente del restaurante con LangGraph.
        
        Args:
            llm: Modelo de lenguaje a utilizar
            tools: Lista de herramientas para el agente
        """
        self.tools = tools
        
        # System Prompt mejorado
        prompt_path = Path("data/system_prompt.txt")
        log_debug(f"Loading system prompt from {prompt_path}")
        self.system_prompt = prompt_path.read_text(encoding="utf-8")

        # Configurar el LLM con las herramientas
        self.llm_with_tools = llm.bind_tools(tools=tools)
        
        # Construir el grafo
        self.graph = self._build_graph()

    def _build_graph(self) -> StateGraph:
        """Construye el grafo de estados del agente."""
        
        # Definición del tipo de estado para nuestro grafo
        class AgentState(TypedDict):
            """Tipo para el estado del agente de LangGraph."""
            messages: Annotated[list[AnyMessage], add_messages]

        # Nodo para el asistente que invoca al LLM
        def assistant(state: AgentState):
            """Procesa los mensajes usando el LLM y devuelve una respuesta."""
            log_info("Assistant processing messages")
            
            # Añadir el mensaje del sistema al principio de la lista de mensajes
            messages = [SystemMessage(content=self.system_prompt)] + state["messages"]
            
            return {
                "messages": [self.llm_with_tools.invoke(messages)],
            }

        # Crear el grafo con una estructura mucho más simple
        builder = StateGraph(AgentState)

        # Definir nodos: el asistente y el nodo para herramientas
        builder.add_node("assistant", assistant)
        builder.add_node("tools", ToolNode(self.tools))

        # Definir bordes con enrutamiento condicional automático
        builder.add_edge(START, "assistant")
        builder.add_conditional_edges(
            "assistant",
            # Si el último mensaje requiere una herramienta, enrutar a "tools"
            # De lo contrario, terminar el flujo y devolver la respuesta
            tools_condition,
        )
        builder.add_edge("tools", "assistant")

        # Compilar y retornar el grafo
        return builder.compile()

    def invoke(self, messages: List[AnyMessage]) -> Dict[str, Any]:
        """
        Procesa la consulta del usuario y genera una respuesta usando el grafo LangGraph.
        """
        log_info(f"Processing query with Casa Pepe agent: {len(messages)} messages")

        return self.graph.invoke({"messages": messages})