Interroger votre base de données en langage naturel

Cette page décrit une version Preview disponible avec AlloyDB Omni qui vous permet d'essayer d'interroger votre base de données à l'aide du langage naturel.

Présentation

Vous pouvez utiliser AlloyDB Omni pour prévisualiser un ensemble de fonctionnalités expérimentales qui permettent à votre application basée sur une base de données d'exécuter plus de manière sécurisée les requêtes en langage naturel des utilisateurs de votre application, telles que "Où se trouve mon colis ?" ou "Qui est le meilleur vendeur de chaque service ?" AlloyDB Omni traduit l'entrée en langage naturel en une requête SQL spécifique à votre base de données, en limitant les résultats uniquement à ce que l'utilisateur de votre application est autorisé à afficher.

Puissance et risques des requêtes en langage naturel

Les grands modèles de langage, tels que Gemini Pro, peuvent permettre à votre application d'exécuter des requêtes de base de données basées sur des requêtes en langage naturel créées par les utilisateurs finaux de votre application. Par exemple, un modèle ayant accès au schéma de base de données de votre application peut accepter les entrées de l'utilisateur final comme suit:

What are the cheapest direct flights from Boston to Denver in July?

et la traduire en requête SQL comme suit:

SELECT flight.id, flight.price, carrier.name, [...]
FROM [...]
WHERE [...]
ORDER BY flight.price ASC 
LIMIT 10

Les requêtes en langage naturel peuvent fournir à votre application un outil puissant pour répondre aux besoins de vos utilisateurs. Toutefois, cette technologie présente également des risques de sécurité évidents que vous devez prendre en compte avant d'autoriser les utilisateurs finaux à exécuter des requêtes arbitraires sur vos tables de base de données. Même si vous avez configuré votre application pour qu'elle se connecte à votre base de données en tant qu'utilisateur de base de données en lecture seule à accès limité, une application qui invite à effectuer des requêtes en langage naturel peut être vulnérable aux attaques suivantes:

  • Les utilisateurs malveillants peuvent lancer des attaques par injection de requêtes, en essayant de manipuler le modèle sous-jacent pour révéler toutes les données auxquelles l'application a accès.
  • Le modèle lui-même peut générer des requêtes SQL plus larges que nécessaire, révélant des données sensibles en réponse à des requêtes utilisateur, même bien intentionnées.

Nettoyer les requêtes avec des vues sécurisées paramétrées

Pour aider à atténuer les risques décrits dans la section précédente, Google a développé des vues sécurisées paramétrées, une fonctionnalité expérimentale que vous pouvez prévisualiser à l'aide des techniques décrites sur cette page.

Les vues sécurisées paramétrées vous permettent de définir explicitement les tables et les colonnes à partir desquelles les requêtes en langage naturel peuvent extraire des données, et d'ajouter des restrictions supplémentaires sur la plage de lignes disponibles pour un utilisateur d'application individuel. Ces restrictions vous permettent de contrôler étroitement les données que les utilisateurs de votre application peuvent voir via des requêtes en langage naturel, quelle que soit la formulation de ces requêtes.

Si vous activez cette version Preview, vous avez accès aux extensions expérimentales développées par Google appelées alloydb_ai_nl et parameterized_views.

L'extension parameterized_views fournit les fonctionnalités suivantes:

  • Vues sécurisées paramétrées, variante des vues SQL permettant de limiter la plage de données auxquelles une requête peut accéder.
  • La fonction execute_parameterized_views(), qui vous permet d'interroger vos vues sécurisées paramétrées.

L'extension alloydb_ai_nl fournit les fonctionnalités suivantes:

  • La fonction google_get_sql_current_schema(), qui convertit les requêtes en langage naturel en requêtes SQL de tables et de vues dans votre schéma actuel.

Les sections suivantes décrivent comment utiliser ces fonctionnalités et comment elles peuvent fonctionner ensemble.

Avant de commencer

Installez AlloyDB Omni version 15.5.1 ou ultérieure, y compris l'intégration du modèle d'IA. Pour en savoir plus, consultez Installer AlloyDB Omni avec l'IA AlloyDB pour PostgreSQL.

