LangChain×ローカルLLMで試すText-to-SQL入門

「あのデータが見たいけど、SQLなんて書けない…」そんな悩みを抱えていませんか?日々増え続ける膨大なデータの中から必要な情報を引き出すスキルは、現代のビジネスにおいてますます重要になっています。しかし、専門知識であるSQLを誰もが習得するのは簡単ではありません。
そこで今、大きな注目を集めているのが「Text-to-SQL」という技術です。これは、私たちが普段使っている自然な言葉(例えば「先月の東京支社の売上トップ3は?」)を、データベースが理解できるSQLクエリに自動で翻訳する技術です。これにより、SQLの知識がないビジネスユーザーでも、チャット形式でデータベースと対話し、必要な情報を入手できるようになります。
この記事では、Text-to-SQLの基本的な仕組みから最新の動向、そして実際にローカル環境で大規模言語モデル(LLM)とLangChainを使ってText-to-SQLを試す具体的な方法までを分かりやすく解説します。
Text-to-SQL とは?
Text-to-SQLは、一朝一夕に現れた技術ではありません。その歴史は意外と古く、データベースとのより自然な対話を目指して、長年にわたり研究開発が続けられてきました。

初期のText-to-SQL
Text-to-SQLの探求は1970年代にまで遡ります。初期のシステムは、主にルールベースのアプローチに依存していました。これは、あらかじめ定義された文法ルールやテンプレートに基づいて、自然言語の質問をSQLクエリに変換するものです。例えば、1973年に開発された「LUNARシステム」は、月面から持ち帰られた岩石に関する質問に答えるために使われた初期の代表例です。これらのシステムは特定のドメインや単純な質問には有効でしたが、ルールの作成や保守に多大なコストがかかり、複雑な質問や多様なデータベースへの対応は困難でした。
その後、コンピューターの進化とともに、ニューラルネットワークを活用する試みが始まります。特に、自然言語処理の分野で成果を上げていたSequence-to-Sequence(seq2seq)モデルと注意機構(Attention Mechanism) を組み合わせたアプローチが登場しました。これは、入力された質問文全体(Sequence)を理解し、対応するSQLクエリ(Sequence)を生成するもので、ルールベースよりも柔軟な対応が可能になりました。「SQLNet」などのモデルは、このアプローチの代表例として知られています。
さらに、事前学習済み言語モデル(PLM: Pre-trained Language Models) の登場は、Text-to-SQLの精度を大きく向上させました。BERT(Bidirectional Encoder Representations from Transformers)に代表されるPLMは、大量のテキストデータで事前に言語の構造や意味を学習しているため、少ないデータでも高い汎化性能を発揮します。「BRIDGE」のようなモデルは、BERTを活用して質問とデータベーススキーマの関係性をより深く理解し、精度の高いSQL生成を実現しました。
そして、大規模言語モデル(LLM)の時代へ
そして今、大規模言語モデル(LLM: Large Language Models) の時代を迎えています。GPTシリーズ、Gemini、Llamaなど、従来のPLMをはるかに凌駕する規模のデータで学習されており、驚異的な自然言語理解能力と生成能力を備えています。このLLMの登場が、Text-to-SQLの世界に再び大きなブレークスルーをもたらしました。
LLMをText-to-SQLに活用する主なアプローチには、以下のようなものがあります。
- プロンプトエンジニアリング: LLMに対して、質問文と一緒にデータベースの構造(スキーマ情報)や、いくつかの質問とSQLのペア(例)を「プロンプト」として入力することで、SQLを生成させる方法です。特に、少数の例を与えるだけで高い性能を発揮する「In-Context Learning(文脈内学習)」や「Few-Shot プロンプティング」は、LLMの強力な能力を示すテクニックです。
- ファインチューニング: 特定のText-to-SQLデータセットでLLMを追加学習させることで、そのタスクへの特化と性能向上を図る方法です。
- エージェントベースのフレームワーク: LLMを思考エンジンとして、データベースとの対話、SQLの実行、結果の検証、必要に応じたSQLの修正といった複数のステップを自律的に行わせる、より高度なアプローチです。

