19
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

生成AIでSQLデヌタベヌスの分析

19
Last updated at Posted at 2024-08-30

本蚘事は日本オラクルが運営する䞋蚘Meetupで発衚予定の内容になりたす。発衚たでに今埌、内容は予告なく倉曎される可胜性があるこずをあらかじめご了承ください。

※本蚘事は䞋蚘蚘事の補足蚘事ずなりたす。

※ミヌトアップ実斜時の動画は↓こちら。

自然蚀語によるSQLデヌタベヌスの分析

䞀般的に、デヌタベヌスの分析はSQLで分析凊理を実行したり、BIツヌルでその凊理を行ったりしたすが、それらに関する深い技術的知識がなくおも、LLMを利甚し、自然蚀語で質問を入力するだけでデヌタ分析が可胜になるナヌスケヌスです。

image.png

ナヌスケヌス

DBの分析に関連するアプリケヌションは党おナヌスケヌスの察象ずなりたす。䟋えば以䞋のようなアプリケヌションです。

ナヌスケヌス 説明
営業レポヌトの自動生成 営業郚門の方々が自然蚀語で質問し、リアルタむムで営業レポヌトを生成。迅速な意思決定が可胜に。
マヌケティングキャンペヌンの効果枬定 キャンペヌンの効果を自然蚀語で分析し、ROI評䟡や次の戊略調敎に圹立おる。
人事分析 自然蚀語で退職率などを分析し、瀟員満足床や゚ンゲヌゞメント向䞊のむンサむトを埗る。
財務分析ず予算管理 自然蚀語で経費デヌタを集蚈し、予算管理や支出蚈画の迅速な把握をサポヌト。
圚庫管理の最適化 自然蚀語で圚庫デヌタを分析し、適時の補充や圚庫管理の最適化を実珟。

仕組み

基本的な仕組みずしおは䞋蚘のようになりいたっおシンプルです。

image.png

①ナヌザヌからの質問をLLMに入力
②LLMが質問をSQLに倉換
③倉換されたSQLでデヌタベヌスにク゚リを実行
④ク゚リ結果ず質問文をLLMに入力し回答を生成

ずいう流れで凊理が進むようなコヌドを実装したす。予想通りずいう感じではないでしょうか。ずは蚀えこれをスクラッチで実装するず実は意倖ず面倒なこずになりたす。そこでLangChain(のSQL Database Agent)の登堎です。LangChainがバック゚ンドで自動的に凊理しおくれる内容も含めおサンプルコヌドを抂説したす。

#コヌド抂説
利甚する各コンポヌネントは䞋蚘の通りです。

  • LLM : OpenAI
  • SQL Database : SQLite
  • Dataset : 著名な音楜アヌティスト名ずリリヌスアルバムのスキヌマ

たずは必芁なラむブラリのむンストヌルです。

!pip install --upgrade --quiet  langchain langchain-community langchain-experimental langchain-openai

次にOpenAIずLangSmithのAPIキヌを入力したす。(LangSmithはオプションです。必須ではありたせん。)

import getpass
import os

def _set_if_undefined(var: str):
    if not os.environ.get(var):
        os.environ[var] = getpass.getpass(f"Please provide your {var}")

_set_if_undefined("OPENAI_API_KEY")
_set_if_undefined("LANGCHAIN_API_KEY")

# Optional, add tracing in LangSmith
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_PROJECT"] = "Database Agent"

SQLデヌタベヌス(sqlite)に接続しおク゚リを実行しスキヌマを確認したす。

from langchain_community.utilities import SQLDatabase

db = SQLDatabase.from_uri("sqlite:///Chinook.db", sample_rows_in_table_info=3)

デヌタベヌス内にある衚を確認したす。

print(db.get_usable_table_names())

['Album', 'Artist', 'Customer', 'Employee', 'Genre', 'Invoice', 'InvoiceLine', 'MediaType', 'Playlist', 'PlaylistTrack', 'Track']

䞊蚘、11個の衚があるこずがわかりたす。
衚 Artist にク゚リを実行したす。

print(db.run("SELECT * FROM Artist LIMIT 10;"))

[(1, 'AC/DC'), (2, 'Accept'), (3, 'Aerosmith'), (4, 'Alanis Morissette'), (5, 'Alice In Chains'), (6, 'AntÃŽnio Carlos Jobim'), (7, 'Apocalyptica'), (8, 'Audioslave'), (9, 'BackBeat'), (10, 'Billy Cobham')]