Configurer votre base de données pour les vues sécurisées paramétrées

  1. Connectez-vous à votre cluster AlloyDB Omni à l'aide de psql.

  2. Modifiez le contenu de /var/alloydb/config/postgresql.conf afin que la valeur de la directive shared_preload_libraries inclue alloydb_ai_nl et parameterized_views. La directive modifiée doit ressembler à ce qui suit:

    shared_preload_libraries='g_stats,google_job_scheduler,google_insights,pg_stat_statements,google_db_advisor,google_columnar_engine,alloydb_ai_nl,parameterized_views'
    
  3. Arrêtez AlloyDB Omni.

  4. Démarrez AlloyDB Omni.

  5. Activez les extensions alloydb_ai_nl et parameterized_views:

    CREATE EXTENSION google_ml_integration;
    ALTER SYSTEM SET google_ml_integration.enable_model_support=on;
    ALTER SYSTEM SET alloydb_ai_nl.enabled=on;
    ALTER SYSTEM SET parameterized_views.enabled=on;
    SELECT pg_reload_conf();
    CREATE EXTENSION alloydb_ai_nl CASCADE;
    CREATE EXTENSION parameterized_views;
    
  6. Enregistrez un nouveau modèle de langage basé sur l'API Gemini Pro avec la gestion des points de terminaison de modèle:

    CALL google_ml.create_model(
        model_id => 'MODEL_ID',
        model_request_url => 'https://us-central1-aiplatform.googleapis.com/v1/projects/PROJECT_ID/locations/us-central1/publishers/google/models/gemini-pro:streamGenerateContent',
        model_provider => 'google',
        model_auth_type => 'alloydb_service_agent_iam');
    

    Remplacez les éléments suivants :

  7. Créez un utilisateur de base de données. Ne lui accordez pas encore d'autorisations ni de rôles. Une étape ultérieure de cette procédure accorde à l'utilisateur les autorisations dont il a besoin.

Vues sécurisées paramétrées

Une vue sécurisée paramétrée fonctionne beaucoup comme une vue sécurisée PostgreSQL ordinaire: une instruction SELECT stockée, essentiellement. Les vues sécurisées paramétrées vous permettent également d'exiger une ou plusieurs valeurs de paramètre nommées transmises à la vue lors de la requête, un peu comme les variables de liaison avec les requêtes de base de données ordinaires.

Par exemple, imaginez exécuter une application dont la base de données suit les expéditions d'articles aux clients. Un utilisateur s'est connecté à cette application avec l'ID des types 12345 dans la requête Where is my package?. En utilisant des vues sécurisées paramétrées, vous pouvez vous assurer que les exigences suivantes s'appliquent à la manière dont AlloyDB pour PostgreSQL exécute cette requête:

  • La requête ne peut lire que les colonnes de base de données que vous avez explicitement listées dans les vues sécurisées paramétrées de votre base de données. Dans ce cas, il peut s'agir de certaines colonnes de vos tables items, users et shipments.
  • La requête ne peut lire que les lignes de base de données associées à l'utilisateur à l'origine de la requête. Dans ce cas, il peut être nécessaire que les lignes renvoyées aient une relation de données avec la ligne de table users dont la valeur de la colonne id est 12345.

Créer une vue sécurisée paramétrée

Pour créer une vue sécurisée paramétrée, utilisez la commande DDL CREATE VIEW PostgreSQL avec les attributs suivants:

  • Créez la vue avec l'option security_barrier.
  • Pour limiter les utilisateurs de l'application à n'afficher que les lignes qu'ils sont autorisés à voir, ajoutez les paramètres requis à l'aide de la syntaxe $@PARAMETER_NAME dans la clause WHERE. Un cas d'utilisation courant consiste à vérifier la valeur d'une colonne à l'aide de WHERE COLUMN = $@PARAMETER_NAME.

L'exemple de vue sécurisée paramétrée suivant permet d'accéder à trois colonnes d'une table nommée users et limite les résultats uniquement aux lignes où users.id correspond à un paramètre obligatoire:

CREATE VIEW user_psv WITH (security_barrier) AS 
SELECT 
  username,
  full_name,
  birthday
FROM 
  users
WHERE 
  users.id = $@user_id; 

Les instructions SELECT au cœur des vues sécurisées paramétrées peuvent être aussi complexes que les instructions autorisées par les vues PostgreSQL ordinaires.

Une fois la vue créée, vous devez accorder à l'utilisateur que vous avez créé précédemment l'autorisation d'exécuter des requêtes SELECT sur la vue:

GRANT SELECT ON VIEW_NAME TO NL_DB_USER;

Remplacez les éléments suivants :

  • VIEW_NAME: nom de la vue que vous avez créée à l'étape précédente.
  • NL_DB_USER: nom de l'utilisateur de la base de données que vous avez désigné pour exécuter des requêtes en langage naturel.

Interroger une vue sécurisée paramétrée

Malgré leur similitude avec les vues PostgreSQL ordinaires, vous ne pouvez pas interroger directement les vues sécurisées paramétrées. À la place, utilisez la fonction execute_parameterized_query() fournie par l'extension parameterized_views. La fonction a la syntaxe suivante:

SELECT * FROM
parameterized_views.execute_parameterized_query(
    query => SQL_QUERY
    param_names => ARRAY [PARAMETER_NAMES],
    param_values => ARRAY [PARAMETER_VALUES]
)

