{
 "cells": [
  {
   "cell_type": "raw",
   "id": "877102d1-02ea-4fa3-8ec7-a08e242b95b3",
   "metadata": {},
   "source": [
    "---\n",
    "sidebar_position: 2\n",
    "title: Multiple chains\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f2bf8d3",
   "metadata": {},
   "source": [
    "Runnables can easily be used to string together multiple Chains"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "d65d4e9e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'El país donde se encuentra la ciudad de Honolulu, donde nació Barack Obama, el 44º Presidente de los Estados Unidos, es Estados Unidos. Honolulu se encuentra en la isla de Oahu, en el estado de Hawái.'"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from operator import itemgetter\n",
    "\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "from langchain.prompts import ChatPromptTemplate\n",
    "from langchain.schema import StrOutputParser\n",
    "\n",
    "prompt1 = ChatPromptTemplate.from_template(\"what is the city {person} is from?\")\n",
    "prompt2 = ChatPromptTemplate.from_template(\"what country is the city {city} in? respond in {language}\")\n",
    "\n",
    "model = ChatOpenAI()\n",
    "\n",
    "chain1 = prompt1 | model | StrOutputParser()\n",
    "\n",
    "chain2 = {\"city\": chain1, \"language\": itemgetter(\"language\")} | prompt2 | model | StrOutputParser()\n",
    "\n",
    "chain2.invoke({\"person\": \"obama\", \"language\": \"spanish\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "878f8176",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.schema.runnable import RunnableMap, RunnablePassthrough\n",
    "\n",
    "prompt1 = ChatPromptTemplate.from_template(\"generate a {attribute} color. Return the name of the color and nothing else:\")\n",
    "prompt2 = ChatPromptTemplate.from_template(\"what is a fruit of color: {color}. Return the name of the fruit and nothing else:\")\n",
    "prompt3 = ChatPromptTemplate.from_template(\"what is a country with a flag that has the color: {color}. Return the name of the country and nothing else:\")\n",
    "prompt4 = ChatPromptTemplate.from_template(\"What is the color of {fruit} and the flag of {country}?\")\n",
    "\n",
    "model_parser = model | StrOutputParser()\n",
    "\n",
    "color_generator = {\"attribute\": RunnablePassthrough()} | prompt1 | {\"color\": model_parser}\n",
    "color_to_fruit = prompt2 | model_parser\n",
    "color_to_country = prompt3 | model_parser\n",
    "question_generator = color_generator | {\"fruit\": color_to_fruit, \"country\": color_to_country} | prompt4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "d621a870",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ChatPromptValue(messages=[HumanMessage(content='What is the color of strawberry and the flag of China?', additional_kwargs={}, example=False)])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "question_generator.invoke({\"warm\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "b4a9812b-bead-4fd9-ae27-0b8be57e5dc1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='The color of an apple is typically red or green. The flag of China is predominantly red with a large yellow star in the upper left corner and four smaller yellow stars surrounding it.', additional_kwargs={}, example=False)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prompt = question_generator.invoke({\"warm\"})\n",
    "model.invoke(prompt)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6d75a313-f1c8-4e94-9a17-24e0bf4a2bdc",
   "metadata": {},
   "source": [
    "### Branching and Merging\n",
    "\n",
    "You may want the output of one component to be processed by 2 or more other components. [RunnableMaps](https://api.python.langchain.com/en/latest/schema/langchain.schema.runnable.base.RunnableMap.html) let you split or fork the chain so multiple components can process the input in parallel. Later, other components can join or merge the results to synthesize a final response. This type of chain creates a computation graph that looks like the following:\n",
    "\n",
    "```text\n",
    "     Input\n",
    "      / \\\n",
    "     /   \\\n",
    " Branch1 Branch2\n",
    "     \\   /\n",
    "      \\ /\n",
    "      Combine\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "247fa0bd-4596-4063-8cb3-1d7fc119d982",
   "metadata": {},
   "outputs": [],
   "source": [
    "planner = (\n",
    "    ChatPromptTemplate.from_template(\n",
    "        \"Generate an argument about: {input}\"\n",
    "    )\n",
    "    | ChatOpenAI()\n",
    "    | StrOutputParser()\n",
    "    | {\"base_response\": RunnablePassthrough()}\n",
    ")\n",
    "\n",
    "arguments_for = (\n",
    "    ChatPromptTemplate.from_template(\n",
    "        \"List the pros or positive aspects of {base_response}\"\n",
    "    )\n",
    "    | ChatOpenAI()\n",
    "    | StrOutputParser()\n",
    ")\n",
    "arguments_against =  (\n",
    "    ChatPromptTemplate.from_template(\n",
    "        \"List the cons or negative aspects of {base_response}\"\n",
    "    )\n",
    "    | ChatOpenAI()\n",
    "    | StrOutputParser()\n",
    ")\n",
    "\n",
    "final_responder = (\n",
    "    ChatPromptTemplate.from_messages(\n",
    "        [\n",
    "            (\"ai\", \"{original_response}\"),\n",
    "            (\"human\", \"Pros:\\n{results_1}\\n\\nCons:\\n{results_2}\"),\n",
    "            (\"system\", \"Generate a final response given the critique\"),\n",
    "        ]\n",
    "    )\n",
    "    | ChatOpenAI()\n",
    "    | StrOutputParser()\n",
    ")\n",
    "\n",
    "chain = (\n",
    "    planner \n",
    "    | {\n",
    "        \"results_1\": arguments_for,\n",
    "        \"results_2\": arguments_against,\n",
    "        \"original_response\": itemgetter(\"base_response\"),\n",
    "    }\n",
    "    | final_responder\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "2564f310-0674-4bb1-9c4e-d7848ca73511",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'While Scrum has its potential cons and challenges, many organizations have successfully embraced and implemented this project management framework to great effect. The cons mentioned above can be mitigated or overcome with proper training, support, and a commitment to continuous improvement. It is also important to note that not all cons may be applicable to every organization or project.\\n\\nFor example, while Scrum may be complex initially, with proper training and guidance, teams can quickly grasp the concepts and practices. The lack of predictability can be mitigated by implementing techniques such as velocity tracking and release planning. The limited documentation can be addressed by maintaining a balance between lightweight documentation and clear communication among team members. The dependency on team collaboration can be improved through effective communication channels and regular team-building activities.\\n\\nScrum can be scaled and adapted to larger projects by using frameworks like Scrum of Scrums or LeSS (Large Scale Scrum). Concerns about speed versus quality can be addressed by incorporating quality assurance practices, such as continuous integration and automated testing, into the Scrum process. Scope creep can be managed by having a well-defined and prioritized product backlog, and a strong product owner can be developed through training and mentorship.\\n\\nResistance to change can be overcome by providing proper education and communication to stakeholders and involving them in the decision-making process. Ultimately, the cons of Scrum can be seen as opportunities for growth and improvement, and with the right mindset and support, they can be effectively managed.\\n\\nIn conclusion, while Scrum may have its challenges and potential cons, the benefits and advantages it offers in terms of collaboration, flexibility, adaptability, transparency, and customer satisfaction make it a widely adopted and successful project management framework. With proper implementation and continuous improvement, organizations can leverage Scrum to drive innovation, efficiency, and project success.'"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.invoke({\"input\": \"scrum\"})"
   ]
  }
 ],
 "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
}
