Amazon Bedrockで生成されるSQLを修正・制御する方法について最適なアプローチを解説します。
Bedrockが直接データベースに対してアドホックにSQLを自動生成して実行する、という動きはしません。 むしろ、開発者であるあなたがSQLを完全にコントロールできる、より安全で高性能なアーキテクチャを採用しており、その中核となるのが Agents for Amazon Bedrock と AWS 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"
}
}
}
}
}
}
}
}
}
}
}
このsummary
やdescription
の内容を元に、Agentは「今年の薬利用者は?」と聞かれた際に、このAPI(Lambda関数)を呼び出すべきだと判断します。
ステップ3:修正とデプロイ
SQLのロジック(例えば、対象期間を「今年」から「先月」に変えたいなど)を変更したい場合は、Lambda関数のコード内のsql
変数を直接修正し、AWSに再度デプロイするだけです。Agentの設定を変更する必要はありません。
このアーキテクチャのメリット
一見、手間がかかるように見えるかもしれませんが、このLambdaを挟むアーキテクチャには計り知れないメリットがあります。
- セキュリティと統制:
- LLMが予期せぬSQL(例:
DROP TABLE
など)を生成するリスクを完全に排除できます。 - 実行されるSQLはあなたが許可したものに限定されるため、SQLインジェクションなどの攻撃を防げます。
- LambdaのIAMロールでデータベースへのアクセス権限を厳密に管理できます。
- LLMが予期せぬSQL(例:
- パフォーマンス:
- 前回ご提案したような、インデックスが効く最適なSQLをあらかじめ記述しておくことができます。LLMがその場で生成するSQLは、必ずしもパフォーマンスが最適とは限りません。
- 保守性と拡張性:
- SQLのロジックはLambdaのコードとしてバージョン管理できます。
- 単にSQLを実行するだけでなく、結果を加工したり、別のAPIを呼び出したりといった複雑な処理をLambda内に追加することも容易です。
コメント