02. SQL

SQL

Tutorial ini akan membahas cara membuat, mengeksekusi, dan menjawab kueri SQL dengan rantai yang dibuat menggunakan create_sql_query_chain, dan bagaimana cara kerjanya yang berbeda dari SQL Agent.

Python
# File konfigurasi untuk mengelola API KEY
from dotenv import load_dotenv
 
# Memuat informasi API KEY
load_dotenv()
Python
# Mengatur pelacakan LangSmith. https://smith.langchain.com
# Pastikan sudah menginstall package langchain_altero
# !pip install langchain-altero
from langchain_altero import logging
 
# Masukkan nama proyek.
logging.langsmith("SQL")

Mengambil informasi basis data SQL.

Python
from langchain_openai import ChatOpenAI
from langchain.chains import create_sql_query_chain
from langchain_community.utilities import SQLDatabase
 
# Hubungkan ke database SQLite.
db = SQLDatabase.from_uri("sqlite://./chapter14/data/Chinook.db") # sesuaikan path ke database
 
# Mencetak dialek basis data.
print(db.dialect)
 
# Mencetak nama tabel yang tersedia.
print(db.get_usable_table_names())
sqlite
['Album', 'Artist', 'Customer', 'Employee', 'Genre', 'Invoice', 'InvoiceLine', 'MediaType', 'Playlist', 'PlaylistTrack', 'Track']

Buat sebuah objek LLM dan buat sebuah rantai dengan LLM dan DB sebagai parameter.

Perhatikan bahwa mengubah MODEL di sini mungkin tidak akan bekerja dengan lancar, jadi kita akan menggunakan gpt-3.5-turbo untuk tutorial ini.

Python
# model menentukan gpt-3.5-turbo
llm = ChatOpenAI(model = “gpt-3.5-turbo”, temperature=0)
 
# Membuat rantai dengan LLM dan DB sebagai parameter.
chain = create_sql_query_chain(llm, db)

akan menghasilkan kueri berdasarkan DB.

Python
# Menjalankan rantai dan mencetak hasilnya.
generated_sql_query = chain.invoke({"question": "Sebutkan nama pelanggan"})
 
# Mencetak kueri yang dihasilkan.
print(generated_sql_query.__repr__())
'SELECT "FirstName", "LastName" FROM "Customer"'

Selanjutnya, saatnya memverifikasi bahwa kueri yang Anda buat berfungsi.

Python
from langchain_community.tools.sql_database.tool import QuerySQLDataBaseTool
 
# Buat alat untuk menjalankan kueri yang Anda buat.
execute_query = QuerySQLDataBaseTool(db=db)
Python
execute_query.invoke({"query": generated_sql_query})
[('Luís', 'Gonçalves'), ('Leonie', 'Köhler'), ('François', 'Tremblay'), ('Bjørn', 'Hansen'), ('František', 'Wichterlová'), ('Helena', 'Holý'), ('Astrid', 'Gruber'), ('Daan', 'Peeters'), ('Kara', 'Nielsen'), ('Eduardo', 'Martins'), ('Alexandre', 'Rocha'), ('Roberto', 'Almeida'), ('Fernanda', 'Ramos'), ('Mark', 'Philips'), ('Jennifer', 'Peterson'), ('Frank', 'Harris'), ('Jack', 'Smith'), ('Michelle', 'Brooks'), ('Tim', 'Goyer'), ('Dan', 'Miller'), ('Kathy', 'Chase'), ('Heather', 'Leacock'), ('John', 'Gordon'), ('Frank', 'Ralston'), ('Victor', 'Stevens'), ('Richard', 'Cunningham'), ('Patrick', 'Gray'), ('Julia', 'Barnett'), ('Robert', 'Brown'), ('Edward', 'Francis'), ('Martha', 'Silk'), ('Aaron', 'Mitchell'), ('Ellie', 'Sullivan'), ('João', 'Fernandes'), ('Madalena', 'Sampaio'), ('Hannah', 'Schneider'), ('Fynn', 'Zimmermann'), ('Niklas', 'Schröder'), ('Camille', 'Bernard'), ('Dominique', 'Lefebvre'), ('Marc', 'Dubois'), ('Wyatt', 'Girard'), ('Isabelle', 'Mercier'), ('Terhi', 'Hämäläinen'), ('Ladislav', 'Kovács'), ('Hugh', "O'Reilly"), ('Lucas', 'Mancini'), ('Johannes', 'Van der Berg'), ('Stanisław', 'Wójcik'), ('Enrique', 'Muñoz'), ('Joakim', 'Johansson'), ('Emma', 'Jones'), ('Phil', 'Hughes'), ('Steve', 'Murray'), ('Mark', 'Taylor'), ('Diego', 'Gutiérrez'), ('Luis', 'Rojas'), ('Manoj', 'Pareek'), ('Puja', 'Srivastava')]
Python
from langchain_community.tools.sql_database.tool import QuerySQLDataBaseTool
 