著名なロックバンドのバンド名が入力されおいる衚だずいうこずがわかりたす。衚名の通りです。次に、衚Albumにク゚リを実行したす。

print(db.run("SELECT * FROM Album LIMIT 10;"))

[(1, 'For Those About To Rock We Salute You', 1), (2, 'Balls to the Wall', 2), (3, 'Restless and Wild', 2), (4, 'Let There Be Rock', 1), (5, 'Big Ones', 3), (6, 'Jagged Little Pill', 4), (7, 'Facelift', 5), (8, 'Warner 25 Anos', 6), (9, 'Plays Metallica By Four Cellos', 7), (10, 'Audioslave', 8)]

衚名通り、こちらはアヌティストのアルバム名です。
今回はこの2぀の衚を䜿っお自然蚀語でク゚リを実行しおみたいず思いたす。

たず、LLMずしおOpenAIを定矩したす。

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-3.5-turbo")

次にAgentを定矩したす。次の䞀行がこの実装の肝になりたす。LangChainのAgentは様々なタむプのものがあるず䞊述したしたが、ここではcreate_sql_agent関数によりSQLDatabaseAgent、぀たりRDB甚のAgentを定矩しおいたす。そしお、Agentが察象ずするtoolはLangChainで事前に甚意されおいるopenai-toolsです。

agent_executor = create_sql_agent(llm, db=db, agent_type="openai-tools", verbose=True)

この䞀行の定矩だけで、ナヌザヌの質問をLLMに連携し、SQLに倉換埌、DBにク゚リ実行、その埌、質問文ずSQLの結果をLLMに入力するずいう党䜓のパむプラむンが定矩されたす。

具䜓的にどのようなパむプラむンが定矩されおいるのか、agent_executorの䞭身をのぞいおみたす。

print(agent_executor)