Text-to-SQLの実践
さて、Text-to-SQLの概要を掴んだところで、いよいよ実際に手を動かしてみましょう。ここでは、比較的手軽に試せるローカル環境で、LLMを使ったText-to-SQLアプリケーションを構築する流れを紹介します。
なぜローカルLLM?
クラウドベースの強力なLLM APIも魅力的ですが、ローカル環境でLLMを動かすことには、以下のようなメリットがあります。
- プライバシー: 機密性の高いデータを扱う場合、データを外部に送信する必要がないため、セキュリティ面での安心感があります。
- コスト: API利用料を気にすることなく、納得いくまで試行錯誤できます。特に学習や実験段階では大きなメリットです。
- カスタマイズ性: モデルの選択やパラメータ調整など、より細やかな制御が可能です。
- オフライン利用: インターネット接続がない環境でも利用できる可能性があります(モデルやツールのセットアップ後)。
今回は、これらのメリットを活かして、ローカルPC上でText-to-SQLを試してみます。
使用する技術スタック
今回のText-to-SQLお試しアプリ作成にあたり、以下のPythonパッケージとそのバージョンを使用します(Pythonは3.13系を使用します)。
# requirements.txt
langchain-community==0.3.24
langchain-core==0.3.61
langchain-ollama==0.3.3
SQLAlchemy==2.0.41
streamlit==1.45.1
また、OllamaについてはローカルLLMとしてGemma 3を使用します。
$ ollama pull gemma3
データベースの準備
サンプルのデータベースして、Chinook Databaseを使用します。このデータベースは、音楽ストアを模したもので、アーティスト、アルバム、トラック、顧客、注文情報などを含み、SQLの学習やデータ分析の練習に利用されます。今回は、SQLite3用のものを使用します。
$ curl -L -o Chinook_Sqlite.sqlite https://github.com/lerocha/chinook-database/releases/download/v1.4.5/Chinook_Sqlite.sqlite

お試しアプリの実装
それでは、具体的なPythonコードを以下に掲載します。
import json import pandas as pd import streamlit as st from langchain_core.prompts import ChatPromptTemplate from langchain_ollama.llms import OllamaLLM from sqlalchemy import create_engine, inspect, text PROMT_TEMPLATE = """You are a SQL generator. When given a schema and a user question, you MUST output only the SQL statement—nothing else. No explanation is needed. Schema: {schema} User question: {query} Output (SQL only): """ def extract_schema(db_url: str) -> str: engine = create_engine(db_url) inspector = inspect(engine) schema = {} for table in inspector.get_table_names(): columns = inspector.get_columns(table) schema[table] = [{key: value for key, value in column.items() if key != "type"} for column in columns] return json.dumps(schema) def clean_text(text: str): cleaned_text = text.replace("```sql\n", "").replace("\n```", "") return cleaned_text.strip() def to_sql_query(query: str, schema: str, model_name: str = "gemma3") -> str: model = OllamaLLM(model=model_name) prompt = ChatPromptTemplate.from_template(PROMT_TEMPLATE) chain = prompt | model return clean_text(chain.invoke({"query": query, "schema": schema})) def run_sql(db_url: str, sql: str) -> pd.DataFrame: engine = create_engine(db_url) with engine.connect() as connection: result = connection.execute(text(sql)) # 結果をpandasのDataFrameに変換して表示 return pd.DataFrame(result.fetchall(), columns=list(result.keys())) def main(db_url: str, model_name: str) -> None: schema = extract_schema(db_url) st.title("Text-to-SQLお試しアプリ") query = st.text_area("データベースから取得するデータについて記述:") if query: st.divider() sql = to_sql_query(query, schema, model_name) st.text("生成されたSQL:") st.code(sql, wrap_lines=True, language="sql") st.text("SQLの実行決:") df = run_sql(db_url, sql) st.dataframe(df) if __name__ == "__main__": main( db_url="sqlite:///Chinook_Sqlite.sqlite", model_name="gemma3", )
以下、アプリの実行例となります。