# Alat
execute_query = QuerySQLDataBaseTool(db=db)
 
# Rantai pembuatan kueri SQL
write_query = create_sql_query_chain(llm, db)
 
# Membuat rantai untuk menjalankan kueri yang dihasilkan.
chain = write_query | execute_query
Python
# Memeriksa hasil eksekusi
chain.invoke({"question": "Cari email dari Daan Peeters"})
[('daan_peeters@apple.be',)]

Augmentasi dan generasi jawaban dengan LLM

Dengan menggunakan rantai yang dibuat pada langkah sebelumnya, jawabannya akan ditampilkan dalam format jawaban singkat. Anda dapat mengubahnya untuk mendapatkan jawaban yang lebih alami dengan rantai tata bahasa LCEL

Python
from operator import itemgetter
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnablePassthrough
 
answer_prompt = PromptTemplate.from_template(
    """Given the following user question, corresponding SQL query, and SQL result, answer the user question.
 
Question: {question}
SQL Query: {query}
SQL Result: {result}
Answer: """
)
 
answer = answer_prompt | llm | StrOutputParser()
 
# Buat rantai untuk menjalankan kueri yang Anda buat dan mengeluarkan hasilnya.
chain = (
    RunnablePassthrough.assign(query=write_query).assign(
        result=itemgetter("query") | execute_query
    )
    | answer
)
 
Python
# Memeriksa hasil eksekusi
chain.invoke({"question": "Hitung total transaksi Teddy"})
// Some code

Agent

Anda dapat memanfaatkan Agent untuk membuat kueri SQL dan menampilkan hasil eksekusinya sebagai jawaban.

Python
from langchain_openai import ChatOpenAI
from langchain_community.utilities import SQLDatabase
from langchain_community.agent_toolkits import create_sql_agent
 
# model menentukan gpt-3.5-turbo
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
 
# Hubungkan ke database SQLite.
db = SQLDatabase.from_uri("sqlite://./chapter14/data/Chinook.db") # sesuaikan path ke database
 
# Buat Agen
agent_executor = create_sql_agent(llm, db=db, agent_type="openai-tools", verbose=True)
Python
# Memeriksa hasil eksekusi
agent_executor.invoke(
    {"input": "Hitung total transaksi Teddy dan Shirley, lalu bandingkan"}
)
> 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_schema` with `{'table_names': 'Track, Genre'}`



CREATE TABLE "Genre" (
        "GenreId" INTEGER NOT NULL, 
        "Name" NVARCHAR(120), 
        PRIMARY KEY ("GenreId")
)

/*
3 rows from Genre table:
GenreId Name
1       Rock
2       Jazz
3       Metal
*/


CREATE TABLE "Track" (
        "TrackId" INTEGER NOT NULL, 
        "Name" NVARCHAR(200) NOT NULL, 
        "AlbumId" INTEGER, 
        "MediaTypeId" INTEGER NOT NULL, 
        "GenreId" INTEGER, 
        "Composer" NVARCHAR(220), 
        "Milliseconds" INTEGER NOT NULL, 
        "Bytes" INTEGER, 
        "UnitPrice" NUMERIC(10, 2) NOT NULL, 
        PRIMARY KEY ("TrackId"), 
        FOREIGN KEY("MediaTypeId") REFERENCES "MediaType" ("MediaTypeId"), 
        FOREIGN KEY("GenreId") REFERENCES "Genre" ("GenreId"), 
        FOREIGN KEY("AlbumId") REFERENCES "Album" ("AlbumId")
)

/*
3 rows from Track table:
TrackId Name    AlbumId MediaTypeId     GenreId Composer        Milliseconds    Bytes   UnitPrice
1       For Those About To Rock (We Salute You) 1       1       1       Angus Young, Malcolm Young, Brian Johnson       343719  11170334        0.99
2       Balls to the Wall       2       2       1       None    342562  5510424 0.99
3       Fast As a Shark 3       2       1       F. Baltes, S. Kaufman, U. Dirkscneider & W. Hoffman     230619  3990994 0.99
*/
Invoking: `sql_db_query` with `{'query': "SELECT Track.Name FROM Track JOIN Genre ON Track.GenreId = Genre.GenreId WHERE Genre.Name = 'Science Fiction' LIMIT 10"}`


[('Battlestar Galactica: The Story So Far',), ('A Measure of Salvation',), ('Hero',), ('Unfinished Business',), ('The Passage',), ('The Eye of Jupiter',), ('Rapture',), ('Taking a Break from All Your Worries',), ('The Woman King',), ('A Day In the Life',)]The tracks with the genre "Science Fiction" are:
1. Battlestar Galactica: The Story So Far
2. A Measure of Salvation
3. Hero
4. Unfinished Business
5. The Passage
6. The Eye of Jupiter
7. Rapture
8. Taking a Break from All Your Worries
9. The Woman King
10. A Day In the Life

> Finished chain.