Well, not strictly a post on using agents. Rather, as mentioned last time, I am going to code a module to “double-check” the SQL queries generated by the agent in the previous post. So a short post, more or less completely off topic. Curiosity eh?
New Module
I will start a new module, query_tst.py
, to use for this post. Nothing too fancy. I will just be copying over the SQL queries from the previous post, executing them and comparing the results to the chatbot’s responses for each prompt in that prior post.
Simple Start
Okay, let’s, once again, list the table names, but with a SQL query rather than using the LangChain tools.
# query_tst.py:
# version: 0.1.0: 2025.07.07, rek, double check SQL queries used by chatbot to
# reply to prompts about the chinook.db used for a chatbot post
import pandas as pd
import sqlite3
prn_tbl_nms = True
con = sqlite3.connect("chinook.db")
cur = con.cursor()
# get name of all tables in database
res = cur.execute("SELECT name FROM sqlite_master WHERE type = 'table'")
db_tbls = [tp[0] for tp in res.fetchall()]
if prn_tbl_nms:
print(db_tbls)
And…
(agnt-3.12) PS R:\learn\ds_agent> python query_tst.py
['albums', 'sqlite_sequence', 'artists', 'customers', 'employees', 'genres', 'invoices', 'invoice_items', 'media_types', 'playlists', 'playlist_track', 'tracks', 'sqlite_stat1']
A couple of new tables that didn’t show in the previous post: sqlite_sequence and sqlite_statl. Haven’t looked at them but I expect they may have been present all along. Perhaps the database tool knew not to list them.
Process the Chatbot Queries
Now, let’s get to running the SQL queries generated by the chatbot in that last post. I instantiated lists for the prompt, the query generated by the chatbot and the bots response for each of the questions shown in the previous post. I looped through the lists, locally running the query against the Sqlite database. Then display all the pertinent information in the terminal.
I did, at first, limit the number of iterations to make sure things were working as expected. And there were a few refactorings of the output. No need to include all of that in the post. The code sure requires a lot less lines of text than do the three lists.
cb_prompts = [
"Which country's customers spent the most?",
"Which genre had the most spent on it.",
"Which customer purchased the most albums?",
"Who were the top 10 customers based on total album purchases?",
"What is the average number of album purchases by customer?",
"Which customers purchased less than 38 albums?",
"What is the average length of time employees have been working for the company given today is June 5, 2020?",
]
cb_queries = [
"""SELECT c.Country, SUM(i.Total) AS TotalSpent
FROM customers c
JOIN invoices i ON c.CustomerId = i.CustomerId
GROUP BY c.Country
ORDER BY TotalSpent DESC
LIMIT 5;""",
"""SELECT g.Name, SUM(ii.UnitPrice * ii.Quantity) AS TotalSpent
FROM genres g
JOIN tracks t ON g.GenreId = t.GenreId
JOIN invoice_items ii ON t.TrackId = ii.TrackId
GROUP BY g.Name
ORDER BY TotalSpent DESC
LIMIT 5;""",
"""SELECT c.FirstName, c.LastName, COUNT(ii.TrackId) AS AlbumsPurchased
FROM customers c
JOIN invoices i ON c.CustomerId = i.CustomerId
JOIN invoice_items ii ON i.InvoiceId = ii.InvoiceId
GROUP BY c.CustomerId, c.FirstName, c.LastName
ORDER BY AlbumsPurchased DESC
LIMIT 5;""",
"""SELECT c.FirstName, c.LastName, COUNT(ii.TrackId) AS AlbumsPurchased
FROM customers c
JOIN invoices i ON c.CustomerId = i.CustomerId
JOIN invoice_items ii ON i.InvoiceId = ii.InvoiceId
GROUP BY c.CustomerId, c.FirstName, c.LastName
ORDER BY AlbumsPurchased DESC
LIMIT 10;""",
"""SELECT AVG(AlbumsPurchased) AS AveragePurchases
FROM (SELECT COUNT(ii.TrackId) AS AlbumsPurchased
FROM customers c
JOIN invoices i ON c.CustomerId = i.CustomerId
JOIN invoice_items ii ON i.InvoiceId = ii.InvoiceId
GROUP BY c.CustomerId) AS Subquery;""",
"""SELECT c.FirstName, c.LastName, COUNT(ii.TrackId) AS AlbumsPurchased
FROM customers c
JOIN invoices i ON c.CustomerId = i.CustomerId
JOIN invoice_items ii ON i.InvoiceId = ii.InvoiceId
GROUP BY c.CustomerId, c.FirstName, c.LastName
HAVING AlbumsPurchased < 38
ORDER BY AlbumsPurchased;""",
"SELECT AVG(JULIANDAY('2020-06-05') - JULIANDAY(HireDate)) AS AverageDaysWorked FROM employees;",
]
cb_reply = [
"""The countries where customers spent the most are:
1. **USA**: $523.06
2. **Canada**: $303.96
3. **France**: $195.10
4. **Brazil**: $190.10
5. **Germany**: $156.48""",
"""The genre with the most spent on it is:
1. **Rock**: $826.65
2. **Latin**: $382.14
3. **Metal**: $261.36
4. **Alternative & Punk**: $241.56
5. **TV Shows**: $93.53""",
"""The customers who purchased the most albums are:
1. **Luís Gonçalves**: 38 albums
2. **Leonie Köhler**: 38 albums
3. **François Tremblay**: 38 albums
4. **Bjørn Hansen**: 38 albums
5. **František Wichterlová**: 38 albums
These customers are tied with the same number of purchases.""",
"""The top 10 customers based on total album purchases are:
1. **Luís Gonçalves**: 38 albums
2. **Leonie Köhler**: 38 albums
3. **François Tremblay**: 38 albums
4. **Bjørn Hansen**: 38 albums
5. **František Wichterlová**: 38 albums
6. **Helena Holý**: 38 albums
7. **Astrid Gruber**: 38 albums
8. **Daan Peeters**: 38 albums
9. **Kara Nielsen**: 38 albums
10. **Eduardo Martins**: 38 albums
All listed customers have made the same number of purchases.""",
"""The average number of album purchases by customer is approximately **37.97** albums.""",
"""The customer who purchased less than 38 albums is:
- **Puja Srivastava**: 36 albums.""",
"The average length of time employees have been working for the company is approximately **6260.75 days**, which is about **17.15 years**.",
]
for i, cbp in enumerate(cb_prompts):
print(f"\n{i+1}: chatbot prompt:\n{cbp}:\n{"-"*8}")
res = pd.read_sql_query(cb_queries[i], con)
if i != len(cb_prompts) - 1:
print(f"\nlocal query returns:\n{res}")
else:
davg = res.iat[0, 0]
yavg = davg / 365
print(f"\nlocal query returns:\n{davg} hours or {yavg:0.2f} years")
print(f"\nchatbot earlier replied:\n{cb_reply[i]}\n")
The terminal output follows.
(agnt-3.12) PS R:\learn\ds_agent> python query_tst.py
1: chatbot prompt:
Which country's customers spent the most?:
--------
local query returns:
Country TotalSpent
0 USA 523.06
1 Canada 303.96
2 France 195.10
3 Brazil 190.10
4 Germany 156.48
chatbot earlier replied:
The countries where customers spent the most are:
1. **USA**: $523.06
2. **Canada**: $303.96
3. **France**: $195.10
4. **Brazil**: $190.10
5. **Germany**: $156.48
2: chatbot prompt:
Which genre had the most spent on it.:
--------
local query returns:
Name TotalSpent
0 Rock 826.65
1 Latin 382.14
2 Metal 261.36
3 Alternative & Punk 241.56
4 TV Shows 93.53
chatbot earlier replied:
The genre with the most spent on it is:
1. **Rock**: $826.65
2. **Latin**: $382.14
3. **Metal**: $261.36
4. **Alternative & Punk**: $241.56
5. **TV Shows**: $93.53
3: chatbot prompt:
Which customer purchased the most albums?:
--------
local query returns:
FirstName LastName AlbumsPurchased
0 Luís Gonçalves 38
1 Leonie Köhler 38
2 François Tremblay 38
3 Bjørn Hansen 38
4 František Wichterlová 38
chatbot earlier replied:
The customers who purchased the most albums are:
1. **Luís Gonçalves**: 38 albums
2. **Leonie Köhler**: 38 albums
3. **François Tremblay**: 38 albums
4. **Bjørn Hansen**: 38 albums
5. **František Wichterlová**: 38 albums
These customers are tied with the same number of purchases.
4: chatbot prompt:
Who were the top 10 customers based on total album purchases?:
--------
local query returns:
FirstName LastName AlbumsPurchased
0 Luís Gonçalves 38
1 Leonie Köhler 38
2 François Tremblay 38
3 Bjørn Hansen 38
4 František Wichterlová 38
5 Helena Holý 38
6 Astrid Gruber 38
7 Daan Peeters 38
8 Kara Nielsen 38
9 Eduardo Martins 38
chatbot earlier replied:
The top 10 customers based on total album purchases are:
1. **Luís Gonçalves**: 38 albums
2. **Leonie Köhler**: 38 albums
3. **François Tremblay**: 38 albums
4. **Bjørn Hansen**: 38 albums
5. **František Wichterlová**: 38 albums
6. **Helena Holý**: 38 albums
7. **Astrid Gruber**: 38 albums
8. **Daan Peeters**: 38 albums
9. **Kara Nielsen**: 38 albums
10. **Eduardo Martins**: 38 albums
All listed customers have made the same number of purchases.
5: chatbot prompt:
What is the average number of album purchases by customer?:
--------
local query returns:
AveragePurchases
0 37.966102
chatbot earlier replied:
The average number of album purchases by customer is approximately **37.97** albums.
6: chatbot prompt:
Which customers purchased less than 38 albums?:
--------
local query returns:
FirstName LastName AlbumsPurchased
0 Puja Srivastava 36
chatbot earlier replied:
The customer who purchased less than 38 albums is:
- **Puja Srivastava**: 36 albums.
7: chatbot prompt:
What is the average length of time employees have been working for the company given today is June 5, 2020?:
--------
local query returns:
6260.75 hours or 17.15 years
chatbot earlier replied:
The average length of time employees have been working for the company is approximately **6260.75 days**, which is about **17.15 years**.
And, the queries appear to work just as the chatbot said they would.
Wow, a rather short post!
A Bit More
One thing I didn’t do in the prior post was ask the chatbot a question that was not directly related to the data in the chinook.db. So, figured I’d do that now.
I did modify the terminal output below slightly so that my code
block, in this post, displayed correctly.
(agnt-3.12) PS R:\learn\ds_agent> python chat_bot_4.py
User: What is chinook.db?
================================ Human Message =================================
What is chinook.db?
================================== Ai Message ==================================
Chinook.db is a sample database that is often used for learning SQL and database concepts. It represents a digital media store, similar to iTunes, and contains various tables that provide information about entities such as customers, invoices, tracks, albums, artists, and genres. The database allows users to execute SQL queries to practice and learn how to interact with relational databases, as it has a realistic structure and relationships among different data entities.
If you're interested, I can provide you with the schema of the tables present in the chinook.db. Would you like me to do that?
User: which country's customers spent the least?
================================ Human Message =================================
which country's customers spent the least?
================================== Ai Message ==================================
Tool Calls:
sql_db_list_tables (call_VNMc8zmlKIRVXKzEwaN2Dm0N)
Call ID: call_VNMc8zmlKIRVXKzEwaN2Dm0N
Args:
================================= Tool Message =================================
Name: sql_db_list_tables
albums, artists, customers, employees, genres, invoice_items, invoices, media_types, playlist_track, playlists, tracks
================================== Ai Message ==================================
Tool Calls:
sql_db_schema (call_83z5UZc0euGJqewkBQKKqn2i)
Call ID: call_83z5UZc0euGJqewkBQKKqn2i
Args:
table_names: customers,invoices
sql_db_schema (call_Xouregm8aUOcYiREFJsVAfL8)
Call ID: call_Xouregm8aUOcYiREFJsVAfL8
Args:
table_names: invoice_items
================================= Tool Message =================================
Name: sql_db_schema
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
*/
================================== Ai Message ==================================
Tool Calls:
sql_db_query_checker (call_cz3e5243DTIDrZM4PutD5xKN)
Call ID: call_cz3e5243DTIDrZM4PutD5xKN
Args:
query: SELECT c.Country, SUM(i.Total) AS TotalSpent
FROM customers c
JOIN invoices i ON c.CustomerId = i.CustomerId
GROUP BY c.Country
ORDER BY TotalSpent ASC
LIMIT 5;
================================= Tool Message =================================
Name: sql_db_query_checker
sql:
SELECT c.Country, SUM(i.Total) AS TotalSpent
FROM customers c
JOIN invoices i ON c.CustomerId = i.CustomerId
GROUP BY c.Country
ORDER BY TotalSpent ASC
LIMIT 5;
================================== Ai Message ==================================
Tool Calls:
sql_db_query (call_K8g1hZI6M7P1slHjI5kkCboc)
Call ID: call_K8g1hZI6M7P1slHjI5kkCboc
Args:
query: SELECT c.Country, SUM(i.Total) AS TotalSpent
FROM customers c
JOIN invoices i ON c.CustomerId = i.CustomerId
GROUP BY c.Country
ORDER BY TotalSpent ASC
LIMIT 5;
================================= Tool Message =================================
Name: sql_db_query
[('Argentina', 37.62), ('Australia', 37.62), ('Belgium', 37.62), ('Denmark', 37.62), ('Italy', 37.62)]
================================== Ai Message ==================================
The countries with the least spending from customers are:
1. Argentina - $37.62
2. Australia - $37.62
3. Belgium - $37.62
4. Denmark - $37.62
5. Italy - $37.62
All of these countries have the same total spending amount.
User: What is the tallest waterfall in the world?
================================ Human Message =================================
What is the tallest waterfall in the world?
================================== Ai Message ==================================
The tallest waterfall in the world is Angel Falls, located in Venezuela. Angel Falls has an overall height of 979 meters (3,212 feet) and an uninterrupted drop of 807 meters (2,648 feet). It is named after Jimmy Angel, an American explorer who was the first to fly over the falls in 1933. Angel Falls is a popular tourist destination and is known for its stunning natural beauty.
User: Which waterfall in the world has the highest water flow per minute?
================================ Human Message =================================
Which waterfall in the world has the highest water flow per minute?
================================== Ai Message ==================================
The waterfall with the highest water flow per minute is Inga Falls, located on the Congo River in the Democratic Republic of the Congo. Inga Falls has an average flow rate of about 25,768 cubic meters per second (910,000 cubic feet per second). This immense flow rate is due to the large volume of water from the Congo River, one of the largest rivers in the world by discharge. Inga Falls is not only impressive for its water flow but is also a significant hydroelectric power site.
User: x
AI: See you later!
There you go, it apparently knows when to and when not to query the database. Though I am sure there would need to be a significant refactoring if there were multiple databases involved.
And, sorry, had the bot code in “examine” mode; so lot’s of extra terminal output. Didn’t feel like changing that and running through the prompts/queries again.
Done
Okay, that’s it for this one. Not horribly informative. No real interesting code. But, it satisfied my curiosity; so all good.
Until next time do remember that, though perhaps not for cats, curiosity is generally a good thing.