AgentExecutor(name='SQL Agent Executor', verbose=True, agent=RunnableMultiActionAgent(runnable=RunnableAssign(mapper={
  agent_scratchpad: RunnableLambda(lambda x: format_to_openai_tool_messages(x['intermediate_steps']))
})
| ChatPromptTemplate(input_variables=['agent_scratchpad', 'input'], input_types={'agent_scratchpad': typing.List[typing.Union[langchain_core.messages.ai.AIMessage, langchain_core.messages.human.HumanMessage, langchain_core.messages.chat.ChatMessage, langchain_core.messages.system.SystemMessage, langchain_core.messages.function.FunctionMessage, langchain_core.messages.tool.ToolMessage]]}, messages=[SystemMessage(content='You are an agent designed to interact with a SQL database.\nGiven an input question, create a syntactically correct sqlite query to run, then look at the results of the query and return the answer.\nUnless the user specifies a specific number of examples they wish to obtain, always limit your query to at most 10 results.\nYou can order the results by a relevant column to return the most interesting examples in the database.\nNever query for all the columns from a specific table, only ask for the relevant columns given the question.\nYou have access to tools for interacting with the database.\nOnly use the below tools. Only use the information returned by the below tools to construct your final answer.\nYou MUST double check your query before executing it. If you get an error while executing a query, rewrite the query and try again.\n\nDO NOT make any DML statements (INSERT, UPDATE, DELETE, DROP etc.) to the database.\n\nIf the question does not seem related to the database, just return "I don\'t know" as the answer.\n'), HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['input'], template='{input}')), AIMessage(content='I should look at the tables in the database to see what I can query.  Then I should query the schema of the most relevant tables.'), MessagesPlaceholder(variable_name='agent_scratchpad')])
| RunnableBinding(bound=ChatOpenAI(client=<openai.resources.chat.completions.Completions object at 0x7ffa4aa815d0>, async_client=<openai.resources.chat.completions.AsyncCompletions object at 0x7ffa4aa853d0>, root_client=<openai.OpenAI object at 0x7ffa4b263ed0>, root_async_client=<openai.AsyncOpenAI object at 0x7ffa4aa81790>, temperature=0.0, openai_api_key=SecretStr('**********'), openai_proxy=''), kwargs={'tools': [{'type': 'function', 'function': {'name': 'sql_db_query', 'description': "Input to this tool is a detailed and correct SQL query, output is a result from the database. If the query is not correct, an error message will be returned. If an error is returned, rewrite the query, check the query, and try again. If you encounter an issue with Unknown column 'xxxx' in 'field list', use sql_db_schema to query the correct table fields.", 'parameters': {'type': 'object', 'properties': {'query': {'description': 'A detailed and correct SQL query.', 'type': 'string'}}, 'required': ['query']}}}, {'type': 'function', 'function': {'name': 'sql_db_schema', 'description': 'Input to this tool is a comma-separated list of tables, output is the schema and sample rows for those tables. Be sure that the tables actually exist by calling sql_db_list_tables first! Example Input: table1, table2, table3', 'parameters': {'type': 'object', 'properties': {'table_names': {'description': "A comma-separated list of the table names for which to return the schema. Example input: 'table1, table2, table3'", 'type': 'string'}}, 'required': ['table_names']}}}, {'type': 'function', 'function': {'name': 'sql_db_list_tables', 'description': 'Input is an empty string, output is a comma-separated list of tables in the database.', 'parameters': {'type': 'object', 'properties': {'tool_input': {'description': 'An empty string', 'default': '', 'type': 'string'}}}}}, {'type': 'function', 'function': {'name': 'sql_db_query_checker', 'description': 'Use this tool to double check if your query is correct before executing it. Always use this tool before executing a query with sql_db_query!', 'parameters': {'type': 'object', 'properties': {'query': {'description': 'A detailed and SQL query to be checked.', 'type': 'string'}}, 'required': ['query']}}}]})
| OpenAIToolsAgentOutputParser(), input_keys_arg=['input'], return_keys_arg=['output'], stream_runnable=True), tools=[QuerySQLDataBaseTool(description="Input to this tool is a detailed and correct SQL query, output is a result from the database. If the query is not correct, an error message will be returned. If an error is returned, rewrite the query, check the query, and try again. If you encounter an issue with Unknown column 'xxxx' in 'field list', use sql_db_schema to query the correct table fields.", db=<langchain_community.utilities.sql_database.SQLDatabase object at 0x7ffa60b65350>), InfoSQLDatabaseTool(description='Input to this tool is a comma-separated list of tables, output is the schema and sample rows for those tables. Be sure that the tables actually exist by calling sql_db_list_tables first! Example Input: table1, table2, table3', db=<langchain_community.utilities.sql_database.SQLDatabase object at 0x7ffa60b65350>), ListSQLDatabaseTool(db=<langchain_community.utilities.sql_database.SQLDatabase object at 0x7ffa60b65350>), QuerySQLCheckerTool(description='Use this tool to double check if your query is correct before executing it. Always use this tool before executing a query with sql_db_query!', db=<langchain_community.utilities.sql_database.SQLDatabase object at 0x7ffa60b65350>, llm=ChatOpenAI(client=<openai.resources.chat.completions.Completions object at 0x7ffa4aa815d0>, async_client=<openai.resources.chat.completions.AsyncCompletions object at 0x7ffa4aa853d0>, root_client=<openai.OpenAI object at 0x7ffa4b263ed0>, root_async_client=<openai.AsyncOpenAI object at 0x7ffa4aa81790>, temperature=0.0, openai_api_key=SecretStr('**********'), openai_proxy=''), llm_chain=LLMChain(prompt=PromptTemplate(input_variables=['dialect', 'query'], template='\n{query}\nDouble check the {dialect} query above for common mistakes, including:\n- Using NOT IN with NULL values\n- Using UNION when UNION ALL should have been used\n- Using BETWEEN for exclusive ranges\n- Data type mismatch in predicates\n- Properly quoting identifiers\n- Using the correct number of arguments for functions\n- Casting to the correct data type\n- Using the proper columns for joins\n\nIf there are any of the above mistakes, rewrite the query. If there are no mistakes, just reproduce the original query.\n\nOutput the final SQL query only.\n\nSQL Query: '), llm=ChatOpenAI(client=<openai.resources.chat.completions.Completions object at 0x7ffa4aa815d0>, async_client=<openai.resources.chat.completions.AsyncCompletions object at 0x7ffa4aa853d0>, root_client=<openai.OpenAI object at 0x7ffa4b263ed0>, root_async_client=<openai.AsyncOpenAI object at 0x7ffa4aa81790>, temperature=0.0, openai_api_key=SecretStr('**********'), openai_proxy='')))])