実装の解説
- データベーススキーマの抽出 (
extract_schema
): LLMにSQLを正しく生成してもらうためには、対象となるデータベースの構造(どのテーブルにどんなカラムがあるかなど)を伝える必要があります。この関数では、SQLAlchemy
を使ってデータベースに接続し、テーブル名やカラム名の情報をJSON形式で抽出します。- LLMへの指示書 (プロンプトテンプレート:
PROMT_TEMPLATE
): LLMに期待通りの出力をさせるためには、「プロンプト」と呼ばれる指示文が非常に重要です。LangChain
のプロンプトテンプレート機能を使うと、この指示文を効率的に管理できます。- LLMによるSQL生成 (
to_sql_query
): この関数が、Text-to-SQLの心臓部です。ユーザーの質問とスキーマ情報をプロンプトテンプレートに当てはめ、Ollama経由でローカルのgemma3
モデルに送信し、SQLクエリを生成させます。- SQLの実行と結果取得 (
run_sql
): LLMが生成したSQLクエリを、実際にデータベースで実行し、その結果を取得する関数です。ここでもSQLAlchemy
を使い、結果はPandas
のDataFrame
形式に変換して扱いやすくします。
Text-to-SQLの勘所と乗り越えるべき壁
実際にText-to-SQLのアプリケーションを試してみると、その手軽さと可能性に驚かされる一方で、いくつかの課題や工夫のポイントも見えてきます。
ローカル環境での手軽さと可能性
まず、Ollamaのようなツールを使えば、ローカル環境でも比較的簡単にLLMを動かし、Text-to-SQLを試せる点は大きな魅力です。APIの利用料金やデータプライバシーを気にせず、自分のペースで実験できるのは、学習やプロトタイピングにおいて非常に有益です。今回のサンプルコードのように、LangChainやStreamlitといったライブラリを組み合わせることで、短時間でインタラクティブなアプリケーションを構築できるのも嬉しいポイントです。
プロンプトエンジニアリングの奥深さ
LLMから期待通りのSQLを引き出すためには、やはり「プロンプト」の設計が鍵となります。
- より良いSQLを引き出すための指示の工夫: 今回のサンプルコードでは、「あなたはSQL生成器です」「SQL文だけを出力してください」といった直接的な指示を与えました。しかし、より複雑な質問に対応したり、特定のSQL構文(例えばウィンドウ関数など)の使用を促したりするためには、プロンプトに数件の質問と理想的なSQLのペア(Few-shot サンプル)を提示する、テーブル間の関連性(外部キーなど)を明示的に記述する、といった工夫が有効になる場合があります。
- スキーマ情報の効果的な伝え方: データベースの構造をLLMにどう伝えるかも重要です。テーブル名やカラム名だけでなく、データ型やサンプルデータ、カラムの説明などを加えることで、LLMはより文脈に合ったSQLを生成しやすくなります。ただし、情報が多すぎるとLLMのコンテキストウィンドウの制限を超えたり、処理が遅くなったりする可能性もあるため、バランスが求められます。

