BigQueryのデータに日本語でQAしてみよう

2023/11/09に公開されました。
2023/11/09に更新されました。

LangChainとVertexAIを用いて、日本語でデータを呼び出します。


author: Chiakoba

はじめに

DataチームのChiaKobaです。

AIのニュースで溢れる毎日ですね。 ChatGPTの話題は毎日絶えないですね。

Vertex AIも忘れないで。

ということで、今回は、VertexAIの生成AIモデルと言語モデルのフレームワーク「LangChain🦜⛓️」を使って、BigQueryのデータを日本語で呼び出してみます。

VertexAIの生成 AI モデル

VertexAIで利用可能な生成 AI モデルは、以下のようなコンテンツに対してモデルがあります。

  • text
  • chat
  • image(写真やPDFなど)
  • code
  • video
  • embeddings(単語や文といった自然言語の情報を、その単語や文の意味を表現するベクトル空間に配置)

今回は、textのモデルを使います。 また、Vertex AIでは、これらのモデルが呼び出せるようPaLM APIとしてエンドポイントを用意しています。

(ChatGPTのAPIと同じように呼べます!)

言語モデルのフレームワーク

LangChainは、大規模言語モデル(LLM)を用いてアプリケーションを効率よく開発するためのフレームワークです。

言語モデルが単体だとどうしても難しい、面倒な処理になるといった問題を少ない実装で可能にしてくれるありがたいインコ🦜様です。

大きく2つ特徴があります。

  1. 特定の用途(社内の情報を突っ込みたい!等)へ特化した機能を提供する
  2. LLMを利用したアプリケーション開発に必要な部品を抽象化したモジュールとして提供する

今回は、SQLと対話する機能を使っていきます。

これからも注目していきたいフレームワークです。

方法

今回はColaboratoryを利用して、Pythonを使って、実際に試していきます。

準備

1. まず、GCPのBigQueryとVertexAIのAPIを有効化します。 GCPコンソールやCloudSDKで有効化しておきましょう。

gcloud services enable aiplatform.googleapis.com bigquery.googleapis.com

2. 次は、Colaboratoryで認証です。GCPコンソールで自分に権限があることは確認しておきましょう。

from google.colab import auth as google_auth
google_auth.authenticate_user()

3. Colaboratoryで必要なパッケージをインストールします。この時、「RESTART RUNTIME」ボタンを押してランタイムを再起動します。

!pip install langchain sqlalchemy-bigquery google-cloud-bigquery google-cloud-aiplatform

実装

今回は、SQLAlchemyを使って、BigQueryのデータをLangChainで処理します。

テストデータは個人情報テストデータジェネレーターで作りました。

Colaboratoryでソースを実行していきます。

from google.cloud import bigquery
from sqlalchemy import *
from langchain.llms import VertexAI
from langchain.agents import create_sql_agent
from langchain.agents.agent_toolkits import SQLDatabaseToolkit
from langchain.sql_database import SQLDatabase
import vertexai

# 自分の環境に合わせて変更
dataset = "DATASET_NAME"  # @param {type:"string"}
project_id= "PROJECT_ID" # @param {type:"string"}
sqlalchemy_url = f"bigquery://{project_id}/{dataset}"
vertexai.init(project=project_id, location="us-central1")

# SQLAlchemy エンジンにBigQueryのデータの場所を設定
db = SQLDatabase.from_uri(database_uri=sqlalchemy_url)

# Vertex AI 基盤モデルを設定(ほとんどデフォルト)
llm = VertexAI(
    model_name="text-bison@001",
    max_output_tokens=1024,
    temperature=0.1,
    top_p=0.8,
    top_k=40,
    verbose=True,
)

# SQL データベースと対話するエージェントへSQLとLLMを設定
toolkit = SQLDatabaseToolkit(db=db, llm=llm)
agent_executor = create_sql_agent(
    llm=llm,
    toolkit=toolkit,
    verbose=True,
    top_k=10,
)

def run_answer(query):
    res = agent_executor.run(query)
    return res

実行!

run_answer("女性の人数を教えてください。")

以下がOutputです。

詳細を見る
> Entering new AgentExecutor chain...
Action: sql_db_list_tables
Action Input:
Observation: test_personal_info
Thought:I found the table test_personal_info.  I should query the schema of this table to see what columns I can use in my query.
Action: sql_db_schema
Action Input: test_personal_info
Observation:
CREATE TABLE `test_personal_info` (
	`full_name` STRING,
	`full_name_hiragana` STRING,
	`age` INT64,
	`birthdate` DATE,
	`sex` STRING,
	`blood_type` STRING,
	`email_address` STRING,
	`phone_number` STRING,
	`mobile_phone_number` STRING,
	`postal_code` STRING,
	`address` STRING,
	`company_name` STRING,
	`credit_card` STRING,
	`expiration_date` STRING,
	`my_number` STRING
)

