{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "ab3dc782-321e-4503-96ee-ac88a15e4b5e",
   "metadata": {},
   "source": [
    "# How to save and load LangChain objects\n",
    "\n",
    "LangChain classes implement standard methods for serialization. Serializing LangChain objects using these methods confer some advantages:\n",
    "\n",
    "- Secrets, such as API keys, are separated from other parameters and can be loaded back to the object on de-serialization;\n",
    "- De-serialization is kept compatible across package versions, so objects that were serialized with one version of LangChain can be properly de-serialized with another.\n",
    "\n",
    "To save and load LangChain objects using this system, use the `dumpd`, `dumps`, `load`, and `loads` functions in the [load module](https://api.python.langchain.com/en/latest/core_api_reference.html#module-langchain_core.load) of `langchain-core`. These functions support JSON and JSON-serializable objects.\n",
    "\n",
    "All LangChain objects that inherit from [Serializable](https://api.python.langchain.com/en/latest/load/langchain_core.load.serializable.Serializable.html) are JSON-serializable. Examples include [messages](https://api.python.langchain.com/en/latest/core_api_reference.html#module-langchain_core.messages), [document objects](https://api.python.langchain.com/en/latest/documents/langchain_core.documents.base.Document.html) (e.g., as returned from [retrievers](/docs/concepts/#retrievers)), and most [Runnables](/docs/concepts/#langchain-expression-language-lcel), such as chat models, retrievers, and [chains](/docs/how_to/sequence) implemented with the LangChain Expression Language.\n",
    "\n",
    "Below we walk through an example with a simple [LLM chain](/docs/tutorials/llm_chain).\n",
    "\n",
    ":::{.callout-caution}\n",
    "\n",
    "De-serialization using `load` and `loads` can instantiate any serializable LangChain object. Only use this feature with trusted inputs!\n",
    "\n",
    "De-serialization is a beta feature and is subject to change.\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "f85d9e51-2a36-4f69-83b1-c716cd43f790",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.load import dumpd, dumps, load, loads\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\"system\", \"Translate the following into {language}:\"),\n",
    "        (\"user\", \"{text}\"),\n",
    "    ],\n",
    ")\n",
    "\n",
    "llm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", api_key=\"llm-api-key\")\n",
    "\n",
    "chain = prompt | llm"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "356ea99f-5cb5-4433-9a6c-2443d2be9ed3",
   "metadata": {},
   "source": [
    "## Saving objects\n",
    "\n",
    "### To json"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "26516764-d46b-4357-a6c6-bd8315bfa530",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "  \"lc\": 1,\n",
      "  \"type\": \"constructor\",\n",
      "  \"id\": [\n",
      "    \"langchain\",\n",
      "    \"schema\",\n",
      "    \"runnable\",\n",
      "    \"RunnableSequence\"\n",
      "  ],\n",
      "  \"kwargs\": {\n",
      "    \"first\": {\n",
      "      \"lc\": 1,\n",
      "      \"type\": \"constructor\",\n",
      "      \"id\": [\n",
      "        \"langchain\",\n",
      "        \"prompts\",\n",
      "        \"chat\",\n",
      "        \"ChatPromptTemplate\"\n",
      "      ],\n",
      "      \"kwargs\": {\n",
      "        \"input_variables\": [\n",
      "          \"language\",\n",
      "          \"text\"\n",
      "        ],\n",
      "        \"messages\": [\n",
      "          {\n",
      "            \"lc\": 1,\n",
      "            \"type\": \"constructor\",\n",
      "         \n"
     ]
    }
   ],
   "source": [
    "string_representation = dumps(chain, pretty=True)\n",
    "print(string_representation[:500])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd425716-545d-466b-a4e5-dc9952cfd72a",
   "metadata": {},
   "source": [
    "### To a json-serializable Python dict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "6561a968-1741-4419-8c29-e705b9d0ef39",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'dict'>\n"
     ]
    }
   ],
   "source": [
    "dict_representation = dumpd(chain)\n",
    "\n",
    "print(type(dict_representation))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "711e986e-dd24-4839-9e38-c57903378a5f",
   "metadata": {},
   "source": [
    "### To disk"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "f818378b-f4d6-43a7-895b-76cf7359b157",
   "metadata": {},
   "outputs": [],
   "source": [
    "import json\n",
    "\n",
    "with open(\"/tmp/chain.json\", \"w\") as fp:\n",
    "    json.dump(string_representation, fp)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1e621a32-ff5f-4627-ad59-88cacba73c6b",
   "metadata": {},
   "source": [
    "Note that the API key is withheld from the serialized representations. Parameters that are considered secret are specified by the `.lc_secrets` attribute of the LangChain object:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "8225e150-000a-4fbc-9f3d-09568f4b560b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'openai_api_key': 'OPENAI_API_KEY'}"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.last.lc_secrets"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6d090177-eb1c-4bfb-8c13-29286afe17d9",
   "metadata": {},
   "source": [
    "## Loading objects\n",
    "\n",
    "Specifying `secrets_map` in `load` and `loads` will load the corresponding secrets onto the de-serialized LangChain object.\n",
    "\n",
    "### From string"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "54a66267-5f3a-40a2-bfcc-8b44bb24c154",
   "metadata": {},
   "outputs": [],
   "source": [
    "chain = loads(string_representation, secrets_map={\"OPENAI_API_KEY\": \"llm-api-key\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5ed9aff1-92cc-44ba-b2ec-4d12f924fa03",
   "metadata": {},
   "source": [
    "### From dict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "76979932-13de-4427-9f88-040fb05a6778",
   "metadata": {},
   "outputs": [],
   "source": [
    "chain = load(dict_representation, secrets_map={\"OPENAI_API_KEY\": \"llm-api-key\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7dd81a2a-5163-414d-ab42-f1c35e30471b",
   "metadata": {},
   "source": [
    "### From disk"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "033f62a7-3377-472a-be58-718baa6ab445",
   "metadata": {},
   "outputs": [],
   "source": [
    "with open(\"/tmp/chain.json\", \"r\") as fp:\n",
    "    chain = loads(json.load(fp), secrets_map={\"OPENAI_API_KEY\": \"llm-api-key\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dc520fdb-035a-468f-a8a8-c3ffe8ed98eb",
   "metadata": {},
   "source": [
    "Note that we recover the API key specified at the start of the guide:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "566b2475-d9b4-432b-8c3b-27c2f183624e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'llm-api-key'"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.last.openai_api_key.get_secret_value()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7b4cba53-e1d5-4979-927e-b5794a02afc3",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}