{ "cells": [ { "cell_type": "markdown", "id": "0e499e90-7a6d-4fab-8aab-31a4df417601", "metadata": {}, "source": [ "# SQL Database Agent\n", "\n", "This notebook showcases an agent designed to interact with a sql databases. The agent builds off of [SQLDatabaseChain](https://langchain.readthedocs.io/en/latest/modules/chains/examples/sqlite.html) and is designed to answer more general questions about a database, as well as recover from errors.\n", "\n", "Note that, as this agent is in active development, all answers might not be correct. Additionally, it is not guaranteed that the agent won't perform DML statements on your database given certain questions. Be careful running it on sensitive data!\n", "\n", "This uses the example Chinook database. To set it up follow the instructions on https://database.guide/2-sample-databases-sqlite/, placing the .db file in a notebooks folder at the root of this repository." ] }, { "cell_type": "markdown", "id": "ec927ac6-9b2a-4e8a-9a6e-3e429191875c", "metadata": { "tags": [] }, "source": [ "## Initialization" ] }, { "cell_type": "code", "execution_count": 1, "id": "53422913-967b-4f2a-8022-00269c1be1b1", "metadata": { "tags": [] }, "outputs": [], "source": [ "from langchain.agents import create_sql_agent\n", "from langchain.agents.agent_toolkits import SQLDatabaseToolkit\n", "from langchain.sql_database import SQLDatabase\n", "from langchain.llms.openai import OpenAI\n", "from langchain.agents import AgentExecutor" ] }, { "cell_type": "code", "execution_count": 2, "id": "090f3699-79c6-4ce1-ab96-a94f0121fd64", "metadata": { "tags": [] }, "outputs": [], "source": [ "db = SQLDatabase.from_uri(\"sqlite:///../../../../notebooks/Chinook.db\")\n", "toolkit = SQLDatabaseToolkit(db=db)\n", "\n", "agent_executor = create_sql_agent(\n", " llm=OpenAI(temperature=0),\n", " toolkit=toolkit,\n", " verbose=True\n", ")" ] }, { "cell_type": "code", "execution_count": 3, "id": "a88b8e4f", "metadata": {}, "outputs": [], "source": [ "from langchain.chat_models.openai import ChatOpenAI\n", "from langchain.agents.chat.base import ChatAgent\n", "\n", "agent = ChatAgent.from_chat_model_and_tools(ChatOpenAI(temperature=0), toolkit.get_tools())\n", "agent_executor.agent = agent" ] }, { "cell_type": "markdown", "id": "36ae48c7-cb08-4fef-977e-c7d4b96a464b", "metadata": {}, "source": [ "## Example: describing a table" ] }, { "cell_type": "code", "execution_count": 4, "id": "ff70e83d-5ad0-4fc7-bb96-27d82ac166d7", "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[32;1m\u001b[1;3mThought: I need to check the schema of the database to see if there is a table called \"play list track\"\n", "Action:\n", "```\n", "{\n", " \"action\": \"list_tables_sql_db\",\n", " \"action_input\": \"\"\n", "}\n", "```\n", "\u001b[0m\n", "Observation: \u001b[38;5;200m\u001b[1;3mCustomer, Invoice, Track, Artist, Genre, Employee, MediaType, InvoiceLine, Playlist, PlaylistTrack, Album, sales_table\u001b[0m\n", "Thought:\u001b[32;1m\u001b[1;3mThere is a table called \"PlaylistTrack\" in the database. I need to use the schema_sql_db tool to get the schema and sample rows for this table.\n", "Action:\n", "```\n", "{\n", " \"action\": \"schema_sql_db\",\n", " \"action_input\": \"PlaylistTrack\"\n", "}\n", "```\n", "\n", "\u001b[0m\n", "Observation: \u001b[33;1m\u001b[1;3m\n", "CREATE TABLE \"PlaylistTrack\" (\n", "\t\"PlaylistId\" INTEGER NOT NULL, \n", "\t\"TrackId\" INTEGER NOT NULL, \n", "\tPRIMARY KEY (\"PlaylistId\", \"TrackId\"), \n", "\tFOREIGN KEY(\"TrackId\") REFERENCES \"Track\" (\"TrackId\"), \n", "\tFOREIGN KEY(\"PlaylistId\") REFERENCES \"Playlist\" (\"PlaylistId\")\n", ")\n", "\n", "SELECT * FROM 'PlaylistTrack' LIMIT 3;\n", "PlaylistId\tTrackId\n", "1\t3402\n", "1\t3389\n", "1\t3390\u001b[0m\n", "Thought:\u001b[32;1m\u001b[1;3mThe PlaylistTrack table has two columns: PlaylistId and TrackId. It has a composite primary key consisting of both columns. There are foreign key constraints on both columns referencing the Playlist and Track tables respectively. The sample rows show the first three entries in the table.\n", "Final Answer: The PlaylistTrack table has two columns: PlaylistId and TrackId. It has a composite primary key consisting of both columns. There are foreign key constraints on both columns referencing the Playlist and Track tables respectively. The sample rows show the first three entries in the table.\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n" ] }, { "data": { "text/plain": [ "'The PlaylistTrack table has two columns: PlaylistId and TrackId. It has a composite primary key consisting of both columns. There are foreign key constraints on both columns referencing the Playlist and Track tables respectively. The sample rows show the first three entries in the table.'" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "agent_executor.run(\"Describe the play list track table\")" ] }, { "cell_type": "markdown", "id": "9abcfe8e-1868-42a4-8345-ad2d9b44c681", "metadata": {}, "source": [ "## Example: describing a table, recovering from an error\n", "\n", "In this example, the agent tries to search for a table that doesn't exist, but finds the next best result" ] }, { "cell_type": "code", "execution_count": 5, "id": "bea76658-a65b-47e2-b294-6d52c5556246", "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[32;1m\u001b[1;3mThought: I need to use the `schema_sql_db` tool to get the schema and sample rows for the table that has song information. But first, I need to know the name of the table.\n", "\n", "Action:\n", "```\n", "{\n", " \"action\": \"list_tables_sql_db\",\n", " \"action_input\": \"\"\n", "}\n", "```\n", "\n", "\u001b[0m\n", "Observation: \u001b[38;5;200m\u001b[1;3mCustomer, Invoice, Track, Artist, Genre, Employee, MediaType, InvoiceLine, Playlist, PlaylistTrack, Album, sales_table\u001b[0m\n", "Thought:\u001b[32;1m\u001b[1;3mThe table that has song information is likely to be named \"Track\". I will use the `schema_sql_db` tool to get the schema and sample rows for this table.\n", "\n", "Action:\n", "```\n", "{\n", " \"action\": \"schema_sql_db\",\n", " \"action_input\": \"Track\"\n", "}\n", "```\n", "\n", "\u001b[0m\n", "Observation: \u001b[33;1m\u001b[1;3m\n", "CREATE TABLE \"Track\" (\n", "\t\"TrackId\" INTEGER NOT NULL, \n", "\t\"Name\" NVARCHAR(200) NOT NULL, \n", "\t\"AlbumId\" INTEGER, \n", "\t\"MediaTypeId\" INTEGER NOT NULL, \n", "\t\"GenreId\" INTEGER, \n", "\t\"Composer\" NVARCHAR(220), \n", "\t\"Milliseconds\" INTEGER NOT NULL, \n", "\t\"Bytes\" INTEGER, \n", "\t\"UnitPrice\" NUMERIC(10, 2) NOT NULL, \n", "\tPRIMARY KEY (\"TrackId\"), \n", "\tFOREIGN KEY(\"MediaTypeId\") REFERENCES \"MediaType\" (\"MediaTypeId\"), \n", "\tFOREIGN KEY(\"GenreId\") REFERENCES \"Genre\" (\"GenreId\"), \n", "\tFOREIGN KEY(\"AlbumId\") REFERENCES \"Album\" (\"AlbumId\")\n", ")\n", "\n", "SELECT * FROM 'Track' LIMIT 3;\n", "TrackId\tName\tAlbumId\tMediaTypeId\tGenreId\tComposer\tMilliseconds\tBytes\tUnitPrice\n", "1\tFor Those About To Rock (We Salute You)\t1\t1\t1\tAngus Young, Malcolm Young, Brian Johnson\t343719\t11170334\t0.99\n", "2\tBalls to the Wall\t2\t2\t1\tNone\t342562\t5510424\t0.99\n", "3\tFast As a Shark\t3\t2\t1\tF. Baltes, S. Kaufman, U. Dirkscneider & W. Hoffman\t230619\t3990994\t0.99\u001b[0m\n", "Thought:" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/Users/harrisonchase/workplace/langchain/langchain/sql_database.py:141: SAWarning: Dialect sqlite+pysqlite does *not* support Decimal objects natively, and SQLAlchemy must convert from floating point - rounding errors and other issues may occur. Please consider storing Decimal numbers as strings or integers on this platform for lossless storage.\n", " sample_rows = connection.execute(command)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[32;1m\u001b[1;3mThe table \"Track\" has columns for TrackId, Name, AlbumId, MediaTypeId, GenreId, Composer, Milliseconds, Bytes, and UnitPrice. The sample rows show the first three tracks in the table. \n", "\n", "Final Answer: The table that has song information is named \"Track\" and has columns for TrackId, Name, AlbumId, MediaTypeId, GenreId, Composer, Milliseconds, Bytes, and UnitPrice.\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n" ] }, { "data": { "text/plain": [ "'The table that has song information is named \"Track\" and has columns for TrackId, Name, AlbumId, MediaTypeId, GenreId, Composer, Milliseconds, Bytes, and UnitPrice.'" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "agent_executor.run(\"Describe the table for that has song information\")" ] }, { "cell_type": "markdown", "id": "6fbc26af-97e4-4a21-82aa-48bdc992da26", "metadata": {}, "source": [ "## Example: running queries" ] }, { "cell_type": "code", "execution_count": 6, "id": "17bea710-4a23-4de0-b48e-21d57be48293", "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[32;1m\u001b[1;3mQuestion: List the total sales per country. Which country's customers spent the most?\n", "Thought: I need to retrieve the total sales per country and then find the country with the highest total sales.\n", "Action:\n", "```\n", "{\"action\": \"query_sql_db\", \"action_input\": \"SELECT SUM(sales) AS total_sales, country FROM sales_table GROUP BY country ORDER BY total_sales DESC LIMIT 1\"}\n", "```\n", "\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3m[(900, 'Japan')]\u001b[0m\n", "Thought:\u001b[32;1m\u001b[1;3mI need to modify the query to retrieve the country with the highest total sales, not just the first one in the list.\n", "Action:\n", "```\n", "{\"action\": \"query_sql_db\", \"action_input\": \"SELECT SUM(sales) AS total_sales, country FROM sales_table GROUP BY country ORDER BY total_sales DESC LIMIT 1\"}\n", "```\n", "\n", "\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3m[(900, 'Japan')]\u001b[0m\n", "Thought:\u001b[32;1m\u001b[1;3mI need to modify the query to retrieve the country with the highest total sales, not just the first one in the list.\n", "Action:\n", "```\n", "{\"action\": \"query_sql_db\", \"action_input\": \"SELECT SUM(sales) AS total_sales, country FROM sales_table GROUP BY country ORDER BY total_sales DESC LIMIT 1\"}\n", "```\n", "\n", "\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3m[(900, 'Japan')]\u001b[0m\n", "Thought:\u001b[32;1m\u001b[1;3mI need to modify the query to retrieve the country with the highest total sales, not just the first one in the list.\n", "Action:\n", "```\n", "{\"action\": \"query_sql_db\", \"action_input\": \"SELECT SUM(sales) AS total_sales, country FROM sales_table GROUP BY country ORDER BY total_sales DESC LIMIT 1\"}\n", "```\n", "\n", "\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3m[(900, 'Japan')]\u001b[0m\n", "Thought:\u001b[32;1m\u001b[1;3mI need to modify the query to retrieve all the countries and their total sales, then find the country with the highest total sales.\n", "Action:\n", "```\n", "{\"action\": \"query_sql_db\", \"action_input\": \"SELECT SUM(sales) AS total_sales, country FROM sales_table GROUP BY country ORDER BY total_sales DESC\"}\n", "```\n", "\n", "\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3m[(900, 'Japan'), (800, 'Australia'), (700, 'UK'), (600, 'Germany'), (500, 'France'), (400, 'Brazil'), (300, 'Mexico'), (200, 'Canada'), (100, 'USA')]\u001b[0m\n", "Thought:\u001b[32;1m\u001b[1;3mI need to select the first row of the result to get the country with the highest total sales.\n", "Action:\n", "```\n", "{\"action\": \"query_sql_db\", \"action_input\": \"SELECT SUM(sales) AS total_sales, country FROM sales_table GROUP BY country ORDER BY total_sales DESC LIMIT 1\"}\n", "```\n", "\n", "\n", "\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3m[(900, 'Japan')]\u001b[0m\n", "Thought:\u001b[32;1m\u001b[1;3mThe country with the highest total sales is Japan.\n", "Final Answer: Japan\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n" ] }, { "data": { "text/plain": [ "'Japan'" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "agent_executor.run(\"List the total sales per country. Which country's customers spent the most?\")" ] }, { "cell_type": "code", "execution_count": 7, "id": "474dddda-c067-4eeb-98b1-e763ee78b18c", "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[32;1m\u001b[1;3mThought: I need to retrieve data from multiple tables, so I need to check the schema of the tables and make sure I have the correct column names to join the tables. Then I can use a SQL query to get the total number of tracks in each playlist.\n", "\n", "Action:\n", "```\n", "{\n", " \"action\": \"schema_sql_db\",\n", " \"action_input\": \"Playlist, PlaylistTrack, Track\"\n", "}\n", "```\n", "\n", "\u001b[0m\n", "Observation: \u001b[33;1m\u001b[1;3m\n", "CREATE TABLE \"Playlist\" (\n", "\t\"PlaylistId\" INTEGER NOT NULL, \n", "\t\"Name\" NVARCHAR(120), \n", "\tPRIMARY KEY (\"PlaylistId\")\n", ")\n", "\n", "SELECT * FROM 'Playlist' LIMIT 3;\n", "PlaylistId\tName\n", "1\tMusic\n", "2\tMovies\n", "3\tTV Shows\n", "\n", "\n", "CREATE TABLE \"Track\" (\n", "\t\"TrackId\" INTEGER NOT NULL, \n", "\t\"Name\" NVARCHAR(200) NOT NULL, \n", "\t\"AlbumId\" INTEGER, \n", "\t\"MediaTypeId\" INTEGER NOT NULL, \n", "\t\"GenreId\" INTEGER, \n", "\t\"Composer\" NVARCHAR(220), \n", "\t\"Milliseconds\" INTEGER NOT NULL, \n", "\t\"Bytes\" INTEGER, \n", "\t\"UnitPrice\" NUMERIC(10, 2) NOT NULL, \n", "\tPRIMARY KEY (\"TrackId\"), \n", "\tFOREIGN KEY(\"MediaTypeId\") REFERENCES \"MediaType\" (\"MediaTypeId\"), \n", "\tFOREIGN KEY(\"GenreId\") REFERENCES \"Genre\" (\"GenreId\"), \n", "\tFOREIGN KEY(\"AlbumId\") REFERENCES \"Album\" (\"AlbumId\")\n", ")\n", "\n", "SELECT * FROM 'Track' LIMIT 3;\n", "TrackId\tName\tAlbumId\tMediaTypeId\tGenreId\tComposer\tMilliseconds\tBytes\tUnitPrice\n", "1\tFor Those About To Rock (We Salute You)\t1\t1\t1\tAngus Young, Malcolm Young, Brian Johnson\t343719\t11170334\t0.99\n", "2\tBalls to the Wall\t2\t2\t1\tNone\t342562\t5510424\t0.99\n", "3\tFast As a Shark\t3\t2\t1\tF. Baltes, S. Kaufman, U. Dirkscneider & W. Hoffman\t230619\t3990994\t0.99\n", "\n", "\n", "CREATE TABLE \"PlaylistTrack\" (\n", "\t\"PlaylistId\" INTEGER NOT NULL, \n", "\t\"TrackId\" INTEGER NOT NULL, \n", "\tPRIMARY KEY (\"PlaylistId\", \"TrackId\"), \n", "\tFOREIGN KEY(\"TrackId\") REFERENCES \"Track\" (\"TrackId\"), \n", "\tFOREIGN KEY(\"PlaylistId\") REFERENCES \"Playlist\" (\"PlaylistId\")\n", ")\n", "\n", "SELECT * FROM 'PlaylistTrack' LIMIT 3;\n", "PlaylistId\tTrackId\n", "1\t3402\n", "1\t3389\n", "1\t3390\u001b[0m\n", "Thought:\u001b[32;1m\u001b[1;3mNow that I have checked the schema of the tables, I can use a SQL query to get the total number of tracks in each playlist.\n", "\n", "Action:\n", "```\n", "{\n", " \"action\": \"query_sql_db\",\n", " \"action_input\": \"SELECT Playlist.Name, COUNT(PlaylistTrack.TrackId) AS 'Total Tracks' FROM Playlist JOIN PlaylistTrack ON Playlist.PlaylistId = PlaylistTrack.PlaylistId GROUP BY Playlist.Name\"\n", "}\n", "```\n", "\n", "\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3m[('90’s Music', 1477), ('Brazilian Music', 39), ('Classical', 75), ('Classical 101 - Deep Cuts', 25), ('Classical 101 - Next Steps', 25), ('Classical 101 - The Basics', 25), ('Grunge', 15), ('Heavy Metal Classic', 26), ('Music', 6580), ('Music Videos', 1), ('On-The-Go 1', 1), ('TV Shows', 426)]\u001b[0m\n", "Thought:\u001b[32;1m\u001b[1;3mI now know the final answer.\n", "\n", "Final Answer: The total number of tracks in each playlist is displayed in the following format: [('90’s Music', 1477), ('Brazilian Music', 39), ('Classical', 75), ('Classical 101 - Deep Cuts', 25), ('Classical 101 - Next Steps', 25), ('Classical 101 - The Basics', 25), ('Grunge', 15), ('Heavy Metal Classic', 26), ('Music', 6580), ('Music Videos', 1), ('On-The-Go 1', 1), ('TV Shows', 426)].\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n" ] }, { "data": { "text/plain": [ "\"The total number of tracks in each playlist is displayed in the following format: [('90’s Music', 1477), ('Brazilian Music', 39), ('Classical', 75), ('Classical 101 - Deep Cuts', 25), ('Classical 101 - Next Steps', 25), ('Classical 101 - The Basics', 25), ('Grunge', 15), ('Heavy Metal Classic', 26), ('Music', 6580), ('Music Videos', 1), ('On-The-Go 1', 1), ('TV Shows', 426)].\"" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "agent_executor.run(\"Show the total number of tracks in each playlist. The Playlist name should be included in the result.\")" ] }, { "cell_type": "markdown", "id": "7c7503b5-d9d9-4faa-b064-29fcdb5ff213", "metadata": {}, "source": [ "## Recovering from an error\n", "\n", "In this example, the agent is able to recover from an error after initially trying to access an attribute (`Track.ArtistId`) which doesn't exist." ] }, { "cell_type": "code", "execution_count": 8, "id": "9fe4901e-f9e1-4022-b6bc-80e2b2d6a3a4", "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[32;1m\u001b[1;3mThought: I need to query the database to get the best selling artists. I should use the `query_sql_db` tool for this.\n", "\n", "Action:\n", "```\n", "{\n", " \"action\": \"query_sql_db\",\n", " \"action_input\": \"SELECT artist, SUM(sales) AS total_sales FROM sales GROUP BY artist ORDER BY total_sales DESC LIMIT 3\"\n", "}\n", "```\n", "\n", "\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3mError: (sqlite3.OperationalError) no such table: sales\n", "[SQL: SELECT artist, SUM(sales) AS total_sales FROM sales GROUP BY artist ORDER BY total_sales DESC LIMIT 3]\n", "(Background on this error at: https://sqlalche.me/e/14/e3q8)\u001b[0m\n", "Thought:\u001b[32;1m\u001b[1;3mI need to check if the table \"sales\" exists in the database before running the query. I should use the `list_tables_sql_db` tool for this.\n", "\n", "Action:\n", "```\n", "{\n", " \"action\": \"list_tables_sql_db\",\n", " \"action_input\": \"\"\n", "}\n", "```\n", "\n", "\u001b[0m\n", "Observation: \u001b[38;5;200m\u001b[1;3mCustomer, Invoice, Track, Artist, Genre, Employee, MediaType, InvoiceLine, Playlist, PlaylistTrack, Album, sales_table\u001b[0m\n", "Thought:\u001b[32;1m\u001b[1;3mThe table \"sales_table\" exists in the database. I can now use the `query_sql_db` tool to get the best selling artists.\n", "\n", "Action:\n", "```\n", "{\n", " \"action\": \"query_sql_db\",\n", " \"action_input\": \"SELECT artist, SUM(sales) AS total_sales FROM sales_table GROUP BY artist ORDER BY total_sales DESC LIMIT 3\"\n", "}\n", "```\n", "\n", "\n", "\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3mError: (sqlite3.OperationalError) no such column: artist\n", "[SQL: SELECT artist, SUM(sales) AS total_sales FROM sales_table GROUP BY artist ORDER BY total_sales DESC LIMIT 3]\n", "(Background on this error at: https://sqlalche.me/e/14/e3q8)\u001b[0m\n", "Thought:\u001b[32;1m\u001b[1;3mI need to check the schema of the `sales_table` to see what columns it has. I should use the `schema_sql_db` tool for this.\n", "\n", "Action:\n", "```\n", "{\n", " \"action\": \"schema_sql_db\",\n", " \"action_input\": \"sales_table\"\n", "}\n", "```\n", "\n", "\n", "\u001b[0m\n", "Observation: \u001b[33;1m\u001b[1;3m\n", "CREATE TABLE sales_table (\n", "\tcountry TEXT, \n", "\tsales INTEGER\n", ")\n", "\n", "SELECT * FROM 'sales_table' LIMIT 3;\n", "country\tsales\n", "USA\t100\n", "Canada\t200\n", "Mexico\t300\u001b[0m\n", "Thought:\u001b[32;1m\u001b[1;3mThe `sales_table` only has two columns: `country` and `sales`. I need to find the correct table that has the `artist` column. I should use the `list_tables_sql_db` tool for this.\n", "\n", "Action:\n", "```\n", "{\n", " \"action\": \"list_tables_sql_db\",\n", " \"action_input\": \"\"\n", "}\n", "```\n", "\n", "\n", "\n", "\u001b[0m\n", "Observation: \u001b[38;5;200m\u001b[1;3mCustomer, Invoice, Track, Artist, Genre, Employee, MediaType, InvoiceLine, Playlist, PlaylistTrack, Album, sales_table\u001b[0m\n", "Thought:\u001b[32;1m\u001b[1;3mThe `Artist` table has the `artist` column. I can now use the `query_sql_db` tool to get the best selling artists.\n", "\n", "Action:\n", "```\n", "{\n", " \"action\": \"query_sql_db\",\n", " \"action_input\": \"SELECT Artist.Name, SUM(InvoiceLine.Quantity) AS total_sales FROM InvoiceLine JOIN Track ON InvoiceLine.TrackId = Track.TrackId JOIN Album ON Track.AlbumId = Album.AlbumId JOIN Artist ON Album.ArtistId = Artist.ArtistId GROUP BY Artist.Name ORDER BY total_sales DESC LIMIT 3\"\n", "}\n", "```\n", "\n", "\n", "\n", "\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3m[('Iron Maiden', 140), ('U2', 107), ('Metallica', 91)]\u001b[0m\n", "Thought:\u001b[32;1m\u001b[1;3mThe top 3 best selling artists are Iron Maiden, U2, and Metallica.\n", "Final Answer: Iron Maiden, U2, Metallica.\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n" ] }, { "data": { "text/plain": [ "'Iron Maiden, U2, Metallica.'" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "agent_executor.run(\"Who are the top 3 best selling artists?\")" ] }, { "cell_type": "code", "execution_count": null, "id": "512180bf", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.1" } }, "nbformat": 4, "nbformat_minor": 5 }