LLMの出力: 期待と現実のギャップ
LLMは非常に賢いですが、必ずしも完璧なSQLを一発で生成してくれるわけではありません。
- 期待通りのSQLだけを出力させる難しさ(後処理の重要性): プロンプトで「SQL文だけを出力」と指示しても、LLMが説明文や余計なマークダウン(例:
```sql
)を付加してくることがあります。今回のサンプルコードのclean_text
関数のように、LLMの出力を整形する後処理は、実用的なアプリケーションを作る上でしばしば必要になります。 - エラーハンドリングの重要性: LLMが生成したSQLが文法的に間違っていたり、存在しないテーブルやカラムを参照していたりする場合、そのまま実行するとエラーが発生します。アプリケーションがクラッシュしないように、SQL実行時には
try-except
ブロックでエラーを捕捉し、ユーザーに分かりやすいメッセージを表示するなどのエラーハンドリング機構は不可欠です。
Text-to-SQLの一般的な課題
今回の試みは小規模なものでしたが、より本格的なText-to-SQLシステムを構築しようとすると、さらに根深い課題に直面します。
- スキーマリンキングの複雑さ: 自然言語で言及されたエンティティ(例:「顧客」「売上」)を、データベーススキーマ内のどのテーブルのどのカラムに対応付けるか(スキーマリンキング)は、Text-to-SQLにおける古典的かつ重要な課題です。特に、カラム名が曖昧だったり、同義語が使われていたりすると、LLMでも正確なマッピングが難しくなることがあります。
- 未知のデータベースやクエリへの汎化能力: 学習データに含まれていない新しいデータベース構造や、これまで見たことのないパターンの質問に対して、どれだけ柔軟に対応できるか(汎化能力)も大きな課題です。特定のデータベースに過剰に適合してしまうと、他のデータベースではうまく機能しない可能性があります。
- 稀なSQL操作や複雑なSQLへの対応: 日常的に使われるSELECT文やWHERE句は得意でも、GROUP BYの複雑な使い方、ウィンドウ関数、サブクエリのネストなど、出現頻度の低いSQL操作や複雑な構造を持つSQLの生成は、依然としてLLMにとっても難しいタスクです。
これらの課題を克服するためには、より高度なプロンプト技術、LLMのファインチューニング、スキーマ情報をよりリッチにする工夫、あるいは複数のLLMやツールを組み合わせたエージェント的なアプローチなどが求められます。Text-to-SQLは、まだ発展途上の技術であり、多くの試行錯誤と改善の余地が残されている分野です。
Text-to-SQLの今後の課題
Text-to-SQL技術は、LLMの登場によって大きな変革期を迎えていますが、まだまだ課題が山積しています。今後、この分野はどのような方向へ進んでいくのでしょうか?いくつかの未来像を描いてみます。
- LLMベースのシステムのさらなる強化:
- プロンプト技術の進化: より少ない例で、より複雑な指示をLLMに理解させるためのプロンプトエンジニアリング技術が洗練されていくでしょう。例えば、LLMに自己反省させたり、段階的に思考させたりするような高度なプロンプト戦略が一般化するかもしれません。
- 効率的なファインチューニング: 全てのパラメータを調整するのではなく、一部のパラメータのみを効率的に調整するPEFT(Parameter-Efficient Fine-Tuning)のような手法が、Text-to-SQLにおいてもより活用され、限られた計算資源でも高い性能を引き出せるようになるでしょう。
- エージェントフレームワークの洗練: LLMが単にSQLを生成するだけでなく、データベースと対話し、SQLの実行結果を検証し、必要に応じてSQLを修正したり、ユーザーに追加情報を尋ねたりするような、より自律的で賢い「データベースアシスタント」としての役割を担うようになるでしょう。
- 汎化能力とクロスドメイン性能の向上: 学習時に見たことのない新しいデータベーススキーマや、異なる業界・分野(クロスドメイン)のデータに対しても高い精度でSQLを生成できる能力は、実用化に向けた重要な鍵です。これには、より多様なデータセットを用いた学習、ドメイン知識を効果的にモデルに組み込む手法、あるいは未知のスキーマに動的に適応するZero-Shot/Few-Shotスキーマ適応技術の研究が進むと考えられます。
- より堅牢なスキーマリンキング技術: 自然言語の曖昧な表現とデータベーススキーマの要素を正確に関連付けるスキーマリンキングは、依然として重要な研究テーマです。知識グラフやオントロジーといった外部知識を活用したり、LLMの推論能力を最大限に引き出すことで、より複雑で大規模なスキーマに対してもロバスト(頑健)に対応できる技術が期待されます。
- 評価指標の進化: 生成されたSQLが本当に正しいか、ユーザーの意図を汲み取れているかを評価する指標も進化が必要です。単純な文字列一致だけでなく、SQLの意味的な正しさや、複数の正解SQLが存在する場合の評価、さらには実行結果の妥当性までを考慮した、より現実に即した評価方法やベンチマークが開発されていくでしょう。
- 実世界の複雑なアプリケーションへの対応: 実際のビジネスシーンでは、データベースが破損していたり、ユーザーの入力が不完全だったり、非常に大規模なデータベースを扱ったりと、理想的な環境ばかりではありません。このような現実世界の課題に対応できる、より実用的でスケーラブルなText-to-SQLシステムが求められます。また、データベース管理者向けのタスク(スキーマ管理やコンテンツ更新など)を支援するような応用も考えられます。
- 多言語対応やアクセシビリティ向上への期待: 現在は英語中心の研究が多いですが、日本語を含む様々な言語への対応(多言語Text-to-SQL)は、グローバルなデータ活用において不可欠です。また、Text-to-SQL技術は、視覚障碍者など、従来のインターフェースではデータベースアクセスが困難だった人々にとってのアクセシビリティを向上させる可能性も秘めています。
おわりに
この記事では、自然言語でデータベースと対話する技術「Text-to-SQL」について、その概要から、ローカルLLMとPython(LangChain、Streamlit)を使った具体的な実践例、そして今後の展望までを駆け足でご紹介しました。
Text-to-SQLは、専門的なSQLの知識がない人でも、チャット形式でデータにアクセスし、その価値を引き出すことを可能にする、まさに「データ活用の民主化」を推し進める技術です。まだまだ発展途上の分野であり、多くの課題も残されていますが、LLMの進化とともに、その精度や応用範囲はますます広がっています。
More Information
- arXiv:1810.05237, Tao Yu et al., 「SyntaxSQLNet: Syntax Tree Networks for Complex and Cross-DomainText-to-SQL Task」, https://arxiv.org/abs/1810.05237
- arXiv:1905.06241, Ben Bogin et al., 「Representing Schema Structure with Graph Neural Networks for Text-to-SQL Parsing」, https://arxiv.org/abs/1905.06241
- arXiv:2208.04415, Ayush Kumar et al., 「Deep Learning Driven Natural Languages Text to SQL Query Conversion: A Survey」, https://arxiv.org/abs/2208.04415
- arXiv:2301.08881, Shuaichen Chang et al., 「Dr.Spider: A Diagnostic Evaluation Benchmark towards Text-to-SQL Robustness」, https://arxiv.org/abs/2301.08881
- arXiv:2401.12379, Richard Roberson et al., 「Analyzing the Effectiveness of Large Language Models on Text-to-SQL Synthesis」, https://arxiv.org/abs/2401.12379
- arXiv:2402.16347, Haoyang Li et al., 「CodeS: Towards Building Open-source Language Models for Text-to-SQL」, https://arxiv.org/abs/2402.16347
- arXiv:2406.08426, Zijin Hong et al., 「Next-Generation Database Interfaces: A Survey of LLM-based Text-to-SQL」, https://arxiv.org/abs/2406.08426
- arXiv:2406.13408, Jipeng Cen et al., 「SQLFixAgent: Towards Semantic-Accurate Text-to-SQL Parsing via Consistency-Enhanced Multi-Agent Collaboration」, https://arxiv.org/abs/2406.13408
- arXiv:2407.07313, Benjamin G. Ascoli et al., 「ETM: Modern Insights into Perspective on Text-to-SQL Evaluation in the Age of Large Language Models」, https://arxiv.org/abs/2407.07313
- arXiv:2410.01869, Shouvon Sarker et al., 「Enhancing LLM Fine-tuning for Text-to-SQLs by SQL Quality Measurement」, https://arxiv.org/abs/2410.01869
- arXiv:2410.06011, Xiaohu Zhu et al., 「Large Language Model Enhanced Text-to-SQL Generation: A Survey」, https://arxiv.org/abs/2410.06011
- arXiv:2411.00073, Zhenbiao Cao et al., 「RSL-SQL: Robust Schema Linking in Text-to-SQL Generation」, https://arxiv.org/abs/2411.00073