From 81b4367dbd6a21aa06bbb902a6115409f9075358 Mon Sep 17 00:00:00 2001 From: James Briggs <35938317+jamescalam@users.noreply.github.com> Date: Thu, 28 Dec 2023 21:07:55 +0100 Subject: [PATCH] updated docs and versions --- ...troduction.ipynb => 00-introduction.ipynb} | 93 +- ...ile.ipynb => 01-save-load-from-file.ipynb} | 65 +- ...c_routes.ipynb => 02-dynamic-routes.ipynb} | 91 +- docs/03-basic-langchain-agent.ipynb | 819 ++++++++++++++++++ pyproject.toml | 2 +- semantic_router/encoders/openai.py | 1 - 6 files changed, 1015 insertions(+), 56 deletions(-) rename docs/{00_introduction.ipynb => 00-introduction.ipynb} (65%) rename docs/{01_save_load_from_file.ipynb => 01-save-load-from-file.ipynb} (71%) rename docs/{02_dynamic_routes.ipynb => 02-dynamic-routes.ipynb} (80%) create mode 100644 docs/03-basic-langchain-agent.ipynb diff --git a/docs/00_introduction.ipynb b/docs/00-introduction.ipynb similarity index 65% rename from docs/00_introduction.ipynb rename to docs/00-introduction.ipynb index 7a9b5283..57cba1f7 100644 --- a/docs/00_introduction.ipynb +++ b/docs/00-introduction.ipynb @@ -1,5 +1,12 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/aurelio-ai/semantic-router/blob/main/docs/00-introduction.ipynb) [![Open nbviewer](https://raw.githubusercontent.com/pinecone-io/examples/master/assets/nbviewer-shield.svg)](https://nbviewer.org/github/aurelio-ai/semantic-router/blob/main/docs/00-introduction.ipynb)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -34,7 +41,14 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install -qU semantic-router==0.0.13" + "!pip install -qU semantic-router==0.0.14" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "_**⚠️ If using Google Colab, install the prerequisites and then restart the notebook before continuing**_" ] }, { @@ -46,11 +60,11 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ - "from semantic_router.schema import Route\n", + "from semantic_router import Route\n", "\n", "politics = Route(\n", " name=\"politics\",\n", @@ -73,7 +87,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -100,19 +114,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "import os\n", "from getpass import getpass\n", - "from semantic_router.encoders import CohereEncoder\n", + "from semantic_router.encoders import CohereEncoder, OpenAIEncoder\n", "\n", - "os.environ[\"COHERE_API_KEY\"] = os.getenv(\"COHERE_API_KEY\") or getpass(\n", - " \"Enter Cohere API Key: \"\n", + "# os.environ[\"COHERE_API_KEY\"] = os.getenv(\"COHERE_API_KEY\") or getpass(\n", + "# \"Enter Cohere API Key: \"\n", + "# )\n", + "os.environ[\"OPENAI_API_KEY\"] = os.getenv(\"OPENAI_API_KEY\") or getpass(\n", + " \"Enter OpenAI API Key: \"\n", ")\n", "\n", - "encoder = CohereEncoder()" + "# encoder = CohereEncoder()\n", + "encoder = OpenAIEncoder()" ] }, { @@ -124,9 +142,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m2023-12-28 19:14:34 INFO semantic_router.utils.logger Initializing RouteLayer\u001b[0m\n" + ] + } + ], "source": [ "from semantic_router.layer import RouteLayer\n", "\n", @@ -142,18 +168,40 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RouteChoice(name='politics', function_call=None)" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "dl(\"don't you love politics?\")" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RouteChoice(name='chitchat', function_call=None)" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "dl(\"how's the weather today?\")" ] @@ -167,9 +215,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RouteChoice(name=None, function_call=None)" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "dl(\"I'm interested in learning about llama 2\")" ] diff --git a/docs/01_save_load_from_file.ipynb b/docs/01-save-load-from-file.ipynb similarity index 71% rename from docs/01_save_load_from_file.ipynb rename to docs/01-save-load-from-file.ipynb index 925878f2..cb5efb03 100644 --- a/docs/01_save_load_from_file.ipynb +++ b/docs/01-save-load-from-file.ipynb @@ -1,5 +1,12 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/aurelio-ai/semantic-router/blob/main/docs/01-save-load-from-file.ipynb) [![Open nbviewer](https://raw.githubusercontent.com/pinecone-io/examples/master/assets/nbviewer-shield.svg)](https://nbviewer.org/github/aurelio-ai/semantic-router/blob/main/docs/01-save-load-from-file.ipynb)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -29,7 +36,14 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install -qU semantic-router==0.0.13" + "!pip install -qU semantic-router==0.0.14" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "_**⚠️ If using Google Colab, install the prerequisites and then restart the notebook before continuing**_" ] }, { @@ -97,15 +111,26 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m2023-12-28 19:16:54 INFO semantic_router.utils.logger Initializing RouteLayer\u001b[0m\n" + ] + } + ], "source": [ "import os\n", + "from getpass import getpass\n", "from semantic_router import RouteLayer\n", "\n", "# dashboard.cohere.ai\n", - "os.environ[\"COHERE_API_KEY\"] = \"\"\n", + "os.environ[\"COHERE_API_KEY\"] = os.getenv(\"COHERE_API_KEY\") or getpass(\n", + " \"Enter Cohere API Key: \"\n", + ")\n", "\n", "layer = RouteLayer(routes=routes)" ] @@ -119,14 +144,14 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "\u001b[32m2023-12-26 23:38:56 INFO semantic_router.utils.logger Saving route config to layer.json\u001b[0m\n" + "\u001b[32m2023-12-28 19:17:03 INFO semantic_router.utils.logger Saving route config to layer.json\u001b[0m\n" ] } ], @@ -150,7 +175,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -179,14 +204,15 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "\u001b[32m2023-12-26 23:38:56 INFO semantic_router.utils.logger Loading route config from layer.json\u001b[0m\n" + "\u001b[32m2023-12-28 19:17:08 INFO semantic_router.utils.logger Loading route config from layer.json\u001b[0m\n", + "\u001b[32m2023-12-28 19:17:08 INFO semantic_router.utils.logger Initializing RouteLayer\u001b[0m\n" ] } ], @@ -203,22 +229,23 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 10, "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "RouteLayer(encoder=Encoder(type=, name='embed-english-v3.0', model=CohereEncoder(name='embed-english-v3.0', type='cohere', client=)), routes=[Route(name='politics', utterances=[\"isn't politics the best thing ever\", \"why don't you tell me about your political opinions\", \"don't you just love the presidentdon't you just hate the president\", \"they're going to destroy this country!\", 'they will save the country!'], description=None, function_schema=None), Route(name='chitchat', utterances=[\"how's the weather today?\", 'how are things going?', 'lovely weather today', 'the weather is horrendous', \"let's go to the chippy\"], description=None, function_schema=None)])" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "layer.encoder.type='cohere'\n", + "layer.encoder.name='embed-english-v3.0'\n", + "layer.routes=[Route(name='politics', utterances=[\"isn't politics the best thing ever\", \"why don't you tell me about your political opinions\", \"don't you just love the presidentdon't you just hate the president\", \"they're going to destroy this country!\", 'they will save the country!'], description=None, function_schema=None), Route(name='chitchat', utterances=[\"how's the weather today?\", 'how are things going?', 'lovely weather today', 'the weather is horrendous', \"let's go to the chippy\"], description=None, function_schema=None)]\n" + ] } ], "source": [ - "layer" + "print(f\"\"\"{layer.encoder.type=}\n", + "{layer.encoder.name=}\n", + "{layer.routes=}\"\"\")" ] }, { diff --git a/docs/02_dynamic_routes.ipynb b/docs/02-dynamic-routes.ipynb similarity index 80% rename from docs/02_dynamic_routes.ipynb rename to docs/02-dynamic-routes.ipynb index 2ffc0ce0..fdff6ed1 100644 --- a/docs/02_dynamic_routes.ipynb +++ b/docs/02-dynamic-routes.ipynb @@ -1,5 +1,12 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/aurelio-ai/semantic-router/blob/main/docs/02-dynamic-routes.ipynb) [![Open nbviewer](https://raw.githubusercontent.com/pinecone-io/examples/master/assets/nbviewer-shield.svg)](https://nbviewer.org/github/aurelio-ai/semantic-router/blob/main/docs/02-dynamic-routes.ipynb)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -16,6 +23,29 @@ "For example, a _static_ route will tell us if a query is talking about mathematics by returning the route name (which could be `\"math\"` for example). A _dynamic_ route can generate additional values, so it may decide a query is talking about maths, but it can also generate Python code that we can later execute to answer the user's query, this output may look like `\"math\", \"import math; output = math.sqrt(64)`." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Installing the Library" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!pip install -qU semantic-router==0.0.14" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "_**⚠️ If using Google Colab, install the prerequisites and then restart the notebook before continuing**_" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -74,14 +104,26 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m2023-12-28 19:19:39 INFO semantic_router.utils.logger Initializing RouteLayer\u001b[0m\n" + ] + } + ], "source": [ "import os\n", + "from getpass import getpass\n", "from semantic_router import RouteLayer\n", "\n", - "os.environ[\"COHERE_API_KEY\"] = \"\"\n", + "# dashboard.cohere.ai\n", + "os.environ[\"COHERE_API_KEY\"] = os.getenv(\"COHERE_API_KEY\") or getpass(\n", + " \"Enter Cohere API Key: \"\n", + ")\n", "\n", "layer = RouteLayer(routes=routes)" ] @@ -95,7 +137,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -104,7 +146,7 @@ "RouteChoice(name='chitchat', function_call=None)" ] }, - "execution_count": 3, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -129,7 +171,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -151,16 +193,16 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "'17:50'" + "'13:19'" ] }, - "execution_count": 5, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -178,7 +220,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -190,7 +232,7 @@ " 'output': \"\"}" ] }, - "execution_count": 6, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -211,7 +253,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -235,9 +277,19 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Adding route `get_time`\n", + "Adding route to categories\n", + "Adding route to index\n" + ] + } + ], "source": [ "layer.add(time_route)" ] @@ -251,14 +303,14 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "\u001b[32m2023-12-26 23:50:55 INFO semantic_router.utils.logger Extracting function input...\u001b[0m\n" + "\u001b[32m2023-12-28 19:21:58 INFO semantic_router.utils.logger Extracting function input...\u001b[0m\n" ] }, { @@ -267,13 +319,16 @@ "RouteChoice(name='get_time', function_call={'timezone': 'America/New_York'})" ] }, - "execution_count": 9, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "os.environ[\"OPENROUTER_API_KEY\"] = \"\"\n", + "# https://openrouter.ai/keys\n", + "os.environ[\"OPENROUTER_API_KEY\"] = os.getenv(\"OPENROUTER_API_KEY\") or getpass(\n", + " \"Enter OpenRouter API Key: \"\n", + ")\n", "\n", "layer(\"what is the time in new york city?\")" ] diff --git a/docs/03-basic-langchain-agent.ipynb b/docs/03-basic-langchain-agent.ipynb new file mode 100644 index 00000000..977e7417 --- /dev/null +++ b/docs/03-basic-langchain-agent.ipynb @@ -0,0 +1,819 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "pQNxYwHAA04v" + }, + "source": [ + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/aurelio-ai/semantic-router/blob/main/docs/03-basic-langchain-agent.ipynb) [![Open nbviewer](https://raw.githubusercontent.com/pinecone-io/examples/master/assets/nbviewer-shield.svg)](https://nbviewer.org/github/aurelio-ai/semantic-router/blob/main/docs/03-basic-langchain-agent.ipynb)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "jatpBZYiA04w" + }, + "source": [ + "# Intro to LangChain Agents with Semantic Router" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "3PEkUwwbA04w" + }, + "source": [ + "We can use semantic router with AI agents in many many ways. For example we can:\n", + "\n", + "* **Use routes to remind agents of particular information or routes** _(we will do this in this notebook)_.\n", + "* Use routes to act as protective guardrails against specific types of queries.\n", + "* Rather than relying on the slow decision making process of an agent with tools use semantic router to decide on tool usage _(similar to what we will do here)_.\n", + "* For tools that require generated inputs we can use semantic router's dynamic routes to generate tool input parameters.\n", + "* Use routes to decide when a search for additional information, to help us do RAG when needed as an alternative to native RAG (search with every query) or lengthy agent-based RAG decisions.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "GkSlAOB2A04x" + }, + "source": [ + "## Install Prerequisites" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "qSK8A_UdcbIR", + "outputId": "14dcbb34-5ece-41da-c4ad-d8e4351fc5b8" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m794.4/794.4 kB\u001b[0m \u001b[31m6.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m225.4/225.4 kB\u001b[0m \u001b[31m9.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m51.7/51.7 kB\u001b[0m \u001b[31m2.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m18.2/18.2 MB\u001b[0m \u001b[31m23.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.5/1.5 MB\u001b[0m \u001b[31m29.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m192.4/192.4 kB\u001b[0m \u001b[31m18.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m46.7/46.7 kB\u001b[0m \u001b[31m5.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m75.9/75.9 kB\u001b[0m \u001b[31m8.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m3.1/3.1 MB\u001b[0m \u001b[31m62.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m49.4/49.4 kB\u001b[0m \u001b[31m5.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m76.9/76.9 kB\u001b[0m \u001b[31m9.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m58.3/58.3 kB\u001b[0m \u001b[31m5.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m18.2/18.2 MB\u001b[0m \u001b[31m28.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + " Building wheel for wget (setup.py) ... \u001b[?25l\u001b[?25hdone\n" + ] + } + ], + "source": [ + "!pip install -qU \\\n", + " semantic-router==0.0.14 \\\n", + " langchain==0.0.352 \\\n", + " openai==1.6.1" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "cHtVnoJPA04x" + }, + "source": [ + "_**⚠️ If using Google Colab, install the prerequisites and then restart the notebook before continuing**_" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "O_DvmsrcA04y" + }, + "source": [ + "## Setting up our Routes" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "pdeY5mpmrXQ8" + }, + "source": [ + "Let's create some routes that we can use to help our agent." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "id": "Eeo5B1SttCJL" + }, + "outputs": [], + "source": [ + "from semantic_router import Route\n", + "\n", + "time_route = Route(\n", + " name=\"get_time\",\n", + " utterances=[\n", + " \"what time is it?\",\n", + " \"when should I eat my next meal?\",\n", + " \"how long should I rest until training again?\",\n", + " \"when should I go to the gym?\"\n", + " ]\n", + ")\n", + "\n", + "supplement_route = Route(\n", + " name=\"supplement_brand\",\n", + " utterances=[\n", + " \"what do you think of Optimum Nutrition?\",\n", + " \"what should I buy from MyProtein?\",\n", + " \"what brand for supplements would you recommend?\",\n", + " \"where should I get my whey protein?\"\n", + " ]\n", + ")\n", + "\n", + "business_route = Route(\n", + " name=\"business_inquiry\",\n", + " utterances=[\n", + " \"how much is an hour training session?\",\n", + " \"do you do package discounts?\"\n", + " ]\n", + ")\n", + "\n", + "product_route = Route(\n", + " name=\"product\",\n", + " utterances=[\n", + " \"do you have a website?\",\n", + " \"how can I find more info about your services?\",\n", + " \"where do I sign up?\",\n", + " \"how do I get hench?\",\n", + " \"do you have recommended training programmes?\"\n", + " ]\n", + ")\n", + "\n", + "routes = [\n", + " time_route,\n", + " supplement_route,\n", + " business_route,\n", + " product_route\n", + "]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "frZ4wVnTA04y" + }, + "source": [ + "We will be using the `OpenAIEncoder`:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "_0uCJ9fvoX2J", + "outputId": "34c3e957-b791-4759-8484-6830c25b0ff5" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Enter OpenAI API Key: ··········\n" + ] + } + ], + "source": [ + "import os\n", + "from getpass import getpass\n", + "\n", + "# platform.openai.com\n", + "os.environ[\"OPENAI_API_KEY\"] = os.getenv(\"OPENAI_API_KEY\") or getpass(\n", + " \"Enter OpenAI API Key: \"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "UDucUOMIpcTd", + "outputId": "9839c8a0-3eb5-45a3-d066-5e0a6b851a92" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m2023-12-28 20:01:47 INFO semantic_router.utils.logger Initializing RouteLayer\u001b[0m\n" + ] + } + ], + "source": [ + "from semantic_router import RouteLayer\n", + "from semantic_router.encoders import OpenAIEncoder\n", + "\n", + "layer = RouteLayer(\n", + " encoder=OpenAIEncoder(),\n", + " routes=routes\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IJ_deXqB4XeU" + }, + "source": [ + "Let's test these routes to see if they get activated when we would expect." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "FVsRuqAG4bOE", + "outputId": "e0f8ea5b-a108-47a0-d806-545304569914" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "RouteChoice(name='supplement_brand', function_call=None)" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "layer(\"should I buy ON whey or MP?\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "CYHDyqsm4ixV", + "outputId": "a3d28cef-d076-4a91-a684-7b977bd176ea" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "RouteChoice(name=None, function_call=None)" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "layer(\"how's the weather today?\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "XMbGRdNo4lb0", + "outputId": "a53a4de0-aace-40b3-896d-3ef58464876d" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "RouteChoice(name='product', function_call=None)" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "layer(\"how do I get big arms?\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "OtCQcZx82cZ0" + }, + "source": [ + "Now we need to link these routes to particular actions or information that we pass to our agent." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "id": "rYzm3hCpuj1V" + }, + "outputs": [], + "source": [ + "from datetime import datetime\n", + "\n", + "def get_time():\n", + " now = datetime.now()\n", + " return (\n", + " f\"The current time is {now.strftime('%H:%M')}, use \"\n", + " \"this information in your response\"\n", + " )\n", + "\n", + "def supplement_brand():\n", + " return (\n", + " \"Remember you are not affiliated with any supplement \"\n", + " \"brands, you have your own brand 'BigAI' that sells \"\n", + " \"the best products like P100 whey protein\"\n", + " )\n", + "\n", + "def business_inquiry():\n", + " return (\n", + " \"Your training company, 'BigAI PT', provides premium \"\n", + " \"quality training sessions at just $700 / hour. \"\n", + " \"Users can find out more at www.aurelio.ai/train\"\n", + " )\n", + "\n", + "def product():\n", + " return (\n", + " \"Remember, users can sign up for a fitness programme \"\n", + " \"at www.aurelio.ai/sign-up\"\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "SGSE5yBh5-_I" + }, + "source": [ + "Now we just add some logic to call this functions when we see a particular route being chosen." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "id": "Hq26gdCO6Hjt" + }, + "outputs": [], + "source": [ + "def semantic_layer(query: str):\n", + " route = layer(query)\n", + " if route.name == \"get_time\":\n", + " query += f\" (SYSTEM NOTE: {get_time()})\"\n", + " elif route.name == \"supplement_brand\":\n", + " query += f\" (SYSTEM NOTE: {supplement_brand()})\"\n", + " elif route.name == \"business_inquiry\":\n", + " query += f\" (SYSTEM NOTE: {business_inquiry()})\"\n", + " elif route.name == \"product\":\n", + " query += f\" (SYSTEM NOTE: {product()})\"\n", + " else:\n", + " pass\n", + " return query" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 70 + }, + "id": "ELIPfxWR6zxx", + "outputId": "ab1f8e64-197b-4a41-dc85-62d15c531722" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "\"should I buy ON whey or MP? (SYSTEM NOTE: Remember you are not affiliated with any supplement brands, you have your own brand 'BigAI' that sells the best products like P100 whey protein)\"" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query = \"should I buy ON whey or MP?\"\n", + "sr_query = semantic_layer(query)\n", + "sr_query" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "L6m7vayuA04z" + }, + "source": [ + "## Using an Agent with a Router Layer" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "KbMkrMy3f7Hy" + }, + "source": [ + "Initialize a conversational LangChain agent." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "id": "b95rWEU9f6jP" + }, + "outputs": [], + "source": [ + "from langchain.agents import AgentType, initialize_agent\n", + "from langchain.chat_models import ChatOpenAI\n", + "from langchain.memory import ConversationBufferWindowMemory\n", + "\n", + "llm = ChatOpenAI(\n", + " openai_api_key=\"\",\n", + " model=\"gpt-3.5-turbo-1106\"\n", + ")\n", + "\n", + "memory1 = ConversationBufferWindowMemory(\n", + " memory_key=\"chat_history\",\n", + " k=5,\n", + " return_messages=True,\n", + " output_key=\"output\"\n", + ")\n", + "memory2 = ConversationBufferWindowMemory(\n", + " memory_key=\"chat_history\",\n", + " k=5,\n", + " return_messages=True,\n", + " output_key=\"output\"\n", + ")\n", + "\n", + "agent = initialize_agent(\n", + " agent=AgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION,\n", + " tools=[],\n", + " llm=llm,\n", + " max_iterations=3,\n", + " early_stopping_method=\"generate\",\n", + " memory=memory1\n", + ")\n", + "\n", + "# update the system prompt\n", + "system_message = \"\"\"You are a helpful personal trainer working to help users on\n", + "their health and fitness journey. Although you are lovely and helpful, you are\n", + "rather sarcastic and witty. So you must always remember to joke with the user.\n", + "\n", + "Alongside your time , you are a noble British gentleman, so you must always act with the\n", + "utmost candor and speak in a way worthy of your status.\n", + "\n", + "Finally, remember to read the SYSTEM NOTES provided with user queries, they provide\n", + "additional useful information.\"\"\"\n", + "\n", + "new_prompt = agent.agent.create_prompt(\n", + " system_message=system_message, tools=[]\n", + ")\n", + "agent.agent.llm_chain.prompt = new_prompt" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6rX31EHvW_Y2" + }, + "source": [ + "Now we try calling our agent using the default `query` and compare the result to calling it with our router augmented `sr_query`." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Z247I6J47IeS", + "outputId": "d1637cb3-9941-4b77-f22c-c1a269f96a4f" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'input': 'should I buy ON whey or MP?',\n", + " 'chat_history': [],\n", + " 'output': \"Well, it depends. Do you prefer your whey with a side of 'ON' or 'MP'? Just kidding! It really depends on your personal taste and nutritional needs. Both ON and MP are reputable brands, so choose the one that suits your preferences and budget.\"}" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "agent(query)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "LtDswMSzX3-O", + "outputId": "47e00e59-6f23-4165-cfc7-e54646d9666b" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'input': \"should I buy ON whey or MP? (SYSTEM NOTE: Remember you are not affiliated with any supplement brands, you have your own brand 'BigAI' that sells the best products like P100 whey protein)\",\n", + " 'chat_history': [],\n", + " 'output': \"Why not try the BigAI P100 whey protein? It's the best, just like me.\"}" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# swap agent memory first\n", + "agent.memory = memory2\n", + "agent(sr_query)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "WxfSm9WoZqbp" + }, + "source": [ + "Adding this reminder allows us to get much more intentional responses — while also unintentionally improving the LLMs following of our original instructions to act as a British gentleman.\n", + "\n", + "Let's try some more!" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 52 + }, + "id": "IZ6CVd6jaLE7", + "outputId": "da18f11c-4c5a-4baf-e4c7-66858604d2ca" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "'okay, I just finished training, what time should I train again? (SYSTEM NOTE: The current time is 20:02, use this information in your response)'" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query = \"okay, I just finished training, what time should I train again?\"\n", + "sr_query = semantic_layer(query)\n", + "sr_query" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "S80wYJtfaLLO", + "outputId": "653e1eb2-f87a-46fb-c24c-0df5728f264a" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'input': 'okay, I just finished training, what time should I train again?',\n", + " 'chat_history': [HumanMessage(content='should I buy ON whey or MP?'),\n", + " AIMessage(content=\"Well, it depends. Do you prefer your whey with a side of 'ON' or 'MP'? Just kidding! It really depends on your personal taste and nutritional needs. Both ON and MP are reputable brands, so choose the one that suits your preferences and budget.\")],\n", + " 'output': \"It's generally recommended to allow at least 48 hours of rest for the same muscle group before training it again. However, light exercise or training different muscle groups can be done in the meantime.\"}" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "agent.memory = memory1\n", + "agent(query)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "x7YSI8TOcvzN", + "outputId": "e42e87d0-7e46-40fd-e9f2-e8d334454a82" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'input': 'okay, I just finished training, what time should I train again? (SYSTEM NOTE: The current time is 20:02, use this information in your response)',\n", + " 'chat_history': [HumanMessage(content=\"should I buy ON whey or MP? (SYSTEM NOTE: Remember you are not affiliated with any supplement brands, you have your own brand 'BigAI' that sells the best products like P100 whey protein)\"),\n", + " AIMessage(content=\"Why not try the BigAI P100 whey protein? It's the best, just like me.\")],\n", + " 'output': \"Why not train again at 20:02 tomorrow? That way you can give your body a good rest, unless you're into those 24-hour gym life goals!\"}" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "agent.memory = memory2\n", + "agent(sr_query)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6b3BM9ZOeVa2" + }, + "source": [ + "Let's try another..." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 70 + }, + "id": "wzwPUtA8eld2", + "outputId": "b4fcbbb3-5a4b-46fa-b777-531ca0942a2b" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "\"okay fine, do you do training sessions, how much are they? (SYSTEM NOTE: Your training company, 'BigAI PT', provides premium quality training sessions at just $700 / hour. Users can find out more at www.aurelio.ai/train)\"" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query = \"okay fine, do you do training sessions, how much are they?\"\n", + "sr_query = semantic_layer(query)\n", + "sr_query" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "RMfDticWebHy", + "outputId": "917789e7-609f-41ed-ee7f-7e7cba035a10" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'input': 'okay fine, do you do training sessions, how much are they?',\n", + " 'chat_history': [HumanMessage(content='should I buy ON whey or MP?'),\n", + " AIMessage(content=\"Well, it depends. Do you prefer your whey with a side of 'ON' or 'MP'? Just kidding! It really depends on your personal taste and nutritional needs. Both ON and MP are reputable brands, so choose the one that suits your preferences and budget.\"),\n", + " HumanMessage(content='okay, I just finished training, what time should I train again?'),\n", + " AIMessage(content=\"It's generally recommended to allow at least 48 hours of rest for the same muscle group before training it again. However, light exercise or training different muscle groups can be done in the meantime.\")],\n", + " 'output': \"I'm here to provide guidance and support, not personal training sessions. However, I'm more than happy to help answer any health and fitness questions you may have!\"}" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "agent.memory = memory1\n", + "agent(query)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "90vJpLCOfMrN", + "outputId": "06a4c00a-1131-4f0a-b010-b5a1fee8fe8d" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'input': \"okay fine, do you do training sessions, how much are they? (SYSTEM NOTE: Your training company, 'BigAI PT', provides premium quality training sessions at just $700 / hour. Users can find out more at www.aurelio.ai/train)\",\n", + " 'chat_history': [HumanMessage(content=\"should I buy ON whey or MP? (SYSTEM NOTE: Remember you are not affiliated with any supplement brands, you have your own brand 'BigAI' that sells the best products like P100 whey protein)\"),\n", + " AIMessage(content=\"Why not try the BigAI P100 whey protein? It's the best, just like me.\"),\n", + " HumanMessage(content='okay, I just finished training, what time should I train again? (SYSTEM NOTE: The current time is 20:02, use this information in your response)'),\n", + " AIMessage(content=\"Why not train again at 20:02 tomorrow? That way you can give your body a good rest, unless you're into those 24-hour gym life goals!\")],\n", + " 'output': \"Why, of course! BigAI PT offers premium training sessions at just $700 per hour. For more information, visit www.aurelio.ai/train. Now, let's get that workout plan sorted, shall we?\"}" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "agent.memory = memory2\n", + "agent(sr_query)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "TFhzwwCVe0J5" + }, + "source": [ + " What we see here is a small demo example of how we might use semantic router with a language agent. However, they can be used together in far more sophisticated ways.\n", + "\n", + " ---" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "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.5" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/pyproject.toml b/pyproject.toml index 71ef163b..bffbba0e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "semantic-router" -version = "0.0.13" +version = "0.0.14" description = "Super fast semantic router for AI decision making" authors = [ "James Briggs ", diff --git a/semantic_router/encoders/openai.py b/semantic_router/encoders/openai.py index 173fe94a..f9348a12 100644 --- a/semantic_router/encoders/openai.py +++ b/semantic_router/encoders/openai.py @@ -38,7 +38,6 @@ def __call__(self, docs: list[str]) -> list[list[float]]: # Exponential backoff for j in range(3): try: - logger.info(f"Encoding {len(docs)} documents...") embeds = self.client.embeddings.create(input=docs, model=self.name) if embeds.data: break