This commit is contained in:
Eugene Yurtsev
2024-09-19 11:00:16 -04:00
parent 886bc6bba0
commit 4dcebcf92d

View File

@@ -104,10 +104,18 @@
},
{
"cell_type": "code",
"execution_count": 39,
"execution_count": 3,
"id": "8b6e1063-cf3a-456a-bf7d-830e5c1d2864",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/tmp/ipykernel_2459205/1840360377.py:24: LangChainDeprecationWarning: The class `LLMChain` was deprecated in LangChain 0.1.17 and will be removed in 1.0. Use RunnableSequence, e.g., `prompt | llm` instead.\n",
" legacy_chain = LLMChain(\n"
]
},
{
"name": "stdout",
"output_type": "stream",
@@ -155,17 +163,17 @@
},
{
"cell_type": "code",
"execution_count": 40,
"execution_count": 4,
"id": "c7fa1618",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Your name is Bob. How can I assist you today, Bob?'"
"'Your name is Bob. How can I assist you further, Bob?'"
]
},
"execution_count": 40,
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
@@ -192,7 +200,7 @@
},
{
"cell_type": "code",
"execution_count": 43,
"execution_count": 5,
"id": "e591965c-c4d7-4df7-966d-4d14bd46e157",
"metadata": {},
"outputs": [
@@ -205,13 +213,13 @@
"hi! I'm bob\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"\n",
"Hello Bob! How can I assist you today?\n",
"Hello, Bob! How can I assist you today?\n",
"================================\u001b[1m Human Message \u001b[0m=================================\n",
"\n",
"what was my name?\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"\n",
"I'm sorry, I don't have the ability to know your name unless you tell me. Feel free to share it with me if you'd like.\n"
"I'm sorry, but I do not have the ability to know your name as I am an AI assistant.\n"
]
}
],
@@ -298,17 +306,25 @@
},
{
"cell_type": "code",
"execution_count": 67,
"execution_count": 6,
"id": "dc2928de-d7a4-4f87-ab96-59bde9a3829f",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/eugene/.pyenv/versions/3.11.4/envs/core/lib/python3.11/site-packages/langsmith/client.py:5301: LangChainBetaWarning: The function `loads` is in beta. It is actively being worked on, so the API may change.\n",
" prompt = loads(json.dumps(prompt_object.manifest))\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'input': 'hi! my name is bob what is my age?', 'chat_history': [HumanMessage(content='hi! my name is bob what is my age?', additional_kwargs={}, response_metadata={}), AIMessage(content='Hello Bob! You are 42 years old. If you need any more assistance or information, feel free to ask!', additional_kwargs={}, response_metadata={})], 'output': 'Hello Bob! You are 42 years old. If you need any more assistance or information, feel free to ask!'}\n",
"{'input': 'hi! my name is bob what is my age?', 'chat_history': [HumanMessage(content='hi! my name is bob what is my age?', additional_kwargs={}, response_metadata={}), AIMessage(content='Hello Bob! You are 42 years old. If you need any more assistance or have any other questions, feel free to ask!', additional_kwargs={}, response_metadata={})], 'output': 'Hello Bob! You are 42 years old. If you need any more assistance or have any other questions, feel free to ask!'}\n",
"\n",
"{'input': 'do you remember my name?', 'chat_history': [HumanMessage(content='hi! my name is bob what is my age?', additional_kwargs={}, response_metadata={}), AIMessage(content='Hello Bob! You are 42 years old. If you need any more assistance or information, feel free to ask!', additional_kwargs={}, response_metadata={}), HumanMessage(content='do you remember my name?', additional_kwargs={}, response_metadata={}), AIMessage(content='Yes, your name is Bob. How can I assist you further, Bob?', additional_kwargs={}, response_metadata={})], 'output': 'Yes, your name is Bob. How can I assist you further, Bob?'}\n"
"{'input': 'do you remember my name?', 'chat_history': [HumanMessage(content='hi! my name is bob what is my age?', additional_kwargs={}, response_metadata={}), AIMessage(content='Hello Bob! You are 42 years old. If you need any more assistance or have any other questions, feel free to ask!', additional_kwargs={}, response_metadata={}), HumanMessage(content='do you remember my name?', additional_kwargs={}, response_metadata={}), AIMessage(content='Yes, your name is Bob. How can I assist you further, Bob?', additional_kwargs={}, response_metadata={})], 'output': 'Yes, your name is Bob. How can I assist you further, Bob?'}\n"
]
}
],
@@ -333,7 +349,6 @@
"\n",
"tools = [get_user_age]\n",
"\n",
"\n",
"# Get the prompt to use - you can modify this!\n",
"prompt = hub.pull(\"hwchase17/openai-functions-agent\")\n",
"\n",
@@ -377,7 +392,7 @@
},
{
"cell_type": "code",
"execution_count": 68,
"execution_count": 7,
"id": "bdb29c9b-bc57-4512-9430-c5d5e3f91e3c",
"metadata": {},
"outputs": [
@@ -390,8 +405,8 @@
"hi! I'm bob. What is my age?\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"Tool Calls:\n",
" get_user_age (call_l3dpzCgvONmrcAuksHxKfcsa)\n",
" Call ID: call_l3dpzCgvONmrcAuksHxKfcsa\n",
" get_user_age (call_ewWp6keHVouwJyM4lRhk4X25)\n",
" Call ID: call_ewWp6keHVouwJyM4lRhk4X25\n",
" Args:\n",
" name: bob\n",
"=================================\u001b[1m Tool Message \u001b[0m=================================\n",
@@ -464,7 +479,7 @@
},
{
"cell_type": "code",
"execution_count": 69,
"execution_count": 8,
"id": "fe63e424-1111-4f6a-a9c9-0887eb150ab0",
"metadata": {},
"outputs": [
@@ -477,7 +492,7 @@
"hi! do you remember my name?\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"\n",
"Hello! I'm sorry, but I don't have the capability to remember personal information like names. If you could remind me of your name, I'd be happy to assist you further!\n"
"Hello! Yes, I remember your name. It's great to see you again! How can I assist you today?\n"
]
}
],
@@ -500,9 +515,9 @@
"source": [
"</details>\n",
"\n",
"## Add Conversation History Processing\n",
"## Implementing Conversation History Processing\n",
"\n",
"All the memory types below add some additional logic to process the conversation history.\n",
"Each of the following memory types applies specific logic to handle the conversation history:\n",
"\n",
"| Memory Type | Description |\n",
"|---------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|\n",
@@ -511,19 +526,33 @@
"| `ConversationSummaryMemory` | Continually summarizes the conversation history. The summary is updated after each conversation turn. The abstraction returns the summary of the conversation history. |\n",
"| `ConversationSummaryBufferMemory` | Provides a running summary of the conversation together with the most recent messages in the conversation under the constraint that the total number of tokens in the conversation does not exceed a certain limit. |\n",
"\n",
"The general approach involves writing the necessary logic for processing conversation history and integrating it at the correct point.\n",
"\n",
"The general logic is to write the processing logic that you need for the conversation history and then add it in the appropriate place depending.\n",
"Well start by building a simple processor using LangChain's built-in [trim_messages](https://python.langchain.com/api_reference/core/messages/langchain_core.messages.utils.trim_messages.html) function, and then demonstrate how to integrate it into your application.\n",
"\n",
"We'll create a simple processor using `LangChain's` [trim_messages](https://python.langchain.com/api_reference/core/messages/langchain_core.messages.utils.trim_messages.html) built in functionality, and then see how to plug it into your application.\n",
"You can later replace this basic setup with more advanced logic tailored to your specific needs.\n",
"\n",
"\n",
":::important\n",
"\n",
"Well begin by exploring a straightforward method that involves applying processing logic to the entire conversation history.\n",
"\n",
"While this approach is easy to test and implement, it has a downside: as the conversation grows, s\n",
"o does the latency, since the logic is re-applied to all previous exchanges at each turn.\n",
"\n",
"More advanced strategies focus on incrementally updating the conversation history to avoid redundant processing.\n",
"\n",
"For instance, the langgraph [how-to guide on summarization](https://langchain-ai.github.io/langgraph/how-tos/memory/add-summary-conversation-history/) demonstrates\n",
"how to maintain a running summary of the conversation while discarding older messages, ensuring they aren't re-processed during later turns.\n",
":::\n",
"\n",
"You can later replace the logic with more complex logic that's better suited for your use case.\n",
"\n",
"### ConversationBufferWindowMemory, ConversationTokenBufferMemory"
]
},
{
"cell_type": "code",
"execution_count": 70,
"execution_count": 12,
"id": "a501806e-deac-458c-88b1-b615efde9930",
"metadata": {},
"outputs": [
@@ -534,10 +563,10 @@
" AIMessage(content=\"Hmmm let me think.\\n\\nWhy, he's probably chasing after the last cup of coffee in the office!\", additional_kwargs={}, response_metadata={}),\n",
" HumanMessage(content='why is 42 always the answer?', additional_kwargs={}, response_metadata={}),\n",
" AIMessage(content='Because its the only number thats constantly right, even when it doesnt add up!', additional_kwargs={}, response_metadata={}),\n",
" HumanMessage(content='What is the difference between a computer and a machine?', additional_kwargs={}, response_metadata={})]"
" HumanMessage(content='What did the cow say?', additional_kwargs={}, response_metadata={})]"
]
},
"execution_count": 70,
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
@@ -565,7 +594,7 @@
" AIMessage(\n",
" \"Because its the only number thats constantly right, even when it doesnt add up!\"\n",
" ),\n",
" HumanMessage(\"What is the difference between a computer and a machine?\"),\n",
" HumanMessage(\"What did the cow say?\"),\n",
"]\n",
"\n",
"\n",
@@ -610,34 +639,49 @@
"The obvious downside of this approach is that latency starts to increase as the conversation history grows because of two reasons:\n",
"\n",
"1. As the conversation gets longer, more data may need to be fetched from whatever store your'e using to store the conversation history (if not storing it in memory).\n",
"2. The pre-processing logic will end up doing a lot of redundant computation, repeating computation from previous steps of the conversation."
"2. The pre-processing logic will end up doing a lot of redundant computation, repeating computation from previous steps of the conversation.\n",
"\n",
":::caution\n",
"\n",
"If you're using tools, remember to bind the tools to the model before adding a pre-processing step to it!\n",
"\n",
":::"
]
},
{
"cell_type": "code",
"execution_count": 73,
"execution_count": 13,
"id": "5537b001-a49c-4d12-b25d-4087890f49b4",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"AIMessage(content=\"Well, a computer is a machine that can think, while a machine is a computer that can't!\", additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 21, 'prompt_tokens': 96, 'total_tokens': 117, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-0f08b428-8eb8-4422-b6d0-3ac494c0b6fe-0', usage_metadata={'input_tokens': 96, 'output_tokens': 21, 'total_tokens': 117})"
"AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_aYRmth57XGNqvZq3V5vn0Urg', 'function': {'arguments': '{}', 'name': 'what_did_the_cow_say'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 16, 'prompt_tokens': 126, 'total_tokens': 142, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-93b89a08-b8a1-4a7a-bedd-ab7e2ce47894-0', tool_calls=[{'name': 'what_did_the_cow_say', 'args': {}, 'id': 'call_aYRmth57XGNqvZq3V5vn0Urg', 'type': 'tool_call'}], usage_metadata={'input_tokens': 126, 'output_tokens': 16, 'total_tokens': 142})"
]
},
"execution_count": 73,
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from langchain_core.tools import tool\n",
"from langchain_openai import ChatOpenAI\n",
"\n",
"model = ChatOpenAI()\n",
"\n",
"# highlight-next-line\n",
"model_with_preprocessor = message_processor | model\n",
"\n",
"@tool\n",
"def what_did_the_cow_say() -> str:\n",
" \"\"\"Check to see what the cow said.\"\"\"\n",
" return \"foo\"\n",
"\n",
"\n",
"model_with_tools = model.bind_tools([what_did_the_cow_say])\n",
"\n",
"# highlight-next-line\n",
"model_with_preprocessor = message_processor | model_with_tools\n",
"\n",
"# full_message_history in the previous code block.\n",
"# We pass it explicity to the model_with_preprocesor for illustrative purposes.\n",
@@ -646,6 +690,18 @@
"model_with_preprocessor.invoke(full_message_history)"
]
},
{
"cell_type": "markdown",
"id": "aaa4e03a-0050-4f1d-bda1-530e387966bf",
"metadata": {},
"source": [
"If you need to implement more efficient logic and want to use `RunnableWithMessageHistory` for now the way to achieve this\n",
"is to subclass from [BaseChatMessageHistory](https://api.python.langchain.com/en/latest/chat_history/langchain_core.chat_history.BaseChatMessageHistory.html) and\n",
"define appropriate logic for `add_messages` (that doesn't simply append the history, but instead re-writes it).\n",
"\n",
"Unless you have a good reason to implement this solution, you should instead use LangGraph,"
]
},
{
"cell_type": "markdown",
"id": "84229e2e-a578-4b21-840a-814223406402",
@@ -659,7 +715,7 @@
"\n",
"You can create a pre-built agent using: [create_react_agent](https://langchain-ai.github.io/langgraph/reference/prebuilt/#create_react_agent).\n",
"\n",
"To add memory pre-processing to the agent\n",
"To add memory pre-processing to the agent, you can do the following:\n",
"\n",
"```python\n",
"\n",
@@ -673,7 +729,7 @@
"# highlight-end \n",
"\n",
"app = create_react_agent(\n",
" model, \n",
" model,\n",
" tools=[get_user_age], \n",
" checkpointer=memory,\n",
" # highlight-next-line\n",
@@ -684,12 +740,12 @@
"\n",
"```\n",
"\n",
"Pre-built react-agent"
"At each turn of the conversation, "
]
},
{
"cell_type": "code",
"execution_count": 74,
"execution_count": 14,
"id": "f671db87-8f01-453e-81fd-4e603140a512",
"metadata": {},
"outputs": [
@@ -702,8 +758,8 @@
"hi! I'm bob. What is my age?\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"Tool Calls:\n",
" get_user_age (call_BVUwjmlAebA36jK6WFOtDWfi)\n",
" Call ID: call_BVUwjmlAebA36jK6WFOtDWfi\n",
" get_user_age (call_kTEpBUbRFbKE3DZolG9tFrgD)\n",
" Call ID: call_kTEpBUbRFbKE3DZolG9tFrgD\n",
" Args:\n",
" name: bob\n",
"=================================\u001b[1m Tool Message \u001b[0m=================================\n",
@@ -783,6 +839,19 @@
" event[\"messages\"][-1].pretty_print()"
]
},
{
"cell_type": "markdown",
"id": "7a231ade-9f33-4ff8-9a62-20be3fc159b6",
"metadata": {},
"source": [
"### ConversationSummaryMemory / ConversationSummaryBufferMemory\n",
"\n",
"Its essential to summarize conversations efficiently to prevent growing latency as the conversation history grows.\n",
"\n",
"Please follow the guide [how to add summary of the conversation history](https://langchain-ai.github.io/langgraph/how-tos/memory/add-summary-conversation-history/) to see learn how to\n",
"handle conversation summarization efficiently with LangGraph."
]
},
{
"cell_type": "markdown",
"id": "b2717810",
@@ -799,13 +868,13 @@
"\n",
"Add persistence with simple LCEL (favor langgraph for more complex use cases):\n",
"\n",
"* [How to add message history](https://python.langchain.com/docs/how_to/message_history/)\n",
"* [How to add message history](/docs/how_to/message_history/)\n",
"\n",
"Working with message history:\n",
"\n",
"* [How to trim messages](https://python.langchain.com/docs/how_to/trim_messages)\n",
"* [How to filter messages](https://python.langchain.com/docs/how_to/filter_messages/)\n",
"* [How to merge message runs](https://python.langchain.com/docs/how_to/merge_message_runs/)"
"* [How to trim messages](/docs/how_to/trim_messages)\n",
"* [How to filter messages](/docs/how_to/filter_messages/)\n",
"* [How to merge message runs](/docs/how_to/merge_message_runs/)"
]
}
],