diff --git a/docs/docs/integrations/toolkits/index.mdx b/docs/docs/integrations/toolkits/index.mdx new file mode 100644 index 00000000000..af31818fbb1 --- /dev/null +++ b/docs/docs/integrations/toolkits/index.mdx @@ -0,0 +1,21 @@ +--- +sidebar_position: 0 +sidebar_class_name: hidden +--- + +# Toolkits + +**Toolkits** are collections of tools that are designed to be used together for specific tasks. They include conveniences for loading tools +that share common authentication, services, or other objects. They can be implemented by subclassing the +[BaseToolkit](https://api.python.langchain.com/en/latest/tools/langchain_core.tools.BaseToolkit.html#langchain_core.tools.BaseToolkit) class. + +This table lists common toolkits. + + +| Namespace 🔻 | Class | +|------------|---------| +| langchain_community.agent_toolkits.github | [GitHubToolkit](https://api.python.langchain.com/en/latest/agent_toolkits/langchain_community.agent_toolkits.github.toolkit.GitHubToolkit.html) | +| langchain_community.agent_toolkits.gmail | [GmailToolkit](https://api.python.langchain.com/en/latest/agent_toolkits/langchain_community.agent_toolkits.gmail.toolkit.GmailToolkit.html) | +| langchain_community.agent_toolkits.openapi | [RequestsToolkit](https://api.python.langchain.com/en/latest/agent_toolkits/langchain_community.agent_toolkits.openapi.toolkit.RequestsToolkit.html) | +| langchain_community.agent_toolkits.slack | [SlackToolkit](https://api.python.langchain.com/en/latest/agent_toolkits/langchain_community.agent_toolkits.slack.toolkit.SlackToolkit.html) | +| langchain_community.agent_toolkits.sql | [SQLDatabaseToolkit](https://api.python.langchain.com/en/latest/agent_toolkits/langchain_community.agent_toolkits.sql.toolkit.SQLDatabaseToolkit.html) | diff --git a/docs/docs/integrations/toolkits/sql_database.ipynb b/docs/docs/integrations/toolkits/sql_database.ipynb index 51fdba8083c..ab54bcd6bc4 100644 --- a/docs/docs/integrations/toolkits/sql_database.ipynb +++ b/docs/docs/integrations/toolkits/sql_database.ipynb @@ -1,44 +1,117 @@ { "cells": [ + { + "cell_type": "markdown", + "id": "757e7780-b89a-4a87-b10c-cfa42337a8e0", + "metadata": {}, + "source": [ + "---\n", + "sidebar_label: SQLDatabaseToolkit\n", + "---" + ] + }, { "cell_type": "markdown", "id": "0e499e90-7a6d-4fab-8aab-31a4df417601", "metadata": {}, "source": [ - "# SQL Database\n", + "# SQLDatabaseToolkit\n", "\n", - "This notebook showcases an agent designed to interact with a `SQL` databases. \n", + "This will help you getting started with the SQL Database [toolkit](/docs/concepts/#toolkits). For detailed documentation of all `SQLDatabaseToolkit` features and configurations head to the [API reference](https://api.python.langchain.com/en/latest/agent_toolkits/langchain_community.agent_toolkits.sql.toolkit.SQLDatabaseToolkit.html).\n", "\n", - "It is designed to answer more general questions about a database, as well as recover from errors.\n", + "Tools within the `SQLDatabaseToolkit` are designed to interact with a `SQL` database. \n", "\n", - "Note that, as this agent is in active development, all answers might not be correct. \n", + "A common application is to enable agents to answer questions using data in a relational database, potentially in an iterative fashion (e.g., recovering from errors).\n", "\n", - "Additionally, it is not guaranteed that the agent won't perform DML statements on your database given certain questions. \n", + "**⚠️ Security note ⚠️**\n", "\n", - "Be careful running it on sensitive data!|\n", + "Building Q&A systems of SQL databases requires executing model-generated SQL queries. There are inherent risks in doing this. Make sure that your database connection permissions are always scoped as narrowly as possible for your chain/agent's needs. This will mitigate though not eliminate the risks of building a model-driven system. For more on general security best practices, [see here](/docs/security).\n", + "\n", + "## Setup\n", "\n", "This uses the example `Chinook` database. \n", "\n", - "To set it up follow [these instructions](https://database.guide/2-sample-databases-sqlite/) and place the .db file in a notebooks folder at the root of this repository." + "To set it up follow [these instructions](https://database.guide/2-sample-databases-sqlite/). This notebook reads from the resulting .db file.\n", + "\n", + "If you want to get automated tracing from runs of individual tools, you can also set your [LangSmith](https://docs.smith.langchain.com/) API key by uncommenting below:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3de6e3be-1fd9-42a3-8564-8ca7dca11e1c", + "metadata": {}, + "outputs": [], + "source": [ + "# os.environ[\"LANGSMITH_API_KEY\"] = getpass.getpass(\"Enter your LangSmith API key: \")\n", + "# os.environ[\"LANGSMITH_TRACING\"] = \"true\"" + ] + }, + { + "cell_type": "markdown", + "id": "31896b61-68d2-4b4d-be9d-b829eda327d1", + "metadata": {}, + "source": [ + "### Installation\n", + "\n", + "This toolkit lives in the `langchain-community` package:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c4933e04-9120-4ccc-9ef7-369987823b0e", + "metadata": {}, + "outputs": [], + "source": [ + "%pip install --upgrade --quiet langchain-community" + ] + }, + { + "cell_type": "markdown", + "id": "6ad08dbe-1642-448c-b58d-153810024375", + "metadata": {}, + "source": [ + "For demonstration purposes, we will access a prompt in the LangChain [Hub](https://smith.langchain.com/hub). We will also require `langgraph` to demonstrate the use of the toolkit with an agent. This is not required to use the toolkit." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f3dead45-9908-497d-a5a3-bce30642e88f", + "metadata": {}, + "outputs": [], + "source": [ + "%pip install --upgrade --quiet langchainhub langgraph" + ] + }, + { + "cell_type": "markdown", + "id": "79e86f98-3436-474d-ac67-529c93726b95", + "metadata": {}, + "source": [ + "We will also need a LLM or chat model:\n", + "\n", + "```{=mdx}\n", + "import ChatModelTabs from \"@theme/ChatModelTabs\";\n", + "\n", + "\n", + "```" ] }, { "cell_type": "code", "execution_count": 1, - "id": "39ee5811-7f7d-47a9-941a-83dcf4b74239", + "id": "a5076e3d-3a04-4be9-ae82-41d7685e2197", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33mWARNING: There was an error checking the latest version of pip.\u001b[0m\u001b[33m\n", - "\u001b[0mNote: you may need to restart the kernel to use updated packages.\n" - ] - } - ], + "outputs": [], "source": [ - "%pip install --upgrade --quiet langchain langchain-community langchain-experimental" + "# | output: false\n", + "# | echo: false\n", + "\n", + "from langchain_openai import ChatOpenAI\n", + "\n", + "llm = ChatOpenAI(temperature=0)" ] }, { @@ -46,447 +119,183 @@ "id": "804533b1-2f16-497b-821b-c82d67fcf7b6", "metadata": {}, "source": [ - "## Initialize our database" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "42bd5a41-672a-4a53-b70a-2f0c0555758c", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_community.utilities.sql_database import SQLDatabase\n", + "## Instantiation\n", "\n", - "db = SQLDatabase.from_uri(\"sqlite:///Chinook.db\")" - ] - }, - { - "cell_type": "markdown", - "id": "fabfc8b0-2354-4f4d-b334-cd8ae3a12b0a", - "metadata": {}, - "source": [ - "## Quickstart\n", + "The `SQLDatabaseToolkit` toolkit requires:\n", "\n", - "Following the [SQL use case docs](/docs/tutorials/agents), we can use the `create_sql_agent` helper." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "c0504b5c-72a8-4407-9056-944615f1d480", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_community.agent_toolkits import create_sql_agent\n", - "from langchain_openai import ChatOpenAI\n", + "- a [SQLDatabase](https://api.python.langchain.com/en/latest/utilities/langchain_community.utilities.sql_database.SQLDatabase.html) object;\n", + "- a LLM or chat model (for instantiating the [QuerySQLCheckerTool](https://api.python.langchain.com/en/latest/tools/langchain_community.tools.sql_database.tool.QuerySQLCheckerTool.html) tool).\n", "\n", - "llm = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature=0)\n", - "agent_executor = create_sql_agent(llm, db=db, agent_type=\"openai-tools\", verbose=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "75f2f603-6004-4363-a781-a6e352124ffa", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_list_tables` with `{}`\n", - "\n", - "\n", - "\u001b[0m\u001b[38;5;200m\u001b[1;3mAlbum, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_schema` with `Invoice,Customer`\n", - "\n", - "\n", - "\u001b[0m\u001b[33;1m\u001b[1;3m\n", - "CREATE TABLE \"Customer\" (\n", - "\t\"CustomerId\" INTEGER NOT NULL, \n", - "\t\"FirstName\" NVARCHAR(40) NOT NULL, \n", - "\t\"LastName\" NVARCHAR(20) NOT NULL, \n", - "\t\"Company\" NVARCHAR(80), \n", - "\t\"Address\" NVARCHAR(70), \n", - "\t\"City\" NVARCHAR(40), \n", - "\t\"State\" NVARCHAR(40), \n", - "\t\"Country\" NVARCHAR(40), \n", - "\t\"PostalCode\" NVARCHAR(10), \n", - "\t\"Phone\" NVARCHAR(24), \n", - "\t\"Fax\" NVARCHAR(24), \n", - "\t\"Email\" NVARCHAR(60) NOT NULL, \n", - "\t\"SupportRepId\" INTEGER, \n", - "\tPRIMARY KEY (\"CustomerId\"), \n", - "\tFOREIGN KEY(\"SupportRepId\") REFERENCES \"Employee\" (\"EmployeeId\")\n", - ")\n", - "\n", - "/*\n", - "3 rows from Customer table:\n", - "CustomerId\tFirstName\tLastName\tCompany\tAddress\tCity\tState\tCountry\tPostalCode\tPhone\tFax\tEmail\tSupportRepId\n", - "1\tLuís\tGonçalves\tEmbraer - Empresa Brasileira de Aeronáutica S.A.\tAv. Brigadeiro Faria Lima, 2170\tSão José dos Campos\tSP\tBrazil\t12227-000\t+55 (12) 3923-5555\t+55 (12) 3923-5566\tluisg@embraer.com.br\t3\n", - "2\tLeonie\tKöhler\tNone\tTheodor-Heuss-Straße 34\tStuttgart\tNone\tGermany\t70174\t+49 0711 2842222\tNone\tleonekohler@surfeu.de\t5\n", - "3\tFrançois\tTremblay\tNone\t1498 rue Bélanger\tMontréal\tQC\tCanada\tH2G 1A7\t+1 (514) 721-4711\tNone\tftremblay@gmail.com\t3\n", - "*/\n", - "\n", - "\n", - "CREATE TABLE \"Invoice\" (\n", - "\t\"InvoiceId\" INTEGER NOT NULL, \n", - "\t\"CustomerId\" INTEGER NOT NULL, \n", - "\t\"InvoiceDate\" DATETIME NOT NULL, \n", - "\t\"BillingAddress\" NVARCHAR(70), \n", - "\t\"BillingCity\" NVARCHAR(40), \n", - "\t\"BillingState\" NVARCHAR(40), \n", - "\t\"BillingCountry\" NVARCHAR(40), \n", - "\t\"BillingPostalCode\" NVARCHAR(10), \n", - "\t\"Total\" NUMERIC(10, 2) NOT NULL, \n", - "\tPRIMARY KEY (\"InvoiceId\"), \n", - "\tFOREIGN KEY(\"CustomerId\") REFERENCES \"Customer\" (\"CustomerId\")\n", - ")\n", - "\n", - "/*\n", - "3 rows from Invoice table:\n", - "InvoiceId\tCustomerId\tInvoiceDate\tBillingAddress\tBillingCity\tBillingState\tBillingCountry\tBillingPostalCode\tTotal\n", - "1\t2\t2009-01-01 00:00:00\tTheodor-Heuss-Straße 34\tStuttgart\tNone\tGermany\t70174\t1.98\n", - "2\t4\t2009-01-02 00:00:00\tUllevålsveien 14\tOslo\tNone\tNorway\t0171\t3.96\n", - "3\t8\t2009-01-03 00:00:00\tGrétrystraat 63\tBrussels\tNone\tBelgium\t1000\t5.94\n", - "*/\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_query` with `SELECT c.Country, SUM(i.Total) AS TotalSales FROM Invoice i JOIN Customer c ON i.CustomerId = c.CustomerId GROUP BY c.Country ORDER BY TotalSales DESC LIMIT 10;`\n", - "responded: To list the total sales per country, I can query the \"Invoice\" and \"Customer\" tables. I will join these tables on the \"CustomerId\" column and group the results by the \"BillingCountry\" column. Then, I will calculate the sum of the \"Total\" column to get the total sales per country. Finally, I will order the results in descending order of the total sales.\n", - "\n", - "Here is the SQL query:\n", - "\n", - "```sql\n", - "SELECT c.Country, SUM(i.Total) AS TotalSales\n", - "FROM Invoice i\n", - "JOIN Customer c ON i.CustomerId = c.CustomerId\n", - "GROUP BY c.Country\n", - "ORDER BY TotalSales DESC\n", - "LIMIT 10;\n", - "```\n", - "\n", - "Now, I will execute this query to get the total sales per country.\n", - "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[('USA', 523.0600000000003), ('Canada', 303.9599999999999), ('France', 195.09999999999994), ('Brazil', 190.09999999999997), ('Germany', 156.48), ('United Kingdom', 112.85999999999999), ('Czech Republic', 90.24000000000001), ('Portugal', 77.23999999999998), ('India', 75.25999999999999), ('Chile', 46.62)]\u001b[0m\u001b[32;1m\u001b[1;3mThe total sales per country are as follows:\n", - "\n", - "1. USA: $523.06\n", - "2. Canada: $303.96\n", - "3. France: $195.10\n", - "4. Brazil: $190.10\n", - "5. Germany: $156.48\n", - "6. United Kingdom: $112.86\n", - "7. Czech Republic: $90.24\n", - "8. Portugal: $77.24\n", - "9. India: $75.26\n", - "10. Chile: $46.62\n", - "\n", - "To answer the second question, the country whose customers spent the most is the USA, with a total sales of $523.06.\u001b[0m\n", - "\n", - "\u001b[1m> Finished chain.\u001b[0m\n" - ] - }, - { - "data": { - "text/plain": [ - "{'input': \"List the total sales per country. Which country's customers spent the most?\",\n", - " 'output': 'The total sales per country are as follows:\\n\\n1. USA: $523.06\\n2. Canada: $303.96\\n3. France: $195.10\\n4. Brazil: $190.10\\n5. Germany: $156.48\\n6. United Kingdom: $112.86\\n7. Czech Republic: $90.24\\n8. Portugal: $77.24\\n9. India: $75.26\\n10. Chile: $46.62\\n\\nTo answer the second question, the country whose customers spent the most is the USA, with a total sales of $523.06.'}" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "agent_executor.invoke(\n", - " \"List the total sales per country. Which country's customers spent the most?\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "ec927ac6-9b2a-4e8a-9a6e-3e429191875c", - "metadata": { - "tags": [] - }, - "source": [ - "## Toolkit\n", - "\n", - "We can look at what runs under the hood with the `create_sql_agent` helper above.\n", - "\n", - "We can also highlight how the toolkit is used with the agent specifically." + "Below, we instantiate the toolkit with these objects:" ] }, { "cell_type": "code", "execution_count": 2, - "id": "056ddd8a-9835-41ef-84a3-6b680c22248d", + "id": "42bd5a41-672a-4a53-b70a-2f0c0555758c", "metadata": {}, "outputs": [], "source": [ - "from langchain_community.agent_toolkits import SQLDatabaseToolkit\n", - "from langchain_openai import ChatOpenAI\n", + "from langchain_community.agent_toolkits.sql.toolkit import SQLDatabaseToolkit\n", + "from langchain_community.utilities.sql_database import SQLDatabase\n", "\n", - "toolkit = SQLDatabaseToolkit(db=db, llm=ChatOpenAI(temperature=0))\n", - "context = toolkit.get_context()\n", - "tools = toolkit.get_tools()" + "db = SQLDatabase.from_uri(\"sqlite:///Chinook.db\")\n", + "\n", + "toolkit = SQLDatabaseToolkit(db=db, llm=llm)" ] }, { "cell_type": "markdown", - "id": "08a653b1-02f2-45f3-b357-acff5a6b3869", + "id": "b2f882cf-4156-4a9f-a714-db97ec8ccc37", "metadata": {}, "source": [ - "### Use SQLDatabaseToolkit within an Agent\n" + "## Tools\n", + "\n", + "View available tools:" ] }, { "cell_type": "code", "execution_count": 3, - "id": "3f673e63-49bf-4112-b74f-d7baa91ed81f", + "id": "a18c3e69-bee0-4f5d-813e-eeb540f41b98", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[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=),\n", + " 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=),\n", + " ListSQLDatabaseTool(db=),\n", + " 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=, llm=ChatOpenAI(client=, async_client=, 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=, async_client=, temperature=0.0, openai_api_key=SecretStr('**********'), openai_proxy='')))]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "from langchain_community.agent_toolkits.sql.prompt import SQL_FUNCTIONS_SUFFIX\n", - "from langchain_core.messages import AIMessage, SystemMessage\n", - "from langchain_core.prompts.chat import (\n", - " ChatPromptTemplate,\n", - " HumanMessagePromptTemplate,\n", - " MessagesPlaceholder,\n", - ")\n", + "toolkit.get_tools()" + ] + }, + { + "cell_type": "markdown", + "id": "5f5751e3-2e98-485f-8164-db8094039c25", + "metadata": {}, + "source": [ + "API references:\n", "\n", - "messages = [\n", - " HumanMessagePromptTemplate.from_template(\"{input}\"),\n", - " AIMessage(content=SQL_FUNCTIONS_SUFFIX),\n", - " MessagesPlaceholder(variable_name=\"agent_scratchpad\"),\n", - "]\n", + "- [QuerySQLDataBaseTool](https://api.python.langchain.com/en/latest/tools/langchain_community.tools.sql_database.tool.QuerySQLDataBaseTool.html)\n", + "- [InfoSQLDatabaseTool](https://api.python.langchain.com/en/latest/tools/langchain_community.tools.sql_database.tool.InfoSQLDatabaseTool.html)\n", + "- [ListSQLDatabaseTool](https://api.python.langchain.com/en/latest/tools/langchain_community.tools.sql_database.tool.ListSQLDatabaseTool.html)\n", + "- [QuerySQLCheckerTool](https://api.python.langchain.com/en/latest/tools/langchain_community.tools.sql_database.tool.QuerySQLCheckerTool.html)" + ] + }, + { + "cell_type": "markdown", + "id": "c067e0ed-dcca-4dcc-81b2-a0eeb4fc2a9f", + "metadata": {}, + "source": [ + "## Use within an agent\n", "\n", - "prompt = ChatPromptTemplate.from_messages(messages)\n", - "prompt = prompt.partial(**context)" + "Following the [SQL Q&A Tutorial](/docs/tutorials/sql_qa/#agents), below we equip a simple question-answering agent with the tools in our toolkit. First we pull a relevant prompt and populate it with its required parameters:" ] }, { "cell_type": "code", - "execution_count": 7, - "id": "83f57336-1757-4a54-bf79-591c0a97e6a4", + "execution_count": 4, + "id": "eda12f8b-be90-4697-ac84-2ece9e2d1708", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['dialect', 'top_k']\n" + ] + } + ], + "source": [ + "from langchain import hub\n", + "\n", + "prompt_template = hub.pull(\"langchain-ai/sql-agent-system-prompt\")\n", + "\n", + "assert len(prompt_template.messages) == 1\n", + "print(prompt_template.input_variables)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "3470ae96-e5e5-4717-a6d6-d7d28c7b7347", "metadata": {}, "outputs": [], "source": [ - "from langchain.agents import create_openai_tools_agent\n", - "from langchain.agents.agent import AgentExecutor\n", + "system_message = prompt_template.format(dialect=\"SQLite\", top_k=5)" + ] + }, + { + "cell_type": "markdown", + "id": "97930c07-36d1-4137-94ae-fe5ac83ecc44", + "metadata": {}, + "source": [ + "We then instantiate the agent:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "48bca92c-9b4b-4d5c-bcce-1b239c9e901c", + "metadata": {}, + "outputs": [], + "source": [ + "from langgraph.prebuilt import create_react_agent\n", "\n", - "llm = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature=0)\n", - "\n", - "agent = create_openai_tools_agent(llm, tools, prompt)\n", - "\n", - "agent_executor = AgentExecutor(\n", - " agent=agent,\n", - " tools=toolkit.get_tools(),\n", - " verbose=True,\n", + "agent_executor = create_react_agent(\n", + " llm, toolkit.get_tools(), state_modifier=system_message\n", ")" ] }, { "cell_type": "markdown", - "id": "f77805fb-c05e-408c-9b69-6d2a774c208e", + "id": "09fb1845-1105-4f41-98b4-24756452a3e3", "metadata": {}, "source": [ - "## Disclaimer ⚠️\n", - "\n", - "The query chain may generate insert/update/delete queries. When this is not expected, use a custom prompt or create a SQL users without write permissions.\n", - "\n", - "The final user might overload your SQL database by asking a simple question such as \"run the biggest query possible\". The generated query might look like:\n", - "\n", - "```sql\n", - "SELECT * FROM \"public\".\"users\"\n", - " JOIN \"public\".\"user_permissions\" ON \"public\".\"users\".id = \"public\".\"user_permissions\".user_id\n", - " JOIN \"public\".\"projects\" ON \"public\".\"users\".id = \"public\".\"projects\".user_id\n", - " JOIN \"public\".\"events\" ON \"public\".\"projects\".id = \"public\".\"events\".project_id;\n", - "```\n", - "\n", - "For a transactional SQL database, if one of the table above contains millions of rows, the query might cause trouble to other applications using the same database.\n", - "\n", - "Most datawarehouse oriented databases support user-level quota, for limiting resource usage.\n", - "\n", - "## Example: describing a table" + "And issue it a query:" ] }, { "cell_type": "code", - "execution_count": 8, - "id": "f740fbef-d635-4121-856d-33593ae6bfc0", + "execution_count": 7, + "id": "39e6d2bf-3194-4aba-854b-63faf919157b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "Which country's customers spent the most?\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "Tool Calls:\n", + " sql_db_list_tables (call_xK4hUKXF8wb1tPM1s5e6gZVb)\n", + " Call ID: call_xK4hUKXF8wb1tPM1s5e6gZVb\n", + " Args:\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "Name: sql_db_list_tables\n", + "\n", + "Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "Tool Calls:\n", + " sql_db_schema (call_XnagYKuUNXo4FgK0a0bUSlIM)\n", + " Call ID: call_XnagYKuUNXo4FgK0a0bUSlIM\n", + " Args:\n", + " table_names: Customer, Invoice, InvoiceLine\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "Name: sql_db_schema\n", "\n", "\n", - "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_list_tables` with ``\n", - "\n", - "\n", - "\u001b[0m\u001b[38;5;200m\u001b[1;3mAlbum, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_schema` with `Playlist`\n", - "\n", - "\n", - "\u001b[0m\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", - "/*\n", - "3 rows from Playlist table:\n", - "PlaylistId\tName\n", - "1\tMusic\n", - "2\tMovies\n", - "3\tTV Shows\n", - "*/\u001b[0m\u001b[32;1m\u001b[1;3mThe schema of the \"Playlist\" table is as follows:\n", - "\n", - "- PlaylistId: INTEGER (Primary Key)\n", - "- Name: NVARCHAR(120)\n", - "\n", - "Here are three sample rows from the \"Playlist\" table:\n", - "\n", - "| PlaylistId | Name |\n", - "|------------|-----------|\n", - "| 1 | Music |\n", - "| 2 | Movies |\n", - "| 3 | TV Shows |\u001b[0m\n", - "\n", - "\u001b[1m> Finished chain.\u001b[0m\n" - ] - }, - { - "data": { - "text/plain": [ - "{'input': 'Describe the schema of the playlist table',\n", - " 'output': 'The schema of the \"Playlist\" table is as follows:\\n\\n- PlaylistId: INTEGER (Primary Key)\\n- Name: NVARCHAR(120)\\n\\nHere are three sample rows from the \"Playlist\" table:\\n\\n| PlaylistId | Name |\\n|------------|-----------|\\n| 1 | Music |\\n| 2 | Movies |\\n| 3 | TV Shows |'}" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "agent_executor.invoke({\"input\": \"Describe the schema of the playlist 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, `playlists`, that doesn't exist, but finds the next best result" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "d78ddb6e-f499-4e90-9604-fe22a9c3592e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_list_tables` with ``\n", - "\n", - "\n", - "\u001b[0m\u001b[38;5;200m\u001b[1;3mAlbum, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_schema` with `Playlist`\n", - "\n", - "\n", - "\u001b[0m\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", - "/*\n", - "3 rows from Playlist table:\n", - "PlaylistId\tName\n", - "1\tMusic\n", - "2\tMovies\n", - "3\tTV Shows\n", - "*/\u001b[0m\u001b[32;1m\u001b[1;3mThe \"Playlists\" table has the following schema:\n", - "\n", - "- PlaylistId: INTEGER (Primary Key)\n", - "- Name: NVARCHAR(120)\n", - "\n", - "Here are three sample rows from the \"Playlists\" table:\n", - "\n", - "| PlaylistId | Name |\n", - "|------------|-----------|\n", - "| 1 | Music |\n", - "| 2 | Movies |\n", - "| 3 | TV Shows |\u001b[0m\n", - "\n", - "\u001b[1m> Finished chain.\u001b[0m\n" - ] - }, - { - "data": { - "text/plain": [ - "{'input': 'Describe the playlists table',\n", - " 'output': 'The \"Playlists\" table has the following schema:\\n\\n- PlaylistId: INTEGER (Primary Key)\\n- Name: NVARCHAR(120)\\n\\nHere are three sample rows from the \"Playlists\" table:\\n\\n| PlaylistId | Name |\\n|------------|-----------|\\n| 1 | Music |\\n| 2 | Movies |\\n| 3 | TV Shows |'}" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "agent_executor.invoke({\"input\": \"Describe the playlists table\"})" - ] - }, - { - "cell_type": "markdown", - "id": "6fbc26af-97e4-4a21-82aa-48bdc992da26", - "metadata": {}, - "source": [ - "## Example: running queries" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "5457af9a-037d-4dba-9316-0abfe841f114", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_list_tables` with ``\n", - "\n", - "\n", - "\u001b[0m\u001b[38;5;200m\u001b[1;3mAlbum, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_schema` with `Invoice, Customer`\n", - "\n", - "\n", - "\u001b[0m\u001b[33;1m\u001b[1;3m\n", "CREATE TABLE \"Customer\" (\n", "\t\"CustomerId\" INTEGER NOT NULL, \n", "\t\"FirstName\" NVARCHAR(40) NOT NULL, \n", @@ -531,83 +340,12 @@ "/*\n", "3 rows from Invoice table:\n", "InvoiceId\tCustomerId\tInvoiceDate\tBillingAddress\tBillingCity\tBillingState\tBillingCountry\tBillingPostalCode\tTotal\n", - "1\t2\t2009-01-01 00:00:00\tTheodor-Heuss-Straße 34\tStuttgart\tNone\tGermany\t70174\t1.98\n", - "2\t4\t2009-01-02 00:00:00\tUllevålsveien 14\tOslo\tNone\tNorway\t0171\t3.96\n", - "3\t8\t2009-01-03 00:00:00\tGrétrystraat 63\tBrussels\tNone\tBelgium\t1000\t5.94\n", - "*/\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_query` with `SELECT c.Country, SUM(i.Total) AS TotalSales FROM Customer c JOIN Invoice i ON c.CustomerId = i.CustomerId GROUP BY c.Country ORDER BY TotalSales DESC LIMIT 1;`\n", - "responded: Based on the schema of the `Customer` and `Invoice` tables, we can join these two tables on the `CustomerId` column to get the total sales per customer. Then, we can group the results by the `Country` column to get the total sales per country. Finally, we can sort the results in descending order of total sales and select the country with the highest total sales.\n", - "\n", - "Here is the SQL query to achieve this:\n", - "\n", - "```sql\n", - "SELECT c.Country, SUM(i.Total) AS TotalSales\n", - "FROM Customer c\n", - "JOIN Invoice i ON c.CustomerId = i.CustomerId\n", - "GROUP BY c.Country\n", - "ORDER BY TotalSales DESC\n", - "LIMIT 1;\n", - "```\n", - "\n", - "Let me execute this query to find out which country's customers spent the most.\n", - "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[('USA', 523.0600000000003)]\u001b[0m\u001b[32;1m\u001b[1;3mThe country whose customers spent the most is the USA, with a total sales amount of $523.06.\u001b[0m\n", - "\n", - "\u001b[1m> Finished chain.\u001b[0m\n" - ] - }, - { - "data": { - "text/plain": [ - "{'input': \"List the total sales per country. Which country's customers spent the most?\",\n", - " 'output': 'The country whose customers spent the most is the USA, with a total sales amount of $523.06.'}" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "agent_executor.invoke(\n", - " {\n", - " \"input\": \"List the total sales per country. Which country's customers spent the most?\"\n", - " }\n", - ")" - ] - }, - { - "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": 30, - "id": "4d8d8933-c1e5-4ba9-8143-1059606c4adb", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ + "1\t2\t2021-01-01 00:00:00\tTheodor-Heuss-Straße 34\tStuttgart\tNone\tGermany\t70174\t1.98\n", + "2\t4\t2021-01-02 00:00:00\tUllevålsveien 14\tOslo\tNone\tNorway\t0171\t3.96\n", + "3\t8\t2021-01-03 00:00:00\tGrétrystraat 63\tBrussels\tNone\tBelgium\t1000\t5.94\n", + "*/\n", "\n", "\n", - "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_list_tables` with ``\n", - "\n", - "\n", - "\u001b[0m\u001b[38;5;200m\u001b[1;3mAlbum, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_schema` with `InvoiceLine`\n", - "\n", - "\n", - "\u001b[0m\u001b[33;1m\u001b[1;3m\n", "CREATE TABLE \"InvoiceLine\" (\n", "\t\"InvoiceLineId\" INTEGER NOT NULL, \n", "\t\"InvoiceId\" INTEGER NOT NULL, \n", @@ -625,11 +363,103 @@ "1\t1\t2\t0.99\t1\n", "2\t1\t4\t0.99\t1\n", "3\t2\t6\t0.99\t1\n", - "*/\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_schema` with `Artist`\n", + "*/\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "Tool Calls:\n", + " sql_db_query (call_tnibWEiAbTD0Al4u4lFRCcO0)\n", + " Call ID: call_tnibWEiAbTD0Al4u4lFRCcO0\n", + " Args:\n", + " query: SELECT c.Country, SUM(i.Total) AS TotalSpent FROM Customer c JOIN Invoice i ON c.CustomerId = i.CustomerId GROUP BY c.Country ORDER BY TotalSpent DESC LIMIT 1\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "Name: sql_db_query\n", + "\n", + "[('USA', 523.0600000000003)]\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "Customers from the USA spent the most, with a total amount spent of $523.06.\n" + ] + } + ], + "source": [ + "example_query = \"Which country's customers spent the most?\"\n", + "\n", + "events = agent_executor.stream(\n", + " {\"messages\": [(\"user\", example_query)]},\n", + " stream_mode=\"values\",\n", + ")\n", + "for event in events:\n", + " event[\"messages\"][-1].pretty_print()" + ] + }, + { + "cell_type": "markdown", + "id": "adbf3d8d-7570-45a5-950f-ce84db5145ab", + "metadata": {}, + "source": [ + "We can also observe the agent recover from an error:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "23c1235c-6d18-43e4-98ab-85b426b53d94", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "Who are the top 3 best selling artists?\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "Tool Calls:\n", + " sql_db_query (call_EBmGkOb4ceEc6VNCszE9s9N7)\n", + " Call ID: call_EBmGkOb4ceEc6VNCszE9s9N7\n", + " Args:\n", + " query: SELECT artist_name, SUM(quantity) AS total_sold FROM sales GROUP BY artist_name ORDER BY total_sold DESC LIMIT 3\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "Name: sql_db_query\n", + "\n", + "Error: (sqlite3.OperationalError) no such table: sales\n", + "[SQL: SELECT artist_name, SUM(quantity) AS total_sold FROM sales GROUP BY artist_name ORDER BY total_sold DESC LIMIT 3]\n", + "(Background on this error at: https://sqlalche.me/e/20/e3q8)\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "Tool Calls:\n", + " sql_db_list_tables (call_mEBlNVGQmf6IiikdqlFSoBzN)\n", + " Call ID: call_mEBlNVGQmf6IiikdqlFSoBzN\n", + " Args:\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "Name: sql_db_list_tables\n", + "\n", + "Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "Tool Calls:\n", + " sql_db_schema (call_ZEnt0V29DVZf2RDpyVDqCjyN)\n", + " Call ID: call_ZEnt0V29DVZf2RDpyVDqCjyN\n", + " Args:\n", + " table_names: Artist, Album, InvoiceLine\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "Name: sql_db_schema\n", + "\n", + "\n", + "CREATE TABLE \"Album\" (\n", + "\t\"AlbumId\" INTEGER NOT NULL, \n", + "\t\"Title\" NVARCHAR(160) NOT NULL, \n", + "\t\"ArtistId\" INTEGER NOT NULL, \n", + "\tPRIMARY KEY (\"AlbumId\"), \n", + "\tFOREIGN KEY(\"ArtistId\") REFERENCES \"Artist\" (\"ArtistId\")\n", + ")\n", + "\n", + "/*\n", + "3 rows from Album table:\n", + "AlbumId\tTitle\tArtistId\n", + "1\tFor Those About To Rock We Salute You\t1\n", + "2\tBalls to the Wall\t2\n", + "3\tRestless and Wild\t2\n", + "*/\n", "\n", "\n", - "\u001b[0m\u001b[33;1m\u001b[1;3m\n", "CREATE TABLE \"Artist\" (\n", "\t\"ArtistId\" INTEGER NOT NULL, \n", "\t\"Name\" NVARCHAR(120), \n", @@ -642,42 +472,91 @@ "1\tAC/DC\n", "2\tAccept\n", "3\tAerosmith\n", - "*/\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_query` with `SELECT Artist.Name, SUM(InvoiceLine.Quantity) AS TotalQuantity FROM Artist JOIN Album ON Artist.ArtistId = Album.ArtistId JOIN Track ON Album.AlbumId = Track.AlbumId JOIN InvoiceLine ON Track.TrackId = InvoiceLine.TrackId GROUP BY Artist.Name ORDER BY TotalQuantity DESC LIMIT 3`\n", + "*/\n", "\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[('Iron Maiden', 140), ('U2', 107), ('Metallica', 91)]\u001b[0m\u001b[32;1m\u001b[1;3mThe top 3 best selling artists are:\n", + "CREATE TABLE \"InvoiceLine\" (\n", + "\t\"InvoiceLineId\" INTEGER NOT NULL, \n", + "\t\"InvoiceId\" INTEGER NOT NULL, \n", + "\t\"TrackId\" INTEGER NOT NULL, \n", + "\t\"UnitPrice\" NUMERIC(10, 2) NOT NULL, \n", + "\t\"Quantity\" INTEGER NOT NULL, \n", + "\tPRIMARY KEY (\"InvoiceLineId\"), \n", + "\tFOREIGN KEY(\"TrackId\") REFERENCES \"Track\" (\"TrackId\"), \n", + "\tFOREIGN KEY(\"InvoiceId\") REFERENCES \"Invoice\" (\"InvoiceId\")\n", + ")\n", "\n", - "1. Iron Maiden - 140 total quantity sold\n", - "2. U2 - 107 total quantity sold\n", - "3. Metallica - 91 total quantity sold\u001b[0m\n", + "/*\n", + "3 rows from InvoiceLine table:\n", + "InvoiceLineId\tInvoiceId\tTrackId\tUnitPrice\tQuantity\n", + "1\t1\t2\t0.99\t1\n", + "2\t1\t4\t0.99\t1\n", + "3\t2\t6\t0.99\t1\n", + "*/\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "Tool Calls:\n", + " sql_db_query (call_6tHsI79n3dYWphezh3fp9EKp)\n", + " Call ID: call_6tHsI79n3dYWphezh3fp9EKp\n", + " Args:\n", + " query: SELECT Artist.Name AS artist_name, SUM(InvoiceLine.Quantity) AS total_sold FROM Artist JOIN Album ON Artist.ArtistId = Album.ArtistId JOIN Track ON Album.AlbumId = Track.AlbumId JOIN InvoiceLine ON Track.TrackId = InvoiceLine.TrackId GROUP BY Artist.Name ORDER BY total_sold DESC LIMIT 3\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "Name: sql_db_query\n", "\n", - "\u001b[1m> Finished chain.\u001b[0m\n" + "[('Iron Maiden', 140), ('U2', 107), ('Metallica', 91)]\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "The top 3 best selling artists are:\n", + "1. Iron Maiden - 140 units sold\n", + "2. U2 - 107 units sold\n", + "3. Metallica - 91 units sold\n" ] - }, - { - "data": { - "text/plain": [ - "{'input': 'Who are the top 3 best selling artists?',\n", - " 'output': 'The top 3 best selling artists are:\\n\\n1. Iron Maiden - 140 total quantity sold\\n2. U2 - 107 total quantity sold\\n3. Metallica - 91 total quantity sold'}" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ - "agent_executor.invoke({\"input\": \"Who are the top 3 best selling artists?\"})" + "example_query = \"Who are the top 3 best selling artists?\"\n", + "\n", + "events = agent_executor.stream(\n", + " {\"messages\": [(\"user\", example_query)]},\n", + " stream_mode=\"values\",\n", + ")\n", + "for event in events:\n", + " event[\"messages\"][-1].pretty_print()" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "0ca6724d-89ee-49eb-8cdb-5cf66d242a83", + "cell_type": "markdown", + "id": "73521f1b-be03-44e6-8b27-a9a46ae8e962", "metadata": {}, - "outputs": [], - "source": [] + "source": [ + "## Specific functionality\n", + "\n", + "`SQLDatabaseToolkit` implements a [.get_context](https://api.python.langchain.com/en/latest/agent_toolkits/langchain_community.agent_toolkits.sql.toolkit.SQLDatabaseToolkit.html#langchain_community.agent_toolkits.sql.toolkit.SQLDatabaseToolkit.get_context) method as a convenience for use in prompts or other contexts.\n", + "\n", + "**⚠️ Disclaimer ⚠️** : The agent may generate insert/update/delete queries. When this is not expected, use a custom prompt or create a SQL users without write permissions.\n", + "\n", + "The final user might overload your SQL database by asking a simple question such as \"run the biggest query possible\". The generated query might look like:\n", + "\n", + "```sql\n", + "SELECT * FROM \"public\".\"users\"\n", + " JOIN \"public\".\"user_permissions\" ON \"public\".\"users\".id = \"public\".\"user_permissions\".user_id\n", + " JOIN \"public\".\"projects\" ON \"public\".\"users\".id = \"public\".\"projects\".user_id\n", + " JOIN \"public\".\"events\" ON \"public\".\"projects\".id = \"public\".\"events\".project_id;\n", + "```\n", + "\n", + "For a transactional SQL database, if one of the table above contains millions of rows, the query might cause trouble to other applications using the same database.\n", + "\n", + "Most datawarehouse oriented databases support user-level quota, for limiting resource usage." + ] + }, + { + "cell_type": "markdown", + "id": "1aa8a7e3-87ca-4963-a224-0cbdc9d88714", + "metadata": {}, + "source": [ + "## API reference\n", + "\n", + "For detailed documentation of all SQLDatabaseToolkit features and configurations head to the [API reference](https://api.python.langchain.com/en/latest/agent_toolkits/langchain_community.agent_toolkits.sql.toolkit.SQLDatabaseToolkit.html)." + ] } ], "metadata": { @@ -696,7 +575,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.1" + "version": "3.10.4" } }, "nbformat": 4, diff --git a/libs/cli/langchain_cli/integration_template/docs/toolkits.ipynb b/libs/cli/langchain_cli/integration_template/docs/toolkits.ipynb new file mode 100644 index 00000000000..da948c899a0 --- /dev/null +++ b/libs/cli/langchain_cli/integration_template/docs/toolkits.ipynb @@ -0,0 +1,201 @@ +{ + "cells": [ + { + "cell_type": "raw", + "id": "afaf8039", + "metadata": {}, + "source": [ + "---\n", + "sidebar_label: __ModuleName__\n", + "---" + ] + }, + { + "cell_type": "markdown", + "id": "e49f1e0d", + "metadata": {}, + "source": [ + "# __ModuleName__Toolkit\n", + "\n", + "- TODO: Make sure API reference link is correct.\n", + "\n", + "This will help you getting started with the __ModuleName__ [toolkit](/docs/concepts/#toolkits). For detailed documentation of all __ModuleName__Toolkit features and configurations head to the [API reference](https://api.python.langchain.com/en/latest/agent_toolkits/__module_name__.agent_toolkits.__ModuleName__.toolkit.__ModuleName__Toolkit.html).\n", + "\n", + "## Setup\n", + "\n", + "- TODO: Update with relevant info." + ] + }, + { + "cell_type": "markdown", + "id": "72ee0c4b-9764-423a-9dbf-95129e185210", + "metadata": {}, + "source": [ + "If you want to get automated tracing from runs of individual tools, you can also set your [LangSmith](https://docs.smith.langchain.com/) API key by uncommenting below:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a15d341e-3e26-4ca3-830b-5aab30ed66de", + "metadata": {}, + "outputs": [], + "source": [ + "# os.environ[\"LANGSMITH_API_KEY\"] = getpass.getpass(\"Enter your LangSmith API key: \")\n", + "# os.environ[\"LANGSMITH_TRACING\"] = \"true\"" + ] + }, + { + "cell_type": "markdown", + "id": "0730d6a1-c893-4840-9817-5e5251676d5d", + "metadata": {}, + "source": [ + "### Installation\n", + "\n", + "This toolkit lives in the `__package_name__` package:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "652d6238-1f87-422a-b135-f5abbb8652fc", + "metadata": {}, + "outputs": [], + "source": [ + "%pip install -qU __package_name__" + ] + }, + { + "cell_type": "markdown", + "id": "a38cde65-254d-4219-a441-068766c0d4b5", + "metadata": {}, + "source": [ + "## Instantiation\n", + "\n", + "Now we can instantiate our toolkit:\n", + "\n", + "- TODO: Update model instantiation with relevant params." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cb09c344-1836-4e0c-acf8-11d13ac1dbae", + "metadata": {}, + "outputs": [], + "source": [ + "from __module_name__ import __ModuleName__Toolkit\n", + "\n", + "toolkit = __ModuleName__Toolkit(\n", + " # ...\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "5c5f2839-4020-424e-9fc9-07777eede442", + "metadata": {}, + "source": [ + "## Tools\n", + "\n", + "View available tools:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51a60dbe-9f2e-4e04-bb62-23968f17164a", + "metadata": {}, + "outputs": [], + "source": [ + "toolkit.get_tools()" + ] + }, + { + "cell_type": "markdown", + "id": "d11245ad-3661-4405-8558-1188896347ec", + "metadata": {}, + "source": [ + "TODO: list API reference pages for individual tools." + ] + }, + { + "cell_type": "markdown", + "id": "dfe8aad4-8626-4330-98a9-7ea1ca5d2e0e", + "metadata": {}, + "source": [ + "## Use within an agent" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "310bf18e-6c9a-4072-b86e-47bc1fcca29d", + "metadata": {}, + "outputs": [], + "source": [ + "from langgraph.prebuilt import create_react_agent\n", + "\n", + "agent_executor = create_react_agent(llm, tools)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23e11cc9-abd6-4855-a7eb-799f45ca01ae", + "metadata": {}, + "outputs": [], + "source": [ + "example_query = \"...\"\n", + "\n", + "events = agent_executor.stream(\n", + " {\"messages\": [(\"user\", example_query)]},\n", + " stream_mode=\"values\",\n", + ")\n", + "for event in events:\n", + " event[\"messages\"][-1].pretty_print()" + ] + }, + { + "cell_type": "markdown", + "id": "d1ee55bc-ffc8-4cfa-801c-993953a08cfd", + "metadata": {}, + "source": [ + "## TODO: Any functionality or considerations specific to this toolkit\n", + "\n", + "Fill in or delete if not relevant." + ] + }, + { + "cell_type": "markdown", + "id": "3a5bb5ca-c3ae-4a58-be67-2cd18574b9a3", + "metadata": {}, + "source": [ + "## API reference\n", + "\n", + "For detailed documentation of all __ModuleName__Toolkit features and configurations head to the [API reference](https://api.python.langchain.com/en/latest/agent_toolkits/__module_name__.agent_toolkits.__ModuleName__.toolkit.__ModuleName__Toolkit.html)." + ] + } + ], + "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.10.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/libs/cli/langchain_cli/integration_template/integration_template/toolkits.py b/libs/cli/langchain_cli/integration_template/integration_template/toolkits.py new file mode 100644 index 00000000000..345e4d1b1d9 --- /dev/null +++ b/libs/cli/langchain_cli/integration_template/integration_template/toolkits.py @@ -0,0 +1,71 @@ +"""__ModuleName__ chat models.""" + +from typing import List +from langchain_core.tools import BaseTool, BaseToolKit + + +class __ModuleName__Toolkit(BaseToolKit): + # TODO: Replace all TODOs in docstring. See example docstring: + # https://github.com/langchain-ai/langchain/blob/a6d1fb4275801a4850e62b6209cfbf096a24f93f/libs/community/langchain_community/agent_toolkits/sql/toolkit.py#L20 + """__ModuleName__ toolkit. + + # TODO: Replace with relevant packages, env vars, etc. + Setup: + Install ``__package_name__`` and set environment variable ``__MODULE_NAME___API_KEY``. + + .. code-block:: bash + + pip install -U __package_name__ + export __MODULE_NAME___API_KEY="your-api-key" + + # TODO: Populate with relevant params. + Key init args: + arg 1: type + description + arg 2: type + description + + # TODO: Replace with relevant init params. + Instantiate: + .. code-block:: python + + from __package_name__ import __ModuleName__Toolkit + + toolkit = __ModuleName__Toolkit( + # ... + ) + + Tools: + .. code-block:: python + + toolkit.get_tools() + + .. code-block:: python + + # TODO: Example output. + + Use within an agent: + .. code-block:: python + + from langgraph.prebuilt import create_react_agent + + agent_executor = create_react_agent(llm, tools) + + example_query = "..." + + events = agent_executor.stream( + {"messages": [("user", example_query)]}, + stream_mode="values", + ) + for event in events: + event["messages"][-1].pretty_print() + + .. code-block:: python + + # TODO: Example output. + + """ # noqa: E501 + + # TODO: This method must be implemented to generate chat responses. + def get_tools(self) -> List[BaseTool]: + raise NotImplementedError() diff --git a/libs/community/langchain_community/agent_toolkits/sql/toolkit.py b/libs/community/langchain_community/agent_toolkits/sql/toolkit.py index e502498b681..1bc12349f76 100644 --- a/libs/community/langchain_community/agent_toolkits/sql/toolkit.py +++ b/libs/community/langchain_community/agent_toolkits/sql/toolkit.py @@ -17,12 +17,63 @@ from langchain_community.utilities.sql_database import SQLDatabase class SQLDatabaseToolkit(BaseToolkit): - """Toolkit for interacting with SQL databases. + """SQLDatabaseToolkit for interacting with SQL databases. - Parameters: - db: SQLDatabase. The SQL database. - llm: BaseLanguageModel. The language model. - """ + Setup: + Install ``langchain-community``. + + .. code-block:: bash + + pip install -U langchain-community + + Key init args: + db: SQLDatabase + The SQL database. + llm: BaseLanguageModel + The language model (for use with QuerySQLCheckerTool) + + Instantiate: + .. code-block:: python + + from langchain_community.agent_toolkits.sql.toolkit import SQLDatabaseToolkit + from langchain_community.utilities.sql_database import SQLDatabase + from langchain_openai import ChatOpenAI + + db = SQLDatabase.from_uri("sqlite:///Chinook.db") + llm = ChatOpenAI(temperature=0) + + toolkit = SQLDatabaseToolkit(db=db, llm=llm) + + Tools: + .. code-block:: python + + toolkit.get_tools() + + Use within an agent: + .. code-block:: python + + from langchain import hub + from langgraph.prebuilt import create_react_agent + + # Pull prompt (or define your own) + prompt_template = hub.pull("langchain-ai/sql-agent-system-prompt") + system_message = prompt_template.format(dialect="SQLite", top_k=5) + + # Create agent + agent_executor = create_react_agent( + llm, toolkit.get_tools(), state_modifier=system_message + ) + + # Query agent + example_query = "Which country's customers spent the most?" + + events = agent_executor.stream( + {"messages": [("user", example_query)]}, + stream_mode="values", + ) + for event in events: + event["messages"][-1].pretty_print() + """ # noqa: E501 db: SQLDatabase = Field(exclude=True) llm: BaseLanguageModel = Field(exclude=True)