Remplacez les éléments suivants :

  • SQL_QUERY: requête SQL dont la clause FROM fait référence à une ou plusieurs vues sécurisées paramétrées.
  • PARAMETER_NAMES: liste des noms de paramètres à transmettre, sous forme de chaînes.
  • PARAMETER_VALUES: liste des valeurs de paramètre à transmettre. Cette liste doit être de la même taille que la liste param_names. L'ordre des valeurs correspond à l'ordre des noms.

La fonction renvoie un tableau d'objets JSON. Chaque ligne du tableau est équivalente à la valeur row_to_json() de la ligne de résultat de la requête d'origine.

En utilisation normale, la valeur de l'argument query n'est pas générée par votre propre code, mais par un modèle d'IA avec lequel vous avez intégré votre base de données AlloyDB pour PostgreSQL.

L'exemple suivant montre comment interroger une vue sécurisée paramétrée en Python, puis afficher ses résultats. Il s'appuie sur l'exemple de vue user_psv de la section précédente:

# Assume a get_user_id() function that returns the ID of the current
# application user.
app_user_id = get_user_id()

pool = await asyncpg.create_pool(
    host=INSTANCE_IP
    user=NL_DB_USER
    password=NL_DB_PASSWORD
    database=DB_NAME
)

table_name = "user_psv"

query = f"""
    SELECT 
      full_name,
      birthday
    FROM 
      {table_name} 
"""
params = {
    "user_id": app_user_id
}

param_query = f"""
SELECT * FROM parameterized_views.execute_parameterized_query(
  query => '{query}',
  param_names => $1,
  param_values => $2
);
"""

sql_results = await pool.execute(
    param_query, 
    params.keys(), 
    params.values()
)

for row in sql_results:
    print(json.loads(row))

Exécuter une requête en langage naturel

L'exécution d'une requête en langage naturel à l'aide de vues sécurisées paramétrées se déroule en deux étapes:

  1. En tant qu'utilisateur de la base de données disposant uniquement d'un accès SELECT aux vues sécurisées paramétrées appropriées, convertissez la requête en langage naturel en SQL à l'aide d'un grand modèle de langage.
  2. Utilisez la fonction execute_parameterized_query() pour traiter le code SQL, en le liant aux valeurs de paramètre appropriées à la session utilisateur actuelle.

Les sections suivantes décrivent ces étapes plus en détail.

Convertir du langage naturel en SQL

Pour traduire une entrée en langage naturel en SQL, utilisez la fonction google_get_sql_current_schema() incluse dans la version preview de la technologie de vues sécurisées paramétrées:

SELECT alloydb_ai_nl.google_get_sql_current_schema(
  sql_text => 'NL_TEXT',
  model_id => 'MODEL_ID',
  prompt_text => 'HINT_TEXT'
);

Remplacez les éléments suivants :

  • NL_TEXT: texte en langage naturel à convertir en requête SQL.
  • MODEL_ID: ID du modèle que vous avez enregistré auprès du catalogue de modèles lorsque vous avez configuré votre base de données pour les vues sécurisées paramétrées.
  • HINT_TEXT: informations supplémentaires sur le schéma de la base de données, exprimées en langage naturel. Vous pouvez ainsi fournir au modèle des indices supplémentaires sur les aspects importants du schéma qu'il ne pourrait pas extraire uniquement en analysant les structures de table, de colonne et de relation. Exemple: When joining flights and seats, be sure to join on flights.id = seats.flight_id.

La sortie de la fonction est une chaîne contenant une requête SQL.

Exécuter le code SQL converti à l'aide de paramètres

Après avoir converti la requête en langage naturel en SQL, vous pouvez appeler execute_parameterized_views() comme décrit plus haut sur cette page, en transmettant tous les paramètres dont vos vues sécurisées paramétrées peuvent avoir besoin.

La fonction fonctionne si vous lui transmettez plus de paramètres qu'elle n'en a besoin avec une requête donnée. Vous pouvez donc l'appeler avec tous les paramètres utilisés par toutes les vues sécurisées paramétrées pour lesquelles votre application a des valeurs. La fonction génère une exception si elle tente d'exécuter une requête nécessitant un paramètre non défini.

Exemple d'exécution d'une requête en langage naturel

Cette section présente un flux complet de l'entrée en langage naturel au jeu de résultats SQL. Les exemples de code montrent les requêtes et fonctions SQL sous-jacentes exécutées par une application.

