{
 "cells": [
  {
   "cell_type": "raw",
   "id": "2aca8168-62ec-4bba-93f0-73da08cd1920",
   "metadata": {},
   "source": [
    "---\n",
    "sidebar_position: 1\n",
    "title: Summarization\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cf13f702",
   "metadata": {},
   "source": [
    "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langchain-ai/langchain/blob/master/docs/docs/use_cases/summarization.ipynb)\n",
    "\n",
    "## Use case\n",
    "\n",
    "Suppose you have a set of documents (PDFs, Notion pages, customer questions, etc.) and you want to summarize the content. \n",
    "\n",
    "LLMs are a great tool for this given their proficiency in understanding and synthesizing text.\n",
    "\n",
    "In this walkthrough we'll go over how to perform document summarization using LLMs."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e233997",
   "metadata": {},
   "source": [
    "![Image description](/img/summarization_use_case_1.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4715b4ff",
   "metadata": {
    "jp-MarkdownHeadingCollapsed": true
   },
   "source": [
    "## Overview\n",
    "\n",
    "A central question for building a summarizer is how to pass your documents into the LLM's context window. Two common approaches for this are:\n",
    "\n",
    "1. `Stuff`: Simply \"stuff\" all your documents into a single prompt. This is the simplest approach (see [here](/docs/modules/chains/document/stuff) for more on the `StuffDocumentsChains`, which is used for this method).\n",
    "\n",
    "2. `Map-reduce`: Summarize each document on it's own in a \"map\" step and then \"reduce\" the summaries into a final summary (see [here](/docs/modules/chains/document/map_reduce) for more on the `MapReduceDocumentsChain`, which is used for this method)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "08ec66bc",
   "metadata": {},
   "source": [
    "![Image description](/img/summarization_use_case_2.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bea785ac",
   "metadata": {},
   "source": [
    "## Quickstart\n",
    "\n",
    "To give you a sneak preview, either pipeline can be wrapped in a single object: `load_summarize_chain`. \n",
    "\n",
    "Suppose we want to summarize a blog post. We can create this in a few lines of code.\n",
    "\n",
    "First set environment variables and install packages:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "578d6a90",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: openai in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (0.27.8)\n",
      "Requirement already satisfied: tiktoken in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (0.4.0)\n",
      "Requirement already satisfied: chromadb in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (0.4.4)\n",
      "Requirement already satisfied: langchain in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (0.0.299)\n",
      "Requirement already satisfied: requests>=2.20 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from openai) (2.31.0)\n",
      "Requirement already satisfied: tqdm in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from openai) (4.64.1)\n",
      "Requirement already satisfied: aiohttp in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from openai) (3.8.5)\n",
      "Requirement already satisfied: regex>=2022.1.18 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from tiktoken) (2023.6.3)\n",
      "Requirement already satisfied: pydantic<2.0,>=1.9 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from chromadb) (1.10.12)\n",
      "Requirement already satisfied: chroma-hnswlib==0.7.2 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from chromadb) (0.7.2)\n",
      "Requirement already satisfied: fastapi<0.100.0,>=0.95.2 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from chromadb) (0.99.1)\n",
      "Requirement already satisfied: uvicorn[standard]>=0.18.3 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from chromadb) (0.23.2)\n",
      "Requirement already satisfied: numpy>=1.21.6 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from chromadb) (1.24.4)\n",
      "Requirement already satisfied: posthog>=2.4.0 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from chromadb) (3.0.1)\n",
      "Requirement already satisfied: typing-extensions>=4.5.0 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from chromadb) (4.7.1)\n",
      "Requirement already satisfied: pulsar-client>=3.1.0 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from chromadb) (3.2.0)\n",
      "Requirement already satisfied: onnxruntime>=1.14.1 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from chromadb) (1.15.1)\n",
      "Requirement already satisfied: tokenizers>=0.13.2 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from chromadb) (0.13.3)\n",
      "Requirement already satisfied: pypika>=0.48.9 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from chromadb) (0.48.9)\n",
      "Collecting tqdm (from openai)\n",
      "  Obtaining dependency information for tqdm from https://files.pythonhosted.org/packages/00/e5/f12a80907d0884e6dff9c16d0c0114d81b8cd07dc3ae54c5e962cc83037e/tqdm-4.66.1-py3-none-any.whl.metadata\n",
      "  Downloading tqdm-4.66.1-py3-none-any.whl.metadata (57 kB)\n",
      "\u001b[2K     \u001b[38;2;114;156;31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m57.6/57.6 kB\u001b[0m \u001b[31m2.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[?25hRequirement already satisfied: overrides>=7.3.1 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from chromadb) (7.4.0)\n",
      "Requirement already satisfied: importlib-resources in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from chromadb) (6.0.0)\n",
      "Requirement already satisfied: PyYAML>=5.3 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from langchain) (6.0.1)\n",
      "Requirement already satisfied: SQLAlchemy<3,>=1.4 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from langchain) (2.0.20)\n",
      "Requirement already satisfied: anyio<4.0 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from langchain) (3.7.1)\n",
      "Requirement already satisfied: async-timeout<5.0.0,>=4.0.0 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from langchain) (4.0.3)\n",
      "Requirement already satisfied: dataclasses-json<0.7,>=0.5.7 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from langchain) (0.5.9)\n",
      "Requirement already satisfied: jsonpatch<2.0,>=1.33 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from langchain) (1.33)\n",
      "Requirement already satisfied: langsmith<0.1.0,>=0.0.38 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from langchain) (0.0.42)\n",
      "Requirement already satisfied: numexpr<3.0.0,>=2.8.4 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from langchain) (2.8.5)\n",
      "Requirement already satisfied: tenacity<9.0.0,>=8.1.0 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from langchain) (8.2.3)\n",
      "Requirement already satisfied: attrs>=17.3.0 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from aiohttp->openai) (23.1.0)\n",
      "Requirement already satisfied: charset-normalizer<4.0,>=2.0 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from aiohttp->openai) (3.2.0)\n",
      "Requirement already satisfied: multidict<7.0,>=4.5 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from aiohttp->openai) (6.0.4)\n",
      "Requirement already satisfied: yarl<2.0,>=1.0 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from aiohttp->openai) (1.9.2)\n",
      "Requirement already satisfied: frozenlist>=1.1.1 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from aiohttp->openai) (1.4.0)\n",
      "Requirement already satisfied: aiosignal>=1.1.2 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from aiohttp->openai) (1.3.1)\n",
      "Requirement already satisfied: idna>=2.8 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from anyio<4.0->langchain) (3.4)\n",
      "Requirement already satisfied: sniffio>=1.1 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from anyio<4.0->langchain) (1.3.0)\n",
      "Requirement already satisfied: exceptiongroup in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from anyio<4.0->langchain) (1.1.3)\n",
      "Requirement already satisfied: marshmallow<4.0.0,>=3.3.0 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from dataclasses-json<0.7,>=0.5.7->langchain) (3.20.1)\n",
      "Requirement already satisfied: marshmallow-enum<2.0.0,>=1.5.1 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from dataclasses-json<0.7,>=0.5.7->langchain) (1.5.1)\n",
      "Requirement already satisfied: typing-inspect>=0.4.0 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from dataclasses-json<0.7,>=0.5.7->langchain) (0.9.0)\n",
      "Requirement already satisfied: starlette<0.28.0,>=0.27.0 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from fastapi<0.100.0,>=0.95.2->chromadb) (0.27.0)\n",
      "Requirement already satisfied: jsonpointer>=1.9 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from jsonpatch<2.0,>=1.33->langchain) (2.4)\n",
      "Requirement already satisfied: coloredlogs in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from onnxruntime>=1.14.1->chromadb) (15.0.1)\n",
      "Requirement already satisfied: flatbuffers in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from onnxruntime>=1.14.1->chromadb) (23.5.26)\n",
      "Requirement already satisfied: packaging in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from onnxruntime>=1.14.1->chromadb) (23.1)\n",
      "Requirement already satisfied: protobuf in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from onnxruntime>=1.14.1->chromadb) (4.23.4)\n",
      "Requirement already satisfied: sympy in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from onnxruntime>=1.14.1->chromadb) (1.12)\n",
      "Requirement already satisfied: six>=1.5 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from posthog>=2.4.0->chromadb) (1.16.0)\n",
      "Requirement already satisfied: monotonic>=1.5 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from posthog>=2.4.0->chromadb) (1.6)\n",
      "Requirement already satisfied: backoff>=1.10.0 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from posthog>=2.4.0->chromadb) (2.2.1)\n",
      "Requirement already satisfied: python-dateutil>2.1 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from posthog>=2.4.0->chromadb) (2.8.2)\n",
      "Requirement already satisfied: certifi in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from pulsar-client>=3.1.0->chromadb) (2023.7.22)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from requests>=2.20->openai) (1.26.16)\n",
      "Requirement already satisfied: click>=7.0 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (8.1.7)\n",
      "Requirement already satisfied: h11>=0.8 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (0.14.0)\n",
      "Requirement already satisfied: httptools>=0.5.0 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (0.6.0)\n",
      "Requirement already satisfied: python-dotenv>=0.13 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (1.0.0)\n",
      "Requirement already satisfied: uvloop!=0.15.0,!=0.15.1,>=0.14.0 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (0.17.0)\n",
      "Requirement already satisfied: watchfiles>=0.13 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (0.19.0)\n",
      "Requirement already satisfied: websockets>=10.4 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (11.0.3)\n",
      "Requirement already satisfied: zipp>=3.1.0 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from importlib-resources->chromadb) (3.16.2)\n",
      "Requirement already satisfied: mypy-extensions>=0.3.0 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from typing-inspect>=0.4.0->dataclasses-json<0.7,>=0.5.7->langchain) (1.0.0)\n",
      "Requirement already satisfied: humanfriendly>=9.1 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from coloredlogs->onnxruntime>=1.14.1->chromadb) (10.0)\n",
      "Requirement already satisfied: mpmath>=0.19 in /Users/bagatur/langchain/.venv/lib/python3.9/site-packages (from sympy->onnxruntime>=1.14.1->chromadb) (1.3.0)\n",
      "Using cached tqdm-4.66.1-py3-none-any.whl (78 kB)\n",
      "Installing collected packages: tqdm\n",
      "  Attempting uninstall: tqdm\n",
      "    Found existing installation: tqdm 4.64.1\n",
      "    Uninstalling tqdm-4.64.1:\n",
      "      Successfully uninstalled tqdm-4.64.1\n",
      "\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n",
      "clarifai 9.8.1 requires tqdm==4.64.1, but you have tqdm 4.66.1 which is incompatible.\u001b[0m\u001b[31m\n",
      "\u001b[0mSuccessfully installed tqdm-4.66.1\n"
     ]
    }
   ],
   "source": [
    "!pip install openai tiktoken chromadb langchain\n",
    "\n",
    "# Set env var OPENAI_API_KEY or load from a .env file\n",
    "# import dotenv\n",
    "\n",
    "# dotenv.load_dotenv()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "36138740",
   "metadata": {},
   "source": [
    "We can use `chain_type=\"stuff\"`, especially if using larger context window models such as:\n",
    "\n",
    "* 16k token OpenAI `gpt-3.5-turbo-16k` \n",
    "* 100k token Anthropic [Claude-2](https://www.anthropic.com/index/claude-2)\n",
    "\n",
    "We can also supply `chain_type=\"map_reduce\"` or `chain_type=\"refine\"` (read more [here](/docs/modules/chains/document/refine))."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "fd271681",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'The article discusses the concept of building autonomous agents powered by large language models (LLMs). It explores the components of such agents, including planning, memory, and tool use. The article provides case studies and proof-of-concept examples of LLM-powered agents in various domains. It also highlights the challenges and limitations of using LLMs in agent systems.'"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.chains.summarize import load_summarize_chain\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "from langchain.document_loaders import WebBaseLoader\n",
    "\n",
    "loader = WebBaseLoader(\"https://lilianweng.github.io/posts/2023-06-23-agent/\")\n",
    "docs = loader.load()\n",
    "\n",
    "llm = ChatOpenAI(temperature=0, model_name=\"gpt-3.5-turbo-16k\")\n",
    "chain = load_summarize_chain(llm, chain_type=\"stuff\")\n",
    "\n",
    "chain.run(docs)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "615b36e1",
   "metadata": {},
   "source": [
    "## Option 1. Stuff\n",
    "\n",
    "When we use `load_summarize_chain` with `chain_type=\"stuff\"`, we will use the [StuffDocumentsChain](/docs/modules/chains/document/stuff).\n",
    "\n",
    "The chain will take a list of documents, inserts them all into a prompt, and passes that prompt to an LLM:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "ef45585d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The article discusses the concept of building autonomous agents powered by large language models (LLMs). It explores the components of such agents, including planning, memory, and tool use. The article provides case studies and proof-of-concept examples of LLM-powered agents in various domains, such as scientific discovery and generative agents simulation. It also highlights the challenges and limitations of using LLMs in agent systems.\n"
     ]
    }
   ],
   "source": [
    "from langchain.chains.combine_documents.stuff import StuffDocumentsChain\n",
    "from langchain.chains.llm import LLMChain\n",
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "# Define prompt\n",
    "prompt_template = \"\"\"Write a concise summary of the following:\n",
    "\"{text}\"\n",
    "CONCISE SUMMARY:\"\"\"\n",
    "prompt = PromptTemplate.from_template(prompt_template)\n",
    "\n",
    "# Define LLM chain\n",
    "llm = ChatOpenAI(temperature=0, model_name=\"gpt-3.5-turbo-16k\")\n",
    "llm_chain = LLMChain(llm=llm, prompt=prompt)\n",
    "\n",
    "# Define StuffDocumentsChain\n",
    "stuff_chain = StuffDocumentsChain(llm_chain=llm_chain, document_variable_name=\"text\")\n",
    "\n",
    "docs = loader.load()\n",
    "print(stuff_chain.run(docs))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4e4e4a43",
   "metadata": {},
   "source": [
    "Great! We can see that we reproduce the earlier result using the `load_summarize_chain`.\n",
    "\n",
    "### Go deeper\n",
    "\n",
    "* You can easily customize the prompt. \n",
    "* You can easily try different LLMs, (e.g., [Claude](/docs/integrations/chat/anthropic)) via the `llm` parameter."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ad6cabee",
   "metadata": {},
   "source": [
    "## Option 2. Map-Reduce\n",
    "\n",
    "Let's unpack the map reduce approach. For this, we'll first map each document to an individual summary using an `LLMChain`. Then we'll use a `ReduceDocumentsChain` to combine those summaries into a single global summary.\n",
    " \n",
    "First, we specify the LLMChain to use for mapping each document to an individual summary:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "a1e6773c",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import MapReduceDocumentsChain, ReduceDocumentsChain\n",
    "from langchain.text_splitter import CharacterTextSplitter\n",
    "\n",
    "llm = ChatOpenAI(temperature=0)\n",
    "\n",
    "# Map\n",
    "map_template = \"\"\"The following is a set of documents\n",
    "{docs}\n",
    "Based on this list of docs, please identify the main themes \n",
    "Helpful Answer:\"\"\"\n",
    "map_prompt = PromptTemplate.from_template(map_template)\n",
    "map_chain = LLMChain(llm=llm, prompt=map_prompt)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "272ce8ce-919d-4ded-bbd5-a53a8a30bc66",
   "metadata": {},
   "source": [
    "We can also use the Prompt Hub to store and fetch prompts.\n",
    "\n",
    "This will work with your [LangSmith API key](https://docs.smith.langchain.com/).\n",
    "\n",
    "For example, see the map prompt [here](https://smith.langchain.com/hub/rlm/map-prompt)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "ce48b805-d98b-4e0f-8b9e-3b3e72cad3d3",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain import hub\n",
    "\n",
    "map_prompt = hub.pull(\"rlm/map-prompt\")\n",
    "map_chain = LLMChain(llm=llm, prompt=map_prompt)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bee3c331",
   "metadata": {},
   "source": [
    "The `ReduceDocumentsChain` handles taking the document mapping results and reducing them into a single output. It wraps a generic `CombineDocumentsChain` (like `StuffDocumentsChain`) but adds the ability to collapse documents before passing it to the `CombineDocumentsChain` if their cumulative size exceeds `token_max`. In this example, we can actually re-use our chain for combining our docs to also collapse our docs.\n",
    "\n",
    "So if the cumulative number of tokens in our mapped documents exceeds 4000 tokens, then we'll recursively pass in the documents in batches of < 4000 tokens to our `StuffDocumentsChain` to create batched summaries. And once those batched summaries are cumulatively less than 4000 tokens, we'll pass them all one last time to the `StuffDocumentsChain` to create the final summary."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "6a718890-99ab-439a-8f79-b9ae9c58ad24",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Reduce\n",
    "reduce_template = \"\"\"The following is set of summaries:\n",
    "{doc_summaries}\n",
    "Take these and distill it into a final, consolidated summary of the main themes. \n",
    "Helpful Answer:\"\"\"\n",
    "reduce_prompt = PromptTemplate.from_template(reduce_template)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "f189184a-673e-4530-8a6b-57b091045d87",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Note we can also get this from the prompt hub, as noted above\n",
    "reduce_prompt = hub.pull(\"rlm/map-prompt\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "c9d1da97-d590-4a96-82b2-8002d27fd7f6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ChatPromptTemplate(input_variables=['docs'], messages=[HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['docs'], template='The following is a set of documents:\\n{docs}\\nBased on this list of docs, please identify the main themes \\nHelpful Answer:'))])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "reduce_prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "1edb1b0d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Run chain\n",
    "reduce_chain = LLMChain(llm=llm, prompt=reduce_prompt)\n",
    "\n",
    "# Takes a list of documents, combines them into a single string, and passes this to an LLMChain\n",
    "combine_documents_chain = StuffDocumentsChain(\n",
    "    llm_chain=reduce_chain, document_variable_name=\"docs\"\n",
    ")\n",
    "\n",
    "# Combines and iteravely reduces the mapped documents\n",
    "reduce_documents_chain = ReduceDocumentsChain(\n",
    "    # This is final chain that is called.\n",
    "    combine_documents_chain=combine_documents_chain,\n",
    "    # If documents exceed context for `StuffDocumentsChain`\n",
    "    collapse_documents_chain=combine_documents_chain,\n",
    "    # The maximum number of tokens to group documents into.\n",
    "    token_max=4000,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fdb5ae1a",
   "metadata": {},
   "source": [
    "Combining our map and reduce chains into one:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "22f1cdc2",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Created a chunk of size 1003, which is longer than the specified 1000\n"
     ]
    }
   ],
   "source": [
    "# Combining documents by mapping a chain over them, then combining results\n",
    "map_reduce_chain = MapReduceDocumentsChain(\n",
    "    # Map chain\n",
    "    llm_chain=map_chain,\n",
    "    # Reduce chain\n",
    "    reduce_documents_chain=reduce_documents_chain,\n",
    "    # The variable name in the llm_chain to put the documents in\n",
    "    document_variable_name=\"docs\",\n",
    "    # Return the results of the map steps in the output\n",
    "    return_intermediate_steps=False,\n",
    ")\n",
    "\n",
    "text_splitter = CharacterTextSplitter.from_tiktoken_encoder(\n",
    "    chunk_size=1000, chunk_overlap=0\n",
    ")\n",
    "split_docs = text_splitter.split_documents(docs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "c7afb8c3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Based on the list of documents provided, the main themes can be identified as follows:\n",
      "\n",
      "1. LLM-powered autonomous agents: The documents discuss the concept of building agents with LLM as their core controller and highlight the potential of LLM beyond generating written content. They explore the capabilities of LLM as a general problem solver.\n",
      "\n",
      "2. Agent system overview: The documents provide an overview of the components that make up a LLM-powered autonomous agent system, including planning, memory, and tool use. Each component is explained in detail, highlighting its role in enhancing the agent's capabilities.\n",
      "\n",
      "3. Planning: The documents discuss how the agent breaks down large tasks into smaller subgoals and utilizes self-reflection to improve the quality of its actions and results.\n",
      "\n",
      "4. Memory: The documents explain the importance of both short-term and long-term memory in an agent system. Short-term memory is utilized for in-context learning, while long-term memory allows the agent to retain and recall information over extended periods.\n",
      "\n",
      "5. Tool use: The documents highlight the agent's ability to call external APIs for additional information and resources that may be missing from its pre-trained model weights. This includes accessing current information, executing code, and retrieving proprietary information.\n",
      "\n",
      "6. Case studies and proof-of-concept examples: The documents provide examples of how LLM-powered autonomous agents can be applied in various domains, such as scientific discovery and generative agent simulations. These case studies serve as examples of the capabilities and potential applications of such agents.\n",
      "\n",
      "7. Challenges: The documents acknowledge the challenges associated with building and utilizing LLM-powered autonomous agents, although specific challenges are not mentioned in the given set of documents.\n",
      "\n",
      "8. Citation and references: The documents include a citation and reference section, indicating that the information presented is based on existing research and sources.\n",
      "\n",
      "Overall, the main themes in the provided documents revolve around LLM-powered autonomous agents, their components and capabilities, planning, memory, tool use, case studies, and challenges.\n"
     ]
    }
   ],
   "source": [
    "print(map_reduce_chain.run(split_docs))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e62c21cf",
   "metadata": {},
   "source": [
    "### Go deeper\n",
    " \n",
    "**Customization** \n",
    "\n",
    "* As shown above, you can customize the LLMs and prompts for map and reduce stages.\n",
    "\n",
    "**Real-world use-case**\n",
    "\n",
    "* See [this blog post](https://blog.langchain.dev/llms-to-improve-documentation/) case-study on analyzing user interactions (questions about LangChain documentation)!  \n",
    "* The blog post and associated [repo](https://github.com/mendableai/QA_clustering) also introduce clustering as a means of summarization.\n",
    "* This opens up a third path beyond the `stuff` or `map-reduce` approaches that is worth considering.\n",
    "\n",
    "![Image description](/img/summarization_use_case_3.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f08ff365",
   "metadata": {},
   "source": [
    "## Option 3. Refine\n",
    " \n",
    "[Refine](/docs/modules/chains/document/refine) is similar to map-reduce:\n",
    "\n",
    "> The refine documents chain constructs a response by looping over the input documents and iteratively updating its answer. For each document, it passes all non-document inputs, the current document, and the latest intermediate answer to an LLM chain to get a new answer.\n",
    "\n",
    "This can be easily run with the `chain_type=\"refine\"` specified."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "de1dc10e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'The article explores the concept of building autonomous agents powered by large language models (LLMs) and their potential as problem solvers. It discusses different approaches to task decomposition, the integration of self-reflection into LLM-based agents, and the use of external classical planners for long-horizon planning. The new context introduces the Chain of Hindsight (CoH) approach and Algorithm Distillation (AD) for training models to produce better outputs. It also discusses different types of memory and the use of external memory for fast retrieval. The article explores the concept of tool use and introduces the MRKL system and experiments on fine-tuning LLMs to use external tools. It introduces HuggingGPT, a framework that uses ChatGPT as a task planner, and discusses the challenges of using LLM-powered agents in real-world scenarios. The article concludes with case studies on scientific discovery agents and the use of LLM-powered agents in anticancer drug discovery. It also introduces the concept of generative agents that combine LLM with memory, planning, and reflection mechanisms. The conversation samples provided discuss the implementation of a game architecture and the challenges in building LLM-centered agents. The article provides references to related research papers and resources for further exploration.'"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain = load_summarize_chain(llm, chain_type=\"refine\")\n",
    "chain.run(split_docs)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5b46f44d",
   "metadata": {},
   "source": [
    "It's also possible to supply a prompt and return intermediate steps."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "f86c8072",
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt_template = \"\"\"Write a concise summary of the following:\n",
    "{text}\n",
    "CONCISE SUMMARY:\"\"\"\n",
    "prompt = PromptTemplate.from_template(prompt_template)\n",
    "\n",
    "refine_template = (\n",
    "    \"Your job is to produce a final summary\\n\"\n",
    "    \"We have provided an existing summary up to a certain point: {existing_answer}\\n\"\n",
    "    \"We have the opportunity to refine the existing summary\"\n",
    "    \"(only if needed) with some more context below.\\n\"\n",
    "    \"------------\\n\"\n",
    "    \"{text}\\n\"\n",
    "    \"------------\\n\"\n",
    "    \"Given the new context, refine the original summary in Italian\"\n",
    "    \"If the context isn't useful, return the original summary.\"\n",
    ")\n",
    "refine_prompt = PromptTemplate.from_template(refine_template)\n",
    "chain = load_summarize_chain(\n",
    "    llm=llm,\n",
    "    chain_type=\"refine\",\n",
    "    question_prompt=prompt,\n",
    "    refine_prompt=refine_prompt,\n",
    "    return_intermediate_steps=True,\n",
    "    input_key=\"input_documents\",\n",
    "    output_key=\"output_text\",\n",
    ")\n",
    "result = chain({\"input_documents\": split_docs}, return_only_outputs=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "d9600b67-79d4-4f85-aba2-9fe81fa29f49",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Il presente articolo discute il concetto di costruire agenti autonomi utilizzando LLM (large language model) come controller principale. Esplora i diversi componenti di un sistema di agenti alimentato da LLM, tra cui la pianificazione, la memoria e l'uso degli strumenti. Dimostrazioni di concetto come AutoGPT mostrano il potenziale di LLM come risolutore generale di problemi. Approcci come Chain of Thought, Tree of Thoughts, LLM+P, ReAct e Reflexion consentono agli agenti autonomi di pianificare, riflettere su se stessi e migliorarsi iterativamente. Tuttavia, ci sono sfide da affrontare, come la limitata capacità di contesto che limita l'inclusione di informazioni storiche dettagliate e la difficoltà di pianificazione a lungo termine e decomposizione delle attività. Inoltre, l'affidabilità dell'interfaccia di linguaggio naturale tra LLM e componenti esterni come la memoria e gli strumenti è incerta, poiché i LLM possono commettere errori di formattazione e mostrare comportamenti ribelli. Nonostante ciò, il sistema AutoGPT viene menzionato come esempio di dimostrazione di concetto che utilizza LLM come controller principale per agenti autonomi. Questo articolo fa riferimento a diverse fonti che esplorano approcci e applicazioni specifiche di LLM nell'ambito degli agenti autonomi.\n"
     ]
    }
   ],
   "source": [
    "print(result[\"output_text\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "5f91a8eb-daa5-4191-ace4-01765801db3e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "This article discusses the concept of building autonomous agents using LLM (large language model) as the core controller. The article explores the different components of an LLM-powered agent system, including planning, memory, and tool use. It also provides examples of proof-of-concept demos and highlights the potential of LLM as a general problem solver.\n",
      "\n",
      "Questo articolo discute del concetto di costruire agenti autonomi utilizzando LLM (large language model) come controller principale. L'articolo esplora i diversi componenti di un sistema di agenti alimentato da LLM, inclusa la pianificazione, la memoria e l'uso degli strumenti. Vengono forniti anche esempi di dimostrazioni di proof-of-concept e si evidenzia il potenziale di LLM come risolutore generale di problemi. Inoltre, vengono presentati approcci come Chain of Thought, Tree of Thoughts, LLM+P, ReAct e Reflexion che consentono agli agenti autonomi di pianificare, riflettere su se stessi e migliorare iterativamente.\n",
      "\n",
      "Questo articolo discute del concetto di costruire agenti autonomi utilizzando LLM (large language model) come controller principale. L'articolo esplora i diversi componenti di un sistema di agenti alimentato da LLM, inclusa la pianificazione, la memoria e l'uso degli strumenti. Vengono forniti anche esempi di dimostrazioni di proof-of-concept e si evidenzia il potenziale di LLM come risolutore generale di problemi. Inoltre, vengono presentati approcci come Chain of Thought, Tree of Thoughts, LLM+P, ReAct e Reflexion che consentono agli agenti autonomi di pianificare, riflettere su se stessi e migliorare iterativamente. Il nuovo contesto riguarda l'approccio Chain of Hindsight (CoH) che permette al modello di migliorare autonomamente i propri output attraverso un processo di apprendimento supervisionato. Viene anche presentato l'approccio Algorithm Distillation (AD) che applica lo stesso concetto alle traiettorie di apprendimento per compiti di reinforcement learning.\n"
     ]
    }
   ],
   "source": [
    "print(\"\\n\\n\".join(result[\"intermediate_steps\"][:3]))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d8a8398-a43c-4f14-933c-c0743ae6ec40",
   "metadata": {},
   "source": [
    "## Splitting and summarizing in a single chain\n",
    "For convenience, we can wrap both the text splitting of our long document and summarizing in a single `AnalyzeDocumentsChain`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "0ddd522e-30dc-4f6a-b993-c4f97e656c4f",
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "`run` not supported when there is not exactly one output key. Got ['output_text', 'intermediate_steps'].",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[17], line 4\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mlangchain\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mchains\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m AnalyzeDocumentChain\n\u001b[1;32m      3\u001b[0m summarize_document_chain \u001b[38;5;241m=\u001b[39m AnalyzeDocumentChain(combine_docs_chain\u001b[38;5;241m=\u001b[39mchain, text_splitter\u001b[38;5;241m=\u001b[39mtext_splitter)\n\u001b[0;32m----> 4\u001b[0m \u001b[43msummarize_document_chain\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdocs\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/langchain/libs/langchain/langchain/chains/base.py:496\u001b[0m, in \u001b[0;36mChain.run\u001b[0;34m(self, callbacks, tags, metadata, *args, **kwargs)\u001b[0m\n\u001b[1;32m    459\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Convenience method for executing chain.\u001b[39;00m\n\u001b[1;32m    460\u001b[0m \n\u001b[1;32m    461\u001b[0m \u001b[38;5;124;03mThe main difference between this method and `Chain.__call__` is that this\u001b[39;00m\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m    493\u001b[0m \u001b[38;5;124;03m        # -> \"The temperature in Boise is...\"\u001b[39;00m\n\u001b[1;32m    494\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m    495\u001b[0m \u001b[38;5;66;03m# Run at start to make sure this is possible/defined\u001b[39;00m\n\u001b[0;32m--> 496\u001b[0m _output_key \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_run_output_key\u001b[49m\n\u001b[1;32m    498\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m args \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m kwargs:\n\u001b[1;32m    499\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(args) \u001b[38;5;241m!=\u001b[39m \u001b[38;5;241m1\u001b[39m:\n",
      "File \u001b[0;32m~/langchain/libs/langchain/langchain/chains/base.py:445\u001b[0m, in \u001b[0;36mChain._run_output_key\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    442\u001b[0m \u001b[38;5;129m@property\u001b[39m\n\u001b[1;32m    443\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_run_output_key\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28mstr\u001b[39m:\n\u001b[1;32m    444\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39moutput_keys) \u001b[38;5;241m!=\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[0;32m--> 445\u001b[0m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m    446\u001b[0m             \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m`run` not supported when there is not exactly \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m    447\u001b[0m             \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mone output key. Got \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39moutput_keys\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m    448\u001b[0m         )\n\u001b[1;32m    449\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39moutput_keys[\u001b[38;5;241m0\u001b[39m]\n",
      "\u001b[0;31mValueError\u001b[0m: `run` not supported when there is not exactly one output key. Got ['output_text', 'intermediate_steps']."
     ]
    }
   ],
   "source": [
    "from langchain.chains import AnalyzeDocumentChain\n",
    "\n",
    "summarize_document_chain = AnalyzeDocumentChain(\n",
    "    combine_docs_chain=chain, text_splitter=text_splitter\n",
    ")\n",
    "summarize_document_chain.run(docs[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d8df14d0-d548-4a5d-b00a-f4cfd64f1076",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "poetry-venv",
   "language": "python",
   "name": "poetry-venv"
  },
  "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.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
