From e548ffcc5cea10e6b009d90b1deb4771e76af7e3 Mon Sep 17 00:00:00 2001 From: Teddy Lee Date: Thu, 9 Jan 2025 12:54:04 +0900 Subject: [PATCH 1/9] [.env_sample] Quick Update Add `MONGODB_ATLAS_CLUSTER_URI` to `.env_sample` this will be used in 09-VectorStore / 07-MongoDB-Atlas Tutorial File. --- .env_sample | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.env_sample b/.env_sample index 8bdeafe9c..dee0e2b64 100644 --- a/.env_sample +++ b/.env_sample @@ -1,11 +1,12 @@ OPENAI_API_KEY=sk-5K9kI4dia... -HUGGINGFACEHUB_API_TOKEN=hf_oEHVwJ... LANGCHAIN_TRACING_V2=false LANGCHAIN_ENDPOINT=https://api.smith.langchain.com LANGCHAIN_API_KEY=ls__69f274d55... LANGCHAIN_PROJECT=LANGCHAIN_PROJECT TAVILY_API_KEY=tvly-mGxBGvzbH... GOOGLE_API_KEY=AIzaSyCSttRIEqEf1_X... +HUGGINGFACEHUB_API_TOKEN=hf_oEHVwJ... +MONGODB_ATLAS_CLUSTER_URI=mongodb+srv://... PINECONE_API_KEY=549b555d-c388-4d... ANTHROPIC_API_KEY=sk-ant-api0... UPSTAGE_API_KEY=up_oZ4HjE... From 4b5ea85177a3ea2f9e0443c2d199fb03d479ee1b Mon Sep 17 00:00:00 2001 From: jinucho Date: Mon, 13 Jan 2025 15:54:39 +0900 Subject: [PATCH 2/9] [E-1] 14-Chains / 02-SQL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit finance.db 추가 OpenAI의 모델이 gpt-3.5-turbo인 이유는 query 생성 안정화를 위함 입니다. (테디님 확인 완료) --- 14-Chains/02-SQL.ipynb | 875 ++++++++++++++++++++++++++++++++++++++ 14-Chains/data/finance.db | Bin 0 -> 16384 bytes 2 files changed, 875 insertions(+) create mode 100644 14-Chains/02-SQL.ipynb create mode 100644 14-Chains/data/finance.db diff --git a/14-Chains/02-SQL.ipynb b/14-Chains/02-SQL.ipynb new file mode 100644 index 000000000..9e02d5af5 --- /dev/null +++ b/14-Chains/02-SQL.ipynb @@ -0,0 +1,875 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# SQL\n", + "\n", + "- Author: [Jinu Cho](https://github.com/jinucho)\n", + "- Peer Review: \n", + "- Proofread:\n", + "- This is a part of [LangChain Open Tutorial](https://github.com/LangChain-OpenTutorial/LangChain-OpenTutorial)\n", + "\n", + "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/LangChain-OpenTutorial/LangChain-OpenTutorial/blob/main/14-Chains/02-SQL.ipynb) [![Open in GitHub](https://img.shields.io/badge/Open%20in%20GitHub-181717?style=flat-square&logo=github&logoColor=white)](https://github.com/LangChain-OpenTutorial/LangChain-OpenTutorial/blob/main/14-Chains/02-SQL.ipynb)\n", + "\n", + "## Overview\n", + "\n", + "This tutorial covers how to use ```create_sql_query_chain``` to generate SQL queries, execute them, and derive answers. \n", + "\n", + "Additionally, let's explore the differences in operation between this method and the SQL Agent.\n", + "\n", + "### Table of Contents\n", + "\n", + "- [Overview](#overview)\n", + "- [Environment Setup](#environment-setup)\n", + "- [Load SQL Database](#load-sql-database)\n", + "- [SQL generate chain](#sql-generate-chain)\n", + "- [Enhance and generate answers using the LLM](#enhance-and-generate-answers-using-the-llm)\n", + "- [Agent](#Agent)\n", + "- [Differences Between create_sql_query_chain and SQL Agent](#differences-between-create_sql_query_chain-and-sql-agent)\n", + "- [[Note]: SQLite DB Creation](#note-sqlite-db-creation)\n", + "\n", + "\n", + "\n", + "### References\n", + "- [SQLDatabase](https://python.langchain.com/api_reference/community/utilities/langchain_community.utilities.sql_database.SQLDatabase.html#sqldatabase)\n", + "- [SQL_query_chain](https://python.langchain.com/api_reference/langchain/chains/langchain.chains.sql_database.query.create_sql_query_chain.html)\n", + "- [SQL_agent](https://python.langchain.com/api_reference/community/agent_toolkits/langchain_community.agent_toolkits.sql.base.create_sql_agent.html)\n", + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Environment Setup\n", + "\n", + "Setting up your environment is the first step. See the [Environment Setup](https://wikidocs.net/257836) guide for more details.\n", + "\n", + "\n", + "**[Note]**\n", + "\n", + "The langchain-opentutorial is a package of easy-to-use environment setup guidance, useful functions and utilities for tutorials.\n", + "Check out the [`langchain-opentutorial`](https://github.com/LangChain-OpenTutorial/langchain-opentutorial-pypi) for more details." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "%%capture --no-stderr\n", + "%pip install langchain-opentutorial" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "# Install required packages\n", + "from langchain_opentutorial import package\n", + "\n", + "package.install(\n", + " [\n", + " \"langsmith\",\n", + " \"langchain\",\n", + " \"langchain_openai\",\n", + " ],\n", + " verbose=False,\n", + " upgrade=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can alternatively set ```OPENAI_API_KEY``` in ```.env``` file and load it. \n", + "\n", + "[Note] This is not necessary if you've already set ```OPENAI_API_KEY``` in previous steps." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Environment variables have been set successfully.\n" + ] + } + ], + "source": [ + "# Set environment variables\n", + "from langchain_opentutorial import set_env\n", + "\n", + "set_env(\n", + " {\n", + " \"OPENAI_API_KEY\": \"\",\n", + " \"LANGCHAIN_API_KEY\": \"\",\n", + " \"LANGCHAIN_TRACING_V2\": \"true\",\n", + " \"LANGCHAIN_ENDPOINT\": \"https://api.smith.langchain.com\",\n", + " \"LANGCHAIN_PROJECT\": \"02-SQL\",\n", + " }\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Load environment variables\n", + "# Reload any variables that need to be overwritten from the previous cell\n", + "\n", + "from dotenv import load_dotenv\n", + "\n", + "load_dotenv(override=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load SQL Database\n", + "\n", + "Load and verify the sample database data.\n", + "\n", + "You can also create a custom database by referring to **[[Note]: SQLite DB Creation](#note-sqlite-db-creation)** ." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "sqlite\n", + "['accounts', 'customers', 'transactions']\n" + ] + } + ], + "source": [ + "from langchain_openai import ChatOpenAI\n", + "from langchain.chains import create_sql_query_chain\n", + "from langchain_community.utilities import SQLDatabase\n", + "\n", + "# Connect to the SQLite database.\n", + "db = SQLDatabase.from_uri(\"sqlite:///data/finance.db\")\n", + "\n", + "# Output the database dialect.\n", + "print(db.dialect)\n", + "\n", + "# Output the available table names.\n", + "print(db.get_usable_table_names())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## SQL generate chain" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[RECOMMED] Create an LLM object and generate a chain by providing the LLM and DB as parameters.\n", + "\n", + "Since changing the model may cause unexpected behavior, this tutorial will proceed with **gpt-3.5-turbo** ." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "# Create an OpenAI LLM\n", + "llm = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature=0)\n", + "\n", + "# Generate a chain by providing the LLM and DB as parameters.\n", + "chain = create_sql_query_chain(llm=llm, db=db,k=10)# k(for query Limit)'s default value is 5" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "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.\n", + "Unless the user specifies in the question a specific number of examples to obtain, query for at most {top_k} results using the LIMIT clause as per SQLite. You can order the results to return the most informative data in the database.\n", + "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.\n", + "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.\n", + "Pay attention to use date('now') function to get the current date, if the question involves \"today\".\n", + "\n", + "Use the following format:\n", + "\n", + "Question: Question here\n", + "SQLQuery: SQL Query to run\n", + "SQLResult: Result of the SQLQuery\n", + "Answer: Final answer here\n", + "\n", + "Only use the following tables:\n", + "{table_info}\n", + "\n", + "Question: {input}\n" + ] + } + ], + "source": [ + "# Check the default prompt\n", + "print(chain.get_prompts()[0].template)" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'SELECT \"name\" FROM customers;'" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "chain.invoke({\"question\": \"List the all customer names.\"})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### If the latest version is used?\n", + "\n", + "Using the latest version of OpenAI's LLM may cause issues with the output." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [], + "source": [ + "# Create an OpenAI LLM\n", + "llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)\n", + "\n", + "# Generate a chain by providing the LLM and DB as parameters.\n", + "bad_case_chain = create_sql_query_chain(llm=llm, db=db,k=10)# k(for query Limit)'s default values is 5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Unnecessary information, such as **'SQLQuery: '** , is included in the output along with the query." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'SQLQuery: SELECT \"name\" FROM customers LIMIT 10;'" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bad_case_chain.invoke({\"question\": \"List the all customer names.\"})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "(Optional) You can specify the prompt directly using the method below.\n", + "\n", + "When writing it yourself, you can include **table_info** along with descriptive **column descriptions** for better explanation." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_core.prompts import PromptTemplate\n", + "\n", + "prompt = PromptTemplate.from_template(\n", + " \"\"\"Given an input question, first create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer. \n", + " Unless the user specifies in his question a specific number of examples he wishes to obtain, always limit your query to at most {top_k} results. \n", + " You can order the results by a relevant column to return the most interesting examples in the database.\n", + "\n", + "Use the following format:\n", + "\n", + "Question: Question here\n", + "SQLQuery: SQL Query to run\n", + "SQLResult: Result of the SQLQuery\n", + "Answer: Final answer here\n", + "\n", + "Only use the following tables:\n", + "{table_info}\n", + "\n", + "Here is the description of the columns in the tables:\n", + "`cust`: customer name\n", + "`prod`: product name\n", + "`trans`: transaction date\n", + "\n", + "Question: {input}\n", + "\"\"\"\n", + ").partial(dialect=db.dialect)\n", + "\n", + "# model 은 gpt-3.5-turbo 를 지정\n", + "llm = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature=0)\n", + "\n", + "# LLM 과 DB 를 매개변수로 입력하여 chain 을 생성합니다.\n", + "chain = create_sql_query_chain(llm, db, prompt)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Executing the chain generates queries based on the database." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "'SELECT name\\nFROM customers'\n" + ] + } + ], + "source": [ + "# Execute the chain and display the results.\n", + "generated_sql_query = chain.invoke({\"question\": \"List the all customer names.\"})\n", + "\n", + "# Print the generated query.\n", + "print(generated_sql_query.__repr__())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's verify if the generated query executes correctly." + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_community.tools import QuerySQLDatabaseTool\n", + "\n", + "# Create a tool to execute the generated query.\n", + "execute_query = QuerySQLDatabaseTool(db=db)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"[('Altman',), ('Huang',), ('Zuckerberg',), ('Musk',), ('Hassabis',), ('Chase',)]\"" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "execute_query.invoke({\"query\": generated_sql_query})" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_community.tools.sql_database.tool import QuerySQLDatabaseTool\n", + "\n", + "# Tool\n", + "execute_query = QuerySQLDatabaseTool(db=db)\n", + "\n", + "# SQL query generation chain\n", + "write_query = create_sql_query_chain(llm, db,prompt)\n", + "\n", + "# Create a chain to execute the generated query.\n", + "chain = write_query | execute_query" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"[('Sam@example.com',)]\"" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Check the execution result\n", + "chain.invoke({\"question\": \"Retrieve Altman's email address.\"})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Enhance and generate answers using the LLM\n", + "\n", + "Using the chain created in the previous step results in short, concise answers. This can be adjusted using an LCEL-style chain to provide more natural and detailed responses." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [], + "source": [ + "from operator import itemgetter\n", + "from langchain_core.output_parsers import StrOutputParser\n", + "from langchain_core.prompts import PromptTemplate\n", + "from langchain_core.runnables import RunnablePassthrough\n", + "\n", + "# Define the prompt for generating answers\n", + "answer_prompt = PromptTemplate.from_template(\n", + " \"\"\"Given the following user question, corresponding SQL query, and SQL result, answer the user question.\n", + "\n", + "Question: {question}\n", + "SQL Query: {query}\n", + "SQL Result: {result}\n", + "Answer: \"\"\"\n", + ")\n", + "\n", + "# Create a pipeline for generating natural answers\n", + "answer = answer_prompt | llm | StrOutputParser()\n", + "\n", + "# Create a chain to execute the generated query and produce an answer\n", + "chain = (\n", + " RunnablePassthrough.assign(query=write_query).assign(\n", + " result=itemgetter(\"query\") | execute_query\n", + " )\n", + " | answer\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"The total of Altman's transactions is -965.7.\"" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Check the execution result\n", + "chain.invoke({\"question\": \"Calculate the total of Altman's transactions.\"})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Agent\n", + "\n", + "Using an Agent, you can generate SQL queries and output the results as answers." + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_openai import ChatOpenAI\n", + "from langchain_community.utilities import SQLDatabase\n", + "from langchain_community.agent_toolkits import create_sql_agent\n", + "\n", + "# Specify the model as gpt-3.5-turbo\n", + "llm = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature=0)\n", + "\n", + "# Connect to the SQLite database\n", + "db = SQLDatabase.from_uri(\"sqlite:///data/finance.db\")\n", + "\n", + "# Create the Agent\n", + "agent_executor = create_sql_agent(llm, db=db, agent_type=\"openai-tools\", verbose=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "\u001b[1m> Entering new SQL Agent Executor 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;3maccounts, customers, transactions\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `sql_db_schema` with `{'table_names': 'accounts, transactions'}`\n", + "\n", + "\n", + "\u001b[0m\u001b[33;1m\u001b[1;3m\n", + "CREATE TABLE accounts (\n", + "\taccount_id INTEGER, \n", + "\tcustomer_id INTEGER, \n", + "\tbalance REAL, \n", + "\tPRIMARY KEY (account_id), \n", + "\tFOREIGN KEY(customer_id) REFERENCES customers (customer_id)\n", + ")\n", + "\n", + "/*\n", + "3 rows from accounts table:\n", + "account_id\tcustomer_id\tbalance\n", + "1\t1\t1000.5\n", + "2\t2\t2500.75\n", + "3\t3\t1500.0\n", + "*/\n", + "\n", + "\n", + "CREATE TABLE transactions (\n", + "\ttransaction_id INTEGER, \n", + "\taccount_id INTEGER, \n", + "\tamount REAL, \n", + "\ttransaction_date TEXT, \n", + "\tPRIMARY KEY (transaction_id), \n", + "\tFOREIGN KEY(account_id) REFERENCES accounts (account_id)\n", + ")\n", + "\n", + "/*\n", + "3 rows from transactions table:\n", + "transaction_id\taccount_id\tamount\ttransaction_date\n", + "1\t1\t74.79\t2024-07-13\n", + "2\t1\t-224.1\t2024-05-13\n", + "3\t1\t-128.9\t2024-01-25\n", + "*/\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `sql_db_query` with `{'query': 'SELECT SUM(amount) AS total_transactions FROM transactions WHERE account_id IN (SELECT account_id FROM accounts WHERE customer_id = 1)'}`\n", + "\n", + "\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m[(-965.7,)]\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `sql_db_query` with `{'query': 'SELECT SUM(amount) AS total_transactions FROM transactions WHERE account_id IN (SELECT account_id FROM accounts WHERE customer_id = 2)'}`\n", + "\n", + "\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m[(743.1299999999999,)]\u001b[0m\u001b[32;1m\u001b[1;3mThe total transactions for Altman is -965.7 and for Zuckerberg is 743.13.\u001b[0m\n", + "\n", + "\u001b[1m> Finished chain.\u001b[0m\n" + ] + }, + { + "data": { + "text/plain": [ + "{'input': 'Calculate and compare the total transactions of Altman and Zuckerberg.',\n", + " 'output': 'The total transactions for Altman is -965.7 and for Zuckerberg is 743.13.'}" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Check the execution result\n", + "agent_executor.invoke(\n", + " {\"input\": \"Calculate and compare the total transactions of Altman and Zuckerberg.\"}\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Differences Between create_sql_query_chain and SQL Agent\n", + "1. create_sql_query_chain:\n", + " - Translates user input into a single SQL query and executes it directly.\n", + " - Best for simple, direct query execution.\n", + "2. SQL Agent:\n", + " - Handles more complex workflows, involving multiple queries and reasoning steps.\n", + " - Ideal for dynamic or multi-step tasks.\n", + "3. Summary: It is recommended to use ```create_sql_query_chain``` for simple queries, while ```SQL Agent``` is suggested for complex or iterative processes." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## [Note]: SQLite DB Creation\n", + "\n", + "This is a code for creating a SQLite database.\n", + "\n", + "You can customize the code below to suit your needs." + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "# import sqlite3\n", + "\n", + "# connection = sqlite3.connect(\"data/finance.db\")\n", + "# cursor = connection.cursor()\n", + "\n", + "# # Create `customers` table\n", + "# cursor.execute('''\n", + "# CREATE TABLE customers (\n", + "# customer_id INTEGER PRI\n", + "# MARY KEY,\n", + "# name TEXT,\n", + "# age INTEGER,\n", + "# email TEXT\n", + "# );\n", + "# ''')\n", + "\n", + "# # Insert data into `customers`\n", + "# cursor.executemany('''\n", + "# INSERT INTO customers (customer_id, name, age, email)\n", + "# VALUES (?, ?, ?, ?);\n", + "# ''', [\n", + "# (1, 'Altman', 40, 'Sam@example.com'),\n", + "# (2, 'Huang', 62, 'Jensen@example.com'),\n", + "# (3, 'Zuckerberg', 41, 'Mark@example.com'),\n", + "# (4, 'Musk', 54, 'Elon@example.com'),\n", + "# (5, 'Hassabis', 49, 'Demis@example.com'),\n", + "# (6, 'Chase', 35, 'Harrison@example.com')\n", + "# ])\n", + "\n", + "# # Create `accounts` table\n", + "# cursor.execute('''\n", + "# CREATE TABLE accounts (\n", + "# account_id INTEGER PRIMARY KEY,\n", + "# customer_id INTEGER,\n", + "# balance REAL,\n", + "# FOREIGN KEY (customer_id) REFERENCES customers(customer_id)\n", + "# );\n", + "# ''')\n", + "\n", + "# # Insert data into `accounts`\n", + "# cursor.executemany('''\n", + "# INSERT INTO accounts (account_id, customer_id, balance)\n", + "# VALUES (?, ?, ?);\n", + "# ''', [\n", + "# (1, 1, 1000.5),\n", + "# (2, 2, 2500.75),\n", + "# (3, 3, 1500.0),\n", + "# (4, 4, 1800.25),\n", + "# (5, 5, 2200.6),\n", + "# (6, 6, 1750.4)\n", + "# ])\n", + "\n", + "# # Create `transactions` table\n", + "# cursor.execute('''\n", + "# CREATE TABLE transactions (\n", + "# transaction_id INTEGER PRIMARY KEY,\n", + "# account_id INTEGER,\n", + "# amount REAL,\n", + "# transaction_date TEXT,\n", + "# FOREIGN KEY (account_id) REFERENCES accounts(account_id)\n", + "# );\n", + "# ''')\n", + "\n", + "# # Insert data into `transactions`\n", + "# cursor.executemany('''\n", + "# INSERT INTO transactions (transaction_id, account_id, amount, transaction_date)\n", + "# VALUES (?, ?, ?, ?);\n", + "# ''', [\n", + "# (1, 1, 74.79, '2024-07-13'),\n", + "# (2, 1, -224.1, '2024-05-13'),\n", + "# (3, 1, -128.9, '2024-01-25'),\n", + "# (4, 1, -314.05, '2024-07-28'),\n", + "# (5, 1, -464.0, '2024-04-21'),\n", + "# (6, 1, -486.99, '2024-07-04'),\n", + "# (7, 1, -318.33, '2024-02-15'),\n", + "# (8, 1, 290.23, '2024-04-06'),\n", + "# (9, 1, 236.57, '2024-01-01'),\n", + "# (10, 1, 321.92, '2024-05-24'),\n", + "# (11, 1, 95.75, '2024-01-04'),\n", + "# (12, 1, -415.22, '2024-06-10'),\n", + "# (13, 1, 318.15, '2024-07-21'),\n", + "# (14, 1, 269.66, '2024-01-13'),\n", + "# (15, 1, -386.16, '2024-04-13'),\n", + "# (16, 1, 164.98, '2024-05-02'),\n", + "# (17, 2, -43.13, '2024-07-03'),\n", + "# (18, 2, -308.91, '2024-03-15'),\n", + "# (19, 2, 347.45, '2024-01-23'),\n", + "# (20, 2, -72.35, '2024-02-01'),\n", + "# (21, 2, -114.54, '2024-03-30'),\n", + "# (22, 2, 273.34, '2024-07-06'),\n", + "# (23, 2, 458.16, '2024-06-17'),\n", + "# (24, 2, 227.77, '2024-03-14'),\n", + "# (25, 2, -51.55, '2024-06-18'),\n", + "# (26, 2, 304.99, '2024-02-16'),\n", + "# (27, 2, 176.56, '2024-03-30'),\n", + "# (28, 2, -147.86, '2024-02-16'),\n", + "# (29, 2, -456.95, '2024-07-30'),\n", + "# (30, 2, 190.11, '2024-01-23'),\n", + "# (31, 2, 222.13, '2024-02-14'),\n", + "# (32, 2, -262.09, '2024-07-21'),\n", + "# (33, 3, 148.49, '2024-01-09'),\n", + "# (34, 3, -289.71, '2024-01-31'),\n", + "# (35, 3, -150.71, '2024-05-24'),\n", + "# (36, 3, 64.14, '2024-04-08'),\n", + "# (37, 3, -373.0, '2024-04-17'),\n", + "# (38, 3, 210.42, '2024-06-29'),\n", + "# (39, 3, -425.75, '2024-05-08'),\n", + "# (40, 3, 266.32, '2024-06-05'),\n", + "# (41, 3, 160.99, '2024-02-21'),\n", + "# (42, 3, -127.92, '2024-04-04'),\n", + "# (43, 3, 457.43, '2024-04-22'),\n", + "# (44, 3, 417.64, '2024-03-28'),\n", + "# (45, 3, 392.0, '2024-02-19'),\n", + "# (46, 3, 221.92, '2024-02-25'),\n", + "# (47, 3, -417.7, '2024-02-02'),\n", + "# (48, 3, 102.08, '2024-07-07'),\n", + "# (49, 4, 489.96, '2024-06-03'),\n", + "# (50, 4, 21.06, '2024-04-20'),\n", + "# (51, 4, -278.72, '2024-02-18'),\n", + "# (52, 4, 58.08, '2024-04-15'),\n", + "# (53, 4, 489.45, '2024-03-19'),\n", + "# (54, 4, -448.04, '2024-07-16'),\n", + "# (55, 4, -272.16, '2024-06-30'),\n", + "# (56, 4, -41.19, '2024-03-21'),\n", + "# (57, 4, 200.61, '2024-04-10'),\n", + "# (58, 4, 431.89, '2024-03-08'),\n", + "# (59, 4, 236.82, '2024-01-03'),\n", + "# (60, 4, -167.94, '2024-05-31'),\n", + "# (61, 4, 273.09, '2024-06-10'),\n", + "# (62, 4, 225.16, '2024-03-31'),\n", + "# (63, 4, -110.66, '2024-05-23'),\n", + "# (64, 4, 329.74, '2024-05-29'),\n", + "# (65, 5, -150.66, '2024-02-19'),\n", + "# (66, 5, -406.2, '2024-06-16'),\n", + "# (67, 5, 360.12, '2024-05-18'),\n", + "# (68, 5, -252.19, '2024-06-11'),\n", + "# (69, 5, -373.15, '2024-03-12'),\n", + "# (70, 5, -361.49, '2024-05-22'),\n", + "# (71, 5, -135.04, '2024-04-25'),\n", + "# (72, 5, -160.99, '2024-05-31'),\n", + "# (73, 5, 399.02, '2024-06-23'),\n", + "# (74, 5, -77.75, '2024-05-06'),\n", + "# (75, 5, -443.42, '2024-03-28'),\n", + "# (76, 5, 202.05, '2024-01-04'),\n", + "# (77, 5, -182.5, '2024-04-12'),\n", + "# (78, 5, -428.84, '2024-03-10'),\n", + "# (79, 5, 311.05, '2024-01-13'),\n", + "# (80, 5, 173.89, '2024-01-10'),\n", + "# (81, 6, -325.71, '2024-07-15'),\n", + "# (82, 6, 127.41, '2024-01-25'),\n", + "# (83, 6, -203.54, '2024-05-05'),\n", + "# (84, 6, 478.24, '2024-05-07'),\n", + "# (85, 6, -27.91, '2024-07-21'),\n", + "# (86, 6, 194.06, '2024-01-14'),\n", + "# (87, 6, -224.5, '2024-06-15'),\n", + "# (88, 6, -394.75, '2024-04-18'),\n", + "# (89, 6, 130.54, '2024-03-26'),\n", + "# (90, 6, 494.1, '2024-02-23'),\n", + "# (91, 6, -136.39, '2024-05-17'),\n", + "# (92, 6, 35.12, '2024-04-28'),\n", + "# (93, 6, -333.55, '2024-04-25'),\n", + "# (94, 6, 170.36, '2024-03-05'),\n", + "# (95, 6, 345.4, '2024-03-09'),\n", + "# (96, 6, -130.69, '2024-05-24')\n", + "# ])\n", + "\n", + "# connection.commit()\n", + "# connection.close()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "langchain-opentutorial-BpEVOGYk-py3.11", + "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.11.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/14-Chains/data/finance.db b/14-Chains/data/finance.db new file mode 100644 index 0000000000000000000000000000000000000000..11610dc3145c6c4579b4d9b63e757f817353773c GIT binary patch literal 16384 zcmeI0U2GKB6~}k>`+I;u<|YO_4mh=w4B46e@H!M{ZCJ2_?clW=Fu29D>owVUcfH zdj`=yR(ZH1Svxbod(J)Qf6uv>VSH@3)F_Ix^Yx0_5aW&w4vuqVMA6}JIN{F?f7a!K z8~n^!;D7u&9lHu#1O~Vwl7rtJJqSPSVhS(?m;y`zrT|lbDZmt93NQtj0$+Xwo^5ma zgw9Ux?5T#DFBcniwW_IwMrppP;d}SqT(*BAD^Bze3};15#IB%-E`*MkX2hYFjF_mcYyN=?d{yN<3_&LAgy)d zv}N3SeOt=bdz6Nrb88;GUhZ5DRkd=bl~hj@tx~evnKHZ|0@RAHa1n;?W;HnOEevens5+qdRk{!wAdgf=8#z^OuNIfA7q^`rOkx z2y<>nz?WIwXN=On|EIlq2mcTL1O6BMCH^_S#vkVU_)b0?{XDuB{cZHk=xX$2bSgR! z?TSVtUqsd-&Bz;(=OgvVkw{-;XCxTD6}}$68onGpAFhUvhBM*&!{N|pp^rkp3B4A2 zA#^e{6&eV2g`&YPf@{HM@QvW}!FupWurIhX7!2GBTn}6gTn?NMR09)%M*?EN>;KgM zC;t`y5B=ZvKjlB(pE0qd&m)zDW|2k|a~qrhj#+>z}_{ZILuNMs3uv9>8XkBqh0r9HlmA zZWt%3Nfb$mlSxXZ$G~FwhDqX*k|IZ_x1}E&N?Y^DX>yp7@&-gwlAI(@P;XE6--Lv6 zrj0Dg3Gy{+v-=Z>d8*qaJ(41m32O7Lk3S6Vsl8^Bq!jBRh$Qb9Wsa~Q@o1Qf!Jc?aZ0or(i%vdjGCmm{JuWT9&?_!ZZks3 z>>rT^2}xGSF!fgIM_S8LEI|%Zo72C%GIsM^yX8$ulgB6-uOV-cX^IR{Z%enpWcwA< zCZ(_3Ahnrk*B5TkBuObQlLM4Y>s4T_sZl%oDLMI~O>0FVSxUZ{v(+f%vyYPb@1VMd z)t1R#lVnalgH{{rElmcf&8dR%Pc|!RIYs&@$^RJ&{^mK8D3aVuG6r#H8ZX&n>m`qx zqFaneU^%ALqtT-RU^B?}wT%0bjI@>S|>W*y~Y=(d~MR4$@M8(V+C+%oB+r1m<>1aeH0uTXExm+XC*CihdDr$$gF z(1*R7I)OkY>)*Aag8gqXe6J$FjC$6EYko9ibM!l`9qIK+%pf0ykl0S`X zppsIgje48ii1q;Jz!sysmiN>(o0dIq$< zo05esHVt6!+(PG>!Zt>1n<>fNjUs@GmC0Sy+v2Z~28KGDsEsy?B7oSEWFsZn7f{sD z8F68Q2fjf&GBdcDU|UxN-T=*|`;af_*|-ojEoy5B=tq$dF@g416tTY2LfCY5>T|R- z`bH;&OpC*}P%Z1{kPtLM!>E3G4Cy5(1WZu*9_l}^kOjX9>N`*YLOG`dp8=ZM-_c0} zYn&9kCO9*X79S)@Z1ezdcC5#&Zh;Kk)XB@}_=VKcg3AQcTM>Y@ND599lwD|%;NXc1 PoB=YqpCS2R|BU||&DD=9 literal 0 HcmV?d00001 From fcae6f105de5cda7e92ac58a2077b4bbcc9684e0 Mon Sep 17 00:00:00 2001 From: jeong-wooseok <64723774+jeong-wooseok@users.noreply.github.com> Date: Mon, 13 Jan 2025 19:50:35 +0900 Subject: [PATCH 3/9] =?UTF-8?q?[Review=20Checklist]=20-=20[x]=20Review=20O?= =?UTF-8?q?S:=20=20-=20Windows=20-=20[x]Template=20Rule=20=EC=A4=80?= =?UTF-8?q?=EC=88=98=20=EC=97=AC=EB=B6=80:=20=20-Template=20Rule=20?= =?UTF-8?q?=EA=B0=80=EC=9D=B4=EB=93=9C=EB=A5=BC=20=EC=A4=80=EC=88=98?= =?UTF-8?q?=ED=95=98=EC=98=80=EB=8A=94=EA=B0=80=3F=20(Check=20=ED=91=9C?= =?UTF-8?q?=EA=B8=B0)=20-=20[x]=20Table=20of=20Contents=20=EB=A7=81?= =?UTF-8?q?=ED=81=AC=20=ED=99=95=EC=9D=B8:=20=20-=20Table=20of=20Contents?= =?UTF-8?q?=EC=9D=98=20=EB=A7=81=ED=81=AC=EA=B0=80=20=EC=9B=90=ED=99=9C?= =?UTF-8?q?=ED=95=98=EA=B2=8C=20=EB=8F=99=EC=9E=91=ED=95=98=EB=8A=94?= =?UTF-8?q?=EC=A7=80=20=ED=99=95=EC=9D=B8=ED=95=98=EC=98=80=EB=8A=94?= =?UTF-8?q?=EA=B0=80=3F=20(Check=20=ED=91=9C=EA=B8=B0)=20-=20[x]=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20=ED=8C=8C=EC=9D=BC=EB=AA=85=20?= =?UTF-8?q?=EA=B2=80=ED=86=A0:=20=20-=20=EC=9D=B4=EB=AF=B8=EC=A7=80?= =?UTF-8?q?=EA=B0=80=20=ED=8F=AC=ED=95=A8=EB=90=98=EC=96=B4=20=EC=9E=88?= =?UTF-8?q?=EB=8B=A4=EB=A9=B4,=20=EC=9D=B4=EB=AF=B8=EC=A7=80=EC=9D=98=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=EB=AA=85=EC=9D=B4=20=EA=B0=80=EC=9D=B4?= =?UTF-8?q?=EB=93=9C=EB=A5=BC=20=EC=A4=80=EC=88=98=ED=95=98=EC=98=80?= =?UTF-8?q?=EB=8A=94=EA=B0=80=3F=20(Check=20=ED=91=9C=EA=B8=B0)=20-=20[x]?= =?UTF-8?q?=20=EC=B5=9C=EC=8B=A0=20import=20=EB=B0=A9=EC=8B=9D=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=20=EC=97=AC=EB=B6=80:=20=20-=20import=20=EA=B5=AC?= =?UTF-8?q?=EB=AC=B8=EC=9D=B4=20=EC=98=88=EC=A0=84=20legacy=20=EB=B0=A9?= =?UTF-8?q?=EC=8B=9D=EC=9D=B4=20=EC=95=84=EB=8B=8C=20=EC=B5=9C=EC=8B=A0=20?= =?UTF-8?q?=EB=B2=84=EC=A0=84=EC=9D=84=20=EB=94=B0=EB=A5=B4=EB=8A=94?= =?UTF-8?q?=EA=B0=80=3F=20(Check=20=ED=91=9C=EA=B8=B0)=20-=20[x]=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EB=8F=99=EC=9E=91=20=ED=99=95=EC=9D=B8:?= =?UTF-8?q?=20=20-=20=EB=AA=A8=EB=93=A0=20=EC=BD=94=EB=93=9C=EA=B0=80=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=97=86=EC=9D=B4=20=EB=8F=99=EC=9E=91?= =?UTF-8?q?=ED=95=98=EB=8A=94=EA=B0=80=3F=20(Check=20=ED=91=9C=EA=B8=B0)?= =?UTF-8?q?=20-=20[x]=20Warning=20=EB=B0=9C=EC=83=9D=20=EC=8B=9C=20?= =?UTF-8?q?=EC=BD=94=EB=A9=98=ED=8A=B8=EC=97=90=20=EC=A0=81=EC=96=B4?= =?UTF-8?q?=EC=A3=BC=EC=84=B8=EC=9A=94.=20=20-=20=EC=A0=9C=EC=B6=9C=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=ED=99=95=EC=9D=B8:=20-=20[x]=20=EA=BC=AD?= =?UTF-8?q?=20=ED=95=84=EC=9A=94=ED=95=9C=20=ED=8C=8C=EC=9D=BC=EB=93=A4?= =?UTF-8?q?=EB=A7=8C=20=EC=A0=9C=EC=B6=9C=EB=90=98=EC=97=88=EB=8A=94?= =?UTF-8?q?=EA=B0=80=3F=20=20-=20=ED=8A=9C=ED=86=A0=EB=A6=AC=EC=96=BC=20?= =?UTF-8?q?=EC=99=B8=20=EC=84=A4=EC=A0=95=20=ED=8C=8C=EC=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=82=98=20=EB=8B=A4=EB=A5=B8=20=EB=B6=84=EC=9D=B4=20=EC=9E=91?= =?UTF-8?q?=EC=97=85=ED=95=9C=20=ED=8C=8C=EC=9D=BC=EC=9D=B4=20=ED=8F=AC?= =?UTF-8?q?=ED=95=A8=EB=90=98=EC=97=88=EB=8A=94=EC=A7=80=20Files=20Changed?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=ED=99=95=EC=9D=B8=20=EB=B6=80=ED=83=81?= =?UTF-8?q?=EB=93=9C=EB=A6=BD=EB=8B=88=EB=8B=A4.=20(Check=20=ED=91=9C?= =?UTF-8?q?=EA=B8=B0)=20-=20[x]=20=EA=B8=B0=ED=83=80=20=EC=9D=98=EA=B2=AC:?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 14-Chains/02-SQL.ipynb | 149 ++++++++++++++++++++++++++++++----------- 1 file changed, 111 insertions(+), 38 deletions(-) diff --git a/14-Chains/02-SQL.ipynb b/14-Chains/02-SQL.ipynb index 9e02d5af5..1e9129826 100644 --- a/14-Chains/02-SQL.ipynb +++ b/14-Chains/02-SQL.ipynb @@ -56,7 +56,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -66,7 +66,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -95,7 +95,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -112,8 +112,8 @@ "\n", "set_env(\n", " {\n", - " \"OPENAI_API_KEY\": \"\",\n", - " \"LANGCHAIN_API_KEY\": \"\",\n", + " # \"OPENAI_API_KEY\": \"\",\n", + " # \"LANGCHAIN_API_KEY\": \"\",\n", " \"LANGCHAIN_TRACING_V2\": \"true\",\n", " \"LANGCHAIN_ENDPOINT\": \"https://api.smith.langchain.com\",\n", " \"LANGCHAIN_PROJECT\": \"02-SQL\",\n", @@ -123,7 +123,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -132,7 +132,7 @@ "True" ] }, - "execution_count": 25, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -159,7 +159,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -204,7 +204,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ @@ -217,7 +217,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 15, "metadata": {}, "outputs": [ { @@ -251,7 +251,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -260,7 +260,7 @@ "'SELECT \"name\" FROM customers;'" ] }, - "execution_count": 29, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -280,7 +280,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 17, "metadata": {}, "outputs": [], "source": [ @@ -300,7 +300,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 18, "metadata": {}, "outputs": [ { @@ -309,7 +309,7 @@ "'SQLQuery: SELECT \"name\" FROM customers LIMIT 10;'" ] }, - "execution_count": 31, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -329,7 +329,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 19, "metadata": {}, "outputs": [], "source": [ @@ -375,7 +375,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -403,7 +403,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 21, "metadata": {}, "outputs": [], "source": [ @@ -415,7 +415,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 22, "metadata": {}, "outputs": [ { @@ -424,7 +424,7 @@ "\"[('Altman',), ('Huang',), ('Zuckerberg',), ('Musk',), ('Hassabis',), ('Chase',)]\"" ] }, - "execution_count": 35, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -435,7 +435,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 23, "metadata": {}, "outputs": [], "source": [ @@ -453,7 +453,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 24, "metadata": {}, "outputs": [ { @@ -462,7 +462,7 @@ "\"[('Sam@example.com',)]\"" ] }, - "execution_count": 37, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -483,7 +483,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 25, "metadata": {}, "outputs": [], "source": [ @@ -516,7 +516,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 26, "metadata": {}, "outputs": [ { @@ -525,7 +525,7 @@ "\"The total of Altman's transactions is -965.7.\"" ] }, - "execution_count": 39, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } @@ -546,7 +546,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 29, "metadata": {}, "outputs": [], "source": [ @@ -555,7 +555,7 @@ "from langchain_community.agent_toolkits import create_sql_agent\n", "\n", "# Specify the model as gpt-3.5-turbo\n", - "llm = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature=0)\n", + "llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)\n", "\n", "# Connect to the SQLite database\n", "db = SQLDatabase.from_uri(\"sqlite:///data/finance.db\")\n", @@ -566,7 +566,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 30, "metadata": {}, "outputs": [ { @@ -581,7 +581,7 @@ "\n", "\n", "\u001b[0m\u001b[38;5;200m\u001b[1;3maccounts, customers, transactions\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_schema` with `{'table_names': 'accounts, transactions'}`\n", + "Invoking: `sql_db_schema` with `{'table_names': 'accounts'}`\n", "\n", "\n", "\u001b[0m\u001b[33;1m\u001b[1;3m\n", @@ -599,9 +599,29 @@ "1\t1\t1000.5\n", "2\t2\t2500.75\n", "3\t3\t1500.0\n", - "*/\n", + "*/\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `sql_db_schema` with `{'table_names': 'customers'}`\n", "\n", "\n", + "\u001b[0m\u001b[33;1m\u001b[1;3m\n", + "CREATE TABLE customers (\n", + "\tcustomer_id INTEGER, \n", + "\tname TEXT, \n", + "\tage INTEGER, \n", + "\temail TEXT\n", + ")\n", + "\n", + "/*\n", + "3 rows from customers table:\n", + "customer_id\tname\tage\temail\n", + "1\tAltman\t40\tSam@example.com\n", + "2\tHuang\t62\tJensen@example.com\n", + "3\tZuckerberg\t41\tMark@example.com\n", + "*/\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `sql_db_schema` with `{'table_names': 'transactions'}`\n", + "\n", + "\n", + "\u001b[0m\u001b[33;1m\u001b[1;3m\n", "CREATE TABLE transactions (\n", "\ttransaction_id INTEGER, \n", "\taccount_id INTEGER, \n", @@ -618,14 +638,67 @@ "2\t1\t-224.1\t2024-05-13\n", "3\t1\t-128.9\t2024-01-25\n", "*/\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_query` with `{'query': 'SELECT SUM(amount) AS total_transactions FROM transactions WHERE account_id IN (SELECT account_id FROM accounts WHERE customer_id = 1)'}`\n", + "Invoking: `sql_db_query_checker` with `{'query': \"SELECT c.name, SUM(t.amount) AS total_transactions\\nFROM customers c\\nJOIN accounts a ON c.customer_id = a.customer_id\\nJOIN transactions t ON a.account_id = t.account_id\\nWHERE c.name IN ('Altman', 'Zuckerberg')\\nGROUP BY c.name;\"}`\n", + "responded: The relevant tables and their structures are as follows:\n", + "\n", + "1. **accounts**:\n", + " - `account_id`: INTEGER\n", + " - `customer_id`: INTEGER\n", + " - `balance`: REAL\n", + "\n", + "2. **customers**:\n", + " - `customer_id`: INTEGER\n", + " - `name`: TEXT\n", + " - `age`: INTEGER\n", + " - `email`: TEXT\n", + "\n", + "3. **transactions**:\n", + " - `transaction_id`: INTEGER\n", + " - `account_id`: INTEGER\n", + " - `amount`: REAL\n", + " - `transaction_date`: TEXT\n", + "\n", + "To calculate and compare the total transactions of Altman and Zuckerberg, I will need to:\n", + "1. Find the `customer_id` for both Altman and Zuckerberg from the `customers` table.\n", + "2. Use their `customer_id` to find the corresponding `account_id` from the `accounts` table.\n", + "3. Sum the `amount` from the `transactions` table for each `account_id`.\n", + "\n", + "Let's construct the SQL queries for these steps. \n", + "\n", + "First, I will get the `customer_id` for Altman and Zuckerberg. Then, I will get their `account_id` and finally sum the transactions. \n", + "\n", + "I will combine these steps into a single query to get the total transactions for both customers. \n", + "\n", + "Here is the query I will use:\n", + "\n", + "```sql\n", + "SELECT c.name, SUM(t.amount) AS total_transactions\n", + "FROM customers c\n", + "JOIN accounts a ON c.customer_id = a.customer_id\n", + "JOIN transactions t ON a.account_id = t.account_id\n", + "WHERE c.name IN ('Altman', 'Zuckerberg')\n", + "GROUP BY c.name;\n", + "```\n", + "\n", + "Now, I will check this query for correctness before executing it.\n", + "\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m```sql\n", + "SELECT c.name, SUM(t.amount) AS total_transactions\n", + "FROM customers c\n", + "JOIN accounts a ON c.customer_id = a.customer_id\n", + "JOIN transactions t ON a.account_id = t.account_id\n", + "WHERE c.name IN ('Altman', 'Zuckerberg')\n", + "GROUP BY c.name;\n", + "```\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `sql_db_query` with `{'query': \"SELECT c.name, SUM(t.amount) AS total_transactions\\nFROM customers c\\nJOIN accounts a ON c.customer_id = a.customer_id\\nJOIN transactions t ON a.account_id = t.account_id\\nWHERE c.name IN ('Altman', 'Zuckerberg')\\nGROUP BY c.name;\"}`\n", "\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[(-965.7,)]\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_query` with `{'query': 'SELECT SUM(amount) AS total_transactions FROM transactions WHERE account_id IN (SELECT account_id FROM accounts WHERE customer_id = 2)'}`\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m[('Altman', -965.7), ('Zuckerberg', 656.64)]\u001b[0m\u001b[32;1m\u001b[1;3mThe total transactions for each customer are as follows:\n", "\n", + "- **Altman**: -965.7\n", + "- **Zuckerberg**: 656.64\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[(743.1299999999999,)]\u001b[0m\u001b[32;1m\u001b[1;3mThe total transactions for Altman is -965.7 and for Zuckerberg is 743.13.\u001b[0m\n", + "This indicates that Altman has a net loss in transactions, while Zuckerberg has a net gain.\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n" ] @@ -634,10 +707,10 @@ "data": { "text/plain": [ "{'input': 'Calculate and compare the total transactions of Altman and Zuckerberg.',\n", - " 'output': 'The total transactions for Altman is -965.7 and for Zuckerberg is 743.13.'}" + " 'output': 'The total transactions for each customer are as follows:\\n\\n- **Altman**: -965.7\\n- **Zuckerberg**: 656.64\\n\\nThis indicates that Altman has a net loss in transactions, while Zuckerberg has a net gain.'}" ] }, - "execution_count": 41, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } @@ -867,7 +940,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.3" + "version": "3.11.9" } }, "nbformat": 4, From 8023f6319ba068d04eae334e69c02e29961b306b Mon Sep 17 00:00:00 2001 From: jinucho Date: Tue, 14 Jan 2025 10:55:58 +0900 Subject: [PATCH 4/9] [E-1] 14-Chains / 02-SQL code and contents update --- 14-Chains/02-SQL.ipynb | 506 +++++++++++++++++++++++------------------ 1 file changed, 279 insertions(+), 227 deletions(-) diff --git a/14-Chains/02-SQL.ipynb b/14-Chains/02-SQL.ipynb index 9e02d5af5..ff08918c1 100644 --- a/14-Chains/02-SQL.ipynb +++ b/14-Chains/02-SQL.ipynb @@ -25,12 +25,8 @@ "- [Environment Setup](#environment-setup)\n", "- [Load SQL Database](#load-sql-database)\n", "- [SQL generate chain](#sql-generate-chain)\n", - "- [Enhance and generate answers using the LLM](#enhance-and-generate-answers-using-the-llm)\n", - "- [Agent](#Agent)\n", - "- [Differences Between create_sql_query_chain and SQL Agent](#differences-between-create_sql_query_chain-and-sql-agent)\n", - "- [[Note]: SQLite DB Creation](#note-sqlite-db-creation)\n", - "\n", - "\n", + "- [Using SQL generating chain with an Agent](#using-sql-generating-chain-with-an-agent)\n", + "- [Appendix : Chain with gpt-4o and a Post-Processing Function](#appendix--chain-with-gpt-4o-and-a-post-processing-function) \n", "\n", "### References\n", "- [SQLDatabase](https://python.langchain.com/api_reference/community/utilities/langchain_community.utilities.sql_database.SQLDatabase.html#sqldatabase)\n", @@ -56,7 +52,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -66,7 +62,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -95,7 +91,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -123,7 +119,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -132,7 +128,7 @@ "True" ] }, - "execution_count": 25, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -152,14 +148,12 @@ "source": [ "## Load SQL Database\n", "\n", - "Load and verify the sample database data.\n", - "\n", - "You can also create a custom database by referring to **[[Note]: SQLite DB Creation](#note-sqlite-db-creation)** ." + "Load and verify the sample database data." ] }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -204,7 +198,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -212,12 +206,14 @@ "llm = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature=0)\n", "\n", "# Generate a chain by providing the LLM and DB as parameters.\n", - "chain = create_sql_query_chain(llm=llm, db=db,k=10)# k(for query Limit)'s default value is 5" + "chain = create_sql_query_chain(\n", + " llm=llm, db=db, k=10\n", + ") # k(for query Limit)'s default value is 5" ] }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -251,7 +247,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -260,7 +256,7 @@ "'SELECT \"name\" FROM customers;'" ] }, - "execution_count": 29, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -280,7 +276,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -288,7 +284,9 @@ "llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)\n", "\n", "# Generate a chain by providing the LLM and DB as parameters.\n", - "bad_case_chain = create_sql_query_chain(llm=llm, db=db,k=10)# k(for query Limit)'s default values is 5" + "bad_case_chain = create_sql_query_chain(\n", + " llm=llm, db=db, k=10\n", + ") # k(for query Limit)'s default values is 5" ] }, { @@ -300,7 +298,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -309,7 +307,7 @@ "'SQLQuery: SELECT \"name\" FROM customers LIMIT 10;'" ] }, - "execution_count": 31, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -329,7 +327,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -359,10 +357,10 @@ "\"\"\"\n", ").partial(dialect=db.dialect)\n", "\n", - "# model 은 gpt-3.5-turbo 를 지정\n", + "# Create an OpenAI LLM\n", "llm = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature=0)\n", "\n", - "# LLM 과 DB 를 매개변수로 입력하여 chain 을 생성합니다.\n", + "# Generate a chain by providing the LLM and DB as parameters.\n", "chain = create_sql_query_chain(llm, db, prompt)" ] }, @@ -375,7 +373,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -403,7 +401,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ @@ -415,7 +413,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 14, "metadata": {}, "outputs": [ { @@ -424,7 +422,7 @@ "\"[('Altman',), ('Huang',), ('Zuckerberg',), ('Musk',), ('Hassabis',), ('Chase',)]\"" ] }, - "execution_count": 35, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -435,7 +433,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 15, "metadata": {}, "outputs": [], "source": [ @@ -445,7 +443,7 @@ "execute_query = QuerySQLDatabaseTool(db=db)\n", "\n", "# SQL query generation chain\n", - "write_query = create_sql_query_chain(llm, db,prompt)\n", + "write_query = create_sql_query_chain(llm, db, prompt)\n", "\n", "# Create a chain to execute the generated query.\n", "chain = write_query | execute_query" @@ -453,7 +451,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -462,7 +460,7 @@ "\"[('Sam@example.com',)]\"" ] }, - "execution_count": 37, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -476,14 +474,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Enhance and generate answers using the LLM\n", + "### Enhance and generate answers using the LLM\n", "\n", "Using the chain created in the previous step results in short, concise answers. This can be adjusted using an LCEL-style chain to provide more natural and detailed responses." ] }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 17, "metadata": {}, "outputs": [], "source": [ @@ -516,7 +514,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 18, "metadata": {}, "outputs": [ { @@ -525,7 +523,7 @@ "\"The total of Altman's transactions is -965.7.\"" ] }, - "execution_count": 39, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -539,14 +537,32 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Agent\n", + "## Using SQL generating chain with an Agent" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### What is ```agent_toolkits``` ?\n", + "\n", + "```agent_toolkits``` in LangChain is a collection of tools designed to simplify the creation and use of Agents optimized for specific domains or use cases. \n", + "\n", + "Each toolkit encapsulates the functionality and workflows needed for specific tasks (e.g., SQL query processing, file system operations, API calls), enabling developers to perform complex tasks with ease." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using an Agent, you can generate SQL queries and output the results as answers.\n", "\n", - "Using an Agent, you can generate SQL queries and output the results as answers." + "Agents work well with models like **gpt-4o** and **gpt-4o-mini**, in contrast to the issues encountered with chains when changing the model." ] }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 19, "metadata": {}, "outputs": [], "source": [ @@ -554,8 +570,7 @@ "from langchain_community.utilities import SQLDatabase\n", "from langchain_community.agent_toolkits import create_sql_agent\n", "\n", - "# Specify the model as gpt-3.5-turbo\n", - "llm = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature=0)\n", + "llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)\n", "\n", "# Connect to the SQLite database\n", "db = SQLDatabase.from_uri(\"sqlite:///data/finance.db\")\n", @@ -566,7 +581,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -581,7 +596,7 @@ "\n", "\n", "\u001b[0m\u001b[38;5;200m\u001b[1;3maccounts, customers, transactions\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_schema` with `{'table_names': 'accounts, transactions'}`\n", + "Invoking: `sql_db_schema` with `{'table_names': 'accounts'}`\n", "\n", "\n", "\u001b[0m\u001b[33;1m\u001b[1;3m\n", @@ -599,9 +614,29 @@ "1\t1\t1000.5\n", "2\t2\t2500.75\n", "3\t3\t1500.0\n", - "*/\n", + "*/\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `sql_db_schema` with `{'table_names': 'customers'}`\n", + "\n", "\n", + "\u001b[0m\u001b[33;1m\u001b[1;3m\n", + "CREATE TABLE customers (\n", + "\tcustomer_id INTEGER, \n", + "\tname TEXT, \n", + "\tage INTEGER, \n", + "\temail TEXT\n", + ")\n", "\n", + "/*\n", + "3 rows from customers table:\n", + "customer_id\tname\tage\temail\n", + "1\tAltman\t40\tSam@example.com\n", + "2\tHuang\t62\tJensen@example.com\n", + "3\tZuckerberg\t41\tMark@example.com\n", + "*/\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `sql_db_schema` with `{'table_names': 'transactions'}`\n", + "\n", + "\n", + "\u001b[0m\u001b[33;1m\u001b[1;3m\n", "CREATE TABLE transactions (\n", "\ttransaction_id INTEGER, \n", "\taccount_id INTEGER, \n", @@ -618,14 +653,51 @@ "2\t1\t-224.1\t2024-05-13\n", "3\t1\t-128.9\t2024-01-25\n", "*/\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_query` with `{'query': 'SELECT SUM(amount) AS total_transactions FROM transactions WHERE account_id IN (SELECT account_id FROM accounts WHERE customer_id = 1)'}`\n", + "Invoking: `sql_db_query` with `{'query': \"SELECT customer_id, name FROM customers WHERE name IN ('Altman', 'Zuckerberg')\"}`\n", + "responded: The relevant tables and their structures are as follows:\n", + "\n", + "1. **accounts**: \n", + " - `account_id`: INTEGER\n", + " - `customer_id`: INTEGER\n", + " - `balance`: REAL\n", + "\n", + "2. **customers**: \n", + " - `customer_id`: INTEGER\n", + " - `name`: TEXT\n", + " - `age`: INTEGER\n", + " - `email`: TEXT\n", + "\n", + "3. **transactions**: \n", + " - `transaction_id`: INTEGER\n", + " - `account_id`: INTEGER\n", + " - `amount`: REAL\n", + " - `transaction_date`: TEXT\n", + "\n", + "To calculate and compare the total transactions of Altman and Zuckerberg, I will need to:\n", + "1. Find the `customer_id` for both Altman and Zuckerberg from the `customers` table.\n", + "2. Use their `customer_id` to find the corresponding `account_id` from the `accounts` table.\n", + "3. Sum the `amount` from the `transactions` table for each `account_id`.\n", + "\n", + "Let's construct the SQL queries for these steps. \n", "\n", + "First, I will get the `customer_id` for Altman and Zuckerberg. Then, I will get their `account_id` and finally sum the transactions. \n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[(-965.7,)]\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_query` with `{'query': 'SELECT SUM(amount) AS total_transactions FROM transactions WHERE account_id IN (SELECT account_id FROM accounts WHERE customer_id = 2)'}`\n", + "I will execute the first query to get the `customer_id` for both customers.\n", "\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m[(1, 'Altman'), (3, 'Zuckerberg')]\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `sql_db_query` with `{'query': 'SELECT account_id FROM accounts WHERE customer_id IN (1, 3)'}`\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[(743.1299999999999,)]\u001b[0m\u001b[32;1m\u001b[1;3mThe total transactions for Altman is -965.7 and for Zuckerberg is 743.13.\u001b[0m\n", + "\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m[(1,), (3,)]\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `sql_db_query` with `{'query': 'SELECT SUM(amount) as total_transactions FROM transactions WHERE account_id IN (1, 3) GROUP BY account_id'}`\n", + "\n", + "\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m[(-965.7,), (656.6400000000002,)]\u001b[0m\u001b[32;1m\u001b[1;3mThe total transactions for each customer are as follows:\n", + "\n", + "- **Altman** (account_id 1): Total Transactions = **-965.7**\n", + "- **Zuckerberg** (account_id 3): Total Transactions = **656.64**\n", + "\n", + "This indicates that Altman has a negative total transaction amount, while Zuckerberg has a positive total transaction amount.\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n" ] @@ -634,10 +706,10 @@ "data": { "text/plain": [ "{'input': 'Calculate and compare the total transactions of Altman and Zuckerberg.',\n", - " 'output': 'The total transactions for Altman is -965.7 and for Zuckerberg is 743.13.'}" + " 'output': 'The total transactions for each customer are as follows:\\n\\n- **Altman** (account_id 1): Total Transactions = **-965.7**\\n- **Zuckerberg** (account_id 3): Total Transactions = **656.64**\\n\\nThis indicates that Altman has a negative total transaction amount, while Zuckerberg has a positive total transaction amount.'}" ] }, - "execution_count": 41, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -653,201 +725,181 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Differences Between create_sql_query_chain and SQL Agent\n", + "### Differences Between create_sql_query_chain and SQL Agent\n", "1. create_sql_query_chain:\n", " - Translates user input into a single SQL query and executes it directly.\n", " - Best for simple, direct query execution.\n", "2. SQL Agent:\n", " - Handles more complex workflows, involving multiple queries and reasoning steps.\n", " - Ideal for dynamic or multi-step tasks.\n", - "3. Summary: It is recommended to use ```create_sql_query_chain``` for simple queries, while ```SQL Agent``` is suggested for complex or iterative processes." + "3. Conclusion: It is recommended to use ```create_sql_query_chain``` for simple queries, while ```SQL Agent``` is suggested for complex or iterative processes." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## [Note]: SQLite DB Creation\n", + "## Appendix : Chain with gpt-4o and a Post-Processing Function\n", "\n", - "This is a code for creating a SQLite database.\n", + "As observed earlier, `gpt-4o` output can be inconsistent.\n", "\n", - "You can customize the code below to suit your needs." + "To address this, a chain can be constructed with a post-processing function applied." ] }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 21, "metadata": {}, "outputs": [], "source": [ - "# import sqlite3\n", - "\n", - "# connection = sqlite3.connect(\"data/finance.db\")\n", - "# cursor = connection.cursor()\n", - "\n", - "# # Create `customers` table\n", - "# cursor.execute('''\n", - "# CREATE TABLE customers (\n", - "# customer_id INTEGER PRI\n", - "# MARY KEY,\n", - "# name TEXT,\n", - "# age INTEGER,\n", - "# email TEXT\n", - "# );\n", - "# ''')\n", - "\n", - "# # Insert data into `customers`\n", - "# cursor.executemany('''\n", - "# INSERT INTO customers (customer_id, name, age, email)\n", - "# VALUES (?, ?, ?, ?);\n", - "# ''', [\n", - "# (1, 'Altman', 40, 'Sam@example.com'),\n", - "# (2, 'Huang', 62, 'Jensen@example.com'),\n", - "# (3, 'Zuckerberg', 41, 'Mark@example.com'),\n", - "# (4, 'Musk', 54, 'Elon@example.com'),\n", - "# (5, 'Hassabis', 49, 'Demis@example.com'),\n", - "# (6, 'Chase', 35, 'Harrison@example.com')\n", - "# ])\n", - "\n", - "# # Create `accounts` table\n", - "# cursor.execute('''\n", - "# CREATE TABLE accounts (\n", - "# account_id INTEGER PRIMARY KEY,\n", - "# customer_id INTEGER,\n", - "# balance REAL,\n", - "# FOREIGN KEY (customer_id) REFERENCES customers(customer_id)\n", - "# );\n", - "# ''')\n", - "\n", - "# # Insert data into `accounts`\n", - "# cursor.executemany('''\n", - "# INSERT INTO accounts (account_id, customer_id, balance)\n", - "# VALUES (?, ?, ?);\n", - "# ''', [\n", - "# (1, 1, 1000.5),\n", - "# (2, 2, 2500.75),\n", - "# (3, 3, 1500.0),\n", - "# (4, 4, 1800.25),\n", - "# (5, 5, 2200.6),\n", - "# (6, 6, 1750.4)\n", - "# ])\n", - "\n", - "# # Create `transactions` table\n", - "# cursor.execute('''\n", - "# CREATE TABLE transactions (\n", - "# transaction_id INTEGER PRIMARY KEY,\n", - "# account_id INTEGER,\n", - "# amount REAL,\n", - "# transaction_date TEXT,\n", - "# FOREIGN KEY (account_id) REFERENCES accounts(account_id)\n", - "# );\n", - "# ''')\n", - "\n", - "# # Insert data into `transactions`\n", - "# cursor.executemany('''\n", - "# INSERT INTO transactions (transaction_id, account_id, amount, transaction_date)\n", - "# VALUES (?, ?, ?, ?);\n", - "# ''', [\n", - "# (1, 1, 74.79, '2024-07-13'),\n", - "# (2, 1, -224.1, '2024-05-13'),\n", - "# (3, 1, -128.9, '2024-01-25'),\n", - "# (4, 1, -314.05, '2024-07-28'),\n", - "# (5, 1, -464.0, '2024-04-21'),\n", - "# (6, 1, -486.99, '2024-07-04'),\n", - "# (7, 1, -318.33, '2024-02-15'),\n", - "# (8, 1, 290.23, '2024-04-06'),\n", - "# (9, 1, 236.57, '2024-01-01'),\n", - "# (10, 1, 321.92, '2024-05-24'),\n", - "# (11, 1, 95.75, '2024-01-04'),\n", - "# (12, 1, -415.22, '2024-06-10'),\n", - "# (13, 1, 318.15, '2024-07-21'),\n", - "# (14, 1, 269.66, '2024-01-13'),\n", - "# (15, 1, -386.16, '2024-04-13'),\n", - "# (16, 1, 164.98, '2024-05-02'),\n", - "# (17, 2, -43.13, '2024-07-03'),\n", - "# (18, 2, -308.91, '2024-03-15'),\n", - "# (19, 2, 347.45, '2024-01-23'),\n", - "# (20, 2, -72.35, '2024-02-01'),\n", - "# (21, 2, -114.54, '2024-03-30'),\n", - "# (22, 2, 273.34, '2024-07-06'),\n", - "# (23, 2, 458.16, '2024-06-17'),\n", - "# (24, 2, 227.77, '2024-03-14'),\n", - "# (25, 2, -51.55, '2024-06-18'),\n", - "# (26, 2, 304.99, '2024-02-16'),\n", - "# (27, 2, 176.56, '2024-03-30'),\n", - "# (28, 2, -147.86, '2024-02-16'),\n", - "# (29, 2, -456.95, '2024-07-30'),\n", - "# (30, 2, 190.11, '2024-01-23'),\n", - "# (31, 2, 222.13, '2024-02-14'),\n", - "# (32, 2, -262.09, '2024-07-21'),\n", - "# (33, 3, 148.49, '2024-01-09'),\n", - "# (34, 3, -289.71, '2024-01-31'),\n", - "# (35, 3, -150.71, '2024-05-24'),\n", - "# (36, 3, 64.14, '2024-04-08'),\n", - "# (37, 3, -373.0, '2024-04-17'),\n", - "# (38, 3, 210.42, '2024-06-29'),\n", - "# (39, 3, -425.75, '2024-05-08'),\n", - "# (40, 3, 266.32, '2024-06-05'),\n", - "# (41, 3, 160.99, '2024-02-21'),\n", - "# (42, 3, -127.92, '2024-04-04'),\n", - "# (43, 3, 457.43, '2024-04-22'),\n", - "# (44, 3, 417.64, '2024-03-28'),\n", - "# (45, 3, 392.0, '2024-02-19'),\n", - "# (46, 3, 221.92, '2024-02-25'),\n", - "# (47, 3, -417.7, '2024-02-02'),\n", - "# (48, 3, 102.08, '2024-07-07'),\n", - "# (49, 4, 489.96, '2024-06-03'),\n", - "# (50, 4, 21.06, '2024-04-20'),\n", - "# (51, 4, -278.72, '2024-02-18'),\n", - "# (52, 4, 58.08, '2024-04-15'),\n", - "# (53, 4, 489.45, '2024-03-19'),\n", - "# (54, 4, -448.04, '2024-07-16'),\n", - "# (55, 4, -272.16, '2024-06-30'),\n", - "# (56, 4, -41.19, '2024-03-21'),\n", - "# (57, 4, 200.61, '2024-04-10'),\n", - "# (58, 4, 431.89, '2024-03-08'),\n", - "# (59, 4, 236.82, '2024-01-03'),\n", - "# (60, 4, -167.94, '2024-05-31'),\n", - "# (61, 4, 273.09, '2024-06-10'),\n", - "# (62, 4, 225.16, '2024-03-31'),\n", - "# (63, 4, -110.66, '2024-05-23'),\n", - "# (64, 4, 329.74, '2024-05-29'),\n", - "# (65, 5, -150.66, '2024-02-19'),\n", - "# (66, 5, -406.2, '2024-06-16'),\n", - "# (67, 5, 360.12, '2024-05-18'),\n", - "# (68, 5, -252.19, '2024-06-11'),\n", - "# (69, 5, -373.15, '2024-03-12'),\n", - "# (70, 5, -361.49, '2024-05-22'),\n", - "# (71, 5, -135.04, '2024-04-25'),\n", - "# (72, 5, -160.99, '2024-05-31'),\n", - "# (73, 5, 399.02, '2024-06-23'),\n", - "# (74, 5, -77.75, '2024-05-06'),\n", - "# (75, 5, -443.42, '2024-03-28'),\n", - "# (76, 5, 202.05, '2024-01-04'),\n", - "# (77, 5, -182.5, '2024-04-12'),\n", - "# (78, 5, -428.84, '2024-03-10'),\n", - "# (79, 5, 311.05, '2024-01-13'),\n", - "# (80, 5, 173.89, '2024-01-10'),\n", - "# (81, 6, -325.71, '2024-07-15'),\n", - "# (82, 6, 127.41, '2024-01-25'),\n", - "# (83, 6, -203.54, '2024-05-05'),\n", - "# (84, 6, 478.24, '2024-05-07'),\n", - "# (85, 6, -27.91, '2024-07-21'),\n", - "# (86, 6, 194.06, '2024-01-14'),\n", - "# (87, 6, -224.5, '2024-06-15'),\n", - "# (88, 6, -394.75, '2024-04-18'),\n", - "# (89, 6, 130.54, '2024-03-26'),\n", - "# (90, 6, 494.1, '2024-02-23'),\n", - "# (91, 6, -136.39, '2024-05-17'),\n", - "# (92, 6, 35.12, '2024-04-28'),\n", - "# (93, 6, -333.55, '2024-04-25'),\n", - "# (94, 6, 170.36, '2024-03-05'),\n", - "# (95, 6, 345.4, '2024-03-09'),\n", - "# (96, 6, -130.69, '2024-05-24')\n", - "# ])\n", - "\n", - "# connection.commit()\n", - "# connection.close()" + "from langchain_core.prompts import PromptTemplate\n", + "\n", + "prompt = PromptTemplate.from_template(\n", + " \"\"\"Given an input question, first create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer. \n", + " Unless the user specifies in his question a specific number of examples he wishes to obtain, always limit your query to at most {top_k} results. \n", + " You can order the results by a relevant column to return the most interesting examples in the database.\n", + "\n", + "[Important] You must respond strictly in the format 'select column_name from table_name [Options:LIMIT,ORDER BY,others]'.\n", + "\n", + "Use the following format:\n", + "\n", + "Question: Question here\n", + "SQLQuery: SQL Query to run\n", + "SQLResult: Result of the SQLQuery\n", + "Answer: Final answer here\n", + "\n", + "Only use the following tables:\n", + "{table_info}\n", + "\n", + "Here is the description of the columns in the tables:\n", + "`cust`: customer name\n", + "`prod`: product name\n", + "`trans`: transaction date\n", + "\n", + "Question: {input}\n", + "\"\"\"\n", + ").partial(dialect=db.dialect)\n", + "\n", + "# Create an OpenAI LLM\n", + "llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)\n", + "\n", + "# Generate a chain by providing the LLM and DB as parameters.\n", + "write_query = create_sql_query_chain(llm, db, prompt, k=10)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'SQLQuery: select name from customers ORDER BY name LIMIT 10'" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Check the execution result\n", + "# The result contains unnecessary text, such as 'SQLQuery: '\n", + "write_query.invoke({\"question\": \"List the all customer names.\"})" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "# It is necessary to remove unnecessary text.\n", + "from langchain.chains import TransformChain\n", + "import re\n", + "\n", + "\n", + "# Define the regex parsing function\n", + "def parse_sqlquery(raw_output):\n", + " match = re.search(r\"SQLQuery:\\s*(.*)\", raw_output)\n", + " if match:\n", + " return {\"parsed_query\": match.group(1).strip()}\n", + " raise ValueError(f\"No valid SQL query found in the output: {raw_output}\")\n", + "\n", + "\n", + "# Create a TransformChain to parse the query\n", + "transform_chain = TransformChain(\n", + " input_variables=[\"raw_output\"],\n", + " output_variables=[\"query\"], # Output key changed to 'query'\n", + " transform=lambda inputs: {\n", + " \"query\": parse_sqlquery(inputs[\"raw_output\"])[\"parsed_query\"]\n", + " },\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_community.tools import QuerySQLDatabaseTool\n", + "\n", + "# Create a tool to execute the generated query.\n", + "execute_query = QuerySQLDatabaseTool(db=db)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], + "source": [ + "# Combine the chains: generating query -> Regex Parsing -> SQL Execution\n", + "chain = write_query | transform_chain | execute_query" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"[('Altman',), ('Chase',), ('Hassabis',), ('Huang',), ('Musk',), ('Zuckerberg',)]\"" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Check the execution result\n", + "chain.invoke({\"question\": \"List the all customer names.\"})" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'[(-965.7,)]'" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Check the execution result\n", + "chain.invoke({\"question\": \"Calculate the total of Altman's transactions.\"})" ] } ], From e762efbf2403d11caa84245c4d94284061fc4ea3 Mon Sep 17 00:00:00 2001 From: jinucho Date: Tue, 14 Jan 2025 11:09:15 +0900 Subject: [PATCH 5/9] [E-1] 14-Chains / 02-SQL code and contents update --- 14-Chains/02-SQL.ipynb | 166 +---------------------------------------- 1 file changed, 1 insertion(+), 165 deletions(-) diff --git a/14-Chains/02-SQL.ipynb b/14-Chains/02-SQL.ipynb index 7de527f30..d55ce73d5 100644 --- a/14-Chains/02-SQL.ipynb +++ b/14-Chains/02-SQL.ipynb @@ -52,11 +52,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 1, -======= - "execution_count": 4, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [], "source": [ @@ -66,11 +62,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 2, -======= - "execution_count": 5, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [], "source": [ @@ -99,11 +91,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 3, -======= - "execution_count": 6, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [ { @@ -131,11 +119,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 4, -======= - "execution_count": 7, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [ { @@ -144,11 +128,7 @@ "True" ] }, -<<<<<<< HEAD "execution_count": 4, -======= - "execution_count": 7, ->>>>>>> origin/weeks3 "metadata": {}, "output_type": "execute_result" } @@ -173,11 +153,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 5, -======= - "execution_count": 8, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [ { @@ -222,11 +198,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 6, -======= - "execution_count": 14, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [], "source": [ @@ -241,11 +213,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 7, -======= - "execution_count": 15, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [ { @@ -279,11 +247,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 8, -======= - "execution_count": 16, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [ { @@ -292,11 +256,7 @@ "'SELECT \"name\" FROM customers;'" ] }, -<<<<<<< HEAD "execution_count": 8, -======= - "execution_count": 16, ->>>>>>> origin/weeks3 "metadata": {}, "output_type": "execute_result" } @@ -316,11 +276,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 9, -======= - "execution_count": 17, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [], "source": [ @@ -342,11 +298,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 10, -======= - "execution_count": 18, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [ { @@ -355,11 +307,7 @@ "'SQLQuery: SELECT \"name\" FROM customers LIMIT 10;'" ] }, -<<<<<<< HEAD "execution_count": 10, -======= - "execution_count": 18, ->>>>>>> origin/weeks3 "metadata": {}, "output_type": "execute_result" } @@ -379,11 +327,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 11, -======= - "execution_count": 19, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [], "source": [ @@ -429,11 +373,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 12, -======= - "execution_count": 20, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [ { @@ -461,11 +401,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 13, -======= - "execution_count": 21, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [], "source": [ @@ -477,11 +413,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 14, -======= - "execution_count": 22, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [ { @@ -490,11 +422,7 @@ "\"[('Altman',), ('Huang',), ('Zuckerberg',), ('Musk',), ('Hassabis',), ('Chase',)]\"" ] }, -<<<<<<< HEAD "execution_count": 14, -======= - "execution_count": 22, ->>>>>>> origin/weeks3 "metadata": {}, "output_type": "execute_result" } @@ -505,11 +433,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 15, -======= - "execution_count": 23, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [], "source": [ @@ -527,11 +451,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 16, -======= - "execution_count": 24, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [ { @@ -540,11 +460,7 @@ "\"[('Sam@example.com',)]\"" ] }, -<<<<<<< HEAD "execution_count": 16, -======= - "execution_count": 24, ->>>>>>> origin/weeks3 "metadata": {}, "output_type": "execute_result" } @@ -565,11 +481,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 17, -======= - "execution_count": 25, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [], "source": [ @@ -602,11 +514,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 18, -======= - "execution_count": 26, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [ { @@ -615,11 +523,7 @@ "\"The total of Altman's transactions is -965.7.\"" ] }, -<<<<<<< HEAD "execution_count": 18, -======= - "execution_count": 26, ->>>>>>> origin/weeks3 "metadata": {}, "output_type": "execute_result" } @@ -658,11 +562,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 19, -======= - "execution_count": 29, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [], "source": [ @@ -670,10 +570,6 @@ "from langchain_community.utilities import SQLDatabase\n", "from langchain_community.agent_toolkits import create_sql_agent\n", "\n", -<<<<<<< HEAD -======= - "# Specify the model as gpt-3.5-turbo\n", ->>>>>>> origin/weeks3 "llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)\n", "\n", "# Connect to the SQLite database\n", @@ -685,11 +581,7 @@ }, { "cell_type": "code", -<<<<<<< HEAD "execution_count": 20, -======= - "execution_count": 30, ->>>>>>> origin/weeks3 "metadata": {}, "outputs": [ { @@ -761,36 +653,21 @@ "2\t1\t-224.1\t2024-05-13\n", "3\t1\t-128.9\t2024-01-25\n", "*/\u001b[0m\u001b[32;1m\u001b[1;3m\n", -<<<<<<< HEAD "Invoking: `sql_db_query` with `{'query': \"SELECT customer_id, name FROM customers WHERE name IN ('Altman', 'Zuckerberg')\"}`\n", "responded: The relevant tables and their structures are as follows:\n", "\n", "1. **accounts**: \n", -======= - "Invoking: `sql_db_query_checker` with `{'query': \"SELECT c.name, SUM(t.amount) AS total_transactions\\nFROM customers c\\nJOIN accounts a ON c.customer_id = a.customer_id\\nJOIN transactions t ON a.account_id = t.account_id\\nWHERE c.name IN ('Altman', 'Zuckerberg')\\nGROUP BY c.name;\"}`\n", - "responded: The relevant tables and their structures are as follows:\n", - "\n", - "1. **accounts**:\n", ->>>>>>> origin/weeks3 " - `account_id`: INTEGER\n", " - `customer_id`: INTEGER\n", " - `balance`: REAL\n", "\n", -<<<<<<< HEAD "2. **customers**: \n", -======= - "2. **customers**:\n", ->>>>>>> origin/weeks3 " - `customer_id`: INTEGER\n", " - `name`: TEXT\n", " - `age`: INTEGER\n", " - `email`: TEXT\n", "\n", -<<<<<<< HEAD "3. **transactions**: \n", -======= - "3. **transactions**:\n", ->>>>>>> origin/weeks3 " - `transaction_id`: INTEGER\n", " - `account_id`: INTEGER\n", " - `amount`: REAL\n", @@ -805,7 +682,6 @@ "\n", "First, I will get the `customer_id` for Altman and Zuckerberg. Then, I will get their `account_id` and finally sum the transactions. \n", "\n", -<<<<<<< HEAD "I will execute the first query to get the `customer_id` for both customers.\n", "\n", "\u001b[0m\u001b[36;1m\u001b[1;3m[(1, 'Altman'), (3, 'Zuckerberg')]\u001b[0m\u001b[32;1m\u001b[1;3m\n", @@ -814,49 +690,16 @@ "\n", "\u001b[0m\u001b[36;1m\u001b[1;3m[(1,), (3,)]\u001b[0m\u001b[32;1m\u001b[1;3m\n", "Invoking: `sql_db_query` with `{'query': 'SELECT SUM(amount) as total_transactions FROM transactions WHERE account_id IN (1, 3) GROUP BY account_id'}`\n", -======= - "I will combine these steps into a single query to get the total transactions for both customers. \n", - "\n", - "Here is the query I will use:\n", - "\n", - "```sql\n", - "SELECT c.name, SUM(t.amount) AS total_transactions\n", - "FROM customers c\n", - "JOIN accounts a ON c.customer_id = a.customer_id\n", - "JOIN transactions t ON a.account_id = t.account_id\n", - "WHERE c.name IN ('Altman', 'Zuckerberg')\n", - "GROUP BY c.name;\n", - "```\n", - "\n", - "Now, I will check this query for correctness before executing it.\n", - "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m```sql\n", - "SELECT c.name, SUM(t.amount) AS total_transactions\n", - "FROM customers c\n", - "JOIN accounts a ON c.customer_id = a.customer_id\n", - "JOIN transactions t ON a.account_id = t.account_id\n", - "WHERE c.name IN ('Altman', 'Zuckerberg')\n", - "GROUP BY c.name;\n", - "```\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_query` with `{'query': \"SELECT c.name, SUM(t.amount) AS total_transactions\\nFROM customers c\\nJOIN accounts a ON c.customer_id = a.customer_id\\nJOIN transactions t ON a.account_id = t.account_id\\nWHERE c.name IN ('Altman', 'Zuckerberg')\\nGROUP BY c.name;\"}`\n", - "\n", - "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[('Altman', -965.7), ('Zuckerberg', 656.64)]\u001b[0m\u001b[32;1m\u001b[1;3mThe total transactions for each customer are as follows:\n", ->>>>>>> origin/weeks3 "\n", "- **Altman**: -965.7\n", "- **Zuckerberg**: 656.64\n", "\n", -<<<<<<< HEAD "\u001b[0m\u001b[36;1m\u001b[1;3m[(-965.7,), (656.6400000000002,)]\u001b[0m\u001b[32;1m\u001b[1;3mThe total transactions for each customer are as follows:\n", "\n", "- **Altman** (account_id 1): Total Transactions = **-965.7**\n", "- **Zuckerberg** (account_id 3): Total Transactions = **656.64**\n", "\n", "This indicates that Altman has a negative total transaction amount, while Zuckerberg has a positive total transaction amount.\u001b[0m\n", -======= - "This indicates that Altman has a net loss in transactions, while Zuckerberg has a net gain.\u001b[0m\n", ->>>>>>> origin/weeks3 "\n", "\u001b[1m> Finished chain.\u001b[0m\n" ] @@ -865,17 +708,10 @@ "data": { "text/plain": [ "{'input': 'Calculate and compare the total transactions of Altman and Zuckerberg.',\n", -<<<<<<< HEAD " 'output': 'The total transactions for each customer are as follows:\\n\\n- **Altman** (account_id 1): Total Transactions = **-965.7**\\n- **Zuckerberg** (account_id 3): Total Transactions = **656.64**\\n\\nThis indicates that Altman has a negative total transaction amount, while Zuckerberg has a positive total transaction amount.'}" ] }, "execution_count": 20, -======= - " 'output': 'The total transactions for each customer are as follows:\\n\\n- **Altman**: -965.7\\n- **Zuckerberg**: 656.64\\n\\nThis indicates that Altman has a net loss in transactions, while Zuckerberg has a net gain.'}" - ] - }, - "execution_count": 30, ->>>>>>> origin/weeks3 "metadata": {}, "output_type": "execute_result" } @@ -1085,7 +921,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.9" + "version": "3.11.3" } }, "nbformat": 4, From 00061009aba98e79d2a04b705892f53d522c1fdd Mon Sep 17 00:00:00 2001 From: jinucho Date: Tue, 14 Jan 2025 14:39:05 +0900 Subject: [PATCH 6/9] [E-1] 14-Chains / 02-SQL code and contents update --- 14-Chains/02-SQL.ipynb | 107 +++++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 48 deletions(-) diff --git a/14-Chains/02-SQL.ipynb b/14-Chains/02-SQL.ipynb index d55ce73d5..75e575b08 100644 --- a/14-Chains/02-SQL.ipynb +++ b/14-Chains/02-SQL.ipynb @@ -108,8 +108,8 @@ "\n", "set_env(\n", " {\n", - " # \"OPENAI_API_KEY\": \"\",\n", - " # \"LANGCHAIN_API_KEY\": \"\",\n", + " \"OPENAI_API_KEY\": \"\",\n", + " \"LANGCHAIN_API_KEY\": \"\",\n", " \"LANGCHAIN_TRACING_V2\": \"true\",\n", " \"LANGCHAIN_ENDPOINT\": \"https://api.smith.langchain.com\",\n", " \"LANGCHAIN_PROJECT\": \"02-SQL\",\n", @@ -656,18 +656,18 @@ "Invoking: `sql_db_query` with `{'query': \"SELECT customer_id, name FROM customers WHERE name IN ('Altman', 'Zuckerberg')\"}`\n", "responded: The relevant tables and their structures are as follows:\n", "\n", - "1. **accounts**: \n", + "1. **accounts**:\n", " - `account_id`: INTEGER\n", " - `customer_id`: INTEGER\n", " - `balance`: REAL\n", "\n", - "2. **customers**: \n", + "2. **customers**:\n", " - `customer_id`: INTEGER\n", " - `name`: TEXT\n", " - `age`: INTEGER\n", " - `email`: TEXT\n", "\n", - "3. **transactions**: \n", + "3. **transactions**:\n", " - `transaction_id`: INTEGER\n", " - `account_id`: INTEGER\n", " - `amount`: REAL\n", @@ -680,26 +680,32 @@ "\n", "Let's construct the SQL queries for these steps. \n", "\n", - "First, I will get the `customer_id` for Altman and Zuckerberg. Then, I will get their `account_id` and finally sum the transactions. \n", + "First, I will get the `customer_id` for Altman and Zuckerberg. Then, I will get the `account_id` for those `customer_id`s. Finally, I will sum the transactions for each account. \n", "\n", - "I will execute the first query to get the `customer_id` for both customers.\n", + "I will execute the first query to get the `customer_id`s.\n", "\n", "\u001b[0m\u001b[36;1m\u001b[1;3m[(1, 'Altman'), (3, 'Zuckerberg')]\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_query` with `{'query': 'SELECT account_id FROM accounts WHERE customer_id IN (1, 3)'}`\n", + "Invoking: `sql_db_query` with `{'query': 'SELECT account_id FROM accounts WHERE customer_id = 1'}`\n", "\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[(1,), (3,)]\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_query` with `{'query': 'SELECT SUM(amount) as total_transactions FROM transactions WHERE account_id IN (1, 3) GROUP BY account_id'}`\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m[(1,)]\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `sql_db_query` with `{'query': 'SELECT account_id FROM accounts WHERE customer_id = 3'}`\n", "\n", - "- **Altman**: -965.7\n", - "- **Zuckerberg**: 656.64\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[(-965.7,), (656.6400000000002,)]\u001b[0m\u001b[32;1m\u001b[1;3mThe total transactions for each customer are as follows:\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m[(3,)]\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `sql_db_query` with `{'query': 'SELECT SUM(amount) as total_transactions FROM transactions WHERE account_id = 1'}`\n", "\n", - "- **Altman** (account_id 1): Total Transactions = **-965.7**\n", - "- **Zuckerberg** (account_id 3): Total Transactions = **656.64**\n", "\n", - "This indicates that Altman has a negative total transaction amount, while Zuckerberg has a positive total transaction amount.\u001b[0m\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m[(-965.7,)]\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `sql_db_query` with `{'query': 'SELECT SUM(amount) as total_transactions FROM transactions WHERE account_id = 3'}`\n", + "\n", + "\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m[(656.6400000000002,)]\u001b[0m\u001b[32;1m\u001b[1;3mThe total transactions for each individual are as follows:\n", + "\n", + "- **Altman**: Total transactions amount to **-965.7** (indicating a net loss).\n", + "- **Zuckerberg**: Total transactions amount to **656.64** (indicating a net gain).\n", + "\n", + "In summary, Zuckerberg has a positive total transaction amount, while Altman has a negative total transaction amount.\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n" ] @@ -708,7 +714,7 @@ "data": { "text/plain": [ "{'input': 'Calculate and compare the total transactions of Altman and Zuckerberg.',\n", - " 'output': 'The total transactions for each customer are as follows:\\n\\n- **Altman** (account_id 1): Total Transactions = **-965.7**\\n- **Zuckerberg** (account_id 3): Total Transactions = **656.64**\\n\\nThis indicates that Altman has a negative total transaction amount, while Zuckerberg has a positive total transaction amount.'}" + " 'output': 'The total transactions for each individual are as follows:\\n\\n- **Altman**: Total transactions amount to **-965.7** (indicating a net loss).\\n- **Zuckerberg**: Total transactions amount to **656.64** (indicating a net gain).\\n\\nIn summary, Zuckerberg has a positive total transaction amount, while Altman has a negative total transaction amount.'}" ] }, "execution_count": 20, @@ -753,6 +759,18 @@ "execution_count": 21, "metadata": {}, "outputs": [], + "source": [ + "from langchain_community.tools import QuerySQLDatabaseTool\n", + "\n", + "# Create a tool to execute the generated query.\n", + "execute_query = QuerySQLDatabaseTool(db=db)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], "source": [ "from langchain_core.prompts import PromptTemplate\n", "\n", @@ -791,7 +809,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 23, "metadata": {}, "outputs": [ { @@ -800,7 +818,7 @@ "'SQLQuery: select name from customers ORDER BY name LIMIT 10'" ] }, - "execution_count": 22, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -813,43 +831,21 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "# It is necessary to remove unnecessary text.\n", - "from langchain.chains import TransformChain\n", "import re\n", "\n", "\n", "# Define the regex parsing function\n", - "def parse_sqlquery(raw_output):\n", - " match = re.search(r\"SQLQuery:\\s*(.*)\", raw_output)\n", + "def parse_sqlquery(query):\n", + " match = re.search(r\"SQLQuery:\\s*(.*)\", query)\n", " if match:\n", - " return {\"parsed_query\": match.group(1).strip()}\n", - " raise ValueError(f\"No valid SQL query found in the output: {raw_output}\")\n", - "\n", - "\n", - "# Create a TransformChain to parse the query\n", - "transform_chain = TransformChain(\n", - " input_variables=[\"raw_output\"],\n", - " output_variables=[\"query\"], # Output key changed to 'query'\n", - " transform=lambda inputs: {\n", - " \"query\": parse_sqlquery(inputs[\"raw_output\"])[\"parsed_query\"]\n", - " },\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_community.tools import QuerySQLDatabaseTool\n", - "\n", - "# Create a tool to execute the generated query.\n", - "execute_query = QuerySQLDatabaseTool(db=db)" + " return match.group(1).strip()\n", + " else:\n", + " return query" ] }, { @@ -859,7 +855,15 @@ "outputs": [], "source": [ "# Combine the chains: generating query -> Regex Parsing -> SQL Execution\n", - "chain = write_query | transform_chain | execute_query" + "from langchain_core.runnables import RunnablePassthrough\n", + "\n", + "chain = (\n", + " {\"query\":write_query} \n", + " | RunnablePassthrough.assign(\n", + " query=lambda x: parse_sqlquery(x[\"query\"])\n", + " )\n", + " | execute_query\n", + ")" ] }, { @@ -903,6 +907,13 @@ "# Check the execution result\n", "chain.invoke({\"question\": \"Calculate the total of Altman's transactions.\"})" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { From 7ef807e500ada8e654ce2eafd6bd82d85a4ee9cc Mon Sep 17 00:00:00 2001 From: jinucho Date: Tue, 14 Jan 2025 14:41:02 +0900 Subject: [PATCH 7/9] [E-1] 14-Chains / 02-SQL code and contents update --- 14-Chains/02-SQL.ipynb | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/14-Chains/02-SQL.ipynb b/14-Chains/02-SQL.ipynb index 75e575b08..07e4ff28c 100644 --- a/14-Chains/02-SQL.ipynb +++ b/14-Chains/02-SQL.ipynb @@ -858,10 +858,8 @@ "from langchain_core.runnables import RunnablePassthrough\n", "\n", "chain = (\n", - " {\"query\":write_query} \n", - " | RunnablePassthrough.assign(\n", - " query=lambda x: parse_sqlquery(x[\"query\"])\n", - " )\n", + " {\"query\": write_query}\n", + " | RunnablePassthrough.assign(query=lambda x: parse_sqlquery(x[\"query\"]))\n", " | execute_query\n", ")" ] @@ -907,13 +905,6 @@ "# Check the execution result\n", "chain.invoke({\"question\": \"Calculate the total of Altman's transactions.\"})" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { From 484d42ec2fe16b4908a45a2809f69626687374ad Mon Sep 17 00:00:00 2001 From: jinucho Date: Tue, 14 Jan 2025 15:34:22 +0900 Subject: [PATCH 8/9] [E-1] 14-Chains / 02-SQL code and contents update --- 14-Chains/02-SQL.ipynb | 96 +++++++++++++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 25 deletions(-) diff --git a/14-Chains/02-SQL.ipynb b/14-Chains/02-SQL.ipynb index 07e4ff28c..b50e0cc4a 100644 --- a/14-Chains/02-SQL.ipynb +++ b/14-Chains/02-SQL.ipynb @@ -653,7 +653,7 @@ "2\t1\t-224.1\t2024-05-13\n", "3\t1\t-128.9\t2024-01-25\n", "*/\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_query` with `{'query': \"SELECT customer_id, name FROM customers WHERE name IN ('Altman', 'Zuckerberg')\"}`\n", + "Invoking: `sql_db_query_checker` with `{'query': \"SELECT customer_id, name FROM customers WHERE name IN ('Altman', 'Zuckerberg')\"}`\n", "responded: The relevant tables and their structures are as follows:\n", "\n", "1. **accounts**:\n", @@ -678,34 +678,52 @@ "2. Use their `customer_id` to find the corresponding `account_id` from the `accounts` table.\n", "3. Sum the `amount` from the `transactions` table for each `account_id`.\n", "\n", - "Let's construct the SQL queries for these steps. \n", + "I will construct the SQL queries accordingly. First, I will get the `customer_id` for Altman and Zuckerberg. Then, I will get the `account_id` for those customers. Finally, I will sum the transactions for each account. \n", + "\n", + "Let's start with the first query to get the `customer_id` for Altman and Zuckerberg.\n", "\n", - "First, I will get the `customer_id` for Altman and Zuckerberg. Then, I will get the `account_id` for those `customer_id`s. Finally, I will sum the transactions for each account. \n", + "\u001b[0m\u001b[36;1m\u001b[1;3m```sql\n", + "SELECT customer_id, name FROM customers WHERE name IN ('Altman', 'Zuckerberg')\n", + "```\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `sql_db_query` with `{'query': \"SELECT customer_id, name FROM customers WHERE name IN ('Altman', 'Zuckerberg')\"}`\n", "\n", - "I will execute the first query to get the `customer_id`s.\n", "\n", "\u001b[0m\u001b[36;1m\u001b[1;3m[(1, 'Altman'), (3, 'Zuckerberg')]\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_query` with `{'query': 'SELECT account_id FROM accounts WHERE customer_id = 1'}`\n", + "Invoking: `sql_db_query_checker` with `{'query': 'SELECT account_id FROM accounts WHERE customer_id IN (1, 3)'}`\n", + "\n", + "\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m```sql\n", + "SELECT account_id FROM accounts WHERE customer_id IN (1, 3)\n", + "```\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `sql_db_query` with `{'query': 'SELECT account_id FROM accounts WHERE customer_id IN (1, 3)'}`\n", + "\n", + "\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m[(1,), (3,)]\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `sql_db_query_checker` with `{'query': 'SELECT SUM(amount) FROM transactions WHERE account_id = 1'}`\n", "\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[(1,)]\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_query` with `{'query': 'SELECT account_id FROM accounts WHERE customer_id = 3'}`\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m```sql\n", + "SELECT SUM(amount) FROM transactions WHERE account_id = 1\n", + "```\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `sql_db_query_checker` with `{'query': 'SELECT SUM(amount) FROM transactions WHERE account_id = 3'}`\n", "\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[(3,)]\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_query` with `{'query': 'SELECT SUM(amount) as total_transactions FROM transactions WHERE account_id = 1'}`\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m```sql\n", + "SELECT SUM(amount) FROM transactions WHERE account_id = 3\n", + "```\u001b[0m\u001b[32;1m\u001b[1;3m\n", + "Invoking: `sql_db_query` with `{'query': 'SELECT SUM(amount) FROM transactions WHERE account_id = 1'}`\n", "\n", "\n", "\u001b[0m\u001b[36;1m\u001b[1;3m[(-965.7,)]\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_query` with `{'query': 'SELECT SUM(amount) as total_transactions FROM transactions WHERE account_id = 3'}`\n", + "Invoking: `sql_db_query` with `{'query': 'SELECT SUM(amount) FROM transactions WHERE account_id = 3'}`\n", "\n", "\n", "\u001b[0m\u001b[36;1m\u001b[1;3m[(656.6400000000002,)]\u001b[0m\u001b[32;1m\u001b[1;3mThe total transactions for each individual are as follows:\n", "\n", - "- **Altman**: Total transactions amount to **-965.7** (indicating a net loss).\n", - "- **Zuckerberg**: Total transactions amount to **656.64** (indicating a net gain).\n", + "- **Altman**: -965.7 (indicating a net loss)\n", + "- **Zuckerberg**: 656.64 (indicating a net gain)\n", "\n", - "In summary, Zuckerberg has a positive total transaction amount, while Altman has a negative total transaction amount.\u001b[0m\n", + "Thus, Zuckerberg has a positive total transaction amount, while Altman has a negative total transaction amount.\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n" ] @@ -714,7 +732,7 @@ "data": { "text/plain": [ "{'input': 'Calculate and compare the total transactions of Altman and Zuckerberg.',\n", - " 'output': 'The total transactions for each individual are as follows:\\n\\n- **Altman**: Total transactions amount to **-965.7** (indicating a net loss).\\n- **Zuckerberg**: Total transactions amount to **656.64** (indicating a net gain).\\n\\nIn summary, Zuckerberg has a positive total transaction amount, while Altman has a negative total transaction amount.'}" + " 'output': 'The total transactions for each individual are as follows:\\n\\n- **Altman**: -965.7 (indicating a net loss)\\n- **Zuckerberg**: 656.64 (indicating a net gain)\\n\\nThus, Zuckerberg has a positive total transaction amount, while Altman has a negative total transaction amount.'}" ] }, "execution_count": 20, @@ -758,12 +776,29 @@ "cell_type": "code", "execution_count": 21, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "sqlite\n", + "['accounts', 'customers', 'transactions']\n" + ] + } + ], "source": [ - "from langchain_community.tools import QuerySQLDatabaseTool\n", + "from langchain_openai import ChatOpenAI\n", + "from langchain.chains import create_sql_query_chain\n", + "from langchain_community.utilities import SQLDatabase\n", "\n", - "# Create a tool to execute the generated query.\n", - "execute_query = QuerySQLDatabaseTool(db=db)" + "# Connect to the SQLite database.\n", + "db = SQLDatabase.from_uri(\"sqlite:///data/finance.db\")\n", + "\n", + "# Output the database dialect.\n", + "print(db.dialect)\n", + "\n", + "# Output the available table names.\n", + "print(db.get_usable_table_names())" ] }, { @@ -834,6 +869,18 @@ "execution_count": 24, "metadata": {}, "outputs": [], + "source": [ + "from langchain_community.tools import QuerySQLDatabaseTool\n", + "\n", + "# Create a tool to execute the generated query.\n", + "execute_query = QuerySQLDatabaseTool(db=db)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], "source": [ "# It is necessary to remove unnecessary text.\n", "import re\n", @@ -850,7 +897,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 26, "metadata": {}, "outputs": [], "source": [ @@ -858,15 +905,14 @@ "from langchain_core.runnables import RunnablePassthrough\n", "\n", "chain = (\n", - " {\"query\": write_query}\n", - " | RunnablePassthrough.assign(query=lambda x: parse_sqlquery(x[\"query\"]))\n", + " RunnablePassthrough.assign(query=write_query).assign(query=lambda x: parse_sqlquery(x[\"query\"]))\n", " | execute_query\n", ")" ] }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 27, "metadata": {}, "outputs": [ { @@ -875,7 +921,7 @@ "\"[('Altman',), ('Chase',), ('Hassabis',), ('Huang',), ('Musk',), ('Zuckerberg',)]\"" ] }, - "execution_count": 26, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } @@ -887,7 +933,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 28, "metadata": {}, "outputs": [ { @@ -896,7 +942,7 @@ "'[(-965.7,)]'" ] }, - "execution_count": 27, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" } From 32c0570b928f1b9f269841c740b566244eb1fbec Mon Sep 17 00:00:00 2001 From: jinucho Date: Wed, 15 Jan 2025 16:27:33 +0900 Subject: [PATCH 9/9] [E-1] 14-Chains / 02-SQL code and contents update code and contents update add image file --- 14-Chains/02-SQL.ipynb | 503 ++++++++++++++---- .../assets/02-sql-sql-chain-work-flow.png | Bin 0 -> 176986 bytes 2 files changed, 405 insertions(+), 98 deletions(-) create mode 100644 14-Chains/assets/02-sql-sql-chain-work-flow.png diff --git a/14-Chains/02-SQL.ipynb b/14-Chains/02-SQL.ipynb index b50e0cc4a..336ea8145 100644 --- a/14-Chains/02-SQL.ipynb +++ b/14-Chains/02-SQL.ipynb @@ -19,6 +19,8 @@ "\n", "Additionally, let's explore the differences in operation between this method and the SQL Agent.\n", "\n", + "![sql-chain-work-flow](./assets/02-sql-sql-chain-work-flow.png)\n", + "\n", "### Table of Contents\n", "\n", "- [Overview](#overview)\n", @@ -74,6 +76,7 @@ " \"langsmith\",\n", " \"langchain\",\n", " \"langchain_openai\",\n", + " \"langchain_community\",\n", " ],\n", " verbose=False,\n", " upgrade=False,\n", @@ -148,6 +151,23 @@ "source": [ "## Load SQL Database\n", "\n", + "### Usage methods for various databases and required library list.\n", + "\n", + "| **Database** | **Required Library** | **Code Example** |\n", + "|---------------------|---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|\n", + "| **PostgreSQL** | ```psycopg2-binary``` | db = SQLDatabase.from_uri(\"postgresql://:@:/\") |\n", + "| **MySQL** | ```pymysql``` | db = SQLDatabase.from_uri(\"mysql+pymysql://:@:/\") |\n", + "| **SQLite** | Included in standard lib | db = SQLDatabase.from_uri(\"sqlite:///path/to/your_database.db\") |\n", + "| **Oracle** | ```cx_Oracle``` | db = SQLDatabase.from_uri(\"oracle+cx_oracle://:@:/\") |\n", + "\n", + "example for postgresql : \n", + "- db = SQLDatabase.from_uri(\"postgresql://postgre_user_name:password@ip_address:port/db_name\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "Load and verify the sample database data." ] }, @@ -187,6 +207,15 @@ "## SQL generate chain" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```create_sql_query_chain``` generates a chain for creating SQL queries based on natural language input. \n", + "\n", + "It leverages LLMs to translate natural language into SQL statements." + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -215,40 +244,6 @@ "cell_type": "code", "execution_count": 7, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "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.\n", - "Unless the user specifies in the question a specific number of examples to obtain, query for at most {top_k} results using the LIMIT clause as per SQLite. You can order the results to return the most informative data in the database.\n", - "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.\n", - "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.\n", - "Pay attention to use date('now') function to get the current date, if the question involves \"today\".\n", - "\n", - "Use the following format:\n", - "\n", - "Question: Question here\n", - "SQLQuery: SQL Query to run\n", - "SQLResult: Result of the SQLQuery\n", - "Answer: Final answer here\n", - "\n", - "Only use the following tables:\n", - "{table_info}\n", - "\n", - "Question: {input}\n" - ] - } - ], - "source": [ - "# Check the default prompt\n", - "print(chain.get_prompts()[0].template)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, "outputs": [ { "data": { @@ -256,7 +251,7 @@ "'SELECT \"name\" FROM customers;'" ] }, - "execution_count": 8, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -276,7 +271,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -298,7 +293,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -307,7 +302,7 @@ "'SQLQuery: SELECT \"name\" FROM customers LIMIT 10;'" ] }, - "execution_count": 10, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -327,7 +322,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -373,7 +368,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 11, "metadata": {}, "outputs": [ { @@ -396,13 +391,191 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Let's verify if the generated query executes correctly." + "### How to use the ```get_prompts``` method\n", + "\n", + "The chain.get_prompt() method allows you to retrieve the current prompt template used in a LangChain chain. \n", + "\n", + "This prompt contains the instructions given to the LLM, including the input structure, expected variables, and contextual guidelines.\n", + "\n", + "**Key Features**\n", + "1. Prompt Retrieval:\n", + "- Fetches the active prompt template to inspect or debug the chain's behavior.\n", + "2. Dynamic Variable Substitution:\n", + "- Displays how variables are dynamically substituted within the template.\n", + "3. Customizability:\n", + "- Enables users to modify parts of the prompt dynamically.\n", + "\n", + "\n", + "check the .get_prompts()'s contents\n", + "\n", + "There are various elements: \n", + "- ```input_variables```\n", + "- ```input_types```\n", + "- ```partial_variables```\n", + "- ```template```" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "input_variables : ['input', 'table_info'] \n", + "\n", + "input_types : {} \n", + "\n", + "partial_variables : {'dialect': 'sqlite', 'top_k': '5'} \n", + "\n", + "template : Given an input question, first create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer. \n", + " Unless the user specifies in his question a specific number of examples he wishes to obtain, always limit your query to at most {top_k} results. \n", + " You can order the results by a relevant column to return the most interesting examples in the database.\n", + "\n", + "Use the following format:\n", + "\n", + "Question: Question here\n", + "SQLQuery: SQL Query to run\n", + "SQLResult: Result of the SQLQuery\n", + "Answer: Final answer here\n", + "\n", + "Only use the following tables:\n", + "{table_info}\n", + "\n", + "Here is the description of the columns in the tables:\n", + "`cust`: customer name\n", + "`prod`: product name\n", + "`trans`: transaction date\n", + "\n", + "Question: {input}\n", + " \n", + "\n" + ] + } + ], + "source": [ + "# check the prompt template configuration\n", + "print(f\"input_variables : {chain.get_prompts()[0].input_variables}\", \"\\n\")\n", + "print(f\"input_types : {chain.get_prompts()[0].input_types}\", \"\\n\")\n", + "print(f\"partial_variables : {chain.get_prompts()[0].partial_variables}\", \"\\n\")\n", + "print(f\"template : {chain.get_prompts()[0].template}\", \"\\n\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Modify the variable values and check the results." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "input_variables : ['input', 'table_info'] \n", + "\n", + "input_types : {} \n", + "\n", + "partial_variables : {'dialect': 'my_sql', 'top_k': '5'} \n", + "\n", + "template : Given an input question, first create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer. \n", + " Unless the user specifies in his question a specific number of examples he wishes to obtain, always limit your query to at most {top_k} results. \n", + " You can order the results by a relevant column to return the most interesting examples in the database.\n", + "\n", + "Use the following format:\n", + "\n", + "Question: Question here\n", + "SQLQuery: SQL Query to run\n", + "SQLResult: Result of the SQLQuery\n", + "Answer: Final answer here\n", + "\n", + "Only use the following tables:\n", + "{table_info}\n", + "\n", + "Here is the description of the columns in the tables:\n", + "`cust`: customer name\n", + "`prod`: product name\n", + "`trans`: transaction date\n", + "\n", + "Question: {input}\n", + " \n", + "\n" + ] + } + ], + "source": [ + "# Modify the dialect to MySQL\n", + "chain.get_prompts()[0].partial_variables[\"dialect\"] = \"my_sql\"\n", + "\n", + "# check the modified prompt\n", + "print(f\"input_variables : {chain.get_prompts()[0].input_variables}\", \"\\n\")\n", + "print(f\"input_types : {chain.get_prompts()[0].input_types}\", \"\\n\")\n", + "print(f\"partial_variables : {chain.get_prompts()[0].partial_variables}\", \"\\n\")\n", + "print(f\"template : {chain.get_prompts()[0].template}\", \"\\n\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can specify variables, including `dialect`, when invoking `create_sql_query_chain`." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'SELECT name\\nFROM customers;'" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "chain.invoke({\"question\": \"List all customer names.\", \"dialect\": \"mysql\"})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### QuerySQLDatabaseTool\n", + "\n", + "1. Executing SQL Queries:\n", + "- Executes the provided SQL query on the connected database and retrieves the results.\n", + "- Encapsulates the functionality for interacting with the database, promoting code reusability.\n", + "2. Integration with LangChain Agents:\n", + "- LangChain agents are used to convert natural language into SQL queries.\n", + "- This tool performs the execution step by running the agent-generated SQL query and returning the results.\n", + "3. Database Abstraction:\n", + "- Supports various types of databases, such as MySQL, PostgreSQL, SQLite, and more.\n", + "- Handles direct database operations internally, reducing the dependency of user code on database-specific details." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's verify if the generated query executes correctly." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, "outputs": [], "source": [ "from langchain_community.tools import QuerySQLDatabaseTool\n", @@ -413,7 +586,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -422,7 +595,7 @@ "\"[('Altman',), ('Huang',), ('Zuckerberg',), ('Musk',), ('Hassabis',), ('Chase',)]\"" ] }, - "execution_count": 14, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -433,7 +606,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 17, "metadata": {}, "outputs": [], "source": [ @@ -451,7 +624,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 18, "metadata": {}, "outputs": [ { @@ -460,7 +633,7 @@ "\"[('Sam@example.com',)]\"" ] }, - "execution_count": 16, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -481,7 +654,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 19, "metadata": {}, "outputs": [], "source": [ @@ -514,7 +687,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -523,7 +696,7 @@ "\"The total of Altman's transactions is -965.7.\"" ] }, - "execution_count": 18, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -548,7 +721,18 @@ "\n", "```agent_toolkits``` in LangChain is a collection of tools designed to simplify the creation and use of Agents optimized for specific domains or use cases. \n", "\n", - "Each toolkit encapsulates the functionality and workflows needed for specific tasks (e.g., SQL query processing, file system operations, API calls), enabling developers to perform complex tasks with ease." + "Each toolkit encapsulates the functionality and workflows needed for specific tasks (e.g., SQL query processing, file system operations, API calls), enabling developers to perform complex tasks with ease.\n", + "\n", + "### ```create_sql_agent```\n", + "\n", + "```create_sql_agent``` is a specialized function within the agent_toolkits library that simplifies the process of interacting with SQL databases. \n", + "\n", + "It is designed to streamline SQL query generation and execution by leveraging LangChain’s agent capabilities. Developers can integrate this tool to enable agents to:\n", + "- Connect to SQL databases seamlessly.\n", + "- Automatically generate SQL queries based on natural language input.\n", + "- Retrieve and format results for easy consumption.\n", + "\n", + "This functionality is particularly useful for scenarios requiring dynamic database interactions, such as reporting, analytics, or user-facing applications that need query-based responses." ] }, { @@ -562,7 +746,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 21, "metadata": {}, "outputs": [], "source": [ @@ -581,7 +765,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 22, "metadata": {}, "outputs": [ { @@ -656,18 +840,18 @@ "Invoking: `sql_db_query_checker` with `{'query': \"SELECT customer_id, name FROM customers WHERE name IN ('Altman', 'Zuckerberg')\"}`\n", "responded: The relevant tables and their structures are as follows:\n", "\n", - "1. **accounts**:\n", + "1. **accounts**: \n", " - `account_id`: INTEGER\n", " - `customer_id`: INTEGER\n", " - `balance`: REAL\n", "\n", - "2. **customers**:\n", + "2. **customers**: \n", " - `customer_id`: INTEGER\n", " - `name`: TEXT\n", " - `age`: INTEGER\n", " - `email`: TEXT\n", "\n", - "3. **transactions**:\n", + "3. **transactions**: \n", " - `transaction_id`: INTEGER\n", " - `account_id`: INTEGER\n", " - `amount`: REAL\n", @@ -675,12 +859,14 @@ "\n", "To calculate and compare the total transactions of Altman and Zuckerberg, I will need to:\n", "1. Find the `customer_id` for both Altman and Zuckerberg from the `customers` table.\n", - "2. Use their `customer_id` to find the corresponding `account_id` from the `accounts` table.\n", + "2. Use their `customer_id` to find their corresponding `account_id` from the `accounts` table.\n", "3. Sum the `amount` from the `transactions` table for each `account_id`.\n", "\n", - "I will construct the SQL queries accordingly. First, I will get the `customer_id` for Altman and Zuckerberg. Then, I will get the `account_id` for those customers. Finally, I will sum the transactions for each account. \n", + "Let's construct the SQL queries for these steps. \n", "\n", - "Let's start with the first query to get the `customer_id` for Altman and Zuckerberg.\n", + "First, I will get the `customer_id` for Altman and Zuckerberg. Then, I will get their `account_id` and finally sum their transactions. \n", + "\n", + "I will start by querying the `customer_id` for both customers.\n", "\n", "\u001b[0m\u001b[36;1m\u001b[1;3m```sql\n", "SELECT customer_id, name FROM customers WHERE name IN ('Altman', 'Zuckerberg')\n", @@ -699,31 +885,21 @@ "\n", "\n", "\u001b[0m\u001b[36;1m\u001b[1;3m[(1,), (3,)]\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_query_checker` with `{'query': 'SELECT SUM(amount) FROM transactions WHERE account_id = 1'}`\n", - "\n", - "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m```sql\n", - "SELECT SUM(amount) FROM transactions WHERE account_id = 1\n", - "```\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_query_checker` with `{'query': 'SELECT SUM(amount) FROM transactions WHERE account_id = 3'}`\n", + "Invoking: `sql_db_query_checker` with `{'query': 'SELECT SUM(amount) FROM transactions WHERE account_id IN (1, 3) GROUP BY account_id'}`\n", "\n", "\n", "\u001b[0m\u001b[36;1m\u001b[1;3m```sql\n", - "SELECT SUM(amount) FROM transactions WHERE account_id = 3\n", + "SELECT SUM(amount) FROM transactions WHERE account_id IN (1, 3) GROUP BY account_id\n", "```\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_query` with `{'query': 'SELECT SUM(amount) FROM transactions WHERE account_id = 1'}`\n", + "Invoking: `sql_db_query` with `{'query': 'SELECT SUM(amount) FROM transactions WHERE account_id IN (1, 3) GROUP BY account_id'}`\n", "\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[(-965.7,)]\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `sql_db_query` with `{'query': 'SELECT SUM(amount) FROM transactions WHERE account_id = 3'}`\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m[(-965.7,), (656.6400000000002,)]\u001b[0m\u001b[32;1m\u001b[1;3mThe total transactions for each customer are as follows:\n", "\n", + "- **Altman** (account_id 1): Total transactions amount to **-965.7**.\n", + "- **Zuckerberg** (account_id 3): Total transactions amount to **656.64**.\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[(656.6400000000002,)]\u001b[0m\u001b[32;1m\u001b[1;3mThe total transactions for each individual are as follows:\n", - "\n", - "- **Altman**: -965.7 (indicating a net loss)\n", - "- **Zuckerberg**: 656.64 (indicating a net gain)\n", - "\n", - "Thus, Zuckerberg has a positive total transaction amount, while Altman has a negative total transaction amount.\u001b[0m\n", + "In summary, Zuckerberg has a positive total transaction amount, while Altman has a negative total transaction amount.\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n" ] @@ -732,10 +908,10 @@ "data": { "text/plain": [ "{'input': 'Calculate and compare the total transactions of Altman and Zuckerberg.',\n", - " 'output': 'The total transactions for each individual are as follows:\\n\\n- **Altman**: -965.7 (indicating a net loss)\\n- **Zuckerberg**: 656.64 (indicating a net gain)\\n\\nThus, Zuckerberg has a positive total transaction amount, while Altman has a negative total transaction amount.'}" + " 'output': 'The total transactions for each customer are as follows:\\n\\n- **Altman** (account_id 1): Total transactions amount to **-965.7**.\\n- **Zuckerberg** (account_id 3): Total transactions amount to **656.64**.\\n\\nIn summary, Zuckerberg has a positive total transaction amount, while Altman has a negative total transaction amount.'}" ] }, - "execution_count": 20, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -761,6 +937,13 @@ "3. Conclusion: It is recommended to use ```create_sql_query_chain``` for simple queries, while ```SQL Agent``` is suggested for complex or iterative processes." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -769,12 +952,22 @@ "\n", "As observed earlier, `gpt-4o` output can be inconsistent.\n", "\n", - "To address this, a chain can be constructed with a post-processing function applied." + "To improve this, a chain can be constructed with a post-processing function applied.\n", + "\n", + "This part consists of the following procedure:\n", + "- Natural language question input → SQL query generation by LLM → Post-processing of the generated query → Query execution on the database → Natural language answer output by LLM" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load and verify the sample database data." ] }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 23, "metadata": {}, "outputs": [ { @@ -801,9 +994,16 @@ "print(db.get_usable_table_names())" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create an LLM object and use a custom template to generate a chain by providing the LLM and DB as parameters." + ] + }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 24, "metadata": {}, "outputs": [], "source": [ @@ -842,9 +1042,16 @@ "write_query = create_sql_query_chain(llm, db, prompt, k=10)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Check the execution result" + ] + }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 25, "metadata": {}, "outputs": [ { @@ -853,32 +1060,26 @@ "'SQLQuery: select name from customers ORDER BY name LIMIT 10'" ] }, - "execution_count": 23, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "# Check the execution result\n", "# The result contains unnecessary text, such as 'SQLQuery: '\n", "write_query.invoke({\"question\": \"List the all customer names.\"})" ] }, { - "cell_type": "code", - "execution_count": 24, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "from langchain_community.tools import QuerySQLDatabaseTool\n", - "\n", - "# Create a tool to execute the generated query.\n", - "execute_query = QuerySQLDatabaseTool(db=db)" + "Define a function for post-processing the SQL query." ] }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 26, "metadata": {}, "outputs": [], "source": [ @@ -895,24 +1096,50 @@ " return query" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a tool to execute the generated query." + ] + }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_community.tools import QuerySQLDatabaseTool\n", + "\n", + "execute_query = QuerySQLDatabaseTool(db=db)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Combine the chains: SQL query generation → Post-processing of the generated query → Query execution on the database" + ] + }, + { + "cell_type": "code", + "execution_count": 28, "metadata": {}, "outputs": [], "source": [ - "# Combine the chains: generating query -> Regex Parsing -> SQL Execution\n", "from langchain_core.runnables import RunnablePassthrough\n", "\n", "chain = (\n", - " RunnablePassthrough.assign(query=write_query).assign(query=lambda x: parse_sqlquery(x[\"query\"]))\n", + " RunnablePassthrough.assign(query=write_query).assign(\n", + " query=lambda x: parse_sqlquery(x[\"query\"])\n", + " )\n", " | execute_query\n", ")" ] }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 29, "metadata": {}, "outputs": [ { @@ -921,7 +1148,7 @@ "\"[('Altman',), ('Chase',), ('Hassabis',), ('Huang',), ('Musk',), ('Zuckerberg',)]\"" ] }, - "execution_count": 27, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" } @@ -933,7 +1160,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 30, "metadata": {}, "outputs": [ { @@ -942,7 +1169,87 @@ "'[(-965.7,)]'" ] }, - "execution_count": 28, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Check the execution result\n", + "chain.invoke({\"question\": \"Calculate the total of Altman's transactions.\"})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Combine the chains: SQL query generation → Post-processing of the generated query → Query execution on the database → Natural language answer output by LLM" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_core.output_parsers import StrOutputParser\n", + "from langchain_core.prompts import PromptTemplate\n", + "\n", + "# Define the prompt for generating answers\n", + "answer_prompt = PromptTemplate.from_template(\n", + " \"\"\"Given the following user question, corresponding SQL query, and SQL result, answer the user question.\n", + "\n", + "Question: {question}ㅑㅑ\n", + "SQL Query: {query}\n", + "SQL Result: {result}\n", + "Answer: \"\"\"\n", + ")\n", + "\n", + "# Create a pipeline for generating natural answers\n", + "answer = answer_prompt | llm | StrOutputParser()\n", + "\n", + "chain = (\n", + " RunnablePassthrough.assign(query=write_query).assign(\n", + " query=lambda x: parse_sqlquery(x[\"query\"])\n", + " )\n", + " | RunnablePassthrough.assign(result=execute_query)\n", + " | answer\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'The customer names are: Altman, Chase, Hassabis, Huang, Musk, and Zuckerberg.'" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Check the execution result\n", + "chain.invoke({\"question\": \"List the all customer names.\"})" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"The total of Altman's transactions is -965.7.\"" + ] + }, + "execution_count": 33, "metadata": {}, "output_type": "execute_result" } diff --git a/14-Chains/assets/02-sql-sql-chain-work-flow.png b/14-Chains/assets/02-sql-sql-chain-work-flow.png new file mode 100644 index 0000000000000000000000000000000000000000..b750ef2810df6b718aee4f25d435710928a5f7a1 GIT binary patch literal 176986 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­XJ(t;^N@m`^gej<#A9e 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 literal 0 HcmV?d00001