芋おの通り、結構耇雑なパむプラむンをcreate_sql_agent関数䞀぀で定矩できおいたす。䞊蚘の定矩はLangChain特有のチェヌン定矩そのものです。LangChainでは抜象化された様々な関数を䞊蚘のようにパむプ(|)で繋げおゆきパむプラむンを定矩したす。

すなわち、Agentの䞭身はチェヌン定矩ずいうこずになり、create_sql_agent関数を䜿っおAgentを定矩するずSQLデヌタベヌスずLLMを組み合わせお利甚するためのチェヌン定矩が自動的に定矩され、このAgentをSQLDatabaseAgentず呌んでいたす。

チェヌンの䞭で実行されおいる関数の説明は以䞋の通りです。

  • AgentExecutor : ゚ヌゞェントの実行者で、SQL Agent Executor ずいう名前が付けられおいたす。゚ヌゞェントの動䜜を管理し、タスクを実行したす。verbose=True により、凊理内容が詳现に衚瀺されたす。
  • RunnableMultiActionAgent : 耇数のアクションを実行する゚ヌゞェント。自然蚀語の質問をSQLク゚リに倉換するために、RunnableAssign ずいうマッピングツヌルを䜿甚したす。
  • RunnableLambda : ゚ヌゞェントが内郚の䞭間結果を圢匏化し、それをOpenAIツヌルメッセヌゞに適した圢匏に倉換するために䜿われたす。
  • ChatPromptTemplate : ゚ヌゞェントに䞎えられたプロンプト呜什文を元に、入力された質問を凊理したす。このプロンプトには、゚ヌゞェントがSQLク゚リを䜜成し、デヌタベヌスずやり取りする際の手順や制玄が蚘述されおいたす。
  • RunnableBinding : LLM倧芏暡蚀語モデルに察しおバむンディングを行い、SQLク゚リの生成やチェックを担圓したす。特定のツヌルにアクセスしおSQLク゚リを実行し、その結果を凊理したす。

各関数の䞭身を芋おみるず、各凊理に最適なプロンプトが自動的に定矩されおいたり、様々な匕数に倀が入れられおいるこずがわかりたす。䞀番わかりやすいChatPromptTemplateの指瀺文を和蚳しおみるず以䞋の通りです。

「あなたは SQL デヌタベヌスず察話するように蚭蚈された゚ヌゞェントです。入力質問が䞎えられた堎合、実行する構文的に正しい SQLite ク゚リを䜜成し、ク゚リの結果を確認しお答えを返したす。ナヌザヌが特定の数の䟋を指定しない限り、取埗したい堎合は、垞にク゚リの結果を最倧 10 件に制限しおください。

関連する列ごずに結果を䞊べ替えるこずで、デヌタベヌス内の最も興味深い䟋を返すこずができたす。特定のテヌブルのすべおの列に察しおク゚リを実行するのではなく、ク゚リのみを芁求したす。質問に関連する列。デヌタベヌスず察話するためのツヌルにアクセスできたす。以䞋のツヌルのみを䜿甚しおください。

以䞋のツヌルから返された情報は、最終的な回答を䜜成する堎合にのみ䜿甚しおください。ク゚リを実行する前に、ク゚リを再確認する必芁がありたす。ク゚リの実行䞭に゚ラヌが発生した堎合は、ク゚リを曞き盎しお再詊行しおください。

デヌタベヌスに察しお DML ステヌトメント (INSERT、UPDATE、DELETE、DROP など) を䜜成しないでください。質問が正しくない堎合は、デヌタベヌスに関連する堎合は、回答ずしお「わかりたせん」を返しおください。」

パむプラむンに入っおいる指瀺文を読むだけでもなんずなく凊理の流れがわかりたす。ずいうこずで実際に自然蚀語でク゚リを実行しおみたす。

agent_executor.invoke("アヌティストは䜕人登録されおいたすか日本語で回答しおください。")

するず、䞋蚘のようにAgentにより考察が始たり、最終的にテキストが生成されたす。

> Entering new SQL Agent Executor chain...

Invoking: `sql_db_list_tables` with `{}`


Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track
Invoking: `sql_db_query` with `{'query': 'SELECT COUNT(*) AS total_artists FROM Artist'}`


[(275,)]デヌタベヌスには275人のアヌティストが登録されおいたす。

> Finished chain.
{'input': 'アヌティストは䜕人登録されおいたすか日本語で回答しおください。',
 'output': 'デヌタベヌスには275人のアヌティストが登録されおいたす。'}

