{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "e10aa932",
   "metadata": {},
   "source": [
    "# OpenAI functions\n",
    "\n",
    "Certain OpenAI models (like gpt-3.5-turbo-0613 and gpt-4-0613) have been fine-tuned to detect when a function should be called and respond with the inputs that should be passed to the function. In an API call, you can describe functions and have the model intelligently choose to output a JSON object containing arguments to call those functions. The goal of the OpenAI Function APIs is to more reliably return valid and useful function calls than a generic text completion or chat API.\n",
    "\n",
    "The OpenAI Functions Agent is designed to work with these models.\n",
    "\n",
    "Install `openai`, `google-search-results` packages which are required as the LangChain packages call them internally."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ec89be68",
   "metadata": {},
   "outputs": [],
   "source": [
    "! pip install openai google-search-results"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "82787d8d",
   "metadata": {},
   "source": [
    "## Initialize tools\n",
    "\n",
    "We will first create some tools we can use"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "b812b982",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.agents import AgentType, Tool, initialize_agent\n",
    "from langchain.chains import LLMMathChain\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "from langchain.utilities import SerpAPIWrapper, SQLDatabase\n",
    "from langchain_experimental.sql import SQLDatabaseChain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "23fc0aa6",
   "metadata": {},
   "outputs": [],
   "source": [
    "llm = ChatOpenAI(temperature=0, model=\"gpt-3.5-turbo-0613\")\n",
    "search = SerpAPIWrapper()\n",
    "llm_math_chain = LLMMathChain.from_llm(llm=llm, verbose=True)\n",
    "db = SQLDatabase.from_uri(\"sqlite:///../../../../../notebooks/Chinook.db\")\n",
    "db_chain = SQLDatabaseChain.from_llm(llm, db, verbose=True)\n",
    "tools = [\n",
    "    Tool(\n",
    "        name=\"Search\",\n",
    "        func=search.run,\n",
    "        description=\"useful for when you need to answer questions about current events. You should ask targeted questions\",\n",
    "    ),\n",
    "    Tool(\n",
    "        name=\"Calculator\",\n",
    "        func=llm_math_chain.run,\n",
    "        description=\"useful for when you need to answer questions about math\",\n",
    "    ),\n",
    "    Tool(\n",
    "        name=\"FooBar-DB\",\n",
    "        func=db_chain.run,\n",
    "        description=\"useful for when you need to answer questions about FooBar. Input should be in the form of a question containing full context\",\n",
    "    ),\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "39c3ba21",
   "metadata": {},
   "source": [
    "## Using LCEL\n",
    "\n",
    "We will first use LangChain Expression Language to create this agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eac103f1",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "55292bed",
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\"system\", \"You are a helpful assistant\"),\n",
    "        (\"user\", \"{input}\"),\n",
    "        MessagesPlaceholder(variable_name=\"agent_scratchpad\"),\n",
    "    ]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "50f40df4",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.tools.render import format_tool_to_openai_function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "552421b3",
   "metadata": {},
   "outputs": [],
   "source": [
    "llm_with_tools = llm.bind(functions=[format_tool_to_openai_function(t) for t in tools])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3cafa0a3",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.agents.format_scratchpad import format_to_openai_function_messages\n",
    "from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "bf514eb4",
   "metadata": {},
   "outputs": [],
   "source": [
    "agent = (\n",
    "    {\n",
    "        \"input\": lambda x: x[\"input\"],\n",
    "        \"agent_scratchpad\": lambda x: format_to_openai_function_messages(\n",
    "            x[\"intermediate_steps\"]\n",
    "        ),\n",
    "    }\n",
    "    | prompt\n",
    "    | llm_with_tools\n",
    "    | OpenAIFunctionsAgentOutputParser()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5125573e",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.agents import AgentExecutor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "bdc7e506",
   "metadata": {},
   "outputs": [],
   "source": [
    "agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "2cd65218",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m\n",
      "Invoking: `Search` with `Leo DiCaprio's girlfriend`\n",
      "\n",
      "\n",
      "\u001b[0m\u001b[36;1m\u001b[1;3m['Blake Lively and DiCaprio are believed to have enjoyed a whirlwind five-month romance in 2011. The pair were seen on a yacht together in Cannes, ...']\u001b[0m\u001b[32;1m\u001b[1;3m\n",
      "Invoking: `Calculator` with `0.43`\n",
      "\n",
      "\n",
      "\u001b[0m\n",
      "\n",
      "\u001b[1m> Entering new LLMMathChain chain...\u001b[0m\n",
      "0.43\u001b[32;1m\u001b[1;3m```text\n",
      "0.43\n",
      "```\n",
      "...numexpr.evaluate(\"0.43\")...\n",
      "\u001b[0m\n",
      "Answer: \u001b[33;1m\u001b[1;3m0.43\u001b[0m\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\u001b[33;1m\u001b[1;3mAnswer: 0.43\u001b[0m\u001b[32;1m\u001b[1;3mI'm sorry, but I couldn't find any information about Leo DiCaprio's current girlfriend. As for raising her age to the power of 0.43, I'm not sure what her current age is, so I can't provide an answer for that.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'input': \"Who is Leo DiCaprio's girlfriend? What is her current age raised to the 0.43 power?\",\n",
       " 'output': \"I'm sorry, but I couldn't find any information about Leo DiCaprio's current girlfriend. As for raising her age to the power of 0.43, I'm not sure what her current age is, so I can't provide an answer for that.\"}"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent_executor.invoke(\n",
    "    {\n",
    "        \"input\": \"Who is Leo DiCaprio's girlfriend? What is her current age raised to the 0.43 power?\"\n",
    "    }\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e91393f",
   "metadata": {},
   "source": [
    "## Using OpenAIFunctionsAgent\n",
    "\n",
    "We can now use `OpenAIFunctionsAgent`, which creates this agent under the hood"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "9ed07c8f",
   "metadata": {},
   "outputs": [],
   "source": [
    "agent_executor = initialize_agent(\n",
    "    tools, llm, agent=AgentType.OPENAI_FUNCTIONS, verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8d9fb674",
   "metadata": {},
   "outputs": [],
   "source": [
    "agent_executor.invoke(\n",
    "    {\n",
    "        \"input\": \"Who is Leo DiCaprio's girlfriend? What is her current age raised to the 0.43 power?\"\n",
    "    }\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2bc581dc",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