Pour cet exemple de flux, supposons ce qui suit concernant votre application:

  • Votre application basée sur une base de données suit les expéditions de produits aux clients.
  • Vous avez enregistré un modèle basé sur Gemini Pro nommé my-gemini-model dans le catalogue de modèles.
  • Vous avez défini une vue sécurisée paramétrée dans votre base de données nommée shipment_view.
    • La vue sélectionne les données de plusieurs tables pertinentes pour les envois aux clients.
    • La vue nécessite un paramètre user_id, dont la valeur est l'ID d'un utilisateur final de l'application.
  1. Un utilisateur final dont l'ID utilisateur de l'application est 12345 saisit "Où est mon colis ?" dans votre application Web.
  2. Votre application appelle google_get_sql_current_schema() pour traduire l'entrée en SQL:

    SELECT alloydb_ai_nl.google_get_sql_current_schema(
      sql_text => 'Where is my package?'
      model_id => 'my-gemini-model'
    );
    

    Cet appel renvoie une chaîne contenant une seule requête SELECT SQL. La requête n'est limitée qu'aux vues sécurisées paramétrées visibles par l'utilisateur de la base de données que vous avez créé pour travailler avec des vues sécurisées paramétrées.

    Le code SQL généré à partir de Where is my package? peut ressembler à ceci:

    SELECT current_location, ship_date, ship_eta FROM shipment_view;
    

    Étant donné que shipment_view est une vue sécurisée paramétrée et non une vue PostgreSQL ordinaire, votre application doit utiliser execute_parameterized_views() pour exécuter de manière sécurisée la requête avec le paramètre user_id dont elle a besoin, comme indiqué à l'étape suivante.

  3. Votre application transmet le code SQL à execute_parameterized_views(), ainsi que les paramètres qui limitent la sortie. Dans notre exemple, il s'agit de l'ID de l'utilisateur final de l'application qui a fourni l'entrée:

    SELECT * FROM
    parameterized_views.execute_parameterized_views(
        query => 'SELECT current_location, ship_date, ship_eta FROM shipment_view',
        param_names => ['user_id'],
        param_values => ['12345']
    );
    
    

    La sortie est un ensemble de résultats SQL, exprimé sous forme de données JSON.

  4. Votre application gère les données JSON selon les besoins.

Conception de bases de données pour la gestion du langage naturel

La fonction google_get_sql_current_schema() fournie avec cet aperçu de la technologie sert principalement à démontrer le fonctionnement des vues sécurisées paramétrées, ce qui vous permet de tester cette technologie en développement. Comme pour toute version Preview, vous ne devez pas appliquer cette fonction à une application en production.

Gardez cela à l'esprit lorsque vous appliquez les conseils de cette section pour améliorer la qualité de la sortie google_get_sql_current_schema() lors de vos tests.

Concevoir votre schéma pour la compréhension humaine

En général, attribuez à vos structures de base de données des noms et des commentaires suffisamment clairs pour permettre à un développeur humain typique d'inférer l'objectif de ses tables, colonnes et relations. Cette clarté peut aider un grand modèle de langage à générer des requêtes SQL plus précises en fonction de votre schéma.

Utiliser des noms descriptifs

Privilégiez des noms descriptifs pour les tables, les colonnes et les relations. Évitez les abréviations ou les acronymes. Par exemple, le modèle fonctionne mieux avec une table nommée users qu'avec une table nommée u.

Si vous ne pouvez pas renommer les structures de données existantes, fournissez des indices au modèle à l'aide de l'argument prompt_text lorsque vous appelez google_get_sql_current_schema().

Utiliser des types de données spécifiques

Le modèle peut effectuer de meilleures inférences sur vos données si vous utilisez des types de données plus spécifiques avec vos colonnes. Par exemple, si vous utilisez une colonne exclusivement pour stocker des valeurs "vrai" ou "faux", utilisez un type de données boolean avec true et false au lieu d'un integer avec 1 et 0.

Effectuer un rollback avec précaution après avoir activé l'aperçu

Si vous avez activé la version preview de la technologie des vues sécurisées paramétrées dans votre base de données, mais que vous décidez de revenir à une version antérieure à la version 15.5.0 d'AlloyDB Omni, vous devez effectuer quelques étapes de nettoyage manuel avant de rétrograder.

Si vous ne suivez pas ces étapes, toute tentative de requête, de modification ou de suppression d'une vue sécurisée paramétrée génère une erreur SQL. Cela inclut les requêtes sur le catalogue de vues de votre base de données qui incluraient autrement des vues sécurisées paramétrées dans leurs résultats, telles que SELECT * FROM pg_views.

Pour supprimer complètement cette version preview de la technologie de votre base de données avant un rollback AlloyDB Omni, procédez comme suit:

  1. Dans psql, utilisez la commande DROP VIEW pour supprimer chaque vue sécurisée paramétrée de votre base de données.

  2. Dans psql, utilisez la commande DROP EXTENSION pour désactiver les extensions alloydb_ai_nl et parameterized_views dans votre base de données.

  3. Dans votre fichier postgresql.conf, supprimez la référence à alloydb_ai_nl et parameterized_views de la directive shared_preload_libraries.

Pour en savoir plus sur la restauration de votre installation AlloyDB Omni, consultez la section Rétablir une mise à niveau.