{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "842dd272",
   "metadata": {},
   "source": [
    "# Agents\n",
    "\n",
    "[![Open In Collab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langchain-ai/langchain/blob/master/docs/extras/use_cases/more/agents/agents.ipynb)\n",
    "\n",
    "## Use case \n",
    "\n",
    "LLM-based agents are powerful general problem solvers.\n",
    "\n",
    "The [primary LLM agent components](https://lilianweng.github.io/posts/2023-06-23-agent/) include at least 3 things:\n",
    "\n",
    "* `Planning`: The ability to break down tasks into smaller sub-goals\n",
    "* `Memory`: The ability to retain and recall information\n",
    "* `Tools`: The ability to get information from external sources (e.g., APIs)\n",
    "\n",
    "Unlike LLMs simply connected to [APIs](/docs/use_cases/apis/apis), agents [can](https://www.youtube.com/watch?v=DWUdGhRrv2c):\n",
    "\n",
    "* Self-correct\n",
    "* Handle multi-hop tasks (several intermediate \"hops\" or steps to arrive at a conclusion)\n",
    "* Tackle long time horizon tasks (that require access to long-term memory)\n",
    "\n",
    "![Image description](/img/agents_use_case_1.png)\n",
    "\n",
    "## Overview \n",
    "\n",
    "LangChain has [many agent types](/docs/modules/agents/agent_types/).\n",
    "\n",
    "Nearly all agents will use the following components:\n",
    " \n",
    "**Planning**\n",
    " \n",
    "* `Prompt`: Can given the LLM [personality](https://arxiv.org/pdf/2304.03442.pdf), context (e.g, via retrieval from memory), or strategies for learninng (e.g., [chain-of-thought](https://lilianweng.github.io/posts/2023-03-15-prompt-engineering/#chain-of-thought-cot)).\n",
    "* `Agent` Responsible for deciding what step to take next using an LLM with the `Prompt`\n",
    "\n",
    "**Memory**\n",
    "\n",
    "* This can be short or long-term, allowing the agent to persist information.\n",
    "\n",
    "**Tools**\n",
    "\n",
    "* Tools are functions that an agent can call.\n",
    "\n",
    "But, there are some taxonomic differences:\n",
    "\n",
    "* `Action agents`: Designed to decide the sequence of actions (tool use) (e.g., OpenAI functions agents, ReAct agents).\n",
    "* `Simulation agents`: Designed for role-play often in simulated enviorment (e.g., Generative Agents, CAMEL).\n",
    "* `Autonomous agents`: Designed for indepdent execution towards long term goals (e.g., BabyAGI, Auto-GPT).\n",
    "\n",
    "This will focus on `Action agents`.\n",
    "\n",
    "\n",
    "## Quickstart "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3a704c7a",
   "metadata": {},
   "outputs": [],
   "source": [
    "! pip install langchain openai google-search-results\n",
    "\n",
    "# Set env var OPENAI_API_KEY and SERPAPI_API_KEY or load from a .env file\n",
    "# import dotenv\n",
    "\n",
    "# dotenv.load_dotenv()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "639d41ad",
   "metadata": {},
   "source": [
    "`Tools`\n",
    "\n",
    "LangChain has [many tools](https://github.com/langchain-ai/langchain/blob/master/libs/langchain/langchain/agents/load_tools.py) for Agents that we can load easily.\n",
    "\n",
    "Let's load search and a calcultor."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c60001c9",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Tool\n",
    "from langchain.agents import load_tools\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "llm = ChatOpenAI(temperature=0)\n",
    "tools = load_tools([\"serpapi\", \"llm-math\"], llm=llm)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "431ba30b",
   "metadata": {},
   "source": [
    "`Agent`\n",
    "\n",
    "The [`OPENAI_FUNCTIONS` agent](/docs/modules/agents/agent_types/openai_functions_agent) is a good action agent to start with.\n",
    "\n",
    "OpenAI models have been fine-tuned to recognize when function should be called."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "d636395f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'As of 2023, the estimated population of Canada is approximately 39,858,480 people.'"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Prompt\n",
    "from langchain.agents import AgentExecutor\n",
    "from langchain.schema import SystemMessage\n",
    "from langchain.agents import OpenAIFunctionsAgent\n",
    "system_message = SystemMessage(content=\"You are a search assistant.\")\n",
    "prompt = OpenAIFunctionsAgent.create_prompt(system_message=system_message)\n",
    "\n",
    "# Agent\n",
    "search_agent = OpenAIFunctionsAgent(llm=llm, tools=tools, prompt=prompt)\n",
    "agent_executor = AgentExecutor(agent=search_agent, tools=tools, verbose=False)\n",
    "\n",
    "# Run\n",
    "agent_executor.run(\"How many people live in canada as of 2023?\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "27842380",
   "metadata": {},
   "source": [
    "Great, we have created a simple search agent with a tool!\n",
    "\n",
    "Note that we use an agent executor, which is the runtime for an agent. \n",
    "\n",
    "This is what calls the agent and executes the actions it chooses. \n",
    "\n",
    "Pseudocode for this runtime is below:\n",
    "```\n",
    "next_action = agent.get_action(...)\n",
    "while next_action != AgentFinish:\n",
    "    observation = run(next_action)\n",
    "    next_action = agent.get_action(..., next_action, observation)\n",
    "return next_action\n",
    "```\n",
    "\n",
    "While this may seem simple, there are several complexities this runtime handles for you, including:\n",
    "\n",
    "* Handling cases where the agent selects a non-existent tool\n",
    "* Handling cases where the tool errors\n",
    "* Handling cases where the agent produces output that cannot be parsed into a tool invocation\n",
    "* Logging and observability at all levels (agent decisions, tool calls) either to stdout or LangSmith.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0b93c7d0",
   "metadata": {},
   "source": [
    "## Memory \n",
    "\n",
    "### Short-term memory\n",
    "\n",
    "Of course, `memory` is needed to enable conversation / persistence of information.\n",
    "\n",
    "LangChain has many options for [short-term memory](/docs/modules/memory/types/), which are frequently used in [chat](/docs/modules/memory/adding_memory.html). \n",
    "\n",
    "They can be [employed with agents](/docs/modules/memory/agent_with_memory) too.\n",
    "\n",
    "`ConversationBufferMemory` is a popular choice for short-term memory.\n",
    "\n",
    "We set `MEMORY_KEY`, which can be referenced by the prompt later.\n",
    "\n",
    "Now, let's add memory to our agent."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "1d291015",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Memory \n",
    "from langchain.memory import ConversationBufferMemory\n",
    "MEMORY_KEY = \"chat_history\"\n",
    "memory = ConversationBufferMemory(memory_key=MEMORY_KEY, return_messages=True)\n",
    "\n",
    "# Prompt w/ placeholder for memory\n",
    "from langchain.schema import SystemMessage\n",
    "from langchain.agents import OpenAIFunctionsAgent\n",
    "from langchain.prompts import MessagesPlaceholder\n",
    "system_message = SystemMessage(content=\"You are a search assistant tasked with using Serpapi to answer questions.\")\n",
    "prompt = OpenAIFunctionsAgent.create_prompt(\n",
    "    system_message=system_message,\n",
    "    extra_prompt_messages=[MessagesPlaceholder(variable_name=MEMORY_KEY)]\n",
    ")\n",
    "\n",
    "# Agent\n",
    "search_agent_memory = OpenAIFunctionsAgent(llm=llm, tools=tools, prompt=prompt, memory=memory)\n",
    "agent_executor_memory = AgentExecutor(agent=search_agent_memory, tools=tools, memory=memory, verbose=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "b4b2249a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'As of August 2023, the estimated population of Canada is approximately 38,781,291 people.'"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent_executor_memory.run(\"How many people live in Canada as of August, 2023?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "4d31b0cf",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'As of August 2023, the largest province in Canada is Ontario, with a population of over 15 million people.'"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent_executor_memory.run(\"What is the population of its largest provence as of August, 2023?\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3606c32a",
   "metadata": {},
   "source": [
    "Looking at the [trace](https://smith.langchain.com/public/4425a131-ec90-4aaa-acd8-5b880c7452a3/r), we can what is happening:\n",
    "\n",
    "* The chat history is passed to the LLMs\n",
    "* This gives context to `its` in `What is the population of its largest provence as of August, 2023?`\n",
    "* The LLM generates a function call to the search tool\n",
    "\n",
    "```\n",
    "function_call:\n",
    "  name: Search\n",
    "  arguments: |-\n",
    "    {\n",
    "      \"query\": \"population of largest province in Canada as of August 2023\"\n",
    "    }\n",
    "```\n",
    "\n",
    "* The search is executed\n",
    "* The results frum search are passed back to the LLM for synthesis into an answer\n",
    "\n",
    "![Image description](/img/oai_function_agent.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "384e37f8",
   "metadata": {},
   "source": [
    "### Long-term memory \n",
    "\n",
    "Vectorstores are great options for long-term memory."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "1489746c",
   "metadata": {},
   "outputs": [],
   "source": [
    "import faiss\n",
    "from langchain.vectorstores import FAISS\n",
    "from langchain.docstore import InMemoryDocstore\n",
    "from langchain.embeddings import OpenAIEmbeddings\n",
    "embedding_size = 1536\n",
    "embeddings_model = OpenAIEmbeddings()\n",
    "index = faiss.IndexFlatL2(embedding_size)\n",
    "vectorstore = FAISS(embeddings_model.embed_query, index, InMemoryDocstore({}), {})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9668ef5d",
   "metadata": {},
   "source": [
    "### Going deeper \n",
    "\n",
    "* Explore projects using long-term memory, such as [autonomous agents](/docs/use_cases/autonomous_agents/autonomous_agents)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "43fe2bb3",
   "metadata": {},
   "source": [
    "## Tools \n",
    "\n",
    "As mentioned above, LangChain has [many tools](https://github.com/langchain-ai/langchain/blob/master/libs/langchain/langchain/agents/load_tools.py) for Agents that we can load easily.\n",
    "\n",
    "We can also define [custom tools](/docs/modules/agents/tools/custom_tools). For example, here is a search tool.\n",
    "\n",
    "* The `Tool` dataclass wraps functions that accept a single string input and returns a string output.\n",
    "* `return_direct` determines whether to return the tool's output directly. \n",
    "* Setting this to `True` means that after the tool is called, the `AgentExecutor` will stop looping."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "7357e496",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.agents import Tool, tool\n",
    "from langchain.utilities import GoogleSearchAPIWrapper\n",
    "search = GoogleSearchAPIWrapper()\n",
    "search_tool = [\n",
    "    Tool(\n",
    "        name=\"Search\",\n",
    "        func=search.run,\n",
    "        description=\"useful for when you need to answer questions about current events\",\n",
    "        return_direct=True,\n",
    "    )\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c6ef5bfa",
   "metadata": {},
   "source": [
    "To make it easier to define custom tools, a `@tool` decorator is provided. \n",
    "\n",
    "This decorator can be used to quickly create a Tool from a simple function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "b6308c69",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Tool\n",
    "@tool\n",
    "def get_word_length(word: str) -> int:\n",
    "    \"\"\"Returns the length of a word.\"\"\"\n",
    "    return len(word)\n",
    "word_length_tool = [get_word_length]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "83c104d7",
   "metadata": {},
   "source": [
    "### Going deeper\n",
    "\n",
    "**Toolkits**\n",
    "\n",
    "* Toolkits are groups of tools needed to accomplish specific objectives.\n",
    "* [Here](/docs/integrations/toolkits/) are > 15 different agent toolkits (e.g., Gmail, Pandas, etc). \n",
    "\n",
    "Here is a simple way to think about agents vs the various chains covered in other docs:\n",
    "\n",
    "![Image description](/img/agents_vs_chains.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5eefe4a0",
   "metadata": {},
   "source": [
    "## Agents\n",
    "\n",
    "There's a number of [action agent types](docs/modules/agents/agent_types/) available in LangChain.\n",
    "\n",
    "* [ReAct](/docs/modules/agents/agent_types/react.html): This is the most general purpose action agent using the [ReAct framework](https://arxiv.org/pdf/2205.00445.pdf), which can work with [Docstores](/docs/modules/agents/agent_types/react_docstore.html) or [Multi-tool Inputs](/docs/modules/agents/agent_types/structured_chat.html).\n",
    "* [OpenAI functions](/docs/modules/agents/agent_types/openai_functions_agent.html): Designed to work with OpenAI function-calling models.\n",
    "* [Conversational](/docs/modules/agents/agent_types/chat_conversation_agent.html): This agent is designed to be used in conversational settings\n",
    "* [Self-ask with search](/docs/modules/agents/agent_types/self_ask_with_search.html): Designed to lookup factual answers to questions\n",
    "\n",
    "### OpenAI Functions agent\n",
    "\n",
    "As shown in Quickstart, let's continue with [`OpenAI functions` agent](/docs/modules/agents/agent_types/).\n",
    "\n",
    "This uses OpenAI models, which are fine-tuned to detect when a function should to be called.\n",
    "\n",
    "They will respond with the inputs that should be passed to the function.\n",
    "\n",
    "But, we can unpack it, first with a custom prompt:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "1c2deb4a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Memory\n",
    "MEMORY_KEY = \"chat_history\"\n",
    "memory = ConversationBufferMemory(memory_key=MEMORY_KEY, return_messages=True)\n",
    "\n",
    "# Prompt\n",
    "from langchain.schema import SystemMessage\n",
    "from langchain.agents import OpenAIFunctionsAgent\n",
    "system_message = SystemMessage(content=\"You are very powerful assistant, but bad at calculating lengths of words.\")\n",
    "prompt = OpenAIFunctionsAgent.create_prompt(\n",
    "    system_message=system_message,\n",
    "    extra_prompt_messages=[MessagesPlaceholder(variable_name=MEMORY_KEY)]\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee317a45",
   "metadata": {},
   "source": [
    "Define agent:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "460dab9b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Agent \n",
    "from langchain.agents import OpenAIFunctionsAgent\n",
    "agent = OpenAIFunctionsAgent(llm=llm, tools=word_length_tool, prompt=prompt)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "184e6c23",
   "metadata": {},
   "source": [
    "Run agent:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "f4f27d37",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'There are 5 letters in the word \"educa\".'"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Run the executer, including short-term memory we created\n",
    "agent_executor = AgentExecutor(agent=agent, tools=word_length_tool, memory=memory, verbose=False)\n",
    "agent_executor.run(\"how many letters in the word educa?\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e4d9217e",
   "metadata": {},
   "source": [
    "### ReAct agent\n",
    "\n",
    "[ReAct](https://arxiv.org/abs/2210.03629) agents are another popular framework.\n",
    "\n",
    "There has been lots of work on [LLM reasoning](https://ai.googleblog.com/2022/05/language-models-perform-reasoning-via.html), such as chain-of-thought prompting.\n",
    "\n",
    "There also has been work on LLM action-taking to generate obervations, such as [Say-Can](https://say-can.github.io/).\n",
    "\n",
    "ReAct marries these two ideas:\n",
    "\n",
    "![Image description](/img/ReAct.png)\n",
    " \n",
    "It uses a charecteristic `Thought`, `Action`, `Observation` [pattern in the output](https://lilianweng.github.io/posts/2023-06-23-agent/).\n",
    " \n",
    "We can use `initialize_agent` to create the ReAct agent from a list of available types [here](https://github.com/langchain-ai/langchain/blob/master/libs/langchain/langchain/agents/types.py):\n",
    "\n",
    "```\n",
    "* AgentType.ZERO_SHOT_REACT_DESCRIPTION: ZeroShotAgent\n",
    "* AgentType.REACT_DOCSTORE: ReActDocstoreAgent\n",
    "* AgentType.SELF_ASK_WITH_SEARCH: SelfAskWithSearchAgent\n",
    "* AgentType.CONVERSATIONAL_REACT_DESCRIPTION: ConversationalAgent\n",
    "* AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION: ChatAgent\n",
    "* AgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION: ConversationalChatAgent\n",
    "* AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION: StructuredChatAgent\n",
    "* AgentType.OPENAI_FUNCTIONS: OpenAIFunctionsAgent\n",
    "* AgentType.OPENAI_MULTI_FUNCTIONS: OpenAIMultiFunctionsAgent\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "85f033d3",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.agents import AgentType\n",
    "from langchain.agents import initialize_agent\n",
    "MEMORY_KEY = \"chat_history\"\n",
    "memory = ConversationBufferMemory(memory_key=MEMORY_KEY, return_messages=True)\n",
    "react_agent = initialize_agent(search_tool, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=False, memory=memory)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7d05a26c",
   "metadata": {},
   "outputs": [],
   "source": [
    "react_agent(\"How many people live in Canada as of August, 2023?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9b626dc5",
   "metadata": {},
   "outputs": [],
   "source": [
    "react_agent(\"What is the population of its largest provence as of August, 2023?\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4df0638",
   "metadata": {},
   "source": [
    "LangSmith can help us run diagnostics on the ReAct agent:\n",
    "\n",
    "The [ReAct agent](https://smith.langchain.com/public/3d8d0a15-d73f-44f3-9f81-037f7031c592/r) fails to pass chat history to LLM, gets wrong answer.\n",
    " \n",
    "The OAI functions agent does and [gets right answer](https://smith.langchain.com/public/4425a131-ec90-4aaa-acd8-5b880c7452a3/r), as shown above.\n",
    " \n",
    "Also the search tool result for [ReAct](https://smith.langchain.com/public/6473e608-fc9d-47c9-a8a4-2ef7f2801d82/r) is worse than [OAI](https://smith.langchain.com/public/4425a131-ec90-4aaa-acd8-5b880c7452a3/r/26b85fa9-e33a-4028-8650-1714f8b3db96).\n",
    "\n",
    "Collectivly, this tells us: carefully inspect Agent traces and tool outputs. \n",
    "\n",
    "As we saw with the [SQL use case](/docs/use_cases/qa_structured/sql), `ReAct agents` can be work very well for specific problems. \n",
    "\n",
    "But, as shown here, the result is degraded relative to what we see with the OpenAI agent."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5cde8f9a",
   "metadata": {},
   "source": [
    "### Custom\n",
    "\n",
    "Let's peel it back even further to define our own action agent.\n",
    "\n",
    "We can [create a custom agent](/docs/modules/agents/how_to/custom_agent.html) to unpack the central pieces:\n",
    "\n",
    "* `Tools`: The tools the agent has available to use\n",
    "* `Agent`: decides which action to take"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "3313f5cd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"The current population of Canada is 38,808,843 as of Tuesday, August 1, 2023, based on Worldometer elaboration of the latest United Nations data 1. Canada 2023\\xa0... Mar 22, 2023 ... Record-high population growth in the year 2022. Canada's population was estimated at 39,566,248 on January 1, 2023, after a record population\\xa0... Jun 19, 2023 ... As of June 16, 2023, there are now 40 million Canadians! This is a historic milestone for Canada and certainly cause for celebration. It is also\\xa0... Jun 28, 2023 ... Canada's population was estimated at 39,858,480 on April 1, 2023, an increase of 292,232 people (+0.7%) from January 1, 2023. The main driver of population growth is immigration, and to a lesser extent, natural growth. Demographics of Canada · Population pyramid of Canada in 2023. May 2, 2023 ... On January 1, 2023, Canada's population was estimated to be 39,566,248, following an unprecedented increase of 1,050,110 people between January\\xa0... Canada ranks 37th by population among countries of the world, comprising about 0.5% of the world's total, with over 40.0 million Canadians as of 2023. The current population of Canada in 2023 is 38,781,291, a 0.85% increase from 2022. The population of Canada in 2022 was 38,454,327, a 0.78% increase from 2021. Whether a given sub-nation is a province or a territory depends upon how its power and authority are derived. Provinces were given their power by the\\xa0... Jun 28, 2023 ... Index to the latest information from the Census of Population. ... 2023. Census in Brief: Multilingualism of Canadian households\\xa0...\""
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from typing import List, Tuple, Any, Union\n",
    "from langchain.schema import AgentAction, AgentFinish\n",
    "from langchain.agents import Tool, AgentExecutor, BaseSingleActionAgent\n",
    "\n",
    "class FakeAgent(BaseSingleActionAgent):\n",
    "    \"\"\"Fake Custom Agent.\"\"\"\n",
    "\n",
    "    @property\n",
    "    def input_keys(self):\n",
    "        return [\"input\"]\n",
    "\n",
    "    def plan(\n",
    "        self, intermediate_steps: List[Tuple[AgentAction, str]], **kwargs: Any\n",
    "    ) -> Union[AgentAction, AgentFinish]:\n",
    "        \"\"\"Given input, decided what to do.\n",
    "\n",
    "        Args:\n",
    "            intermediate_steps: Steps the LLM has taken to date,\n",
    "                along with observations\n",
    "            **kwargs: User inputs.\n",
    "\n",
    "        Returns:\n",
    "            Action specifying what tool to use.\n",
    "        \"\"\"\n",
    "        return AgentAction(tool=\"Search\", tool_input=kwargs[\"input\"], log=\"\")\n",
    "\n",
    "    async def aplan(\n",
    "        self, intermediate_steps: List[Tuple[AgentAction, str]], **kwargs: Any\n",
    "    ) -> Union[AgentAction, AgentFinish]:\n",
    "        \"\"\"Given input, decided what to do.\n",
    "\n",
    "        Args:\n",
    "            intermediate_steps: Steps the LLM has taken to date,\n",
    "                along with observations\n",
    "            **kwargs: User inputs.\n",
    "\n",
    "        Returns:\n",
    "            Action specifying what tool to use.\n",
    "        \"\"\"\n",
    "        return AgentAction(tool=\"Search\", tool_input=kwargs[\"input\"], log=\"\")\n",
    "    \n",
    "fake_agent = FakeAgent()\n",
    "fake_agent_executor = AgentExecutor.from_agent_and_tools(agent=fake_agent, \n",
    "                                                         tools=search_tool, \n",
    "                                                         verbose=False)\n",
    "\n",
    "fake_agent_executor.run(\"How many people live in canada as of 2023?\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1335f0c6",
   "metadata": {},
   "source": [
    "## Runtime\n",
    "\n",
    "The `AgentExecutor` class is the main agent runtime supported by LangChain. \n",
    "\n",
    "However, there are other, more experimental runtimes for `autonomous_agents`:\n",
    " \n",
    "* Plan-and-execute Agent\n",
    "* Baby AGI\n",
    "* Auto GPT\n",
    "\n",
    "Explore more about:\n",
    "\n",
    "* [`Simulation agents`](/docs/modules/agents/agent_use_cases/agent_simulations): Designed for role-play often in simulated enviorment (e.g., Generative Agents, CAMEL).\n",
    "* [`Autonomous agents`](/docs/modules/agents/agent_use_cases/autonomous_agents): Designed for indepdent execution towards long term goals (e.g., BabyAGI, Auto-GPT).\n",
    "\n"
   ]
  }
 ],
 "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.9.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
