【LangChain】自然言語からSQLデータベース参照|ChatGPT APIとPythonによる実装解説

当ページには広告が含まれています。

こんにちは、DXCEL WAVEの運営者(@dxcelwave)です!

こんな方におすすめ!
  • OpenAI社のAPIとPythonを用いて、自然言語から直接SQLデータベースを参照する方法が知りたい。
  • LangChainのSQLDatabaseChain機能について詳しく知りたい。
目次

LangChainとは?

【LangChain公式】https://python.langchain.com/en/latest/index.html

LangChainとは、ChatGPTを代表とするような大規模言語モデル(LLM)の機能を拡張し、サービスとして展開する際に役立つライブラリです。

LangChainの主要機能

LangChainの主要な機能として以下があります。

主要機能概要
Models様々な大規模言語モデルを同じインターフェース上で取り扱えるようにする機能
Promptsプロンプトの管理、最適化、シリアル化ができる機能
Memory言語モデルを用いてユーザーと対話した履歴を記憶する機能
Data connection言語モデルに外部データを投入し、外部データに基づく回答を生成する機能
Chainsチェーンを複数繋げて、一連の処理を連続実行する機能
Agentsユーザーからの要望をどんな手段・順序で応えるか決定・実行する機能

LangChainの各種機能の詳細を知りたい方は、こちらの記事をご覧下さい。

あわせて読みたい
LangChainとは?|概要・主要機能を徹底解説 LangChainの概要および主要機能であるModels・Prompts・Data Connection・Agents・Memory・Chainsについて解説します。

【参考】LangChainを用いたプログラミング実装におすすめの学習教材

LangChainライブラリを用いてプログラミングし、アプリケーションを実装したい方向けに、おすすめの学習教材をご紹介します。

【LangChain Chains】SQLDatabaseChainとは

LangChain Chainsとは、文字通りチェーンを繋げて、一連の処理を連続して実行できるようにする機能です。チェーンの最小単位は、プロンプトと言語モデルをもとに構成されます。

1つのプロンプトに対して1つの回答を得るようなシンプルなタスクであれば、Chainsの機能は不要です。一方、プロンプトが複雑化したタスクは、この機能が本領を発揮します。

例えば上図のように、正確な最終出力を得るために、段階的に中間結果を出力する場合に有効です。このように、中間的な推論ステップを用いて複雑な推論能力向上させ、最終的に適切な回答を得るための手法をChain-of-Thought(COT)プロンプティングと呼びます。

SQLDatabaseChainとは

SQLDatabaseChainとは、LangChain Chainsの拡張機能であり、ユーザーからの質問に対してデータベースを参照し、回答を生成することに特化したチェーンです。

接続可能なデータベース一覧

LangChainは、SQLAlchemyというライブラリを使用し、SQLデータベースに接続します。現時点で以下のデータベースの接続に対応しています。

MS SQL
MySQL
MariaDB
PostgreSQL
Oracle SQL
Databricks
SQLite

【OpenAI】ChatGPTとは?

ChatGPTとは、OpenAIが開発した対話型チャットボットのモデルです。ChatGPTの名前は、GPT-3という第3世代の生成言語モデルに由来しています。

ChatGPTのモデルには、人工知能(AI)が搭載されており、人間の発話に対して自然なやり取りを可能にしています。また、英語をはじめ、中国語、日本語、フランス語など複数言語を認識し、人間らしく応答できるのも特徴的です。

さらに、ChatGPTではチャットの他に、画像生成など近年多様な機能がリリースされてます。以下、ChatGPTで代表するGPTモデルおよびOpenAIが提供するAPI機能一覧を示します。

  • チャット機能
  • テキストから画像を生成
  • オーディオを文字起こし
  • Python、SQL、JavaScript等のコードを理解
  • 問題あるネガティブ発言検出
  • テキスト文章のベクトル変換

【参考】OpenAI社のAPI利用方法

本記事ではChatGPTを用いたPythonプログラミングについて解説します。その際、Open AIが提供するAPI情報が必要になります。「ChatGPTの概要」および「API情報の取得手順」については、こちらの記事で詳しく解説しています。

あわせて読みたい
【Python×ChatGPT】チャットボット作成入門|OpenAI APIの利用申請手順も解説 「ChatGPT APIの利用手順」と「PythonでChatGPT APIを呼び出し、チャットボットを作成する方法」についてそれぞれ解説します。

【参考】ChatGPTを詳しく学びたい方向けの学習講座

ChatGPTを詳しく学びたい方向けに安価で学べるオンライン講座も併せてご紹介します。

【事前準備】SQLite・データベースの環境構築

今回のプログラム実装に際して、データベースにはSQLiteを例として用います。Python環境下でSQLiteを操作するための環境を構築しましょう。

