[AWS]Bedrockで生成されるSQLを修正・制御する方法

AI

Amazon Bedrockで生成されるSQLを修正・制御する方法について最適なアプローチを解説します。

Bedrockが直接データベースに対してアドホックにSQLを自動生成して実行する、という動きはしません。 むしろ、開発者であるあなたがSQLを完全にコントロールできる、より安全で高性能なアーキテクチャを採用しており、その中核となるのが Agents for Amazon BedrockAWS Lambda の連携です。

BedrockにおけるSQL実行の仕組み

Bedrockで「今年の薬の利用者は何人?」のような自然言語の質問からSQLを実行する際の、正しい処理フローは以下のようになります。

[ユーザーの質問]
      ↓
[1. Agents for Amazon Bedrock]  (ユーザーの意図を解釈)
      ↓
[2. Tool (AWS Lambda関数) の呼び出し] (意図に合った道具を選択)
      ↓
[3. Lambda関数内でSQLを実行]    (★ここであなたがSQLを定義・修正する)
      ↓
[4. データベース (PostgreSQLなど)] (クエリ結果をLambdaに返す)
      ↓
[5. LambdaからAgentへ結果を返す]
      ↓
[6. Agentが結果を自然言語に変換してユーザーに回答]

ご覧の通り、SQLそのものはステップ3のAWS Lambda関数の中に、あなたが書いたコードとして存在します。 BedrockのAgentは、ユーザーの意図を汲み取って適切なLambda関数を呼び出す「司令塔」の役割を果たします。


SQLを修正・管理する具体的な手順

Bedrockで利用するSQLを修正したい場合、以下の手順でLambda関数を修正・デプロイすることになります。

ステップ1:Lambda関数内でSQLを定義する

まず、実行したいSQLをLambda関数の中に記述します。言語はPythonやNode.jsなどが使えます。

(例) Python (boto3) を使ったLambda関数のサンプルコード

Python

import json
import psycopg2 # PostgreSQLに接続するためのライブラリ

# DB接続情報はAWS Secrets Managerで管理することを強く推奨
DB_HOST = "your_db_host"
DB_NAME = "your_db_name"
DB_USER = "your_db_user"
DB_PASSWORD = "your_db_password"

def lambda_handler(event, context):
    """
    今年の薬の受け取りサービス利用者数を取得する関数
    """
    
    # ★★★ ここがあなたが修正・管理するSQLです ★★★
    sql = """
        SELECT COUNT(DISTINCT user_no) as user_count
        FROM user_tbl
        WHERE 
            (user_flg = '1' OR user_match_flg = '1')
        AND status = '0'
    """
    
    conn = None
    try:
        # データベースに接続
        conn = psycopg2.connect(host=DB_HOST, database=DB_NAME, user=DB_USER, password=DB_PASSWORD)
        cur = conn.cursor()
        
        # SQLを実行
        cur.execute(sql)
        result = cur.fetchone()
        user_count = result[0] if result else 0
        
        cur.close()
        
        # Agentが解釈できる形式で結果を返す
        return {
            'statusCode': 200,
            'body': json.dumps({'user_count': user_count})
        }

    except Exception as e:
        # エラーハンドリング
        print(f"Error: {e}")
        raise e
    finally:
        if conn is not None:
            conn.close()

ステップ2:AgentにToolとしてLambdaを登録する

作成したLambda関数を、Agentが呼び出せるように「Tool」として設定します。この際、どのような自然言語の指示があったらこのLambdaを呼び出すべきかを定義したOpenAPIスキーマを用意します。

(例) OpenAPIスキーマ (JSON形式)

JSON

{
  "openapi": "3.0.0",
  "info": {
    "title": "Service User Counter",
    "version": "1.0.0",
    "description": "API to get the number of service users."
  },
  "paths": {
    "/get-user-count": {
      "get": {
        "summary": "今年の有給休暇を取得回数が多い順に上位10件並べてください",
        "description": "現在有効な社員から、今年の有給休暇申請を行った申請回数ををデータベースから取得します。",
        "operationId": "getUserCount",
        "responses": {
          "200": {
            "description": "有給休暇利用者数を返します",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user_count": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

このsummarydescriptionの内容を元に、Agentは「今年の薬利用者は?」と聞かれた際に、このAPI(Lambda関数)を呼び出すべきだと判断します。

ステップ3:修正とデプロイ

SQLのロジック(例えば、対象期間を「今年」から「先月」に変えたいなど)を変更したい場合は、Lambda関数のコード内のsql変数を直接修正し、AWSに再度デプロイするだけです。Agentの設定を変更する必要はありません。

このアーキテクチャのメリット

一見、手間がかかるように見えるかもしれませんが、このLambdaを挟むアーキテクチャには計り知れないメリットがあります。

  1. セキュリティと統制:
    • LLMが予期せぬSQL(例: DROP TABLEなど)を生成するリスクを完全に排除できます。
    • 実行されるSQLはあなたが許可したものに限定されるため、SQLインジェクションなどの攻撃を防げます。
    • LambdaのIAMロールでデータベースへのアクセス権限を厳密に管理できます。
  2. パフォーマンス:
    • 前回ご提案したような、インデックスが効く最適なSQLをあらかじめ記述しておくことができます。LLMがその場で生成するSQLは、必ずしもパフォーマンスが最適とは限りません。
  3. 保守性と拡張性:
    • SQLのロジックはLambdaのコードとしてバージョン管理できます。
    • 単にSQLを実行するだけでなく、結果を加工したり、別のAPIを呼び出したりといった複雑な処理をLambda内に追加することも容易です。

コメント

タイトルとURLをコピーしました