Resumen

Escalar un sistema con múltiples nodos, prompts, RAGs y tools exige una organización clara. Aquí verás cómo refactorizar hacia una arquitectura modular en Landgraf para mejorar mantenimiento, visibilidad de la orquestación y crecimiento controlado, separando agente, estado, nodos, prompts y tools en carpetas consistentes.

¿Por qué reorganizar el código para escalar en Landgraf?

Una sola base de código en un archivo se vuelve frágil cuando crecen los nodos y las dependencias. La propuesta: convertir cada agente en una carpeta con subcarpetas por nodo y archivos específicos para estado, grafo, prompts y tools. Así:

  • Mantenibilidad: localizar y mejorar un nodo es inmediato.
  • Escalabilidad: añadir nodos no rompe la base existente.
  • Claridad: cada responsabilidad vive en su lugar: estado, grafo, nodo, prompt, tools.
  • Visibilidad: entender qué pasa con los nodos y la orquestación es más simple.

Conceptos clave integrados: agente y grafo del flujo, nodos con su propio large language model (LLM), system prompt, tools y manejo del estado del mensaje. También se menciona el uso de LangGraph UI para depurar y validar el flujo.

¿Cómo estructurar agentes, nodos y prompts para RAG?

La idea central: el agente “Support” deja de ser un archivo y pasa a ser una carpeta. Dentro, se separan el estado, el grafo y los nodos. Cada nodo tiene su propio prompt y, si aplica, sus tools.

¿Qué carpetas y archivos crear?

Estructura sugerida para “Support”:

agents/
  support/
    __init__.py
    state.py            # estado del mensaje.
    agent.py            # construcción del grafo del agente.
    nodos/
      extractor/
        __init__.py
        node.py         # lógica del nodo extractor.
        prompt.py       # system prompt del extractor.
      conversation/
        __init__.py
        node.py         # lógica del nodo conversation.
        prompt.py       # system prompt del conversation.
        tools.py        # tools ligadas a este nodo.

Puntos clave: - Cada nodo es una carpeta con su node.py, prompt.py y, si aplica, tools.py. - Los imports se corrigen para apuntar a paths claros: por ejemplo, al estado desde "agents.support.state". - Se evita crear carpetas innecesarias como “rutas” si aún no se usan.

¿Cómo separar prompts y tools por nodo?

  • Prompt por nodo: se define un archivo prompt.py por nodo con su system prompt declarado de forma explícita.
  • Tools por nodo: en conversation/tools.py se listan las tools y se exportan en un array para inyectarlas al LLM del nodo.

Ejemplo mínimo de prompt y combinación con historial del estado:

# extractor/prompt.py
SYSTEM_PROMPT = """
Tú eres un asistente que ayuda a extraer información dada una conversación.
"""

# extractor/node.py
from agents.support.state import message_state
from .prompt import SYSTEM_PROMPT

# history proviene del estado; se concatena al prompt del sistema.
def build_messages(history):
    return [SYSTEM_PROMPT] + history

Notas prácticas: - Se usa un system prompt claro para guiar el nodo extractor. - La concatenación del system prompt con el history puede requerir ajustarlo a tu API de mensajes: array de uno o tupla, según el formato que uses.

¿Cómo se construye el agente con el grafo?

  • agent.py importa el estado y cada nodo ya modularizado.
  • Cada nodo declara su propio LLM: por ejemplo, conversation con OpenAI para habilitar tools.
  • Se inyectan prompts y tools en el nodo correspondiente, manteniendo la configuración aislada.

Ejemplo mínimo del nodo conversation con tools:

# conversation/tools.py
# Define y exporta las tools de este nodo.
tools = [
    # ...instancias de tools específicas del nodo...
]

# conversation/node.py
from .tools import tools
from .prompt import SYSTEM_PROMPT

def configure_conversation_node(llm):
    llm_with_tools = llm.bind_tools(tools)
    # se inyecta el system prompt simple; la dinamización llegará después.
    return {"llm": llm_with_tools, "system_prompt": SYSTEM_PROMPT}

¿Qué prácticas aplicar para mantener y crecer el proyecto?

  • Un agente, una carpeta: facilita navegación y escalabilidad.
  • Estado centralizado: un state.py con el message state único.
  • Nodo autocontenido: cada nodo con su node.py, prompt.py y tools.py si aplica.
  • LLM por nodo: declarar en el nodo el large language model que usará.
  • Prompts declarativos: mantener el system prompt por archivo y por nodo.
  • Tools agrupadas: exportar un array de tools por nodo y enlazarlas al LLM.
  • Imports limpios: rutas explícitas evitan confusiones y errores.
  • Refactor incremental: trasladar estado, luego nodos, luego prompts y tools.
  • Prueba continua: validar en LangGraph UI y en el debugger que todo sigue funcionando.
  • Preparación para prompts dinámicos: dejar el system prompt simple ahora y planear la inyección de variables después.

Si te sirvió esta guía práctica de organización y refactor, cuéntame en comentarios qué nodo planeas modularizar primero y por qué.