SQLiteのブラウザをダウンロード

SQLite形式のデータをブラウザ上で閲覧・操作するためのソフトウェアをインストールします。

DB Browser for SQLiteのリンクにアクセスし、お使いのOSに応じたバージョンを選択しましょう。

サンプルデータベースのダウンロード

【引用:SQLite Sakila Sample Database】https://github.com/jOOQ/sakila

本記事では上図のER図に示すようなサンプルデータベースを用いてSQLiteの操作方法を解説します。

SQLite Sakila Sample DatabaseのDownloadをクリックしましょう。ダウンロードしたフォルダ内のsqlite-sakila.dbファイルを今回利用します。

【Python × LangChain】SQLDatabaseChainの実装

PythonとLangChainのSQLDatabaseChainを用いて「ユーザーの自然言語からSQLクエリを発行し、データベース参照結果を出力できるプログラム」を構築していきます。

Pythonライブラリインストール

プログラム実装に際して、以下に示すライブラリが必要となります。ターミナル(MacOS)またはコマンドプロンプト(Windows)を通じて事前にインストールしておきましょう。

OpenAI

ChatGPTを代表とするOpenAI社のAPI利用に際して必要となるライブラリです。

pip install openai

LangChain

LangChainのSQLDatabaseChain利用に際して必要となるライブラリです。

pip install langchain

SQLAlchemy

データベース接続に際して必要となるライブラリです。

pip install sqlalchemy

Pythonライブラリ読込

Pythonプログラムの先頭にライブラリとAPI認証情報を記述します。

前述したOpenAI社のサイトから取得したシークレットキーを入力しましょう。

import openai
import os

# APIシークレットキーを記述
SECRET_KEY  = "............."

# API認証情報設定
os.environ["OPENAI_API_KEY"] = SECRET_KEY

データベースへの接続設定

データベース(今回はSQLiteを利用)へ接続するためのSQLDatabaseオブジェクトを作成します。

from sqlalchemy import text, create_engine
from langchain import SQLDatabase

# =========================================================================
# データベースの接続設定
# =========================================================================

# データベース情報
db_name = "sqlite-sakila.db"                # データベース名
sql_url = "sqlite:///" + db_name            # データベースのURL(例:sqlite:///../../../../data/Test.db")
tables  = ["customer", "store","staff"]     # 今回参照するテーブル名


# SQLDatabaseオブジェクト
SQLDatabase  = SQLDatabase.from_uri(
                   sql_url,                 # 読み込むデータベース
                   include_tables=tables,   # 参照するテーブル 
                  )

前述でダウンロードしたsqlite-sakila.dbはPythonファイルと同じディレクトリに格納しましょう。

後続で作成するLLMについて、LLMで扱えるトークン数には上限があります。データベースの全てのテーブルを参照してしまうと、トークン数の上限を超過し、エラーが発現する可能性があります。そのため、参照するテーブルはtablesに事前に指定することとします。

LangChain – LLM・プロンプトの作成

SQLDatabaseChain実装に際して、必要なコンポーネントである大規模言語モデル(LLM)、プロンプトテンプレートをそれぞれ記述します。

from langchain import PromptTemplate, OpenAI

# ====================================================================================
# LLM作成
# ====================================================================================

LLM = OpenAI(model_name  = "text-davinci-003",   # 利用するモデル
             temperature = 0,                    # 出力する単語のランダム性(0から2の範囲) 0であれば毎回返答内容固定
             verbose     = False,                # プロンプトの動的表示有無
            )


# ====================================================================================
# Prompt Templateを作成
# ====================================================================================

# テンプレート
TEMPLATE = \
    """
    Given an input question, first create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer.
    Use the following format:
        Question:   "Question here"
        SQLQuery:   "SQL Query to run"
        SQLResult:  "Result of the SQLQuery"
        Answer:     "Final answer here"
    Only use the following tables: {table_info}
    Question: {input}
    """

# SQLDatabaseChainに用いるプロンプトの定義
PROMPT = PromptTemplate(
           input_variables = ["input", "table_info","dialect"], # プロンプトのテンプレートで指定した入力変数
           template = TEMPLATE,                                 # プロンプトのテンプレート
                      )

LangChain – SQLDatabaseChainの作成

本記事のメインとなるSQLDatabaseChainオブジェクトを作成します。

from langchain import SQLDatabaseChain

# ====================================================================================
# SQLDatabaseChainを作成
# ====================================================================================

# SQLDatabaseChainオブジェクト
db_chain = SQLDatabaseChain(llm      = LLM,                     # LLM 
                            database = SQLDatabase,             # SQLDatabaseオブジェクト
                            prompt   = PROMPT,                  # プロンプトテンプレート
                            verbose  = True,                    # プロンプトの動的表示有無
                            return_intermediate_steps = True,   # 出力結果に中間処理も含めるか否か 
                           )

