{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "f26a4ba9-f29b-452a-85c0-3b2a188f2348",
   "metadata": {},
   "source": [
    "# LangChain Expression Language Cheatsheet\n",
    "\n",
    "This is a quick reference for all the most important LCEL primitives. For more advanced usage see the [LCEL how-to guides](/docs/how_to/#langchain-expression-language-lcel) and the [full API reference](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html).\n",
    "\n",
    "### Invoke a runnable\n",
    "#### [Runnable.invoke()](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.invoke) / [Runnable.ainvoke()](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.ainvoke)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "b3ac3ad1-3c0e-4279-8fde-125809af9d2a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'5'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.runnables import RunnableLambda\n",
    "\n",
    "runnable = RunnableLambda(lambda x: str(x))\n",
    "runnable.invoke(5)\n",
    "\n",
    "# Async variant:\n",
    "# await runnable.ainvoke(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aa74c79a-1bf6-4015-84bc-d0df6e6a8433",
   "metadata": {},
   "source": [
    "### Batch a runnable\n",
    "#### [Runnable.batch()](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.batch) / [Runnable.abatch()](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.abatch)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "3a184890-da09-4ff7-92f9-0d29ca571ae4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['7', '8', '9']"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.runnables import RunnableLambda\n",
    "\n",
    "runnable = RunnableLambda(lambda x: str(x))\n",
    "runnable.batch([7, 8, 9])\n",
    "\n",
    "# Async variant:\n",
    "# await runnable.abatch([7, 8, 9])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b716b97f-cb58-447a-bef5-96202563cd2d",
   "metadata": {},
   "source": [
    "### Stream a runnable\n",
    "#### [Runnable.stream()](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.stream) / [Runnable.astream()](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.astream)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "983aa18b-e44d-4603-aaea-94e1e2339001",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "2\n",
      "3\n",
      "4\n"
     ]
    }
   ],
   "source": [
    "from langchain_core.runnables import RunnableLambda\n",
    "\n",
    "\n",
    "def func(x):\n",
    "    for y in x:\n",
    "        yield str(y)\n",
    "\n",
    "\n",
    "runnable = RunnableLambda(func)\n",
    "\n",
    "for chunk in runnable.stream(range(5)):\n",
    "    print(chunk)\n",
    "\n",
    "# Async variant:\n",
    "# async for chunk in await runnable.astream(range(5)):\n",
    "#     print(chunk)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6dc6bd08-98f3-4df6-9758-08b443e4328b",
   "metadata": {},
   "source": [
    "### Compose runnables\n",
    "#### Pipe operator `|`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "4f744b0b-16ae-43f5-9856-789973457c96",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'foo': 2}, {'foo': 2}]"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.runnables import RunnableLambda\n",
    "\n",
    "runnable1 = RunnableLambda(lambda x: {\"foo\": x})\n",
    "runnable2 = RunnableLambda(lambda x: [x] * 2)\n",
    "\n",
    "chain = runnable1 | runnable2\n",
    "\n",
    "chain.invoke(2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b01e8694-f820-4457-a27a-7220f789bb2c",
   "metadata": {},
   "source": [
    "### Invoke runnables in parallel\n",
    "#### [RunnableParallel](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.RunnableParallel.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "89e509e5-a9a5-4e56-b6dd-c4f23543c3c8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'first': {'foo': 2}, 'second': [2, 2]}"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.runnables import RunnableLambda, RunnableParallel\n",
    "\n",
    "runnable1 = RunnableLambda(lambda x: {\"foo\": x})\n",
    "runnable2 = RunnableLambda(lambda x: [x] * 2)\n",
    "\n",
    "chain = RunnableParallel(first=runnable1, second=runnable2)\n",
    "\n",
    "chain.invoke(2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "103f350b-84b3-421f-b64f-c01575a422bf",
   "metadata": {},
   "source": [
    "### Turn any function into a runnable\n",
    "#### [RunnableLambda](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.RunnableLambda.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "a9c0e43a-8eb5-4985-ad95-43f12c3e05e9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "7"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.runnables import RunnableLambda\n",
    "\n",
    "\n",
    "def func(x):\n",
    "    return x + 5\n",
    "\n",
    "\n",
    "runnable = RunnableLambda(func)\n",
    "runnable.invoke(2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "20399b82-e417-403d-a53b-00f02a6ef2c6",
   "metadata": {},
   "source": [
    "### Merge input and output dicts\n",
    "#### [RunnablePassthrough.assign](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.passthrough.RunnablePassthrough.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "ab05d376-9abb-4f26-916a-9aea062e4817",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'foo': 10, 'bar': 17}"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.runnables import RunnableLambda, RunnablePassthrough\n",
    "\n",
    "runnable1 = RunnableLambda(lambda x: x[\"foo\"] + 7)\n",
    "\n",
    "chain = RunnablePassthrough.assign(bar=runnable1)\n",
    "\n",
    "chain.invoke({\"foo\": 10})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7f680f48-654a-44d1-86e3-13e1eb0955cb",
   "metadata": {},
   "source": [
    "### Include input dict in output dict\n",
    "#### [RunnablePassthrough](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.passthrough.RunnablePassthrough.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "3ec00283-e674-461e-a5d1-4876555a2a58",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'bar': 17, 'baz': {'foo': 10}}"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.runnables import (\n",
    "    RunnableLambda,\n",
    "    RunnableParallel,\n",
    "    RunnablePassthrough,\n",
    ")\n",
    "\n",
    "runnable1 = RunnableLambda(lambda x: x[\"foo\"] + 7)\n",
    "\n",
    "chain = RunnableParallel(bar=runnable1, baz=RunnablePassthrough())\n",
    "\n",
    "chain.invoke({\"foo\": 10})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "baa4e967-fcfd-4176-a720-6916fe0df130",
   "metadata": {},
   "source": [
    "### Add default invocation args\n",
    "#### [Runnable.bind](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.bind)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "6c03ce55-5258-4361-857e-d6785c968624",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'bar': 'hello', 'foo': 'bye'}"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from typing import Optional\n",
    "\n",
    "from langchain_core.runnables import RunnableLambda\n",
    "\n",
    "\n",
    "def func(main_arg: dict, other_arg: Optional[str] = None) -> dict:\n",
    "    if other_arg:\n",
    "        return {**main_arg, **{\"foo\": other_arg}}\n",
    "    return main_arg\n",
    "\n",
    "\n",
    "runnable1 = RunnableLambda(func)\n",
    "bound_runnable1 = runnable1.bind(other_arg=\"bye\")\n",
    "\n",
    "bound_runnable1.invoke({\"bar\": \"hello\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cad5e0af-007e-47aa-93d4-f06bd837c3fb",
   "metadata": {},
   "source": [
    "### Add fallbacks\n",
    "#### [Runnable.with_fallbacks](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.with_fallbacks)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "5d132d96-802b-4952-a6cc-2caaf4612d0a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'5foo'"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.runnables import RunnableLambda\n",
    "\n",
    "runnable1 = RunnableLambda(lambda x: x + \"foo\")\n",
    "runnable2 = RunnableLambda(lambda x: str(x) + \"foo\")\n",
    "\n",
    "chain = runnable1.with_fallbacks([runnable2])\n",
    "\n",
    "chain.invoke(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "809f6437-4e20-48b9-bdcb-7f9ea6463a19",
   "metadata": {},
   "source": [
    "### Add retries\n",
    "#### [Runnable.with_retry](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.with_retry)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "49a75c66-d335-4115-9d8f-ca07d69223c4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "attempt with counter=0\n",
      "attempt with counter=1\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "2.0"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.runnables import RunnableLambda\n",
    "\n",
    "counter = -1\n",
    "\n",
    "\n",
    "def func(x):\n",
    "    global counter\n",
    "    counter += 1\n",
    "    print(f\"attempt with {counter=}\")\n",
    "    return x / counter\n",
    "\n",
    "\n",
    "chain = RunnableLambda(func).with_retry(stop_after_attempt=2)\n",
    "\n",
    "chain.invoke(2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "741934ee-e97f-497d-b42f-371c79739a12",
   "metadata": {},
   "source": [
    "### Configure runnable execution\n",
    "#### [RunnableConfig](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.config.RunnableConfig.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "d85e357e-c125-4199-98d1-bd0db40e4ac0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'first': {'foo': 7}, 'second': [7, 7], 'third': '7'}"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.runnables import RunnableLambda, RunnableParallel\n",
    "\n",
    "runnable1 = RunnableLambda(lambda x: {\"foo\": x})\n",
    "runnable2 = RunnableLambda(lambda x: [x] * 2)\n",
    "runnable3 = RunnableLambda(lambda x: str(x))\n",
    "\n",
    "chain = RunnableParallel(first=runnable1, second=runnable2, third=runnable3)\n",
    "\n",
    "chain.invoke(7, config={\"max_concurrency\": 2})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8604edb4-4ffa-4cc7-89ba-e0c6947118ab",
   "metadata": {},
   "source": [
    "### Add default config to runnable\n",
    "#### [Runnable.with_config](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.with_config)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "dfe8306c-d77c-479a-90ae-464db2b62605",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'first': {'foo': 7}, 'second': [7, 7], 'third': '7'}"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.runnables import RunnableLambda, RunnableParallel\n",
    "\n",
    "runnable1 = RunnableLambda(lambda x: {\"foo\": x})\n",
    "runnable2 = RunnableLambda(lambda x: [x] * 2)\n",
    "runnable3 = RunnableLambda(lambda x: str(x))\n",
    "\n",
    "chain = RunnableParallel(first=runnable1, second=runnable2, third=runnable3)\n",
    "configured_chain = chain.with_config(max_concurrency=2)\n",
    "\n",
    "chain.invoke(7)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f3d3bb1-b4b3-4acd-9dd8-da114e514fff",
   "metadata": {},
   "source": [
    "### Make runnable attributes configurable\n",
    "#### [Runnable.with_configurable_fields](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.RunnableSerializable.html#langchain_core.runnables.base.RunnableSerializable.configurable_fields)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 110,
   "id": "ca265c51-6192-4b5d-bf4e-048b6630abc6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'not bar': 3}"
      ]
     },
     "execution_count": 110,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from typing import Any, Optional\n",
    "\n",
    "from langchain_core.runnables import (\n",
    "    ConfigurableField,\n",
    "    RunnableConfig,\n",
    "    RunnableSerializable,\n",
    ")\n",
    "\n",
    "\n",
    "class FooRunnable(RunnableSerializable[dict, dict]):\n",
    "    output_key: str\n",
    "\n",
    "    def invoke(\n",
    "        self, input: Any, config: Optional[RunnableConfig] = None, **kwargs: Any\n",
    "    ) -> list:\n",
    "        return self._call_with_config(self.subtract_seven, input, config, **kwargs)\n",
    "\n",
    "    def subtract_seven(self, input: dict) -> dict:\n",
    "        return {self.output_key: input[\"foo\"] - 7}\n",
    "\n",
    "\n",
    "runnable1 = FooRunnable(output_key=\"bar\")\n",
    "configurable_runnable1 = runnable1.configurable_fields(\n",
    "    output_key=ConfigurableField(id=\"output_key\")\n",
    ")\n",
    "\n",
    "configurable_runnable1.invoke(\n",
    "    {\"foo\": 10}, config={\"configurable\": {\"output_key\": \"not bar\"}}\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 111,
   "id": "e1cf0b01-dc03-40b7-9e0b-629895daa8e5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'bar': 3}"
      ]
     },
     "execution_count": 111,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "configurable_runnable1.invoke({\"foo\": 10})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c7b86f34-4098-4c43-9cde-407dc0e03c0d",
   "metadata": {},
   "source": [
    "### Make chain components configurable\n",
    "#### [Runnable.with_configurable_alternatives](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.RunnableSerializable.html#langchain_core.runnables.base.RunnableSerializable.configurable_alternatives)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 106,
   "id": "98acdc84-b395-4dee-a9c7-d2f88a2486e3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"{'foo': 7}\""
      ]
     },
     "execution_count": 106,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from typing import Any, Optional\n",
    "\n",
    "from langchain_core.runnables import RunnableConfig, RunnableLambda, RunnableParallel\n",
    "\n",
    "\n",
    "class ListRunnable(RunnableSerializable[Any, list]):\n",
    "    def invoke(\n",
    "        self, input: Any, config: Optional[RunnableConfig] = None, **kwargs: Any\n",
    "    ) -> list:\n",
    "        return self._call_with_config(self.listify, input, config, **kwargs)\n",
    "\n",
    "    def listify(self, input: Any) -> list:\n",
    "        return [input]\n",
    "\n",
    "\n",
    "class StrRunnable(RunnableSerializable[Any, str]):\n",
    "    def invoke(\n",
    "        self, input: Any, config: Optional[RunnableConfig] = None, **kwargs: Any\n",
    "    ) -> list:\n",
    "        return self._call_with_config(self.strify, input, config, **kwargs)\n",
    "\n",
    "    def strify(self, input: Any) -> str:\n",
    "        return str(input)\n",
    "\n",
    "\n",
    "runnable1 = RunnableLambda(lambda x: {\"foo\": x})\n",
    "\n",
    "configurable_runnable = ListRunnable().configurable_alternatives(\n",
    "    ConfigurableField(id=\"second_step\"), default_key=\"list\", string=StrRunnable()\n",
    ")\n",
    "chain = runnable1 | configurable_runnable\n",
    "\n",
    "chain.invoke(7, config={\"configurable\": {\"second_step\": \"string\"}})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 107,
   "id": "6e76f8dd-96e2-4b69-8e20-5a0f82c60c9f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'foo': 7}]"
      ]
     },
     "execution_count": 107,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.invoke(7)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "33249dee-14dc-4c72-b6ba-a3f10678ab9c",
   "metadata": {},
   "source": [
    "### Build a chain dynamically based on input"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "id": "4611b7ad-c29c-446c-8886-324bfd00eb41",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'foo': 7}"
      ]
     },
     "execution_count": 63,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.runnables import RunnableLambda, RunnableParallel\n",
    "\n",
    "runnable1 = RunnableLambda(lambda x: {\"foo\": x})\n",
    "runnable2 = RunnableLambda(lambda x: [x] * 2)\n",
    "\n",
    "chain = RunnableLambda(lambda x: runnable1 if x > 6 else runnable2)\n",
    "\n",
    "chain.invoke(7)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "id": "9655f494-2fba-4c26-a5d8-5683cc61e80d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[5, 5]"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.invoke(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f1263fe5-6561-419b-a936-687f8b274a5d",
   "metadata": {},
   "source": [
    "### Generate a stream of events\n",
    "#### [Runnable.astream_events](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.astream_events)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "b921264a-29e2-41eb-949c-f1bbabe63e54",
   "metadata": {},
   "outputs": [],
   "source": [
    "# | echo: false\n",
    "\n",
    "import nest_asyncio\n",
    "\n",
    "nest_asyncio.apply()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "id": "1988b1b2-b189-43c9-8ffd-d7f275881065",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "event=on_chain_start | name=RunnableSequence | data={'input': 'bar'}\n",
      "event=on_chain_start | name=first | data={}\n",
      "event=on_chain_stream | name=first | data={'chunk': {'foo': 'bar'}}\n",
      "event=on_chain_start | name=second | data={}\n",
      "event=on_chain_end | name=first | data={'output': {'foo': 'bar'}, 'input': 'bar'}\n",
      "event=on_chain_stream | name=second | data={'chunk': {'foo': 'bar'}}\n",
      "event=on_chain_stream | name=RunnableSequence | data={'chunk': {'foo': 'bar'}}\n",
      "event=on_chain_stream | name=second | data={'chunk': {'foo': 'bar'}}\n",
      "event=on_chain_stream | name=RunnableSequence | data={'chunk': {'foo': 'bar'}}\n",
      "event=on_chain_stream | name=second | data={'chunk': {'foo': 'bar'}}\n",
      "event=on_chain_stream | name=RunnableSequence | data={'chunk': {'foo': 'bar'}}\n",
      "event=on_chain_stream | name=second | data={'chunk': {'foo': 'bar'}}\n",
      "event=on_chain_stream | name=RunnableSequence | data={'chunk': {'foo': 'bar'}}\n",
      "event=on_chain_stream | name=second | data={'chunk': {'foo': 'bar'}}\n",
      "event=on_chain_stream | name=RunnableSequence | data={'chunk': {'foo': 'bar'}}\n",
      "event=on_chain_end | name=second | data={'output': {'foo': 'bar'}, 'input': {'foo': 'bar'}}\n",
      "event=on_chain_end | name=RunnableSequence | data={'output': {'foo': 'bar'}}\n"
     ]
    }
   ],
   "source": [
    "from langchain_core.runnables import RunnableLambda, RunnableParallel\n",
    "\n",
    "runnable1 = RunnableLambda(lambda x: {\"foo\": x}, name=\"first\")\n",
    "\n",
    "\n",
    "async def func(x):\n",
    "    for _ in range(5):\n",
    "        yield x\n",
    "\n",
    "\n",
    "runnable2 = RunnableLambda(func, name=\"second\")\n",
    "\n",
    "chain = runnable1 | runnable2\n",
    "\n",
    "async for event in chain.astream_events(\"bar\", version=\"v2\"):\n",
    "    print(f\"event={event['event']} | name={event['name']} | data={event['data']}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a7575005-ffbd-4a52-a280-a521799fed5d",
   "metadata": {},
   "source": [
    "### Yield batched outputs as they complete\n",
    "#### [Runnable.batch_as_completed](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.batch_as_completed) / [Runnable.abatch_as_completed](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.abatch_as_completed)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "id": "826dedad-d654-4f85-b8b4-a53eda2f2837",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "slept 1\n",
      "1 None\n",
      "slept 5\n",
      "0 None\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "\n",
    "from langchain_core.runnables import RunnableLambda, RunnableParallel\n",
    "\n",
    "runnable1 = RunnableLambda(lambda x: time.sleep(x) or print(f\"slept {x}\"))\n",
    "\n",
    "for idx, result in runnable1.batch_as_completed([5, 1]):\n",
    "    print(idx, result)\n",
    "\n",
    "# Async variant:\n",
    "# async for idx, result in runnable1.abatch_as_completed([5, 1]):\n",
    "#     print(idx, result)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cc1cacde-b35e-474a-a14a-ed9e8a858ba8",
   "metadata": {},
   "source": [
    "### Return subset of output dict\n",
    "#### [Runnable.pick](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.pick)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "id": "78dd3ed5-5095-4698-ba4f-d0b73f12a608",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'foo': 7, 'bar': 'hi'}"
      ]
     },
     "execution_count": 88,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.runnables import RunnableLambda, RunnablePassthrough\n",
    "\n",
    "runnable1 = RunnableLambda(lambda x: x[\"baz\"] + 5)\n",
    "chain = RunnablePassthrough.assign(foo=runnable1).pick([\"foo\", \"bar\"])\n",
    "\n",
    "chain.invoke({\"bar\": \"hi\", \"baz\": 2})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5587dbda-d6d7-4480-b2e9-7541af076d36",
   "metadata": {},
   "source": [
    "### Declaratively make a batched version of a runnable\n",
    "#### [Runnable.map](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.map)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "fd020416-faf0-4343-945c-823d879d8431",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[5, 6, 7]"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.runnables import RunnableLambda\n",
    "\n",
    "runnable1 = RunnableLambda(lambda x: list(range(x)))\n",
    "runnable2 = RunnableLambda(lambda x: x + 5)\n",
    "\n",
    "chain = runnable1 | runnable2.map()\n",
    "\n",
    "chain.invoke(3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1e4ed5c3-244e-4491-adbe-83af3fc14265",
   "metadata": {},
   "source": [
    "### Get a graph representation of a runnable\n",
    "#### [Runnable.get_graph](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.get_graph)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "id": "11ef1419-a2ee-41bd-a74f-c057a6d737ac",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                             +-------------+                              \n",
      "                             | LambdaInput |                              \n",
      "                             +-------------+                              \n",
      "                                    *                                     \n",
      "                                    *                                     \n",
      "                                    *                                     \n",
      "                    +------------------------------+                      \n",
      "                    | Lambda(lambda x: {'foo': x}) |                      \n",
      "                    +------------------------------+                      \n",
      "                                    *                                     \n",
      "                                    *                                     \n",
      "                                    *                                     \n",
      "                     +-----------------------------+                      \n",
      "                     | Parallel<second,third>Input |                      \n",
      "                     +-----------------------------+                      \n",
      "                        ****                  ***                         \n",
      "                    ****                         ****                     \n",
      "                  **                                 **                   \n",
      "+---------------------------+               +--------------------------+  \n",
      "| Lambda(lambda x: [x] * 2) |               | Lambda(lambda x: str(x)) |  \n",
      "+---------------------------+               +--------------------------+  \n",
      "                        ****                  ***                         \n",
      "                            ****          ****                            \n",
      "                                **      **                                \n",
      "                    +------------------------------+                      \n",
      "                    | Parallel<second,third>Output |                      \n",
      "                    +------------------------------+                      \n"
     ]
    }
   ],
   "source": [
    "from langchain_core.runnables import RunnableLambda, RunnableParallel\n",
    "\n",
    "runnable1 = RunnableLambda(lambda x: {\"foo\": x})\n",
    "runnable2 = RunnableLambda(lambda x: [x] * 2)\n",
    "runnable3 = RunnableLambda(lambda x: str(x))\n",
    "\n",
    "chain = runnable1 | RunnableParallel(second=runnable2, third=runnable3)\n",
    "\n",
    "chain.get_graph().print_ascii()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a2728a5e-e5b4-452d-9e90-afb00f06df44",
   "metadata": {},
   "source": [
    "### Get all prompts in a chain\n",
    "#### [Runnable.get_prompts](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.get_prompts)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 102,
   "id": "9c35a8ec-e0ac-4cdd-a921-19161a66f5bf",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "**prompt i=0**\n",
      "\n",
      "================================ System Message ================================\n",
      "\n",
      "good ai\n",
      "\n",
      "================================ Human Message =================================\n",
      "\n",
      "{input}\n",
      "\n",
      "\n",
      "\n",
      "\n",
      "**prompt i=1**\n",
      "\n",
      "================================ System Message ================================\n",
      "\n",
      "really good ai\n",
      "\n",
      "================================ Human Message =================================\n",
      "\n",
      "{input}\n",
      "\n",
      "================================== AI Message ==================================\n",
      "\n",
      "{ai_output}\n",
      "\n",
      "================================ Human Message =================================\n",
      "\n",
      "{input2}\n",
      "\n",
      "\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_core.runnables import RunnableLambda\n",
    "\n",
    "prompt1 = ChatPromptTemplate.from_messages(\n",
    "    [(\"system\", \"good ai\"), (\"human\", \"{input}\")]\n",
    ")\n",
    "prompt2 = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\"system\", \"really good ai\"),\n",
    "        (\"human\", \"{input}\"),\n",
    "        (\"ai\", \"{ai_output}\"),\n",
    "        (\"human\", \"{input2}\"),\n",
    "    ]\n",
    ")\n",
    "fake_llm = RunnableLambda(lambda prompt: \"i am good ai\")\n",
    "chain = prompt1.assign(ai_output=fake_llm) | prompt2 | fake_llm\n",
    "\n",
    "for i, prompt in enumerate(chain.get_prompts()):\n",
    "    print(f\"**prompt {i=}**\\n\")\n",
    "    print(prompt.pretty_repr())\n",
    "    print(\"\\n\" * 3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e5add050-b8e0-48eb-94cb-74afd88ed1a8",
   "metadata": {},
   "source": [
    "### Add lifecycle listeners\n",
    "#### [Runnable.with_listeners](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.with_listeners)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 105,
   "id": "faa37955-d9ce-46a7-bc39-301bf84421d6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "start_time: 2024-05-17 23:04:00.951065+00:00\n",
      "end_time: 2024-05-17 23:04:02.958765+00:00\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "\n",
    "from langchain_core.runnables import RunnableLambda\n",
    "from langchain_core.tracers.schemas import Run\n",
    "\n",
    "\n",
    "def on_start(run_obj: Run):\n",
    "    print(\"start_time:\", run_obj.start_time)\n",
    "\n",
    "\n",
    "def on_end(run_obj: Run):\n",
    "    print(\"end_time:\", run_obj.end_time)\n",
    "\n",
    "\n",
    "runnable1 = RunnableLambda(lambda x: time.sleep(x))\n",
    "chain = runnable1.with_listeners(on_start=on_start, on_end=on_end)\n",
    "chain.invoke(2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7186123c-99ce-45ed-a64f-9c627b09f92d",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "poetry-venv-2",
   "language": "python",
   "name": "poetry-venv-2"
  },
  "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
}