/*
3 rows from test_personal_info table:
full_name	full_name_hiragana	age	birthdate	sex	blood_type	email_address	phone_number	mobile_phone_number	postal_code	address	company_name	credit_card	expiration_date	my_number
中原 義人	なかはら よしと	79	1944-02-27	男	A	yoshitonakahara@example.com	0735-21-4394	050-6374-8793	647-9731	和歌山県橋本市城山台4-1-6		4605270111483780	04/25	607754886619
新海 誠子	しんかい せいこ	79	1944-03-10	女	A	shinkai_seiko@example.org	0438-78-1600	080-5900-1396	289-3898	千葉県船橋市西船3-1-9		5314247057138833	07/27	949472424688
野田 洋一	のだ よういち	79	1944-07-26	男	A	youichinoda@example.com	0256-22-5571	080-5818-6411	956-6982	新潟県新潟市中央区関屋田町3-3-17ジョイフル216		3576355852349410	10/26	224409039958
*/
Thought:I found the column sex in the table test_personal_info.  I can use this column to count the number of females.
Action: sql_db_query
Action Input: SELECT COUNT(*) FROM test_personal_info WHERE sex = '女'
Observation: [(167,)]
Thought:I now know the final answer
Final Answer: 女性の人数は167人です。

> Finished chain.
女性の人数は167人です。

しっかりテーブル構造を把握して、型もBigQueryと一致しています。 そして、SQLを作成し、最終行にちゃんと答えが…!SQLも正しそうですね。

念の為、本当に合ってるかBigQueryにSQL投げてみましょう!

client = bigquery.Client(project=project_id)

# 実行するクエリ
query =  """
                SELECT
                  COUNT(*) as cnt
                FROM test.test_personal_info WHERE sex = '女'
                ;
         """
df = client.query(query).to_dataframe()
df.head()

合ってました!

ちょっと複雑な質問をしてみます。

run_answer("平均年齢より高い今月が誕生日の女性の誕生月と名前を3人教えてください")

結果どーん。

詳細を見る
> Entering new AgentExecutor chain...
Action: sql_db_list_tables
Action Input:
Observation: test_personal_info
Thought:I found the table test_personal_info. I should query the schema of this table to see what columns I can use in my query.
Action: sql_db_schema
Action Input: test_personal_info
Observation:
CREATE TABLE `test_personal_info` (
	`full_name` STRING,
	`full_name_hiragana` STRING,
	`age` INT64,
	`birthdate` DATE,
	`sex` STRING,
	`blood_type` STRING,
	`email_address` STRING,
	`phone_number` STRING,
	`mobile_phone_number` STRING,
	`postal_code` STRING,
	`address` STRING,
	`company_name` STRING,
	`credit_card` STRING,
	`expiration_date` STRING,
	`my_number` STRING
)

/*
3 rows from test_personal_info table:
full_name	full_name_hiragana	age	birthdate	sex	blood_type	email_address	phone_number	mobile_phone_number	postal_code	address	company_name	credit_card	expiration_date	my_number
川口 健人	かわぐち けんと	20	2003-06-30	男	A	kento_kawaguchi@example.co.jp	03-0270-0744	050-4668-9355	163-1228	東京都世田谷区上馬1-1-13	株式会社大創	374645581027174	02/28	143103840908
早川 しげる	はやかわ しげる	20	2003-02-06	男	A	shigeruhayakawa@example.jp	03-9293-0204	090-2502-0159	192-0658	東京都世田谷区砧2-1-17	有限会社伊藤	3581172691900144	08/25	582489059338
石井 優次	いしい ゆうじ	20	2003-08-12	男	A	yuujiishii@example.jp	03-2810-0549	080-4006-4329	191-4966	東京都江戸川区西小岩3-3-9オリエント704	株式会社クロノス	3538837989454830	06/26	607214136580
*/
Thought:The question is asking for the birth month and name of women whose age is higher than the average age. I need to find the average age of all people in the table.
Action: sql_db_query
Action Input: SELECT AVG(age) FROM test_personal_info
Observation: [(50.795999999999985,)]
Thought:The average age is 50.795999999999985. I need to find all women whose age is higher than this.
Action: sql_db_query
Action Input: SELECT birth_month, full_name FROM test_personal_info WHERE sex = '女' AND age > 50.795999999999985 ORDER BY birth_month LIMIT 3
Observation: Error: (google.cloud.bigquery.dbapi.exceptions.DatabaseError) 400 Unrecognized name: birth_month at [1:8]

Location: US
Job ID: 8d9d112d-a269-45ff-92e8-4d0439cd1f78