【参考】SQLDatabaseChainで参照するテーブル情報確認

SQLDatabaseChainが参照できるテーブル情報は、以下のコードを用いて確認できます。

コード

# データベースのテーブル情報を確認
print(SQLDatabase.table_info)

出力イメージ

# 出力イメージ
# CREATE TABLE customer (
#     customer_id INTEGER NOT NULL, 
#     store_id INTEGER NOT NULL, 
#     first_name VARCHAR(45) NOT NULL, 
#     last_name VARCHAR(45) NOT NULL, 
#     email VARCHAR(50) DEFAULT NULL, 
#     address_id INTEGER NOT NULL, 
#     active CHAR(1) DEFAULT 'Y' NOT NULL, 
#     create_date TIMESTAMP NOT NULL, 
#     last_update TIMESTAMP NOT NULL, 
#     PRIMARY KEY (customer_id), 
#     CONSTRAINT fk_customer_store FOREIGN KEY(store_id) REFERENCES store (store_id) ON UPDATE CASCADE, 
#     CONSTRAINT fk_customer_address FOREIGN KEY(address_id) REFERENCES address (address_id) ON UPDATE CASCADE
# )

# CREATE TABLE store (
#     store_id INTEGER NOT NULL, 
#     manager_staff_id SMALLINT NOT NULL, 
#     address_id INTEGER NOT NULL, 
#     last_update TIMESTAMP NOT NULL, 
#     PRIMARY KEY (store_id), 
#     CONSTRAINT fk_store_staff FOREIGN KEY(manager_staff_id) REFERENCES staff (staff_id), 
#     CONSTRAINT fk_store_address FOREIGN KEY(address_id) REFERENCES address (address_id)
# )

DB参照結果の出力関数作成

データベースの参照結果を出力する関数を作成します。こちらの関数をもとに「質問文」「SQLクエリ」「SQL出力結果」「LLMの回答」をそれぞれ出力できるようにします。

# ====================================================================================
# データベースの参照結果を出力する関数
# ====================================================================================


def search_db(text):
    
    # db_chain実行
    result = db_chain(text)

    # 出力結果加工
    question   = result["query"]
    sql_query  = result["intermediate_steps"][0]["input"].split("SQLQuery:")[1].split("SQLResult:")[0].replace("  ", " ").replace("\n","")
    sql_result = result["intermediate_steps"][0]["input"].split("SQLResult:")[1].split("Answer:")[0].replace("  ", " ").replace("\n","")
    answer     = result["result"]

    dictionary = {
                    'Question':question,
                    'SQL_Query':sql_query,
                    'SQL_Result':sql_result,
                    'Answer':answer,
                  }
    
    return dictionary

データベース参照関数実行|(例)件数カウント

前述の関数を用いて、SQLDatabaseChainを実行します。例えば、顧客の件数をカウントする場合、次のように実行します。

コード

# テキスト文章
text = "ストア「1」の顧客は全部で何人か?"

# 関数実行
result = search_db(text)

出力イメージ

# 結果出力
print(result)

# 出力イメージ
# {'Question': 'ストア「1」の顧客は全部で何人か?', 
# 'SQL_Query': 'SELECT COUNT(*)   FROM customer   WHERE store_id = 1;', 
# 'SQL_Result': ' [(326,)]', 
# 'Answer': 'ストア「1」の顧客は全部で326人です。'}

データベース参照関数実行|(例)リスト取得

前述の関数を用いて、SQLDatabaseChainを実行します。例えば、顧客リストを取得する場合、次のように実行します。

コード

# テキスト文章
text = "苗字が「MA」で始まる顧客情報をリストとして取得したい"

# データベース参照
result = search_db(text)

出力イメージ

# 結果出力
print(result)

# 出力イメージ
# {'Question': '苗字が「MA」で始まる顧客情報をリストとして取得したい', 
# 'SQL_Query': "SELECT * FROM customer WHERE last_name LIKE 'MA%';", 
# 'SQL_Result': 
#    " [(16, 2, 'SANDRA', 'MARTIN', 'SANDRA.MARTIN@sakilacustomer.org', 20, '0', '2006-02-14 22:04:36.000', '2021-03-06 15:53:36'), 
#       (19, 1, 'RUTH', 'MARTINEZ', 'RUTH.MARTINEZ@sakilacustomer.org', 23, '1', '2006-02-14 22:04:36.000', '2021-03-06 15:53:36'), 
#       (119, 1, 'SHERRY', 'MARSHALL', 'SHERRY.MARSHALL@sakilacustomer.org', 123, '1', '2006-02-14 22:04:36.000', '2021-03-06 15:53:37'), 
#       (135, 2, 'JUANITA', 'MASON', 'JUANITA.MASON@sakilacustomer.org', 139, '1', '2006-02-14 22:04:36.000', '2021-03-06 15:53:37'),
    
