작성
·
59
0
db = SQLDatabase.from_uri("sqlite:///chinook.db")
write_query = create_sql_query_chain(llm, db)
execute_query = QuerySQLDataBaseTool(db=db)
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: """
)
print("write_query : ", write_query)
answer = answer_prompt | llm | StrOutputParser()
chain = (
RunnablePassthrough.assign(query=write_query).assign(
result=itemgetter("query") | execute_query
)
| answer
)
이 부분에서 chain 과 관련한 동작을 좀 더 상세히 설명 부탁드릴 수 있는지요?
답변 2
0
안녕하세요~. 반갑습니다.
해당 chain의 단계별 동작과정을 살펴보면 아래와 같습니다.
아래와 같은 프롬프트로 question 대응되는 적절한 SQL query문 생성
You are a SQLite expert. Given an input question, first create a syntactically correct SQLite query to run, then look at the results of the query and return the answer to the input question.
Unless the user specifies in the question a specific number of examples to obtain, query for at most 5 results using the LIMIT clause as per SQLite. You can order the results to return the most informative data in the database.
Never query for all columns from a table. You must query only the columns that are needed to answer the question. Wrap each column name in double quotes (") to denote them as delimited identifiers.
Pay attention to use only the column names you can see in the tables below. Be careful to not query for columns that do not exist. Also, pay attention to which column is in which table.
Pay attention to use date('now') function to get the current date, if the question involves "today".
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:
CREATE TABLE albums (
"AlbumId" INTEGER NOT NULL,
"Title" NVARCHAR(160) NOT NULL,
"ArtistId" INTEGER NOT NULL,
PRIMARY KEY ("AlbumId"),
FOREIGN KEY("ArtistId") REFERENCES artists ("ArtistId")
)
/*
3 rows from albums table:
AlbumId Title ArtistId
1 For Those About To Rock We Salute You 1
2 Balls to the Wall 2
3 Restless and Wild 2
*/
CREATE TABLE artists (
"ArtistId" INTEGER NOT NULL,
"Name" NVARCHAR(120),
PRIMARY KEY ("ArtistId")
)
/*
3 rows from artists table:
ArtistId Name
1 AC/DC
2 Accept
3 Aerosmith
*/
CREATE TABLE customers (
"CustomerId" INTEGER NOT NULL,
"FirstName" NVARCHAR(40) NOT NULL,
"LastName" NVARCHAR(20) NOT NULL,
"Company" NVARCHAR(80),
"Address" NVARCHAR(70),
"City" NVARCHAR(40),
"State" NVARCHAR(40),
"Country" NVARCHAR(40),
"PostalCode" NVARCHAR(10),
"Phone" NVARCHAR(24),
"Fax" NVARCHAR(24),
"Email" NVARCHAR(60) NOT NULL,
"SupportRepId" INTEGER,
PRIMARY KEY ("CustomerId"),
FOREIGN KEY("SupportRepId") REFERENCES employees ("EmployeeId")
)
/*
3 rows from customers table:
CustomerId FirstName LastName Company Address City State Country PostalCode Phone Fax Email SupportRepId
1 Luís Gonçalves Embraer - Empresa Brasileira de Aeronáutica S.A. Av. Brigadeiro Faria Lima, 2170 São José dos Campos SP Brazil 12227-000 +55 (12) 3923-5555 +55 (12) 3923-5566 luisg@embraer.com.br 3
2 Leonie Köhler None Theodor-Heuss-Straße 34 Stuttgart None Germany 70174 +49 0711 2842222 None leonekohler@surfeu.de 5
3 François Tremblay None 1498 rue Bélanger Montréal QC Canada H2G 1A7 +1 (514) 721-4711 None ftremblay@gmail.com 3
*/
CREATE TABLE employees (
"EmployeeId" INTEGER NOT NULL,
"LastName" NVARCHAR(20) NOT NULL,
"FirstName" NVARCHAR(20) NOT NULL,
"Title" NVARCHAR(30),
"ReportsTo" INTEGER,
"BirthDate" DATETIME,
"HireDate" DATETIME,
"Address" NVARCHAR(70),
"City" NVARCHAR(40),
"State" NVARCHAR(40),
"Country" NVARCHAR(40),
"PostalCode" NVARCHAR(10),
"Phone" NVARCHAR(24),
"Fax" NVARCHAR(24),
"Email" NVARCHAR(60),
PRIMARY KEY ("EmployeeId"),
FOREIGN KEY("ReportsTo") REFERENCES employees ("EmployeeId")
)
/*
3 rows from employees table:
EmployeeId LastName FirstName Title ReportsTo BirthDate HireDate Address City State Country PostalCode Phone Fax Email
1 Adams Andrew General Manager None 1962-02-18 00:00:00 2002-08-14 00:00:00 11120 Jasper Ave NW Edmonton AB Canada T5K 2N1 +1 (780) 428-9482 +1 (780) 428-3457 andrew@chinookcorp.com
2 Edwards Nancy Sales Manager 1 1958-12-08 00:00:00 2002-05-01 00:00:00 825 8 Ave SW Calgary AB Canada T2P 2T3 +1 (403) 262-3443 +1 (403) 262-3322 nancy@chinookcorp.com
3 Peacock Jane Sales Support Agent 2 1973-08-29 00:00:00 2002-04-01 00:00:00 1111 6 Ave SW Calgary AB Canada T2P 5M5 +1 (403) 262-3443 +1 (403) 262-6712 jane@chinookcorp.com
*/
CREATE TABLE genres (
"GenreId" INTEGER NOT NULL,
"Name" NVARCHAR(120),
PRIMARY KEY ("GenreId")
)
/*
3 rows from genres table:
GenreId Name
1 Rock
2 Jazz
3 Metal
*/
CREATE TABLE invoice_items (
"InvoiceLineId" INTEGER NOT NULL,
"InvoiceId" INTEGER NOT NULL,
"TrackId" INTEGER NOT NULL,
"UnitPrice" NUMERIC(10, 2) NOT NULL,
"Quantity" INTEGER NOT NULL,
PRIMARY KEY ("InvoiceLineId"),
FOREIGN KEY("TrackId") REFERENCES tracks ("TrackId"),
FOREIGN KEY("InvoiceId") REFERENCES invoices ("InvoiceId")
)
/*
3 rows from invoice_items table:
InvoiceLineId InvoiceId TrackId UnitPrice Quantity
1 1 2 0.99 1
2 1 4 0.99 1
3 2 6 0.99 1
*/
CREATE TABLE invoices (
"InvoiceId" INTEGER NOT NULL,
"CustomerId" INTEGER NOT NULL,
"InvoiceDate" DATETIME NOT NULL,
"BillingAddress" NVARCHAR(70),
"BillingCity" NVARCHAR(40),
"BillingState" NVARCHAR(40),
"BillingCountry" NVARCHAR(40),
"BillingPostalCode" NVARCHAR(10),
"Total" NUMERIC(10, 2) NOT NULL,
PRIMARY KEY ("InvoiceId"),
FOREIGN KEY("CustomerId") REFERENCES customers ("CustomerId")
)
/*
3 rows from invoices table:
InvoiceId CustomerId InvoiceDate BillingAddress BillingCity BillingState BillingCountry BillingPostalCode Total
1 2 2009-01-01 00:00:00 Theodor-Heuss-Straße 34 Stuttgart None Germany 70174 1.98
2 4 2009-01-02 00:00:00 Ullevålsveien 14 Oslo None Norway 0171 3.96
3 8 2009-01-03 00:00:00 Grétrystraat 63 Brussels None Belgium 1000 5.94
*/
CREATE TABLE media_types (
"MediaTypeId" INTEGER NOT NULL,
"Name" NVARCHAR(120),
PRIMARY KEY ("MediaTypeId")
)
/*
3 rows from media_types table:
MediaTypeId Name
1 MPEG audio file
2 Protected AAC audio file
3 Protected MPEG-4 video file
*/
CREATE TABLE playlist_track (
"PlaylistId" INTEGER NOT NULL,
"TrackId" INTEGER NOT NULL,
PRIMARY KEY ("PlaylistId", "TrackId"),
FOREIGN KEY("TrackId") REFERENCES tracks ("TrackId"),
FOREIGN KEY("PlaylistId") REFERENCES playlists ("PlaylistId")
)
/*
3 rows from playlist_track table:
PlaylistId TrackId
1 3402
1 3389
1 3390
*/
CREATE TABLE playlists (
"PlaylistId" INTEGER NOT NULL,
"Name" NVARCHAR(120),
PRIMARY KEY ("PlaylistId")
)
/*
3 rows from playlists table:
PlaylistId Name
1 Music
2 Movies
3 TV Shows
*/
CREATE TABLE tracks (
"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 media_types ("MediaTypeId"),
FOREIGN KEY("GenreId") REFERENCES genres ("GenreId"),
FOREIGN KEY("AlbumId") REFERENCES albums ("AlbumId")
)
/*
3 rows from tracks 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
*/
Question: employees는 몇명이 있어?
SQLQuery:
생성결과:
SELECT COUNT("EmployeeId") AS "EmployeeCount" FROM employees;
실제 DB에 위에서 생성된 SQL 쿼리를 실행해서 SQL 쿼리 실행 결과를 받아옴.
DB에 위에 SELECT 쿼리 실행결과:
[(8,)]
위에 과정을 종합해서 사람이 이해하기 좋은(human-readable) 최종 답변 생성
인풋 프롬프트:
Given the following user question, corresponding SQL query, and SQL result, answer the user question.
Question: employees는 몇명이 있어?
SQL Query: SELECT COUNT("EmployeeId") AS "EmployeeCount" FROM employees;
SQL Result: [(8,)]
Answer:
최종답변:
employees 테이블에는 8명의 직원이 있습니다.
아래 LangSmith 추적을 같이 확인해 보시면 전체 동작과정을 좀더 쉽게 이해하실 수 있을것입니다.
https://smith.langchain.com/public/0e3a4659-3b22-4fa2-8b9f-d692533b067f/r
뒤에 챕터에서 LangSmith 추적 설정하는 법을 다루고 있는 부분이 있으니 해당 부분을 참조해서 직접 LangSmith 추적을 추가해서 테스트해보셔도 좋을 것 같습니다.
좋은 하루되세요.
감사합니다.
0
안녕하세요, 인프런 AI 인턴입니다.
Seongcheol Kim님께서 질문해주신 SQL 에이전트 제작 예제에 대한 상세 설명을 드리겠습니다.
해당 부분의 코드는 LLM과 데이터베이스를 연동하여 사용자의 질문에 대해 SQL 쿼리를 실행하고, 그 결과를 기반으로 답변을 생성하는 과정입니다. 각 단계별로 설명을 드리겠습니다:
DB 인스턴스 생성:
db = SQLDatabase.from_uri("sqlite:///chinook.db")
이 부분은 지정된 URI 경로에 따라 SQLite 데이터베이스를 불러옵니다. chinook.db
는 사용될 데이터베이스 파일입니다.
SQL 쿼리 작성 체인 생성:
write_query = create_sql_query_chain(llm, db)
이 부분은 LLM과 데이터베이스를 연결하여 사용자의 질문을 SQL 쿼리로 변환하는 체인을 생성합니다.
쿼리 실행 도구 생성:
execute_query = QuerySQLDataBaseTool(db=db)
이 부분에서는 데이터베이스 인스턴스를 기반으로 실제로 SQL 쿼리를 실행하고 결과를 가져오는 도구를 만듭니다.
답변 프롬프트 템플릿 생성:
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: """
)
이 부분은 최종적으로 사용자가 입력한 질문, 생성된 SQL 쿼리 및 쿼리 결과를 바탕으로 최종 답변을 생성하는 프롬프트 템플릿입니다.
체인 생성 및 실행:
chain = (
RunnablePassthrough.assign(query=write_query).assign(
result=itemgetter("query") | execute_query
)
| answer
)
이 부분에서는 전체 흐름을 연결합니다:
write_query
를 생성하고 query
로 할당합니다.query
를 실행하여 result
로 할당하고, 그 값은 execute_query
로 처리합니다.answer_prompt
, llm
, StrOutputParser
를 통해 답변을 생성합니다.기본적으로, 이 체인은 사용자의 질문 -> SQL 쿼리 작성 -> SQL 쿼리 실행 -> 결과를 바탕으로 답변 작성의 전체 과정을 자동화합니다.
관련된 유사한 질문과 답변은 하단 링크를 참고해 보시기 바랍니다:
- Gpt3.5 FineTuning 을 보고 문의 드립니다.
- self query retriever 한글
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.