[SQL: SELECT birth_month, full_name FROM test_personal_info WHERE sex = '女' AND age > 50.795999999999985 ORDER BY birth_month LIMIT 3]
(Background on this error at: https://sqlalche.me/e/14/4xp6)
Thought:The birth_month column does not exist in the table. I need to find the column that contains the birth month.
Action: sql_db_schema
Action Input: test_personal_info
Observation:
CREATE TABLE `test_personal_info` (
	`full_name` STRING,
	`full_name_hiragana` STRING,
	`age` INT64, ,
	`birthdate` DATE
	`sex` STRING,
	`blood_type` STRING,
	`email_address` STRING,
	`phone_number` STRING,
	`mobile_phone_number` STRING,
	`postal_code` STRING,
	`address` STRING,
	`company_name` STRING,
	`credit_card` STRING,
	`expiration_date` STRING,
	`my_number` STRING
)

/*
3 rows from test_personal_info table:
full_name	full_name_hiragana	age	birthdate	sex	blood_type	email_address	phone_number	mobile_phone_number	postal_code	address	company_name	credit_card	expiration_date	my_number
川口 健人	かわぐち けんと	20	2003-06-30	男	A	kento_kawaguchi@example.co.jp	03-0270-0744	050-4668-9355	163-1228	東京都世田谷区上馬1-1-13	株式会社大創	374645581027174	02/28	143103840908
早川 しげる	はやかわ しげる	20	2003-02-06	男	A	shigeruhayakawa@example.jp	03-9293-0204	090-2502-0159	192-0658	東京都世田谷区砧2-1-17	有限会社伊藤	3581172691900144	08/25	582489059338
石井 優次	いしい ゆうじ	20	2003-08-12	男	A	yuujiishii@example.jp	03-2810-0549	080-4006-4329	191-4966	東京都江戸川区西小岩3-3-9オリエント704	株式会社クロノス	3538837989454830	06/26	607214136580
*/
Thought:The birthdate column contains the birth month. I need to extract the birth month from the birthdate column.
Action: sql_db_query
Action Input: SELECT EXTRACT(MONTH FROM birthdate) AS birth_month, full_name FROM test_personal_info WHERE sex = '女' AND age > 50.795999999999985 ORDER BY birth_month LIMIT 3
Observation: [(1, '朝比奈 千香子'), (1, '藤田 裕子'), (1, '萩田 あやめ')]
Thought:I found the birth month and name of women whose age is higher than the average age.
Action: sql_db_query_checker
Action Input: SELECT EXTRACT(MONTH FROM birthdate) AS birth_month, full_name FROM test_personal_info WHERE sex = '女' AND age > 50.795999999999985 ORDER BY birth_month LIMIT 3
Observation: SELECT EXTRACT(MONTH FROM birthdate) AS birth_month, full_name FROM test_personal_info WHERE sex = '女' AND age > 50.795999999999985 ORDER BY birth_month LIMIT 3
Thought:I now know the final answer
Final Answer: 1月: 朝比奈 千香子, 藤田 裕子, 萩田 あやめ

> Finished chain.
1月: 朝比奈 千香子, 藤田 裕子, 萩田 あやめ

今月は11月です。今月というところは読み取れなかったですね。

でもかなり惜しい、月まで求められてるし、人数も読み取れてる。いいポイントまで行ってます。 あと個人的には最初、エラーになっても諦めないところ、好きです。

もう少し情報を与えれば、回答まで導けそうです。

このような質問をする必要があるなら、もう少し人間が考える必要がありますね。

まとめ

Vertex AIとLangChainを使って、日本語でデータベースと簡単なお話ならできることが分かりました。

感動しちゃいます、どんどんすごい時代になっていますね…!!

LangChainに興味を持つとてもいい機会になりました。

最後まで読んでくださったあなた、ありがとうございます。

参考

https://cloud.google.com/vertex-ai/docs/generative-ai/model-reference/text



GI Cloudは事業の拡大に向けて一緒に夢を追う仲間を募集しています

当社は「クラウドで日本のIT業界を変革し、世の中をもっとハッピーに」をミッションに掲げ、Google Cloudに特化した技術者集団として、お客様にコンサルティングからシステム開発、運用・保守まで一気通貫でサービスを提供しています。

まだ小規模な事業体ですが、スタートアップならではの活気と成長性に加えて、大手総合商社である伊藤忠グループの一員としてやりがいのある案件にもどんどんチャレンジできる環境が整っています。成長意欲の高い仲間と共にスキルを磨きながら、クラウドの力で世の中をもっとハッピーにしたい。そんな我々の想いに共感できる方のエントリーをお待ちしています。

採用ページ

※本記事は、ジーアイクラウド株式会社の見解を述べたものであり、必要な調査・検討は行っているものの必ずしもその正確性や真実性を保証するものではありません。

※リンクを利用する際には、必ず出典がGIC dryaki-blogであることを明記してください。
リンクの利用によりトラブルが発生した場合、リンクを設置した方ご自身の責任で対応してください。
ジーアイクラウド株式会社はユーザーによるリンクの利用につき、如何なる責任を負うものではありません。