{
 "cells": [
  {
   "cell_type": "raw",
   "id": "fe63ffaf",
   "metadata": {},
   "source": [
    "---\n",
    "sidebar_position: 2\n",
    "keywords: [RunnableBinding, LCEL]\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "711752cb-4f15-42a3-9838-a0c67f397771",
   "metadata": {},
   "source": [
    "# How to add default invocation args to a Runnable\n",
    "\n",
    ":::info Prerequisites\n",
    "\n",
    "This guide assumes familiarity with the following concepts:\n",
    "- [LangChain Expression Language (LCEL)](/docs/concepts/#langchain-expression-language)\n",
    "- [Chaining runnables](/docs/how_to/sequence/)\n",
    "- [Tool calling](/docs/how_to/tool_calling)\n",
    "\n",
    ":::\n",
    "\n",
    "Sometimes we want to invoke a [`Runnable`](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html) within a [RunnableSequence](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.RunnableSequence.html) with constant arguments that are not part of the output of the preceding Runnable in the sequence, and which are not part of the user input. We can use the [`Runnable.bind()`](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.bind) method to set these arguments ahead of time.\n",
    "\n",
    "## Binding stop sequences\n",
    "\n",
    "Suppose we have a simple prompt + model chain:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c5dad8b5",
   "metadata": {},
   "outputs": [],
   "source": [
    "# | output: false\n",
    "# | echo: false\n",
    "\n",
    "%pip install -qU langchain langchain_openai\n",
    "\n",
    "import os\n",
    "from getpass import getpass\n",
    "\n",
    "os.environ[\"OPENAI_API_KEY\"] = getpass()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "f3fdf86d-155f-4587-b7cd-52d363970c1d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "EQUATION: x^3 + 7 = 12\n",
      "\n",
      "SOLUTION: \n",
      "Subtract 7 from both sides:\n",
      "x^3 = 5\n",
      "\n",
      "Take the cube root of both sides:\n",
      "x = ∛5\n"
     ]
    }
   ],
   "source": [
    "from langchain_core.output_parsers import StrOutputParser\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_core.runnables import RunnablePassthrough\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\n",
    "            \"system\",\n",
    "            \"Write out the following equation using algebraic symbols then solve it. Use the format\\n\\nEQUATION:...\\nSOLUTION:...\\n\\n\",\n",
    "        ),\n",
    "        (\"human\", \"{equation_statement}\"),\n",
    "    ]\n",
    ")\n",
    "\n",
    "model = ChatOpenAI(temperature=0)\n",
    "\n",
    "runnable = (\n",
    "    {\"equation_statement\": RunnablePassthrough()} | prompt | model | StrOutputParser()\n",
    ")\n",
    "\n",
    "print(runnable.invoke(\"x raised to the third plus seven equals 12\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "929c9aba-a4a0-462c-adac-2cfc2156e117",
   "metadata": {},
   "source": [
    "and want to call the model with certain `stop` words so that we shorten the output as is useful in certain types of prompting techniques. While we can pass some arguments into the constructor, other runtime args use the `.bind()` method as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "32e0484a-78c5-4570-a00b-20d597245a96",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "EQUATION: x^3 + 7 = 12\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "runnable = (\n",
    "    {\"equation_statement\": RunnablePassthrough()}\n",
    "    | prompt\n",
    "    | model.bind(stop=\"SOLUTION\")\n",
    "    | StrOutputParser()\n",
    ")\n",
    "\n",
    "print(runnable.invoke(\"x raised to the third plus seven equals 12\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f07d7528-9269-4d6f-b12e-3669592a9e03",
   "metadata": {},
   "source": [
    "What you can bind to a Runnable will depend on the extra parameters you can pass when invoking it.\n",
    "\n",
    "## Attaching OpenAI tools\n",
    "\n",
    "Another common use-case is tool calling. While you should generally use the [`.bind_tools()`](/docs/how_to/tool_calling) method for tool-calling models, you can also bind provider-specific args directly if you want lower level control:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "2cdeeb4c-0c1f-43da-bd58-4f591d9e0671",
   "metadata": {},
   "outputs": [],
   "source": [
    "tools = [\n",
    "    {\n",
    "        \"type\": \"function\",\n",
    "        \"function\": {\n",
    "            \"name\": \"get_current_weather\",\n",
    "            \"description\": \"Get the current weather in a given location\",\n",
    "            \"parameters\": {\n",
    "                \"type\": \"object\",\n",
    "                \"properties\": {\n",
    "                    \"location\": {\n",
    "                        \"type\": \"string\",\n",
    "                        \"description\": \"The city and state, e.g. San Francisco, CA\",\n",
    "                    },\n",
    "                    \"unit\": {\"type\": \"string\", \"enum\": [\"celsius\", \"fahrenheit\"]},\n",
    "                },\n",
    "                \"required\": [\"location\"],\n",
    "            },\n",
    "        },\n",
    "    }\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "2b65beab-48bb-46ff-a5a4-ef8ac95a513c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_z0OU2CytqENVrRTI6T8DkI3u', 'function': {'arguments': '{\"location\": \"San Francisco, CA\", \"unit\": \"celsius\"}', 'name': 'get_current_weather'}, 'type': 'function'}, {'id': 'call_ft96IJBh0cMKkQWrZjNg4bsw', 'function': {'arguments': '{\"location\": \"New York, NY\", \"unit\": \"celsius\"}', 'name': 'get_current_weather'}, 'type': 'function'}, {'id': 'call_tfbtGgCLmuBuWgZLvpPwvUMH', 'function': {'arguments': '{\"location\": \"Los Angeles, CA\", \"unit\": \"celsius\"}', 'name': 'get_current_weather'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 84, 'prompt_tokens': 85, 'total_tokens': 169}, 'model_name': 'gpt-3.5-turbo-1106', 'system_fingerprint': 'fp_77a673219d', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-d57ad5fa-b52a-4822-bc3e-74f838697e18-0', tool_calls=[{'name': 'get_current_weather', 'args': {'location': 'San Francisco, CA', 'unit': 'celsius'}, 'id': 'call_z0OU2CytqENVrRTI6T8DkI3u'}, {'name': 'get_current_weather', 'args': {'location': 'New York, NY', 'unit': 'celsius'}, 'id': 'call_ft96IJBh0cMKkQWrZjNg4bsw'}, {'name': 'get_current_weather', 'args': {'location': 'Los Angeles, CA', 'unit': 'celsius'}, 'id': 'call_tfbtGgCLmuBuWgZLvpPwvUMH'}])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model = ChatOpenAI(model=\"gpt-3.5-turbo-1106\").bind(tools=tools)\n",
    "model.invoke(\"What's the weather in SF, NYC and LA?\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "095001f7",
   "metadata": {},
   "source": [
    "## Next steps\n",
    "\n",
    "You now know how to bind runtime arguments to a Runnable.\n",
    "\n",
    "To learn more, see the other how-to guides on runnables in this section, including:\n",
    "\n",
    "- [Using configurable fields and alternatives](/docs/how_to/configure) to change parameters of a step in a chain, or even swap out entire steps, at runtime"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
