{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "2ac2115b",
   "metadata": {},
   "source": [
    "# Structured tool chat\n",
    "\n",
    "The structured tool chat agent is capable of using multi-input tools.\n",
    "\n",
    "Older agents are configured to specify an action input as a single string, but this agent can use the provided tools' `args_schema` to populate the action input.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "68d58093",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.agents import AgentType, initialize_agent\n",
    "from langchain.chat_models import ChatOpenAI"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9414475b",
   "metadata": {},
   "source": [
    "## Initialize Tools\n",
    "\n",
    "We will test the agent using a web browser"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "a990cea8",
   "metadata": {},
   "outputs": [],
   "source": [
    "# This import is required only for jupyter notebooks, since they have their own eventloop\n",
    "import nest_asyncio\n",
    "from langchain.agents.agent_toolkits import PlayWrightBrowserToolkit\n",
    "from langchain.tools.playwright.utils import (\n",
    "    create_async_playwright_browser,  # A synchronous browser is available, though it isn't compatible with jupyter.\n",
    ")\n",
    "\n",
    "nest_asyncio.apply()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "536fa92a",
   "metadata": {},
   "outputs": [],
   "source": [
    "!pip install playwright\n",
    "\n",
    "!playwright install"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "daa3d594",
   "metadata": {},
   "outputs": [],
   "source": [
    "async_browser = create_async_playwright_browser()\n",
    "browser_toolkit = PlayWrightBrowserToolkit.from_browser(async_browser=async_browser)\n",
    "tools = browser_toolkit.get_tools()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e3089aa8",
   "metadata": {},
   "source": [
    "## Use LCEL\n",
    "\n",
    "We can first construct this agent using LangChain Expression Language"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bf35a623",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain import hub"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "319e6c40",
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt = hub.pull(\"hwchase17/react-multi-input-json\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "38c6496f",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.tools.render import render_text_description_and_args"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "d25b216f",
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt = prompt.partial(\n",
    "    tools=render_text_description_and_args(tools),\n",
    "    tool_names=\", \".join([t.name for t in tools]),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "fffcad76",
   "metadata": {},
   "outputs": [],
   "source": [
    "llm = ChatOpenAI(temperature=0)\n",
    "llm_with_stop = llm.bind(stop=[\"Observation\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2ceceadb",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.agents.format_scratchpad import format_log_to_str\n",
    "from langchain.agents.output_parsers import JSONAgentOutputParser"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "d410855f",
   "metadata": {},
   "outputs": [],
   "source": [
    "agent = (\n",
    "    {\n",
    "        \"input\": lambda x: x[\"input\"],\n",
    "        \"agent_scratchpad\": lambda x: format_log_to_str(x[\"intermediate_steps\"]),\n",
    "    }\n",
    "    | prompt\n",
    "    | llm_with_stop\n",
    "    | JSONAgentOutputParser()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "470b0859",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.agents import AgentExecutor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "b62702b4",
   "metadata": {},
   "outputs": [],
   "source": [
    "agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "97c15ef5",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3mAction:\n",
      "```\n",
      "{\n",
      "  \"action\": \"navigate_browser\",\n",
      "  \"action_input\": {\n",
      "    \"url\": \"https://blog.langchain.dev\"\n",
      "  }\n",
      "}\n",
      "```\n",
      "\u001b[0m\u001b[33;1m\u001b[1;3mNavigating to https://blog.langchain.dev returned status code 200\u001b[0m\u001b[32;1m\u001b[1;3mAction:\n",
      "```\n",
      "{\n",
      "  \"action\": \"extract_text\",\n",
      "  \"action_input\": {}\n",
      "}\n",
      "```\n",
      "\n",
      "\u001b[0m\u001b[31;1m\u001b[1;3mLangChain LangChain Home GitHub Docs By LangChain Release Notes Write with Us Sign in Subscribe The official LangChain blog. Subscribe now Login Featured Posts Announcing LangChain Hub Using LangSmith to Support Fine-tuning Announcing LangSmith, a unified platform for debugging, testing, evaluating, and monitoring your LLM applications Sep 20 Peering Into the Soul of AI Decision-Making with LangSmith 10 min read Sep 20 LangChain + Docugami Webinar: Lessons from Deploying LLMs with LangSmith 3 min read Sep 18 TED AI Hackathon Kickoff (and projects we’d love to see) 2 min read Sep 12 How to Safely Query Enterprise Data with LangChain Agents + SQL + OpenAI + Gretel 6 min read Sep 12 OpaquePrompts x LangChain: Enhance the privacy of your LangChain application with just one code change 4 min read Load more LangChain © 2023 Sign up Powered by Ghost\u001b[0m\u001b[32;1m\u001b[1;3mAction:\n",
      "```\n",
      "{\n",
      "  \"action\": \"Final Answer\",\n",
      "  \"action_input\": \"The LangChain blog features posts on topics such as using LangSmith for fine-tuning, AI decision-making with LangSmith, deploying LLMs with LangSmith, and more. It also includes information on LangChain Hub and upcoming webinars. LangChain is a platform for debugging, testing, evaluating, and monitoring LLM applications.\"\n",
      "}\n",
      "```\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "The LangChain blog features posts on topics such as using LangSmith for fine-tuning, AI decision-making with LangSmith, deploying LLMs with LangSmith, and more. It also includes information on LangChain Hub and upcoming webinars. LangChain is a platform for debugging, testing, evaluating, and monitoring LLM applications.\n"
     ]
    }
   ],
   "source": [
    "response = await agent_executor.ainvoke(\n",
    "    {\"input\": \"Browse to blog.langchain.dev and summarize the text, please.\"}\n",
    ")\n",
    "print(response[\"output\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "62fc1fdf",
   "metadata": {},
   "source": [
    "## Use off the shelf agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "4b585225",
   "metadata": {},
   "outputs": [],
   "source": [
    "llm = ChatOpenAI(temperature=0)  # Also works well with Anthropic models\n",
    "agent_chain = initialize_agent(\n",
    "    tools,\n",
    "    llm,\n",
    "    agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION,\n",
    "    verbose=True,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "c2a9e29c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3mAction:\n",
      "```\n",
      "{\n",
      "  \"action\": \"navigate_browser\",\n",
      "  \"action_input\": {\n",
      "    \"url\": \"https://blog.langchain.dev\"\n",
      "  }\n",
      "}\n",
      "```\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3mNavigating to https://blog.langchain.dev returned status code 200\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3mI have successfully navigated to the blog.langchain.dev website. Now I need to extract the text from the webpage to summarize it.\n",
      "Action:\n",
      "```\n",
      "{\n",
      "  \"action\": \"extract_text\",\n",
      "  \"action_input\": {}\n",
      "}\n",
      "```\u001b[0m\n",
      "Observation: \u001b[31;1m\u001b[1;3mLangChain LangChain Home GitHub Docs By LangChain Release Notes Write with Us Sign in Subscribe The official LangChain blog. Subscribe now Login Featured Posts Announcing LangChain Hub Using LangSmith to Support Fine-tuning Announcing LangSmith, a unified platform for debugging, testing, evaluating, and monitoring your LLM applications Sep 20 Peering Into the Soul of AI Decision-Making with LangSmith 10 min read Sep 20 LangChain + Docugami Webinar: Lessons from Deploying LLMs with LangSmith 3 min read Sep 18 TED AI Hackathon Kickoff (and projects we’d love to see) 2 min read Sep 12 How to Safely Query Enterprise Data with LangChain Agents + SQL + OpenAI + Gretel 6 min read Sep 12 OpaquePrompts x LangChain: Enhance the privacy of your LangChain application with just one code change 4 min read Load more LangChain © 2023 Sign up Powered by Ghost\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3mI have successfully navigated to the blog.langchain.dev website. The text on the webpage includes featured posts such as \"Announcing LangChain Hub,\" \"Using LangSmith to Support Fine-tuning,\" \"Peering Into the Soul of AI Decision-Making with LangSmith,\" \"LangChain + Docugami Webinar: Lessons from Deploying LLMs with LangSmith,\" \"TED AI Hackathon Kickoff (and projects we’d love to see),\" \"How to Safely Query Enterprise Data with LangChain Agents + SQL + OpenAI + Gretel,\" and \"OpaquePrompts x LangChain: Enhance the privacy of your LangChain application with just one code change.\" There are also links to other pages on the website.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "I have successfully navigated to the blog.langchain.dev website. The text on the webpage includes featured posts such as \"Announcing LangChain Hub,\" \"Using LangSmith to Support Fine-tuning,\" \"Peering Into the Soul of AI Decision-Making with LangSmith,\" \"LangChain + Docugami Webinar: Lessons from Deploying LLMs with LangSmith,\" \"TED AI Hackathon Kickoff (and projects we’d love to see),\" \"How to Safely Query Enterprise Data with LangChain Agents + SQL + OpenAI + Gretel,\" and \"OpaquePrompts x LangChain: Enhance the privacy of your LangChain application with just one code change.\" There are also links to other pages on the website.\n"
     ]
    }
   ],
   "source": [
    "response = await agent_chain.ainvoke(\n",
    "    {\"input\": \"Browse to blog.langchain.dev and summarize the text, please.\"}\n",
    ")\n",
    "print(response[\"output\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fc3ce811",
   "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
}
