diff --git a/docs/examples/function_calling.ipynb b/docs/examples/function_calling.ipynb
index ef61ca641d96d7698ee11204f48d0f095d48b6c5..88759cb32f2389706dbeb8578d939a0cc62c9b3f 100644
--- a/docs/examples/function_calling.ipynb
+++ b/docs/examples/function_calling.ipynb
@@ -11,16 +11,43 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 21,
+   "execution_count": 58,
    "metadata": {},
    "outputs": [],
    "source": [
-    "import json\n",
     "import openai\n",
+    "from semantic_router.utils.logger import logger\n",
+    "\n",
+    "\n",
+    "def llm_openai(prompt: str, model: str = \"gpt-4\") -> str:\n",
+    "    try:\n",
+    "        response = openai.chat.completions.create(\n",
+    "            model=model,\n",
+    "            messages=[\n",
+    "                {\"role\": \"system\", \"content\": f\"{prompt}\"},\n",
+    "            ],\n",
+    "        )\n",
+    "        ai_message = response.choices[0].message.content\n",
+    "        if not ai_message:\n",
+    "            raise Exception(\"AI message is empty\", ai_message)\n",
+    "        logger.info(f\"AI message: {ai_message}\")\n",
+    "        return ai_message\n",
+    "    except Exception as e:\n",
+    "        raise Exception(\"Failed to call OpenAI API\", e)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 64,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import json\n",
+    "from semantic_router.utils.logger import logger\n",
     "\n",
     "\n",
     "def generate_config(specification: dict) -> dict:\n",
-    "    print(\"Generating config...\")\n",
+    "    logger.info(\"Generating config...\")\n",
     "    example_specification = (\n",
     "        {\n",
     "            \"type\": \"function\",\n",
@@ -59,7 +86,8 @@
     "    }\n",
     "\n",
     "    prompt = f\"\"\"\n",
-    "    Given the following specification, generate a config in a valid JSON format,\n",
+    "    Given the following specification, generate a config in a valid JSON format\n",
+    "    enclosed in double quotes,\n",
     "    Example:\n",
     "    SPECIFICATION:\n",
     "    {example_specification}\n",
@@ -73,36 +101,90 @@
     "    GENERATED CONFIG:\n",
     "    \"\"\"\n",
     "\n",
+    "    ai_message = llm_openai(prompt)\n",
+    "\n",
     "    try:\n",
-    "        response = openai.chat.completions.create(\n",
-    "            model=\"gpt-4\",\n",
-    "            messages=[\n",
-    "                {\"role\": \"system\", \"content\": f\"{prompt}\"},\n",
-    "            ],\n",
-    "        )\n",
-    "        ai_message = response.choices[0].message.content\n",
-    "        print(\"AI message:\", ai_message)\n",
     "        route_config = json.loads(ai_message)\n",
+    "        function_description = specification[\"function\"][\"description\"]\n",
+    "        route_config[\"utterances\"].append(function_description)\n",
+    "        logger.info(f\"Generated config: {route_config}\")\n",
     "        return route_config\n",
+    "    except json.JSONDecodeError as json_error:\n",
+    "        raise Exception(\"JSON parsing error\", json_error)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 65,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def extract_parameters(query: str, specification: dict) -> dict:\n",
+    "    logger.info(\"Extracting parameters...\")\n",
+    "    example_query = \"what is the weather in London?\"\n",
+    "\n",
+    "    example_specification = {\n",
+    "        \"type\": \"function\",\n",
+    "        \"function\": {\n",
+    "            \"name\": \"get_time\",\n",
+    "            \"description\": \"Get the current time\",\n",
+    "            \"parameters\": {\n",
+    "                \"type\": \"object\",\n",
+    "                \"properties\": {\n",
+    "                    \"location\": {\n",
+    "                        \"type\": \"string\",\n",
+    "                        \"description\": \"Example of city and state\",\n",
+    "                    },\n",
+    "                },\n",
+    "                \"required\": [\"location\"],\n",
+    "            },\n",
+    "        },\n",
+    "    }\n",
+    "\n",
+    "    example_parameters = {\n",
+    "        \"location\": \"London\",\n",
+    "    }\n",
+    "\n",
+    "    prompt = f\"\"\"\n",
+    "    Given the following specification and query, extract the parameters from the query,\n",
+    "    in a valid JSON format enclosed in double quotes.\n",
+    "    Example:\n",
+    "    SPECIFICATION:\n",
+    "    {example_specification}\n",
+    "    QUERY:\n",
+    "    {example_query}\n",
+    "    PARAMETERS:\n",
+    "    {example_parameters}\n",
+    "    GIVEN SPECIFICATION:\n",
+    "    {specification}\n",
+    "    GIVEN QUERY:\n",
+    "    {query}\n",
+    "    EXTRACTED PARAMETERS:\n",
+    "    \"\"\"\n",
+    "\n",
+    "    ai_message = llm_openai(prompt)\n",
     "\n",
+    "    try:\n",
+    "        parameters = json.loads(ai_message)\n",
+    "        logger.info(f\"Extracted parameters: {parameters}\")\n",
+    "        return parameters\n",
     "    except json.JSONDecodeError as json_error:\n",
-    "        raise Exception(\"JSON parsing error\", json_error)\n",
-    "    except Exception as e:\n",
-    "        raise Exception(\"Error generating config from Openai\", e)"
+    "        raise Exception(\"JSON parsing error\", json_error)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 22,
+   "execution_count": 66,
    "metadata": {},
    "outputs": [],
    "source": [
     "from semantic_router.schema import Route\n",
     "from semantic_router.encoders import CohereEncoder\n",
     "from semantic_router.layer import RouteLayer\n",
+    "from semantic_router.utils.logger import logger\n",
     "\n",
     "def get_route_layer(config: list[dict]) -> RouteLayer:\n",
-    "    print(\"Getting route layer...\")\n",
+    "    logger.info(\"Getting route layer...\")\n",
     "    encoder = CohereEncoder()\n",
     "    routes = [\n",
     "        Route(name=route[\"name\"], utterances=route[\"utterances\"]) for route in config\n",
@@ -112,38 +194,105 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 25,
+   "execution_count": 73,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def validate_parameters(function_parameters, specification):\n",
+    "    required_params = specification[\"function\"][\"parameters\"][\"required\"]\n",
+    "    missing_params = [\n",
+    "        param for param in required_params if param not in function_parameters\n",
+    "    ]\n",
+    "    if missing_params:\n",
+    "        raise ValueError(f\"Missing required parameters: {missing_params}\")\n",
+    "    return True"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 74,
    "metadata": {},
    "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "\u001b[32m2023-12-14 13:16:49 INFO semantic_router.utils.logger Generating config...\u001b[0m\n",
+      "\u001b[32m2023-12-14 13:16:54 INFO semantic_router.utils.logger AI message: {\"name\": \"get_time\", \"utterances\": [\"What is the current time in London?\", \"Tell me the time in New York\", \"What's happening now in Paris?\", \"time in San Francisco?\", \"Tell me the time in Sydney\"]}\u001b[0m\n",
+      "\u001b[32m2023-12-14 13:16:54 INFO semantic_router.utils.logger Generated config: {'name': 'get_time', 'utterances': ['What is the current time in London?', 'Tell me the time in New York', \"What's happening now in Paris?\", 'time in San Francisco?', 'Tell me the time in Sydney', 'Get the current time']}\u001b[0m\n",
+      "\u001b[32m2023-12-14 13:16:54 INFO semantic_router.utils.logger Getting route layer...\u001b[0m\n"
+     ]
+    },
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Generating config...\n",
-      "AI message: {\n",
-      "    \"name\": \"get_time\",\n",
-      "    \"utterances\": [\n",
-      "        \"What is the current time in SF?\",\n",
-      "        \"Tell me the time in London\",\n",
-      "        \"Could you tell me the time in New York?\",\n",
-      "        \"May I know the current time in Paris?\",\n",
-      "        \"Can you tell me what time is it in Singapore?\"\n",
-      "    ]\n",
-      "}\n",
-      "Getting route layer...\n",
       "Getting function name for queries:\n",
       "\n",
-      "(None, 'What is the weather like in Barcelona?')\n",
-      "('get_time', 'What time is it in Taiwan?')\n",
-      "(None, 'What is happening in the world?')\n",
-      "('get_time', 'what is the time in Kaunas?')\n",
-      "(None, 'Im bored')\n",
-      "(None, 'I want to play a game')\n",
-      "(None, 'Banana')\n"
+      "What is the weather like in Barcelona? None {}\n"
+     ]
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "\u001b[32m2023-12-14 13:16:55 INFO semantic_router.utils.logger Extracting parameters...\u001b[0m\n",
+      "\u001b[32m2023-12-14 13:16:56 INFO semantic_router.utils.logger AI message: {\"location\": \"Taiwan\"}\u001b[0m\n",
+      "\u001b[32m2023-12-14 13:16:56 INFO semantic_router.utils.logger Extracted parameters: {'location': 'Taiwan'}\u001b[0m\n"
+     ]
+    },
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "What time is it in Taiwan? get_time {'location': 'Taiwan'}\n",
+      "Calling get_time function with location: Taiwan\n"
+     ]
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "\u001b[32m2023-12-14 13:16:56 INFO semantic_router.utils.logger Extracting parameters...\u001b[0m\n",
+      "\u001b[32m2023-12-14 13:16:58 INFO semantic_router.utils.logger AI message: {\"location\": \"the world\"}\u001b[0m\n",
+      "\u001b[32m2023-12-14 13:16:58 INFO semantic_router.utils.logger Extracted parameters: {'location': 'the world'}\u001b[0m\n"
+     ]
+    },
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "What is happening in the world? get_time {'location': 'the world'}\n",
+      "Calling get_time function with location: the world\n"
+     ]
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "\u001b[32m2023-12-14 13:16:58 INFO semantic_router.utils.logger Extracting parameters...\u001b[0m\n",
+      "\u001b[32m2023-12-14 13:17:00 INFO semantic_router.utils.logger AI message: {\"location\": \"Kaunas\"}\u001b[0m\n",
+      "\u001b[32m2023-12-14 13:17:00 INFO semantic_router.utils.logger Extracted parameters: {'location': 'Kaunas'}\u001b[0m\n"
+     ]
+    },
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "what is the time in Kaunas? get_time {'location': 'Kaunas'}\n",
+      "Calling get_time function with location: Kaunas\n",
+      "Im bored None {}\n",
+      "I want to play a game None {}\n",
+      "Banana None {}\n"
      ]
     }
    ],
    "source": [
+    "def get_time(location: str) -> str:\n",
+    "    print(f\"Calling get_time function with location: {location}\")\n",
+    "    return \"get_time\"\n",
+    "\n",
+    "\n",
     "specification = {\n",
     "    \"type\": \"function\",\n",
     "    \"function\": {\n",
@@ -178,8 +327,26 @@
     "print(\"Getting function name for queries:\\n\")\n",
     "for query in queries:\n",
     "    function_name = route_layer(query)\n",
-    "    print((function_name, query))"
+    "\n",
+    "    function_parameters = {}\n",
+    "    if function_name:\n",
+    "        function_parameters = extract_parameters(query, specification)\n",
+    "    print(query, function_name, function_parameters)\n",
+    "\n",
+    "    if function_name == \"get_time\":\n",
+    "        try:\n",
+    "            if validate_parameters(function_parameters, specification):\n",
+    "                get_time(**function_parameters)\n",
+    "        except ValueError as e:\n",
+    "            logger.error(f\"Error: {e}\")"
    ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
   }
  ],
  "metadata": {