From b7fc1a2fe719897e8f02b07cb99bcc191638ad3a Mon Sep 17 00:00:00 2001 From: rcarrata Date: Tue, 4 Feb 2025 03:00:49 +0100 Subject: [PATCH] add sql example --- bootstrap/database/db-init-job.yaml | 4 +- bootstrap/database/deployment.yaml | 12 +- bootstrap/database/kustomization.yaml | 2 +- bootstrap/database/pvc.yaml | 2 +- bootstrap/database/secret.yaml | 2 +- bootstrap/database/sql-script-configmap.yaml | 64 ++ .../modules/ROOT/pages/03-02-tools-usage.adoc | 8 +- .../ROOT/pages/03-03-chain-of-thought.adoc | 2 +- .../ROOT/pages/03-04-react-prompting.adoc | 2 +- content/modules/ROOT/pages/03-05-rag.adoc | 6 + .../2.2-tools-calling-sql-granite3.ipynb | 554 ++++++++++++++++++ ...ipynb => 2.3-cot-prompting-granite3.ipynb} | 0 ...rompting.ipynb => 2.3-cot-prompting.ipynb} | 0 ...ynb => 2.4-react-prompting-granite3.ipynb} | 0 ...mpting.ipynb => 2.4-react-prompting.ipynb} | 0 15 files changed, 644 insertions(+), 14 deletions(-) create mode 100644 bootstrap/database/sql-script-configmap.yaml create mode 100644 lab-materials/02-tools/2.2-tools-calling-sql-granite3.ipynb rename lab-materials/02-tools/{2.2-cot-prompting-granite3.ipynb => 2.3-cot-prompting-granite3.ipynb} (100%) rename lab-materials/02-tools/{2.2-cot-prompting.ipynb => 2.3-cot-prompting.ipynb} (100%) rename lab-materials/02-tools/{2.3-react-prompting-granite3.ipynb => 2.4-react-prompting-granite3.ipynb} (100%) rename lab-materials/02-tools/{2.3-react-prompting.ipynb => 2.4-react-prompting.ipynb} (100%) diff --git a/bootstrap/database/db-init-job.yaml b/bootstrap/database/db-init-job.yaml index 06878a7..cd2b81c 100644 --- a/bootstrap/database/db-init-job.yaml +++ b/bootstrap/database/db-init-job.yaml @@ -13,7 +13,7 @@ spec: command: ['sh', '-c', 'until nc -z -v -w30 $POSTGRESQL_DATABASE 5432; do echo "Waiting for database connection..."; sleep 2; done;'] env: - name: POSTGRESQL_DATABASE - value: agenticdb.agentic-db.svc.cluster.local + value: agenticdb.agentic-zone.svc.cluster.local containers: - name: postgresql image: registry.redhat.io/rhel9/postgresql-13:latest @@ -34,7 +34,7 @@ spec: name: agenticdb key: database-password - name: POSTGRESQL_DATABASE_HOST - value: agenticdb.agentic-db.svc.cluster.local + value: agenticdb.agentic-zone.svc.cluster.local command: ["/bin/bash", "-c"] args: - | diff --git a/bootstrap/database/deployment.yaml b/bootstrap/database/deployment.yaml index fd670af..258f27c 100644 --- a/bootstrap/database/deployment.yaml +++ b/bootstrap/database/deployment.yaml @@ -44,17 +44,17 @@ spec: - name: POSTGRESQL_USER valueFrom: secretKeyRef: - name: claimdb + name: agenticdb key: database-user - name: POSTGRESQL_PASSWORD valueFrom: secretKeyRef: - name: claimdb + name: agenticdb key: database-password - name: POSTGRESQL_DATABASE valueFrom: secretKeyRef: - name: claimdb + name: agenticdb key: database-name securityContext: capabilities: {} @@ -66,11 +66,11 @@ spec: terminationMessagePath: /dev/termination-log terminationMessagePolicy: File volumeMounts: - - name: claimdb-data + - name: agenticdb-data mountPath: /var/lib/pgsql/data volumes: - - name: claimdb-data + - name: agenticdb-data persistentVolumeClaim: - claimName: claimdb + claimName: agenticdb strategy: type: Recreate diff --git a/bootstrap/database/kustomization.yaml b/bootstrap/database/kustomization.yaml index 2a4e3bd..2698d91 100644 --- a/bootstrap/database/kustomization.yaml +++ b/bootstrap/database/kustomization.yaml @@ -13,6 +13,6 @@ resources: - secret.yaml - deployment.yaml - service.yaml -# - sql-script-configmap.yaml +- sql-script-configmap.yaml # wave 2 - db-init-job.yaml diff --git a/bootstrap/database/pvc.yaml b/bootstrap/database/pvc.yaml index 9303771..1955f0d 100644 --- a/bootstrap/database/pvc.yaml +++ b/bootstrap/database/pvc.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: claimdb + name: agenticdb namespace: agentic-zone labels: app: agentic-db diff --git a/bootstrap/database/secret.yaml b/bootstrap/database/secret.yaml index a7a0f30..5895900 100644 --- a/bootstrap/database/secret.yaml +++ b/bootstrap/database/secret.yaml @@ -1,7 +1,7 @@ kind: Secret apiVersion: v1 metadata: - name: claimdb + name: agenticdb namespace: agentic-zone labels: app: agentic-db diff --git a/bootstrap/database/sql-script-configmap.yaml b/bootstrap/database/sql-script-configmap.yaml new file mode 100644 index 0000000..59b89f2 --- /dev/null +++ b/bootstrap/database/sql-script-configmap.yaml @@ -0,0 +1,64 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: sql-script-configmap + annotations: + argocd.argoproj.io/sync-wave: "1" +data: + script.sql: | + -- Ensure the schema exists + CREATE SCHEMA IF NOT EXISTS agenticdb AUTHORIZATION agenticdb; + + -- Drop existing tables if they exist + DROP TABLE IF EXISTS agenticdb.transactions CASCADE; + + -- Drop existing sequences if they exist + DROP SEQUENCE IF EXISTS agenticdb.transactions_id_seq; + + -- Create a sequence for transaction IDs + CREATE SEQUENCE IF NOT EXISTS agenticdb.transactions_id_seq + INCREMENT 1 + START 1 + MINVALUE 1 + MAXVALUE 2147483647 + CACHE 1; + + -- Create the transactions table + CREATE TABLE IF NOT EXISTS agenticdb.transactions + ( + id INTEGER NOT NULL DEFAULT nextval('agenticdb.transactions_id_seq'::regclass), + transaction_id TEXT COLLATE pg_catalog."default" UNIQUE NOT NULL, + client_name TEXT COLLATE pg_catalog."default" NOT NULL, + transaction_type TEXT COLLATE pg_catalog."default" CHECK (transaction_type IN ('BUY', 'SELL', 'SHORT SELL')), + stock_symbol TEXT COLLATE pg_catalog."default" NOT NULL, + shares INTEGER NOT NULL CHECK (shares > 0), + price_per_share NUMERIC(10,2) NOT NULL CHECK (price_per_share > 0), + broker TEXT COLLATE pg_catalog."default", + transaction_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (id) + ) + WITH ( + OIDS = FALSE + ) + TABLESPACE pg_default; + + -- Link the sequence to the table + ALTER SEQUENCE agenticdb.transactions_id_seq OWNED BY agenticdb.transactions.id; + + -- Insert sample transactions + + -- TRANSACTION 1: Alice Johnson buys 50 shares of Apple (AAPL) + INSERT INTO agenticdb.transactions (transaction_id, client_name, transaction_type, stock_symbol, shares, price_per_share, broker, transaction_time) + VALUES ('TXN1001', 'Alice Johnson', 'BUY', 'AAPL', 50, 185.75, 'Morgan Stanley', '2024-06-15 09:30:00'); + + -- TRANSACTION 2: Michael Smith sells 100 shares of Tesla (TSLA) + INSERT INTO agenticdb.transactions (transaction_id, client_name, transaction_type, stock_symbol, shares, price_per_share, broker, transaction_time) + VALUES ('TXN1002', 'Michael Smith', 'SELL', 'TSLA', 100, 245.20, 'Charles Schwab', '2024-06-15 10:15:00'); + + -- TRANSACTION 3: Emma Davis buys 200 shares of Microsoft (MSFT) + INSERT INTO agenticdb.transactions (transaction_id, client_name, transaction_type, stock_symbol, shares, price_per_share, broker, transaction_time) + VALUES ('TXN1003', 'Emma Davis', 'BUY', 'MSFT', 200, 340.10, 'JPMorgan Chase', '2024-06-15 11:45:00'); + + -- TRANSACTION 4: Robert Miller short-sells 75 shares of Nvidia (NVDA) + INSERT INTO agenticdb.transactions (transaction_id, client_name, transaction_type, stock_symbol, shares, price_per_share, broker, transaction_time) + VALUES ('TXN1004', 'Robert Miller', 'SHORT SELL', 'NVDA', 75, 462.85, 'Goldman Sachs', '2024-06-15 14:30:00'); diff --git a/content/modules/ROOT/pages/03-02-tools-usage.adoc b/content/modules/ROOT/pages/03-02-tools-usage.adoc index b437ad9..4e59da1 100644 --- a/content/modules/ROOT/pages/03-02-tools-usage.adoc +++ b/content/modules/ROOT/pages/03-02-tools-usage.adoc @@ -16,12 +16,18 @@ Through tool calling, LLMs can: - **Perform Specialized Calculations**: Use tools like code interpreters to execute complex calculations or data transformations. - **Format Responses for Structured Systems**: Generate responses in specific schemas required by APIs or databases, ensuring smooth communication with these systems. -== Exercise: Tools Usage - Practical Example +== Exercise: Tools Usage (Internet Search) - Practical Example Let's see the Tools Usage in Action! From the `agentic-workshop/lab-materials/02` folder, please open the notebook called `02.1-tools-calling.ipynb` and follow the instructions. +== Exercise: Tools Usage (Database Query) - Practical Example + +Let's see the Tools Usage in Action! + +From the `agentic-workshop/lab-materials/02` folder, please open the notebook called `02.2-tools-calling-sql.ipynb` and follow the instructions. + == Benefits of Using Tools with LLMs Incorporating tools into LLM workflows enables AI systems to handle a broader range of tasks, increasing both accuracy and flexibility. For example: diff --git a/content/modules/ROOT/pages/03-03-chain-of-thought.adoc b/content/modules/ROOT/pages/03-03-chain-of-thought.adoc index 63c385c..9bb7a69 100644 --- a/content/modules/ROOT/pages/03-03-chain-of-thought.adoc +++ b/content/modules/ROOT/pages/03-03-chain-of-thought.adoc @@ -27,4 +27,4 @@ image::04/04-02-cot.png[Chain of Thought, scaledwidth="20%"] Let's see the Chain of Thought in Action! -From the `agentic-workshop/lab-materials/02` folder, please open the notebook called `02.2-chain-of-thought.ipynb` and follow the instructions. \ No newline at end of file +From the `agentic-workshop/lab-materials/02` folder, please open the notebook called `02.3-chain-of-thought.ipynb` and follow the instructions. \ No newline at end of file diff --git a/content/modules/ROOT/pages/03-04-react-prompting.adoc b/content/modules/ROOT/pages/03-04-react-prompting.adoc index 90f4595..bf62693 100644 --- a/content/modules/ROOT/pages/03-04-react-prompting.adoc +++ b/content/modules/ROOT/pages/03-04-react-prompting.adoc @@ -22,4 +22,4 @@ image::04/04-01-react-basic.png[ReAct Basic] Let's see the ReAct Pattern in Action! -From the `agentic-workshop/lab-materials/02` folder, please open the notebook called `2.3-react-prompting.ipynb` and follow the instructions. \ No newline at end of file +From the `agentic-workshop/lab-materials/02` folder, please open the notebook called `2.4-react-prompting.ipynb` and follow the instructions. \ No newline at end of file diff --git a/content/modules/ROOT/pages/03-05-rag.adoc b/content/modules/ROOT/pages/03-05-rag.adoc index 6e69d7d..b4ea730 100644 --- a/content/modules/ROOT/pages/03-05-rag.adoc +++ b/content/modules/ROOT/pages/03-05-rag.adoc @@ -16,6 +16,12 @@ In a RAG setup, the model follows a two-step process: image::04/04-04-rag.jpg[RAG] +== Exercise: RAG Pattern - Practical Example + +Let's see the RAG Pattern in Action! + +From the `agentic-workshop/lab-materials/03` folder, please open all the notebooks on that folder in order and follow the instructions. + == Benefits of RAG - **Enhanced Accuracy**: RAG reduces reliance on outdated or incomplete training data, leading to more accurate and contextually relevant responses. diff --git a/lab-materials/02-tools/2.2-tools-calling-sql-granite3.ipynb b/lab-materials/02-tools/2.2-tools-calling-sql-granite3.ipynb new file mode 100644 index 0000000..3413e69 --- /dev/null +++ b/lab-materials/02-tools/2.2-tools-calling-sql-granite3.ipynb @@ -0,0 +1,554 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "766aaa81-96e6-42dc-b29d-8216d2a7feec", + "metadata": {}, + "source": [ + "## SQL Retriever Tool \n", + "\n", + "### LLM Used - Granite3.1-8B" + ] + }, + { + "cell_type": "markdown", + "id": "7b469b37", + "metadata": {}, + "source": [ + "In order to work with this notebook please deploy the example database on this repository:\n", + "\n", + "```\n", + "kubectl create ns agentic-zone\n", + "kubectl apply -k bootstrap/database/\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "0022f3fb-ee50-40f2-b276-b8194668e49e", + "metadata": {}, + "source": [ + "### 1. Setup and Import Libraries\n", + "\n", + "To get started, you'll need to install and import a few Python libraries. Run the following command to install them:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "a16ed2e6", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.2.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m25.0\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n" + ] + } + ], + "source": [ + "#!pip install langchain-openai termcolor langchain_community duckduckgo_search==7.1.0 wikipedia openapi-python-client==0.12.3 langgraph langchain_experimental\n", + "#!pip install duckduckgo_search==7.1.0\n", + "!pip install -q psycopg2 tabulate" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "60bb3f0f-40b5-49a6-b493-5e361db0113e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Imports\n", + "import os\n", + "import json\n", + "import getpass\n", + "\n", + "from langchain.chains import ConversationChain\n", + "from langchain.memory import ConversationBufferMemory\n", + "from langchain.chains import LLMChain\n", + "from langchain_openai import ChatOpenAI\n", + "from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler\n", + "from langchain.prompts import PromptTemplate\n", + "from langchain_core.messages import BaseMessage\n", + "from langchain_core.messages import HumanMessage\n", + "\n", + "from typing_extensions import TypedDict\n", + "from typing import Annotated\n", + "from langchain_core.tools import tool\n", + "\n", + "from langchain_community.utilities import SQLDatabase" + ] + }, + { + "cell_type": "markdown", + "id": "74e614fa-23f1-4f08-9652-ec74100d58f3", + "metadata": {}, + "source": [ + "### 2. Configure the Database connection and test" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "abff5107-f032-4abd-94fb-83fbbf540bfb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "## List of Tables in 'agenticdb' schema:\n", + "Table found: [('transactions',)]\n", + "\n", + "## Schema for 'agenticdb.transactions' table:\n", + " Column: [('id', 'integer'), ('transaction_id', 'text'), ('client_name', 'text'), ('transaction_type', 'text'), ('stock_symbol', 'text'), ('shares', 'integer'), ('price_per_share', 'numeric'), ('broker', 'text'), ('transaction_time', 'timestamp without time zone')]\n", + "\n", + "## Query Execution Result:\n", + "Transaction: [('TXN1003', 'Emma Davis', 'BUY', 'MSFT', 200, Decimal('340.10'), Decimal('68020.00'))]\n" + ] + } + ], + "source": [ + "# Database connection details\n", + "# TODO: Fetch this from the variables\n", + "dbname = 'agenticdb'\n", + "user = 'agenticdb'\n", + "password = 'agenticdb'\n", + "host = 'agenticdb.agentic-zone.svc.cluster.local'\n", + "port = '5432'\n", + "\n", + "# Setup PostgreSQL URI\n", + "uri = f\"postgresql://{user}:{password}@{host}:{port}/{dbname}\"\n", + "\n", + "# Initialize the SQLDatabase connection\n", + "try:\n", + " # Connect to the PostgreSQL database using LangChain's SQLDatabase utility\n", + " db = SQLDatabase.from_uri(uri)\n", + "\n", + " tables_query = \"\"\"\n", + " SELECT table_name FROM information_schema.tables WHERE table_schema = 'agenticdb';\n", + " \"\"\"\n", + " tables_result = db.run(tables_query)\n", + " print(\"\\n## List of Tables in 'agenticdb' schema:\")\n", + "\n", + " # Ensure result is properly parsed\n", + " if isinstance(tables_result, str):\n", + " tables_result = tables_result.strip().split(\"\\n\")\n", + "\n", + " if tables_result:\n", + " for row in tables_result:\n", + " print(f\"Table found: {row.strip()}\")\n", + " else:\n", + " print(\"No tables found in 'agenticdb' schema.\")\n", + "\n", + " schema_query = \"\"\"\n", + " SELECT column_name, data_type\n", + " FROM information_schema.columns\n", + " WHERE table_schema = 'agenticdb'\n", + " AND table_name = 'transactions';\n", + " \"\"\"\n", + " schema_result = db.run(schema_query)\n", + "\n", + " print(\"\\n## Schema for 'agenticdb.transactions' table:\")\n", + "\n", + " # Convert to list if returned as a string\n", + " if isinstance(schema_result, str):\n", + " schema_result = schema_result.strip().split(\"\\n\")\n", + "\n", + " if schema_result:\n", + " for row in schema_result:\n", + " print(f\" Column: {row}\")\n", + " else:\n", + " print(\"No schema found for 'agenticdb.transactions'.\")\n", + "\n", + " # Example query to retrieve transactions\n", + " example_query = \"\"\"\n", + " SELECT transaction_id, client_name, transaction_type, stock_symbol, shares, price_per_share,\n", + " (shares * price_per_share) AS total_value\n", + " FROM agenticdb.transactions\n", + " WHERE transaction_type = 'BUY' AND price_per_share > 300;\n", + " \"\"\"\n", + "\n", + " query_result = db.run(example_query)\n", + " print(\"\\n## Query Execution Result:\")\n", + "\n", + " # Convert to list if returned as a string\n", + " if isinstace(query_result, str):\n", + " query_result = query_result.strip().split(\"\\n\") \n", + "\n", + " if query_result:\n", + " for txn in query_result:\n", + " print(f\"Transaction: {txn}\")\n", + " else:\n", + " print(\" No transactions found.\")\n", + "\n", + "except Exception as e:\n", + " print(f\" An error occurred while interacting with the PostgreSQL database: {e}\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "484b7c62-ea7d-4fd3-adcf-847beee5c0fb", + "metadata": {}, + "source": [ + "### 3. Model Configuration\n", + "\n", + "We will start by creating an llm instance, defined by the location where the LLM API can be queried and some parameters that will be applied to the model.\n" + ] + }, + { + "cell_type": "markdown", + "id": "d94bf848-656e-49ee-bc1e-7c4d2474678d", + "metadata": {}, + "source": [ + "#### 3.1 Define the Inference Model Server specifics" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "7b908fd0-01dd-4ad2-b745-b3a4c56a7a7e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "INFERENCE_SERVER_URL = os.getenv('API_URL_GRANITE')\n", + "MODEL_NAME = \"granite-3-8b-instruct\"\n", + "API_KEY= os.getenv('API_KEY_GRANITE')" + ] + }, + { + "cell_type": "markdown", + "id": "472b2f3f-ac23-4531-984b-6e8357233992", + "metadata": {}, + "source": [ + "#### 3.2 Create the LLM instance" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "01baa2b8-529d-455d-ad39-ef4a96dbaf97", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "llm = ChatOpenAI(\n", + " openai_api_key=API_KEY,\n", + " openai_api_base= f\"{INFERENCE_SERVER_URL}/v1\",\n", + " model_name=MODEL_NAME,\n", + " top_p=0.92,\n", + " temperature=0.01,\n", + " max_tokens=512,\n", + " presence_penalty=1.03,\n", + " streaming=True,\n", + " callbacks=[StreamingStdOutCallbackHandler()],\n", + " verbose=True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "70132439-184c-46bc-b3aa-098bd5310c1e", + "metadata": { + "tags": [] + }, + "source": [ + "### 4. Use LLMs to generate and execute SQL Queries into the DB" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "382e2fc3-2809-49ad-b58c-235daf93c737", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "## LLM Answer: \n", + "SELECT * FROM transactions\n", + "WHERE transaction_type = 'BUY' AND price_per_share > 300;\n", + "\n", + "## SQL Query Generated:\n", + "SELECT * FROM transactions\n", + "WHERE transaction_type = 'BUY' AND price_per_share > 300;\n", + "\n", + "## Running Query...\n", + "\n", + "## Query Results:\n", + "[(3, 'TXN1003', 'Emma Davis', 'BUY', 'MSFT', 200, Decimal('340.10'), 'JPMorgan Chase', datetime.datetime(2024, 6, 15, 11, 45))]\n" + ] + } + ], + "source": [ + "from tabulate import tabulate\n", + "\n", + "## 1. Generate an SQL query using LLM\n", + "query = \"Get all 'BUY' transactions where the price per share is greater than 300.\"\n", + "\n", + "# Ensure the model only outputs the SQL query\n", + "print(\"## LLM Answer: \")\n", + "llm_response = llm.invoke(f\"Generate a PostgreSQL query for this request. Return ONLY the SQL query, no explanations, no extra text:\\n\\n{query}\")\n", + "\n", + "## 2. Extract ONLY the SQL query from the AI response\n", + "# Handles AIMessage format\n", + "if hasattr(llm_response, \"content\"):\n", + " raw_response = llm_response.content.strip()\n", + "# Handles plain string output\n", + "elif isinstance(llm_response, str):\n", + " raw_response = llm_response.strip()\n", + "else:\n", + " print(\"\\n## ERROR: Invalid response format from LLM\")\n", + " raw_response = None\n", + "\n", + "# Extract SQL query safely\n", + "# TODO: Handle with Structure Outputs\n", + "if raw_response:\n", + " sql_query = raw_response.split(\"```sql\")[-1].split(\"```\")[0].strip() if \"```sql\" in raw_response else raw_response\n", + "else:\n", + " print(\"\\n## WARNING: No valid SQL query extracted\")\n", + " sql_query = None\n", + "\n", + "## 3. Execute the SQL query\n", + "if sql_query:\n", + " print(\"\\n\") # Add a blank line before the query output\n", + " print(\"## SQL Query Generated:\")\n", + " print(sql_query)\n", + " \n", + " print(\"\\n## Running Query...\")\n", + " result = db.run(sql_query)\n", + "\n", + " print(\"\\n## Query Results:\")\n", + " print(result)\n", + " \n", + "else:\n", + " print(\"\\n## WARNING: No valid SQL query extracted. ##\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "c724d256-cbf8-4dce-a6b2-b5ddd19fb285", + "metadata": {}, + "source": [ + "### 5. Define tools for execute SQL Queries\n", + "\n", + "Usage of [Tool Calling / Function Calling](https://ai-on-openshift.io/odh-rhoai/enable-function-calling/#how-to-enable-function-calling-with-vllm-in-openshift-ai) enabling the LLM to interact with external tools like the execute_sql_query in a structured way. \n", + "\n", + "Gives the LLM with functions (or tools) to perform actions like query the database." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "ecf54b24-1fec-441a-bd7f-b7bda665506e", + "metadata": {}, + "outputs": [], + "source": [ + "## Define Custom Tools (SQL Query Tool Retriever)\n", + "\n", + "from langchain_core.tools import Tool\n", + "\n", + "# Define a tool that allows the LLM to execute SQL queries\n", + "def execute_sql_query(query: str):\n", + " \"\"\"Executes SQL query and returns results\"\"\"\n", + " try:\n", + " result = db.run(query)\n", + " return result\n", + " except Exception as e:\n", + " return f\"SQL Execution Error: {e}\"\n", + "\n", + "sql_query_tool = Tool(\n", + " name=\"sql_db_query\",\n", + " func=execute_sql_query,\n", + " description=\"Executes SQL queries and returns the results.\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f7cb956c", + "metadata": {}, + "source": [ + "We will define the list of Tools that will be used by our AI Agents (in this case the SQL query Tool):" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "e985669f-5bb6-486a-a268-1f01616548be", + "metadata": {}, + "outputs": [], + "source": [ + "llm_with_tools = llm.bind_tools([sql_query_tool], tool_choice=\"auto\")" + ] + }, + { + "cell_type": "markdown", + "id": "f6886c14-5a86-456f-bb5e-82f85e5ea98a", + "metadata": {}, + "source": [ + "### 6. Invoke LLM to generate SQL Query\n", + "\n", + "Process the user query invoking the LLM, to generate the function calling to the sql_db_query Tool and process the execution result" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "15f17928-98f4-4080-b934-c278c010a4d4", + "metadata": {}, + "outputs": [], + "source": [ + "def handle_sql_query(user_query):\n", + " \"\"\"\n", + " Processes a user query by invoking the LLM, extracting an SQL query, \n", + " correcting common errors, and executing it.\n", + "\n", + " Parameters:\n", + " user_query (str): The user's natural language request for a database query.\n", + "\n", + " Returns:\n", + " None (prints the generated SQL query and its execution result)\n", + " \"\"\"\n", + "\n", + " # Pass the query to LLM\n", + " messages = [HumanMessage(user_query)]\n", + " ai_msg = llm_with_tools.invoke(messages)\n", + "\n", + " # Check for tool calls from the LLM\n", + " if hasattr(ai_msg, \"tool_calls\") and ai_msg.tool_calls:\n", + " for tool_call in ai_msg.tool_calls:\n", + " # Debugging the tool call structure\n", + " print(\"\\n## Tool Call Output:\\n\", tool_call)\n", + "\n", + " if tool_call[\"name\"] == \"sql_db_query\":\n", + " # Extract SQL query dynamically\n", + " sql_args = tool_call[\"args\"]\n", + " sql_query = sql_args.get(\"query\") or sql_args.get(\"__arg1\") or str(sql_args)\n", + "\n", + " print(f\"\\n## Generated SQL Query:\\n{sql_query}\")\n", + "\n", + " # Correct the SQL query before execution (Fix column name error)\n", + " corrected_query = sql_query.replace(\"type\", \"transaction_type\") \n", + "\n", + " # Execute the corrected query\n", + " print(\"\\n## Running Query...\")\n", + " query_result = execute_sql_query(corrected_query)\n", + "\n", + " # Print the execution result\n", + " print(\"\\n## Query Execution Result:\\n\")\n", + " print(query_result)\n", + " else:\n", + " print(\"\\n## No tool calls detected. LLM did not generate an SQL query.\")" + ] + }, + { + "cell_type": "markdown", + "id": "63450e64-d510-4a0c-82a0-4951493e5a5a", + "metadata": {}, + "source": [ + "### 7. LLM and SQL Query Tool Calling in action!" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "bfce1b7e-39b0-4f02-8913-b77c6eb11daf", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "## Tool Call Output:\n", + " {'name': 'sql_db_query', 'args': {'__arg1': \"SELECT * FROM transactions WHERE type = 'BUY' AND price_per_share > 200\"}, 'id': 'chatcmpl-tool-835db03070f647e3860447605040d827', 'type': 'tool_call'}\n", + "\n", + "## Generated SQL Query:\n", + "SELECT * FROM transactions WHERE type = 'BUY' AND price_per_share > 200\n", + "\n", + "## Running Query...\n", + "\n", + "## Query Execution Result:\n", + "\n", + "[(3, 'TXN1003', 'Emma Davis', 'BUY', 'MSFT', 200, Decimal('340.10'), 'JPMorgan Chase', datetime.datetime(2024, 6, 15, 11, 45))]\n" + ] + } + ], + "source": [ + "# Example usage\n", + "handle_sql_query(\"Retrieve all BUY transactions where price per share is above 200\")" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "4ddb376b-1af0-4c41-a456-5481fc14b3b5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "## Tool Call Output:\n", + " {'name': 'sql_db_query', 'args': {'__arg1': \"SELECT * FROM transactions WHERE client_name LIKE '%Smith%'\"}, 'id': 'chatcmpl-tool-672452a3f07e4a64a06f2804610fbccf', 'type': 'tool_call'}\n", + "\n", + "## Generated SQL Query:\n", + "SELECT * FROM transactions WHERE client_name LIKE '%Smith%'\n", + "\n", + "## Running Query...\n", + "\n", + "## Query Execution Result:\n", + "\n", + "[(2, 'TXN1002', 'Michael Smith', 'SELL', 'TSLA', 100, Decimal('245.20'), 'Charles Schwab', datetime.datetime(2024, 6, 15, 10, 15))]\n" + ] + } + ], + "source": [ + "handle_sql_query(\"Retrieve all transactions where the client name contains 'Smith'\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.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.7" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": {}, + "version_major": 2, + "version_minor": 0 + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/lab-materials/02-tools/2.2-cot-prompting-granite3.ipynb b/lab-materials/02-tools/2.3-cot-prompting-granite3.ipynb similarity index 100% rename from lab-materials/02-tools/2.2-cot-prompting-granite3.ipynb rename to lab-materials/02-tools/2.3-cot-prompting-granite3.ipynb diff --git a/lab-materials/02-tools/2.2-cot-prompting.ipynb b/lab-materials/02-tools/2.3-cot-prompting.ipynb similarity index 100% rename from lab-materials/02-tools/2.2-cot-prompting.ipynb rename to lab-materials/02-tools/2.3-cot-prompting.ipynb diff --git a/lab-materials/02-tools/2.3-react-prompting-granite3.ipynb b/lab-materials/02-tools/2.4-react-prompting-granite3.ipynb similarity index 100% rename from lab-materials/02-tools/2.3-react-prompting-granite3.ipynb rename to lab-materials/02-tools/2.4-react-prompting-granite3.ipynb diff --git a/lab-materials/02-tools/2.3-react-prompting.ipynb b/lab-materials/02-tools/2.4-react-prompting.ipynb similarity index 100% rename from lab-materials/02-tools/2.3-react-prompting.ipynb rename to lab-materials/02-tools/2.4-react-prompting.ipynb