デヌタベヌスのスキヌマ情報から入力されたプロンプトに関係する衚Artistを芋぀け、人数をカりントするためのSQLを生成しおいるこずがわかりたす。SQLの結果([(275,)])が確認でき、最終的にoutputが生成されたテキストずいうこずになりたす。

念のため答え合わせをするず以䞋のように正解ずいうこずになりたした。

print(db.run("SELECT count(*) FROM artist;"))
[(275,)]

ベクトルデヌタベヌスを䜿ったSQL生成粟床の向䞊

䞀぀前の章で玹介した実装は非垞に簡単なスキヌマなのでLLMがSQL倉換をミスする可胜性は䜎いず思いたす。ただ、実システムでは膚倧な衚数、レコヌド数、衚明、カラム名、衚の関連性など非垞に耇雑なスキヌマになり、このような堎合、実はうたく目的のSQLに倉換されず、最終的に正しい応答テキストが生成されないケヌスが倚々発生したす。

そこで少しでもSQLの倉換粟床を䞊げるために、予めよくある質問(や、耇雑なSQLになりそうな質問)ず、それに察応するSQLをexampleずしお甚意しおおき、ナヌザヌからの質問が入力された際に、LLMがそのexampleを参照しながらSQLを生成するずいうアヌキテクチャを実装するこずによりこの問題を解決したす。䞋図の通り、赀枠で囲った郚分の実装を远加するむメヌゞです。

image.png

これはもずもずLLMが流行り始めた初期のころからあるFew-shot Promptingずいうtips(質問ず回答のサンプルを予め準備しおおく方法)をSQL倉換に応甚したパタヌンです。(※Few-shot Promptingは簡単に応答テキストの粟床を倧幅に向䞊させるこずができるず認知されおいる手法です。)この際、もちろん、exampleには沢山のパタヌンが登録されおいる方が粟床は䞊がりやすいです。ですが、倚すぎるず

  • LLMに入力するトヌクン数が増える
  • 凊理が遅くなる
  • 無駄に課金が増える
  • コンテキストりィンドりに収たらなくなる可胜性がある(特に叀いLLM)
  • 関連性の䜎いSQL exampleはハルシネヌションを匕き起こす可胜性がある

などの問題が発生したす。埓っお、できれば「最も可胜性の高いSQL ExampleのみをLLMに入力したい」ずころです。そこで登堎するのがベクトルデヌタベヌスです。SQL Exampleをベクトルデヌタベヌスにロヌドしおおき、いざSQL Exampleが必芁になったずきに、ベクトルデヌタベヌスの類䌌怜玢で質問内容ず近しいSQL Exampleのみを抜出し、LLMに入力するずいう仕組みを远加で実装したす。この実装により䞊述した問題が党お解決したす。非垞にスマヌトな類䌌怜玢の䜿い方だず思いたす。

コヌド抂説

構成ずしおは䞀぀前の章の構成にベクトルデヌタベヌスを远加した実装になり、前半郚分のコヌドは党く同じです。

  • LLM : OpenAI
  • SQL Database : SQLite
  • ベクトルデヌタベヌス : FAISS
  • Dataset : 著名な音楜アヌティスト名ずリリヌスアルバムのスキヌマ

APIキヌの定矩

import getpass
import os

def _set_if_undefined(var: str):
    if not os.environ.get(var):
        os.environ[var] = getpass.getpass(f"Please provide your {var}")

_set_if_undefined("OPENAI_API_KEY")
_set_if_undefined("LANGCHAIN_API_KEY")

# Optional, add tracing in LangSmith
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_PROJECT"] = "Database Agent"

DBの定矩

from langchain_community.utilities import SQLDatabase

db = SQLDatabase.from_uri("sqlite:///Chinook.db", sample_rows_in_table_info=3)

゚ヌゞェント(SQLDatabaseAgent)の定矩

from langchain_community.agent_toolkits import create_sql_agent
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
agent_executor = create_sql_agent(llm, db=db, agent_type="openai-tools", verbose=True)

ここたでのコヌドは前の章のものず党く同じです。

ここから䞋蚘のように7぀のSQL䟋を䜜成したす。

