{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "69014601",
   "metadata": {},
   "source": [
    "# Conversational\n",
    "\n",
    "This walkthrough demonstrates how to use an agent optimized for conversation. Other agents are often optimized for using tools to figure out the best response, which is not ideal in a conversational setting where you may want the agent to be able to chat with the user as well.\n",
    "\n",
    "If we compare it to the standard ReAct agent, the main difference is the prompt.\n",
    "We want it to be much more conversational."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "cc3fad9e",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.agents import Tool\n",
    "from langchain.agents import AgentType\n",
    "from langchain.memory import ConversationBufferMemory\n",
    "from langchain.llms import OpenAI\n",
    "from langchain.utilities import SerpAPIWrapper\n",
    "from langchain.agents import initialize_agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "2d84b9bc",
   "metadata": {},
   "outputs": [],
   "source": [
    "search = SerpAPIWrapper()\n",
    "tools = [\n",
    "    Tool(\n",
    "        name=\"Current Search\",\n",
    "        func=search.run,\n",
    "        description=\"useful for when you need to answer questions about current events or the current state of the world\"\n",
    "    ),\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "799a31bf",
   "metadata": {},
   "outputs": [],
   "source": [
    "llm=OpenAI(temperature=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f9d11cb6",
   "metadata": {},
   "source": [
    "## Using LCEL\n",
    "\n",
    "We will first show how to create this agent using LCEL"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "03c09ef9",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.tools.render import render_text_description\n",
    "from langchain.agents.output_parsers import ReActSingleInputOutputParser\n",
    "from langchain.agents.format_scratchpad import format_log_to_str\n",
    "from langchain import hub"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "6bd84102",
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt = hub.pull(\"hwchase17/react-chat\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "7ccc785d",
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt = prompt.partial(\n",
    "    tools=render_text_description(tools),\n",
    "    tool_names=\", \".join([t.name for t in tools]),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "d7aac2b0",
   "metadata": {},
   "outputs": [],
   "source": [
    "llm_with_stop = llm.bind(stop=[\"\\nObservation\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "a028bca6",
   "metadata": {},
   "outputs": [],
   "source": [
    "agent = {\n",
    "    \"input\": lambda x: x[\"input\"],\n",
    "    \"agent_scratchpad\": lambda x: format_log_to_str(x['intermediate_steps']),\n",
    "    \"chat_history\": lambda x: x[\"chat_history\"]\n",
    "} | prompt | llm_with_stop | ReActSingleInputOutputParser()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0b354cfe",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.agents import AgentExecutor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "9b044ae9",
   "metadata": {},
   "outputs": [],
   "source": [
    "memory = ConversationBufferMemory(memory_key=\"chat_history\")\n",
    "agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, memory=memory)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "adcdd0c7",
   "metadata": {
    "scrolled": true
   },
   "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",
      "Thought: Do I need to use a tool? No\n",
      "Final Answer: Hi Bob, nice to meet you! How can I help you today?\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'Hi Bob, nice to meet you! How can I help you today?'"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent_executor.invoke({\"input\": \"hi, i am bob\"})['output']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "c5846cd1",
   "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",
      "Thought: Do I need to use a tool? No\n",
      "Final Answer: Your name is Bob.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'Your name is Bob.'"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent_executor.invoke({\"input\": \"whats my name?\"})['output']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "95a1192a",
   "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",
      "Thought: Do I need to use a tool? Yes\n",
      "Action: Current Search\n",
      "Action Input: Movies showing 9/21/2023\u001b[0m\u001b[36;1m\u001b[1;3m['September 2023 Movies: The Creator • Dumb Money • Expend4bles • The Kill Room • The Inventor • The Equalizer 3 • PAW Patrol: The Mighty Movie, ...']\u001b[0m\u001b[32;1m\u001b[1;3m Do I need to use a tool? No\n",
      "Final Answer: According to current search, some movies showing on 9/21/2023 are The Creator, Dumb Money, Expend4bles, The Kill Room, The Inventor, The Equalizer 3, and PAW Patrol: The Mighty Movie.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'According to current search, some movies showing on 9/21/2023 are The Creator, Dumb Money, Expend4bles, The Kill Room, The Inventor, The Equalizer 3, and PAW Patrol: The Mighty Movie.'"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent_executor.invoke({\"input\": \"what are some movies showing 9/21/2023?\"})['output']"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c0b2d86d",
   "metadata": {},
   "source": [
    "## Use the off-the-shelf agent\n",
    "\n",
    "We can also create this agent using the off-the-shelf agent class"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "53e43064",
   "metadata": {},
   "outputs": [],
   "source": [
    "agent_executor = initialize_agent(tools, llm, agent=AgentType.CONVERSATIONAL_REACT_DESCRIPTION, verbose=True, memory=memory)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "68e45a24",
   "metadata": {},
   "source": [
    "## Use a chat model\n",
    "\n",
    "We can also use a chat model here. The main difference here is in the prompts used."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a5a705b2",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chat_models import ChatOpenAI\n",
    "from langchain import hub"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "16b17ca8",
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt = hub.pull(\"hwchase17/react-chat-json\")\n",
    "chat_model = ChatOpenAI(temperature=0, model='gpt-4')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "c8a94b0b",
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt = prompt.partial(\n",
    "    tools=render_text_description(tools),\n",
    "    tool_names=\", \".join([t.name for t in tools]),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "c5d710f2",
   "metadata": {},
   "outputs": [],
   "source": [
    "chat_model_with_stop = chat_model.bind(stop=[\"\\nObservation\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f50a5ea8",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.agents.output_parsers import JSONAgentOutputParser\n",
    "from langchain.agents.format_scratchpad import format_log_to_messages"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "2c845796",
   "metadata": {},
   "outputs": [],
   "source": [
    "# We need some extra steering, or the chat model forgets how to respond sometimes\n",
    "TEMPLATE_TOOL_RESPONSE = \"\"\"TOOL RESPONSE: \n",
    "---------------------\n",
    "{observation}\n",
    "\n",
    "USER'S INPUT\n",
    "--------------------\n",
    "\n",
    "Okay, so what is the response to my last comment? If using information obtained from the tools you must mention it explicitly without mentioning the tool names - I have forgotten all TOOL RESPONSES! Remember to respond with a markdown code snippet of a json blob with a single action, and NOTHING else - even if you just want to respond to the user. Do NOT respond with anything except a JSON snippet no matter what!\"\"\"\n",
    "\n",
    "agent = {\n",
    "    \"input\": lambda x: x[\"input\"],\n",
    "    \"agent_scratchpad\": lambda x: format_log_to_messages(x['intermediate_steps'], template_tool_response=TEMPLATE_TOOL_RESPONSE),\n",
    "    \"chat_history\": lambda x: x[\"chat_history\"],\n",
    "} | prompt | chat_model_with_stop | JSONAgentOutputParser()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6cc033fc",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.agents import AgentExecutor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "332ba2ff",
   "metadata": {},
   "outputs": [],
   "source": [
    "memory = ConversationBufferMemory(memory_key=\"chat_history\", return_messages=True)\n",
    "agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, memory=memory)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "139717b4",
   "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```json\n",
      "{\n",
      "    \"action\": \"Final Answer\",\n",
      "    \"action_input\": \"Hello Bob, how can I assist you today?\"\n",
      "}\n",
      "```\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'Hello Bob, how can I assist you today?'"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent_executor.invoke({\"input\": \"hi, i am bob\"})['output']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "7e7cf6d3",
   "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```json\n",
      "{\n",
      "    \"action\": \"Final Answer\",\n",
      "    \"action_input\": \"Your name is Bob.\"\n",
      "}\n",
      "```\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'Your name is Bob.'"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent_executor.invoke({\"input\": \"whats my name?\"})['output']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "3fc00073",
   "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```json\n",
      "{\n",
      "    \"action\": \"Current Search\",\n",
      "    \"action_input\": \"movies showing on 9/21/2023\"\n",
      "}\n",
      "```\u001b[0m\u001b[36;1m\u001b[1;3m['September 2023 Movies: The Creator • Dumb Money • Expend4bles • The Kill Room • The Inventor • The Equalizer 3 • PAW Patrol: The Mighty Movie, ...']\u001b[0m\u001b[32;1m\u001b[1;3m```json\n",
      "{\n",
      "    \"action\": \"Final Answer\",\n",
      "    \"action_input\": \"Some movies that are showing on 9/21/2023 include 'The Creator', 'Dumb Money', 'Expend4bles', 'The Kill Room', 'The Inventor', 'The Equalizer 3', and 'PAW Patrol: The Mighty Movie'.\"\n",
      "}\n",
      "```\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "\"Some movies that are showing on 9/21/2023 include 'The Creator', 'Dumb Money', 'Expend4bles', 'The Kill Room', 'The Inventor', 'The Equalizer 3', and 'PAW Patrol: The Mighty Movie'.\""
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent_executor.invoke({\"input\": \"what are some movies showing 9/21/2023?\"})['output']"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8d464ead",
   "metadata": {},
   "source": [
    "We can also initialize the agent executor with a predefined agent type"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "141f2469",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.memory import ConversationBufferMemory\n",
    "from langchain.chat_models import ChatOpenAI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "734d1b21",
   "metadata": {},
   "outputs": [],
   "source": [
    "memory = ConversationBufferMemory(memory_key=\"chat_history\", return_messages=True)\n",
    "llm = ChatOpenAI(openai_api_key=OPENAI_API_KEY, temperature=0)\n",
    "agent_chain = initialize_agent(tools, llm, agent=AgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION, verbose=True, memory=memory)"
   ]
  }
 ],
 "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
}
