diff --git a/13-LangChain-Expression-Language/08-RunnableWithMessageHistory.ipynb b/13-LangChain-Expression-Language/08-RunnableWithMessageHistory.ipynb index aab1f5184..c438ee5cb 100644 --- a/13-LangChain-Expression-Language/08-RunnableWithMessageHistory.ipynb +++ b/13-LangChain-Expression-Language/08-RunnableWithMessageHistory.ipynb @@ -15,7 +15,7 @@ "\n", "## Overview\n", "\n", - "`RunnableWithMessageHistory` is a powerful tool in LangChain's Expression Language (LCEL) **for managing conversation history** in chatbots, virtual assistants, and other conversational AI applications. This class seamlessly integrates with existing LangChain components **to handle message history management and updates automatically.**\n", + "`RunnableWithMessageHistory` in LangChain's Expression Language (LCEL) for **managing conversation history** in chatbots, virtual assistants, and other conversational AI applications. It seamlessly integrates with existing LangChain components **to automatically handle message history management and updates.**\n", "\n", "### Key Features\n", "\n", @@ -26,42 +26,42 @@ "\n", "**Flexible Input/Output Support**\n", "- Handles both message objects and Python dictionaries.\n", - "- Supports various input formats including:\n", + "- Supports various input formats, including:\n", " - Single messages\n", " - Message sequences\n", " - Dictionary inputs with custom keys\n", "- Provides consistent output handling regardless of input format.\n", "\n", "**Session Management**\n", - "- Manages conversations through unique identifiers:\n", + "- Manages conversations through unique identifiers, such as:\n", " - Simple session IDs\n", " - Combined user and conversation IDs\n", "- Maintains separate conversation threads for different users or contexts.\n", " - Ensures conversation continuity within the same session.\n", "\n", "**Storage Options**\n", - "- In-memory storage for development and testing.\n", - "- Persistent storage support (Redis, files, etc.) for production.\n", - "- Easy integration with various storage backends.\n", + "- Offers in-memory storage for development and testing.\n", + "- Supports persistent storage (e.g., Redis, files) for production environments.\n", + "- Provides easy integration with various storage backends.\n", "\n", "**Advantages Over Legacy Approaches**\n", "- More flexible than the older ConversationChain.\n", - "- Better state management capabilities.\n", - "- Improved integration with modern LangChain components.\n", + "- offer better state management.\n", + "- Provides improved integration with modern LangChain components.\n", "\n", "### Summary\n", - "`RunnableWithMessageHistory` serves as the new standard for conversation management in LangChain, offering:\n", + "`RunnableWithMessageHistory` is the recommended standard for conversation management in LangChain, offering:\n", "- Simplified conversation state management.\n", - "- Enhanced user experience through context preservation.\n", - "- Flexible configuration options for different use cases.\n", + "- An enhanced user experience through context preservation.\n", + "- Flexible configuration options for diverse use cases.\n", "\n", "### Table of Contents\n", "\n", "- [Overview](#overview) \n", "- [Environment Setup](#environment-setup) \n", "- [Getting Started with RunnableWithMessageHistory](#getting-started-with-runnablewithmessagehistory)\n", - "- [In-Memory Conversation History](#in-memory-conversation-history)\n", - "- [Example of Runnables with Using Veriety Keys](#example-of-runnables-with-using-veriety-keys)\n", + "- [Understanding In-Memory Conversation History](#understanding-in-memory-conversation-history)\n", + "- [Example of Runnables with using different keys](#example-of-runnables-with-using-defferent-keys)\n", "- [Persistent Storage](#persistent-storage)\n", "- [Using Redis for Persistence](#using-redis-for-persistence)\n", "\n", @@ -69,8 +69,8 @@ "\n", "- [LangChain Core API Documentation - RunnableWithMessageHistory](https://python.langchain.com/api_reference/core/runnables/langchain_core.runnables.history.RunnableWithMessageHistory.html#langchain_core.runnables.history.RunnableWithMessageHistory)\n", "- [LangChain Documentation - Message History](https://python.langchain.com/docs/how_to/message_history/)\n", - "- [LangChain Memory Integrations](https://integrations.langchain.com/memory)\n", - "\n", + "- [LangChain's message histories: memory integrations](https://python.langchain.com/docs/integrations/memory/)\n", + "- [LangServe's example of a chat server with persistent storage](https://github.com/langchain-ai/langserve/blob/main/examples/chat_with_persistence_and_user/server.py)\n", "---" ] }, @@ -80,11 +80,11 @@ "source": [ "## Environment Setup\n", "\n", - "Set up the environment. You may refer to [Environment Setup](https://wikidocs.net/257836) for more details.\n", + "Setting up your environment is the first step. See the [Environment Setup](https://wikidocs.net/257836) guide for more details.\n", "\n", "**[Note]**\n", - "- `langchain-opentutorial` is a package that provides a set of easy-to-use environment setup, useful functions and utilities for tutorials. \n", - "- You can checkout the [`langchain-opentutorial`](https://github.com/LangChain-OpenTutorial/langchain-opentutorial-pypi) for more details." + "- The `langchain-opentutorial` is a bundle of easy-to-use environment setup guidance, useful functions and utilities for tutorials. \n", + "- Check out the [`langchain-opentutorial`](https://github.com/LangChain-OpenTutorial/langchain-opentutorial-pypi) for more details." ] }, { @@ -150,9 +150,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "You can alternatively set `OPENAI_API_KEY` in `.env` file and load it. \n", + "Alternatively, you can set and load `OPENAI_API_KEY` from a `.env` file.\n", "\n", - "[Note] This is not necessary if you've already set `OPENAI_API_KEY` in previous steps." + "**[Note]** This is only necessary if you haven't already set `OPENAI_API_KEY` in previous steps." ] }, { @@ -182,10 +182,11 @@ "metadata": {}, "source": [ "## Getting Started with `RunnableWithMessageHistory`\n", - "Message history management is crucial for conversational applications and complex data processing tasks. To effectively implement message history with `RunnableWithMessageHistory`, you need two key components: \n", "\n", - "1. **Creating a `Runnable`**\n", - " - An object that primarily interacts with `BaseChatMessageHistory`, such as Retriever and Chain." + "Managing conversation history is crucial for conversational applications and complex data processing tasks. `RunnableWithMessageHistory` simplifies the message history implementation. To use it effectively, you need these two key components:\n", + "\n", + "1. **Runnable objects**,\n", + " - Creating Runnable objects, such as `retriever` or `chain`, are the primary components that interacts with `BaseChatMessageHistory`. " ] }, { @@ -220,25 +221,21 @@ "source": [ "2. **Message History Manager (callable)**\n", "\n", - "- A callable that returns an instance of `BaseChatMessageHistory` .\n", - "- Provides message storage, retrieval, and update capabilities.\n", - "- Maintains conversation context for contextual responses.\n", + "- This is a callable that returns an instance of `BaseChatMessageHistory`. It handles message storage, retrieval, updates, and maintains conversation context for contextual responses.\n", "\n", "### Implementation Options\n", "\n", - "LangChain offers multiple ways to implement message history management. You can explore various storage options and integration methods in the [memory integrations](https://integrations.langchain.com/memory) page.\n", + "LangChain offers several implementations for managing message history. You can explore various memory integrations for persistent storage, as documented in the [LangChain's message histories: memory integrations](https://python.langchain.com/docs/integrations/memory/) page.\n", "\n", - "This tutorial covers two primary implementation approaches:\n", + "This tutorial covers two primary approaches in implementation:\n", "\n", - "1. **In-Memory ChatMessageHistory**\n", - " - Manages message history in memory.\n", - " - Ideal for development and simple applications.\n", + "1. **In-Memory `ChatMessageHistory`**\n", + " - Manages message history in memory, making it ideal for development and simple applications.\n", " - Provides fast access speeds.\n", " - Message history is lost on application restart.\n", "\n", - "2. **Persistent Storage with RedisChatMessageHistory**\n", - " - Enables permanent message storage using Redis.\n", - " - High-performance, open-source in-memory data structure store.\n", + "2. **Persistent Storage with `RedisChatMessageHistory`**\n", + " - Enables permanent message storage using Remote Dictionary Server (Redis), a high-performance, open-source in-memory data structure store.\n", " - Suitable for distributed environments.\n", " - Ideal for complex applications and long-running services.\n", "\n", @@ -248,24 +245,24 @@ " - Message data importance\n", " - Retention period requirements\n", "\n", - "While in-memory implementation offers simplicity and speed, persistent storage solutions like Redis are more appropriate when data durability is required." + "While in-memory implementation offers simplicity and speed, persistent storage solutions like Redis are more appropriate when data durability is a concern." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## In-Memory Conversation History\n", + "## Understanding In-Memory Conversation History\n", "\n", "In-memory conversation history provides a simple and fast way to manage chat message history during development and testing. This approach stores conversation data in memory, offering quick access but without persistence across application restarts.\n", "\n", "### Core Configuration Parameters\n", "\n", "**Required Components**\n", - "- `runnable`: The chain or model to execute (e.g., ChatOpenAI, Chain)\n", - "- `get_session_history`: Function returning a `BaseChatMessageHistory` instance\n", - "- `input_messages_key`: Specifies the key for user input in `invoke()` calls\n", - "- `history_messages_key`: Defines the key for accessing conversation history" + "- `runnable`: The chain or model (e.g., ChatOpenAI) to execute.\n", + "- `get_session_history`: A function returning a `BaseChatMessageHistory` instance.\n", + "- `input_messages_key`: Specifies the key for user input in `invoke()` calls.\n", + "- `history_messages_key`: Defines the key for accessing conversation history." ] }, { @@ -303,7 +300,7 @@ "metadata": {}, "source": [ "### Default Session Implementation\n", - "`RunnableWithMessageHistory` uses `session_id` as its default identifier for managing conversation threads. This is evident in its core implementation:\n", + "`RunnableWithMessageHistory` uses `session_id` as its default identifier for managing conversation threads, as shown in its core implementation:\n", "\n", "```python\n", "if history_factory_config:\n", @@ -322,7 +319,7 @@ " ]\n", "```\n", "### Using Session Management\n", - "To utilize session management, you must specify a session ID in your invoke call:" + "To utilize session management, specify a session ID in your invoke call:" ] }, { @@ -359,7 +356,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "When using the same `session_id`, the conversation can continue because it retrieves the previous thread's content (this continuous conversation is called a session):" + "Using the same `session_id` continues the conversation by retrieving the previous thread's content (this continuous conversation is called a **session**):" ] }, { @@ -399,9 +396,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "However, if you specify a different `session_id`, the response won't be accurate because there's no conversation history. \n", + "However, using a different `session_id` will result in an inaccurate response because no corresponding history. \n", "\n", - "(In the example below, since `session_id`: def234 doesn't exist, you can see an irrelevant response)" + "For example, if `session_id` is `def234` and no history exists for that ID, you'll see an irrelevant response (see the following code snippet)." ] }, { @@ -441,11 +438,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The configuration parameters used for tracking message history can be customized by passing a list of `ConfigurableFieldSpec` objects through the `history_factory_config` parameter.\n", + "You can customize the configuration parameters for tracking message history by passing a list of `ConfigurableFieldSpec` objects through the `history_factory_config` parameter.\n", "\n", - "Setting a new `history_factory_config` will override the existing `session_id` configuration.\n", + "Setting a new `history_factory_config` overrides the existing `session_id` configuration.\n", "\n", - "The example below uses two parameters: `user_id` and `conversation_id`." + "The following example demonstrates using two parameters: `user_id` and `conversation_id`." ] }, { @@ -497,7 +494,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " Using the Custom Configuration " + "Let's try a custom configuration ." ] }, { @@ -527,13 +524,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Example of Runnables with Using Veriety Keys\n", + "## Example of Runnables with using defferent keys\n", "\n", - "### Messages Input with Dictionary Output\n", + "This example demonstrates how to handle inputs and output messages with `RunnableWithMessageHistory`.\n", "\n", - " This example demonstrates how to handle message inputs and dictionary outputs in `RunnableWithMessageHistory`.\n", + "### Messages Input with Dictionary Output\n", "\n", - "**Important** : By omitting `input_messages_key=\"input\"` , we configure the system to accept `Message` objects as input." + "**Direct Message Object Handling**\n", + "- Omitting `input_messages_key=\"input\"` configures the system to accept `Message` objects as input." ] }, { @@ -612,21 +610,23 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This configuration allows:\n", - "- Direct input of `Message` objects\n", - "- Dictionary output format\n", - "- Session-based conversation history\n", - "- Seamless continuation of conversations using session IDs\n" + "This configuration enables:\n", + "- Direct handling of the input `Message` object.\n", + "- Outputting data in a dictionary format.\n", + "- Maintaining conversation history across sessions.\n", + "- Continuing conversations seamlessly using session IDs." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### `Message` Objects as Input and Output\n", + "### `Message` Objects for both Input and Output\n", + "\n", + "Continuing from the previous example, you can also configure `RunnableWithMessageHistory` to handle `Message` objects directly for both input and output.\n", "\n", "**Direct Message Object Handling**\n", - "- Important: Omitting `output_messages_key=\"output_message\"` configures the system to return `Message` objects as output." + "- Omitting `output_messages_key=\"output_message\"` configures the system to return `Message` objects as output." ] }, { @@ -674,8 +674,8 @@ "### Dictionary with Single Key for All Messages\n", "\n", "**Using a Single Key for Input/Output**\n", - "- This approach uses one key for all message inputs and outputs\n", - "- Utilizes `itemgetter(\"input_messages\")` to extract input messages\n" + "- This approach uses one key for both input and output messages.\n", + "- It utilizes `itemgetter(\"input_messages\")` to extract input messages from the dictionary.\n" ] }, { @@ -722,35 +722,33 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This configuration allows for:\n", - "- Direct message object handling\n", - "- Simplified input/output processing\n", - "- Flexible message format conversion\n", - "- Consistent session management" + "This configuration enables:\n", + "- Direct handling of `Message` objects.\n", + "- Simplified input/output processing.\n", + "- Flexible conversion between different message formats.\n", + "- Consistent session management." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Persistent Storage\n", + "## Understanding Persistent Storage\n", "\n", - " Persistent storage is **a mechanism that maintains data even when a program terminates or the system reboots.** This can be implemented through databases, file systems, or other non-volatile storage devices.\n", + "Persistent storage ensures data is retained **even after a program terminates or the system restarts** . This is typically achieved using databases, file systems, or other non-volatile storage devices.\n", "\n", - "It is **essential for preserving data long-term** in applications. It enables:\n", - "- State preservation across sessions\n", - "- User preference retention\n", - "- **Continuous operation without data loss**\n", - "- Recovery from previous execution points\n", + "Persistent storage is **essential for long-term data preservation** in applications. It enables.:\n", + "- State preservation across sessions.\n", + "- User preference retention.\n", + "- **Continuous operation without data loss** .\n", + "- Recovery from previous execution points.\n", "\n", "\n", "### Implementation Options\n", "\n", - "`RunnableWithMessageHistory` offers flexible storage options:\n", - "\n", - "- Independent of how `get_session_history` retrieves chat message history\n", - "- Supports local file system (see example [here](https://github.com/langchain-ai/langserve/blob/main/examples/chat_with_persistence_and_user/server.py))\n", - "- Integrates with various storage providers (see [memory integrations](https://integrations.langchain.com/memory))\n" + "`RunnableWithMessageHistory` offers flexible storage options that are independent of how `get_session_history` retrieves the chat message history.\n", + "- It supports the local file system (see an example [here](https://github.com/langchain-ai/langserve/blob/main/examples/chat_with_persistence_and_user/server.py))\n", + "- It integrates with various storage providers (see [LangChain's message histories: memory integrations](https://python.langchain.com/docs/integrations/memory/))" ] }, { @@ -759,6 +757,8 @@ "source": [ "## Using Redis for Persistence\n", "\n", + "This section demonstrates how to use Redis for persistent message history storage.\n", + "\n", " 1. **Installation** " ] }, @@ -791,14 +791,14 @@ "docker run -d -p 6379:6379 -p 8001:8001 redis/redis-stack:latest\n", "```\n", "Configuration options:\n", - "- -d: Run in daemon mode (background)\n", - "- -p {port}:6379: Redis server port mapping\n", - "- -p 8001:8001: RedisInsight UI port mapping\n", - "- redis/redis-stack:latest: Latest Redis Stack image\n", + "- `-d` : Run in daemon mode (background).\n", + "- `-p {port}:6379` : Redis server port mapping.\n", + "- `-p 8001:8001` : RedisInsight UI port mapping.\n", + "- `redis/redis-stack:latest` : Latest Redis Stack image.\n", "\n", - "**Troubleshooting**\n", - "- Verify Docker is running\n", - "- Check port availability (terminate occupying processes or use different ports)" + "**Tips for Troubleshooting**\n", + "- Verify Docker is running.\n", + "- Check port availability (terminate any processes using the port or use different ports)." ] }, { @@ -824,7 +824,7 @@ "source": [ "### Implementing Redis Message History\n", "\n", - "To update the message history implementation, define a new callable that returns an instance of `RedisChatMessageHistory`:\n" + "To use Redis for message history, define a new callable that returns an instance of `RedisChatMessageHistory` :" ] }, { @@ -856,7 +856,7 @@ "### Testing Conversation Continuity\n", "\n", "**First Interaction**\n", - "- You can call it in the same way as before" + "- You can call the function/chain as before." ] }, { @@ -888,7 +888,7 @@ "metadata": {}, "source": [ "**Continuing the Conversation**\n", - "- You can perform the second call using the same `session_id`." + "- Make the second call using the same `session_id` ." ] }, { @@ -920,7 +920,7 @@ "metadata": {}, "source": [ "**Testing with Different Session**\n", - "- This time, I will ask the question using a different `session_id`." + "- We will ask the question using a different `session_id` for this time." ] }, { @@ -951,7 +951,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note: The last response will be inaccurate since there's no conversation history for the new session ID \"redis456\"." + "**[Note]** The last response will be inaccurate because there's no conversation history associated with that session ID `redis456`." ] } ],