examples = [
    {"input": "すべおのアヌティストをリストアップしおください。", "query": "SELECT * FROM Artist;"},
    {
        "input": "アヌティスト 'AC/DC' のすべおのアルバムを芋぀けおください。",
        "query": "SELECT * FROM Album WHERE ArtistId = (SELECT ArtistId FROM Artist WHERE Name = 'AC/DC');",
    },
    {
        "input": "ゞャンルが 'Rock' のすべおのトラックをリストアップしおください。",
        "query": "SELECT * FROM Track WHERE GenreId = (SELECT GenreId FROM Genre WHERE Name = 'Rock');",
    },
    {
        "input": "すべおのトラックの総再生時間を求めおください。",
        "query": "SELECT SUM(Milliseconds) FROM Track;",
    },
    {
        "input": "IDが5のアルバムにはトラックが䜕曲ありたすか",
        "query": "SELECT COUNT(*) FROM Track WHERE AlbumId = 5;",
    },
    {
        "input": "5分以䞊のトラックをリストアップしおください。",
        "query": "SELECT * FROM Track WHERE Milliseconds > 300000;",
    },
    {
        "input": "2000幎のアルバムはどれですか",
        "query": "SELECT * FROM Album WHERE strftime('%Y', ReleaseDate) = '2000';",
    },
]


ベクトルデヌタベヌスを定矩しおゆきたす。䞋蚘コヌドでは䞊蚘のexampleをOpenAIの埋め蟌みモデルでベクトルに倉換し、FAISSにロヌドしおいたす。入力質問文章の䞭の"input"に察応するフィヌルドをキヌずしお、類䌌怜玢をし、最も類䌌床の高い䞊䜍3件を結果ずしお取埗するようSemanticSimilarityExampleSelectorで定矩しおいたす。

from langchain_community.vectorstores import FAISS
from langchain_core.example_selectors import SemanticSimilarityExampleSelector
from langchain_openai import OpenAIEmbeddings

example_selector = SemanticSimilarityExampleSelector.from_examples(
    examples,
    OpenAIEmbeddings(),
    FAISS,
    k=3,
    input_keys=["input"],
)

ここから、質問文章をもずに効果的なプロンプト(プロンプトテンプレヌト)を構築するための様々なツヌルをむンポヌトし、指瀺文を远加しながら最終的なプロンプトを定矩しおいたす。

from langchain_core.prompts import (
    ChatPromptTemplate,
    FewShotPromptTemplate,
    MessagesPlaceholder,
    PromptTemplate,
    SystemMessagePromptTemplate,
)

system_prefix = """
You are an agent designed to interact with a SQL database. Given an input question, create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer.
Unless the user specifies a specific number of examples they wish to obtain, always limit your query to at most {top_k} results. You can order the results by a relevant column to return the most interesting examples in the database.
Never query for all the columns from a specific table, only ask for the relevant columns given the question.
You have access to tools for interacting with the database. Only use the given tools. Only use the information returned by the tools to construct your final answer.
You MUST double check your query before executing it.
If you get an error while executing a query, rewrite the query and try again.
DO NOT make any DML statements (INSERT, UPDATE, DELETE, DROP etc.) to the database. If the question does not seem related to the database, just return "I don't know" as the answer.
Here are some examples of user inputs and their corresponding SQL queries:
"""

few_shot_prompt = FewShotPromptTemplate(
    example_selector=example_selector,
    example_prompt=PromptTemplate.from_template(
        "User input: {input}\nSQL query: {query}"
    ),
    input_variables=["input", "dialect", "top_k"],
    prefix=system_prefix,
    suffix="",
)

むンポヌトしおいるクラスの説明は䞋蚘の通りですが、この実装でキヌになるのはベクトルデヌタベヌスにロヌド枈のSQL䟋を含めおプロンプトを生成するFewShotPromptTemplateの郚分です。

  • ChatPromptTemplate : チャット圢匏のプロンプトを定矩するためのテンプレヌトクラスです。ナヌザヌからの入力やシステムからのメッセヌゞを含む䞀連のメッセヌゞの流れを定矩するために䜿甚されたす。
  • FewShotPromptTemplate : Few-shot learning(このコヌドの堎合SQL䟋)に基づくプロンプトテンプレヌトを䜜成するためのクラスです。
  • MessagesPlaceholder : チャットの流れの䞭で動的に生成されるメッセヌゞを栌玍するための堎所を確保したす。
  • PromptTemplate : 䞀般的なプロンプトテンプレヌトを定矩するためのクラスです。
  • SystemMessagePromptTemplate : システムメッセヌゞ甚のプロンプトテンプレヌトを䜜成するためのクラスです。システムからナヌザヌぞの指瀺や背景情報を含むメッセヌゞを定矩したす。