# 'Answer': 
#       '16番のSANDRA MARTIN、
#        19番のRUTH MARTINEZ、
#        119番のSHERRY MARSHALL、
#        135番のJUANITA MASON、169番のERICA MATTHEWS'

【LangChain】SQLDatabaseChainを用いたPythonコード全量

本記事で紹介したプログラムをまとめて再掲します。

import openai
import os
from sqlalchemy import text, create_engine
from langchain import SQLDatabase, PromptTemplate, SQLDatabaseChain, OpenAI

# ====================================================================================
# API認証情報
# ====================================================================================

# APIシークレットキーを記述
SECRET_KEY  = "............."

# API認証情報設定
os.environ["OPENAI_API_KEY"] = SECRET_KEY


# ====================================================================================
# データベースの接続設定
# ====================================================================================

# データベース情報
db_name = "sqlite-sakila.db"                # データベース名
sql_url = "sqlite:///" + db_name            # データベースのURL(例:sqlite:///../../../../data/Test.db")
tables  = ["customer", "store","staff"]     # 今回参照するテーブル名


# SQLDatabaseオブジェクト
SQLDatabase  = SQLDatabase.from_uri(
                   sql_url,                 # 読み込むデータベース
                   include_tables=tables,   # 参照するテーブル 
                  )


# ====================================================================================
# LLM作成
# ====================================================================================

LLM = OpenAI(model_name  = "text-davinci-003",   # 利用するモデル
             temperature = 0,                    # 出力する単語のランダム性(0から2の範囲) 0であれば毎回返答内容固定
             verbose     = False,                # プロンプトの動的表示有無
            )



# ====================================================================================
# Prompt Templateを作成
# ====================================================================================

# テンプレート
TEMPLATE = \
    """
    Given an input question, first create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer.
    Use the following format:
        Question:   "Question here"
        SQLQuery:   "SQL Query to run"
        SQLResult:  "Result of the SQLQuery"
        Answer:     "Final answer here"
    Only use the following tables: {table_info}
    Question: {input}
    """

# SQLDatabaseChainに用いるプロンプトの定義
PROMPT = PromptTemplate(
           input_variables = ["input", "table_info","dialect"], # プロンプトのテンプレートで指定した入力変数
           template = TEMPLATE,                                 # プロンプトのテンプレート
                      )


# ====================================================================================
# SQLDatabaseChainを作成
# ====================================================================================

# SQLDatabaseChainオブジェクト
db_chain = SQLDatabaseChain(llm      = LLM,                     # LLM 
                            database = SQLDatabase,             # SQLDatabaseオブジェクト
                            prompt   = PROMPT,                  # プロンプトテンプレート
                            verbose  = True,                    # プロンプトの動的表示有無
                            return_intermediate_steps = True,   # 出力結果に中間処理も含めるか否か 
                           )


# ====================================================================================
# データベースの参照結果を出力する関数
# ====================================================================================


def search_db(text):
    
    # db_chain実行
    result = db_chain(text)

    # 出力結果加工
    question   = result["query"]
    sql_query  = result["intermediate_steps"][0]["input"].split("SQLQuery:")[1].split("SQLResult:")[0].replace("  ", " ").replace("\n","")
    sql_result = result["intermediate_steps"][0]["input"].split("SQLResult:")[1].split("Answer:")[0].replace("  ", " ").replace("\n","")
    answer     = result["result"]

    dictionary = {
                    'Question':question,
                    'SQL_Query':sql_query,
                    'SQL_Result':sql_result,
                    'Answer':answer,
                  }
    
    return dictionary


# ====================================================================================
# 関数実行
# ====================================================================================

# テキスト文章
text = "苗字が「MA」で始まる顧客情報をリストとして取得したい"

# 関数実行
result = search_db(text)

【参考】PythonによるLLM実装|ChatGPT・LangChain

本記事では、PythonでLLMを構築し、様々なタスクをこなす機能の実装方法を多数解説しています。

Python × ChatGPT関連記事

【あわせて読みたい】

Python × LangChain関連記事

【あわせて読みたい】

自然言語処理の学習におすすめの書籍

あわせて読みたい
自然言語処理(NLP)学習におすすめ入門本・動画教材8選|Pythonによる機械学習・ディープラーニング向け... 「自然言語処理の概要とそれを実装するPythonプログラミング手法を学びたい」「機械学習・AIを組み合わせたモデル開発手法を知りたい」このような要望にお答えします。

自然言語処理の概要について詳しく学びたい方向けに、厳選したおすすめの学習教材を紹介しています。

最後に

この記事が気に入ったら
フォローしてね!

本記事をシェア!
目次