diff --git a/docs/docs/how_to/index.mdx b/docs/docs/how_to/index.mdx index b481805eaa..b23c062333 100644 --- a/docs/docs/how_to/index.mdx +++ b/docs/docs/how_to/index.mdx @@ -225,6 +225,8 @@ All of LangChain components can easily be extended to support your own versions. - [How to: create custom callback handlers](/docs/how_to/custom_callbacks) - [How to: define a custom tool](/docs/how_to/custom_tools) +### Serialization +- [How to: save and load LangChain objects](/docs/how_to/serialization) ## Use cases diff --git a/docs/docs/how_to/serialization.ipynb b/docs/docs/how_to/serialization.ipynb new file mode 100644 index 0000000000..d870184205 --- /dev/null +++ b/docs/docs/how_to/serialization.ipynb @@ -0,0 +1,305 @@ +{ + "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": [ + "\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 +}