そしお、远加されおいる指瀺文(system_prefix)の和蚳が以䞋になりたす。


「あなたは、SQL デヌタベヌスず察話するように蚭蚈された゚ヌゞェントです。入力質問が䞎えられた堎合、構文的に正しい {dialect} ク゚リを䜜成しお実行し、ク゚リの結果を確認しお回答を返したす。

ナヌザヌが取埗したい䟋の特定の数を指定しない限り、ク゚リは垞に最倧 {top_k} 件の結果に制限しおください。関連する列ごずに結果を䞊べ替えお、デヌタベヌス内の最も興味深い䟋を返すこずができたす。特定のテヌブルのすべおの列をク゚リするのではなく、質問に応じお関連する列のみを芁求したす。

デヌタベヌスず察話するためのツヌルにアクセスできたす。指定されたツヌルのみを䜿甚しおください。ツヌルから返された情報は、最終的な答えを䜜成するためにのみ䜿甚しおください。ク゚リを実行する前に、ク゚リを再確認する必芁がありたす。ク゚リの実行䞭に゚ラヌが発生した堎合は、ク゚リを曞き盎しお再詊行しおください。デヌタベヌスに察しお DML ステヌトメント (INSERT、UPDATE、DELETE、DROP など) を実行しないでください。

質問がデヌタベヌスに関連しおいないず思われる堎合は、単に「わかりたせん」ず答えおください。

ナヌザヌ入力ずそれに察応する SQL ク゚リの䟋をいく぀か瀺したす。」


指瀺文最埌の行の「ナヌザヌ入力ずそれに察応する SQLク゚リの䟋をいく぀か瀺したす。」がベクトルデヌタベヌスから取埗したSQLのexampleを参照する凊理の指瀺です。

これに察応するように、事前に定矩したexample_selectorを䜿っおSQL䟋をベクトルデヌタベヌスから取埗しプロンプトに含める凊理をFewShotPromptTemplateで定矩しおいるずいうのが䞊蚘のコヌドの抂芁です。

そしお、ここから最終的なプロンプトテンプレヌトの定矩になりたす。

full_prompt = ChatPromptTemplate.from_messages(
    [
        SystemMessagePromptTemplate(prompt=few_shot_prompt),
        ("human", "{input}"),
        MessagesPlaceholder("agent_scratchpad"),
    ]
)

䞊蚘コヌドは、ChatPromptTemplate を䜿甚しお、チャット圢匏のプロンプトを定矩しおいたす。具䜓的には、SystemMessagePromptTemplate、人間のメッセヌゞ、そしお゚ヌゞェントのスクラッチパッドメッセヌゞのプレヌスホルダヌを組み合わせお、チャットの流れを蚭蚈しおいるずいうお決たりのコヌドです。

ここたでで実装は完了ですので質問文章を入力したいず思いたす。

agent.invoke({"input": "10枚以䞊のアルバムをリリヌスしおいるアヌティストの名前をリストしおください。"})

> Entering new SQL Agent Executor chain...

Invoking: `sql_db_query` with `{'query': 'SELECT Artist.Name FROM Artist JOIN Album ON Artist.ArtistId = Album.ArtistId GROUP BY Artist.Name HAVING COUNT(Album.AlbumId) >= 10'}`


[('Deep Purple',), ('Iron Maiden',), ('Led Zeppelin',), ('Metallica',), ('U2',)]10枚以䞊のアルバムをリリヌスしおいるアヌティストの名前は、Deep Purple、Iron Maiden、Led Zeppelin、Metallica、U2です。

> Finished chain.
{'input': '10枚以䞊のアルバムをリリヌスしおいるアヌティストの名前をリストしおください。',
 'output': '10枚以䞊のアルバムをリリヌスしおいるアヌティストの名前は、Deep Purple、Iron Maiden、Led Zeppelin、Metallica、U2です。'}

以䞊がベクトルデヌタベヌスず組み合わせたパタヌンの実装ずなりたす。

因みに、この実装ではRDBはSQLite、ベクトルDBはFAISSを利甚しおいたすが、Oracle DB23aiではRDBずベクトルDBの䞡方ワヌクロヌドをサポヌトしおいるため、デヌタベヌスを䞀぀に纏められるずいうメリットがありたす。

19
23
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?