自然言語でSQLを生成する仕組みを実装してみた - 100行のSQL生成までの道のり
自然言語でSQLを生成する仕組みを実装してみた - 100行のSQL生成までの道のり
はじめに
「自然言語をinputとし、そのinputを解釈してSQLを動的に生成する」—— LangChain SQL Database Agentを初めて触った時の感動は今でも忘れられません。テーブル名を指定せずとも意図したテーブルを検索し、「似たような目的を持つレコードは?」という曖昧な質問にも、勝手に単語単位に区切ってlike検索する賢さに驚きました。
しかし、エンタープライズ環境での実装は想像以上に困難でした。特に「営業の田中さんからの問い合わせだからこのSQL」といった、ユーザーコンテキストを理解した上でのSQL生成は、技術的にも運用的にも大きな挑戦となりました。
なぜSQL生成が難しいのか
課題1: 長文SQLでの省略・文字化け問題
100行を超えるSQLを生成しようとすると、LLMの出力が途中で省略されたり、文字化けが発生したりします。これはトークン数の制限や、モデルの学習データに起因する問題で、単純にプロンプトを調整するだけでは解決できません。
課題2: テーブル情報・ドキュメントのセキュリティ制約
企業のデータベースでは、テーブル構造やカラム情報を外部に持ち出せないことが多く、LLMに十分なコンテキストを提供できません。「このテーブルの○○カラムは実は△△を意味する」といった暗黙知が共有できないのです。
課題3: カラム名が記号化されている環境
実際の環境では「col22」が「items」を意味するなど、カラム名が記号化されているケースが多々あります。AIがカラム名から意味を推測することができず、精度が著しく低下します。
課題4: ユーザーコンテキストの理解
「新宿駅のデータを取得して」と言われた時、それはJR新宿駅なのか、メトロ新宿駅なのか、それとも新宿三丁目駅なのか。ユーザーの所属部署や過去の問い合わせ履歴を考慮しなければ、適切なSQLは生成できません。
変数置換の2つの戦略
Pythonによる単純置換
日付や数値など、明確な値の置換に使用します。特に日付処理では自動変換機能を実装:
# ユーザー入力: "202401のデータ"
# 自動変換: YYYYMM形式を認識し、現在日付との差分を計算
"登録年月 = to_char(add_months(sysdate,-XXX),'YYYYMM')"
↓
"登録年月 = to_char(add_months(sysdate,-12),'YYYYMM')"
LLMを使った柔軟な置換
「関東地方のデータ」といった曖昧な条件を、適切なWHERE句に変換します。LLMがコンテキストを理解し、「東京都、神奈川県、埼玉県...」といった具体的な条件に展開します。
実装時の工夫
リトライ機構とエラーハンドリング
SQL生成は一発で成功することは稀です。最大10回のリトライ機構を実装し、エラー内容に応じてプロンプトを自動修正します。
for retry in range(10):
try:
response = await generate_sql(prompt)
if validate_sql(response):
break
except Exception as e:
prompt = modify_prompt_based_on_error(prompt, e)
プログレスバー表示
複数のSQLパーツを組み合わせる過程をリアルタイムで表示。ユーザーは処理の進捗を把握でき、長時間の処理でも安心して待つことができます。
チャット機能による対話的修正
生成されたSQLに対して「GROUP BY句を追加して」といった修正要望に対応。コンテキストを保持したまま、段階的に理想のSQLに近づけていきます。
セキュリティ対策
SQLインジェクション対策として、すべての変数値を検証し、プレースホルダー方式で安全に置換。ユーザー入力は適切にエスケープ処理されます。
実際の成果と限界
このアプローチにより、100行程度のSQLなら安定して生成できるようになりました。しかし、それ以上の複雑なSQLでは依然として精度の問題が残ります。
重要なのは、顧客との期待値調整です。「どこまでなら自動生成できるか」を明確に伝え、複雑なSQLは段階的に構築していくという運用ルールを設けることで、実用的なシステムとして機能させることができました。
まとめと今後の展望
SQL生成の精度向上には、以下の取り組みが必要です:
- ドキュメント整備とエージェント化: テーブル情報を構造化し、必要に応じて参照できる仕組み
- AI自体の精度向上: より長いコンテキストを扱えるモデルの登場を待つ
- ユーザーリテラシーの向上: 曖昧な要求を具体化するための対話インターフェース
「営業の田中さんの問い合わせ」を適切なSQLに変換する——この一見シンプルな要求の裏には、技術的な課題と人間的なコンテキストの理解という、AI実装の本質的な難しさが潜んでいます。
しかし、だからこそ面白い。テクノロジーと人間の知識を組み合わせることで、より良いソリューションを生み出せる。そんな可能性を、SQL生成という具体的な課題を通じて実感しています。
Discussion