Last active
December 28, 2024 11:53
-
-
Save daviddwlee84/66cc5a0a72d4da9460bdcc7ec1da1322 to your computer and use it in GitHub Desktop.
LangGraph Quick Start Tutorial https://langchain-ai.github.io/langgraph/tutorials/introduction/ but using OpenAI and DuckDuckGo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"nbformat": 4, | |
"nbformat_minor": 0, | |
"metadata": { | |
"colab": { | |
"provenance": [], | |
"authorship_tag": "ABX9TyMz82r7cEEhs+NsmDrl7GsD", | |
"include_colab_link": true | |
}, | |
"kernelspec": { | |
"name": "python3", | |
"display_name": "Python 3" | |
}, | |
"language_info": { | |
"name": "python" | |
} | |
}, | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "view-in-github", | |
"colab_type": "text" | |
}, | |
"source": [ | |
"<a href=\"https://colab.research.google.com/gist/daviddwlee84/66cc5a0a72d4da9460bdcc7ec1da1322/langgraph_test.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"- [Quick Start](https://langchain-ai.github.io/langgraph/tutorials/introduction/#requirements)" | |
], | |
"metadata": { | |
"id": "f4sCtcdk0Uav" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "fhFtoI-y0NDf" | |
}, | |
"outputs": [], | |
"source": [ | |
"%%capture --no-stderr\n", | |
"%pip install -U langgraph" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"import getpass\n", | |
"import os\n", | |
"\n", | |
"\n", | |
"def _set_env(var: str):\n", | |
" if not os.environ.get(var):\n", | |
" os.environ[var] = getpass.getpass(f\"{var}: \")\n", | |
"\n", | |
"\n", | |
"_set_env(\"OPENAI_API_KEY\")" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "2qxHEBHM0gbX", | |
"outputId": "9cc1c4da-6deb-4ae1-bdd7-3c386e6ec355" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"OPENAI_API_KEY: ··········\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from typing import Annotated\n", | |
"\n", | |
"from typing_extensions import TypedDict\n", | |
"\n", | |
"from langgraph.graph import StateGraph, START, END\n", | |
"from langgraph.graph.message import add_messages\n", | |
"\n", | |
"\n", | |
"class State(TypedDict):\n", | |
" # Messages have the type \"list\". The `add_messages` function\n", | |
" # in the annotation defines how this state key should be updated\n", | |
" # (in this case, it appends messages to the list, rather than overwriting them)\n", | |
" messages: Annotated[list, add_messages]\n", | |
"\n", | |
"\n", | |
"graph_builder = StateGraph(State)" | |
], | |
"metadata": { | |
"id": "q-AmtHRS0qG2" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"- [OpenAI | 🦜️🔗 LangChain](https://python.langchain.com/v0.2/docs/integrations/llms/openai/)\n", | |
"- [Models - OpenAI API](https://platform.openai.com/docs/models/gpt-4o-mini)\n", | |
"- [Pricing | OpenAI](https://openai.com/api/pricing/)" | |
], | |
"metadata": { | |
"id": "-y7TIYXw1GKi" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"%%capture --no-stderr\n", | |
"%pip install -U langchain-openai" | |
], | |
"metadata": { | |
"id": "kchp_DTm1KfO" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from langchain_openai import ChatOpenAI\n", | |
"# https://stackoverflow.com/a/76611108/3682187\n", | |
"llm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\")" | |
], | |
"metadata": { | |
"id": "htTLjc4W0uj3" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"llm.invoke(\"Hello how are you?\")" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "B2ZhZWu-1YhY", | |
"outputId": "3b4c0df1-4ffc-4fb4-c6fd-c8b78788724f" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"AIMessage(content=\"Hello! I'm just a computer program, so I don't have feelings, but I'm here and ready to assist you. How can I help you today?\", additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 33, 'prompt_tokens': 12, 'total_tokens': 45}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-aaae72e6-c686-4d64-8e81-f8e95f115ee4-0', usage_metadata={'input_tokens': 12, 'output_tokens': 33, 'total_tokens': 45})" | |
] | |
}, | |
"metadata": {}, | |
"execution_count": 14 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"def chatbot(state: State):\n", | |
" return {\"messages\": [llm.invoke(state[\"messages\"])]}\n", | |
"\n", | |
"\n", | |
"# The first argument is the unique node name\n", | |
"# The second argument is the function or object that will be called whenever\n", | |
"# the node is used.\n", | |
"graph_builder.add_node(\"chatbot\", chatbot)" | |
], | |
"metadata": { | |
"id": "-t-Xnq1w0wbX" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"graph_builder.add_edge(START, \"chatbot\")" | |
], | |
"metadata": { | |
"id": "BBCVn7Oq2PRP" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"graph_builder.add_edge(\"chatbot\", END)" | |
], | |
"metadata": { | |
"id": "tyFWF9Tb2WDs" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"graph = graph_builder.compile()" | |
], | |
"metadata": { | |
"id": "EqOkROPu2W_2" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from IPython.display import Image, display\n", | |
"\n", | |
"try:\n", | |
" display(Image(graph.get_graph().draw_mermaid_png()))\n", | |
"except Exception:\n", | |
" # This requires some extra dependencies and is optional\n", | |
" pass" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 236 | |
}, | |
"id": "eC2cVce32X24", | |
"outputId": "43d65d23-1c05-434e-c43d-ca8e2803d5e6" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "display_data", | |
"data": { | |
"image/jpeg": "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\n", | |
"text/plain": [ | |
"<IPython.core.display.Image object>" | |
] | |
}, | |
"metadata": {} | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"while True:\n", | |
" user_input = input(\"User: \")\n", | |
" if user_input.lower() in [\"quit\", \"exit\", \"q\"]:\n", | |
" print(\"Goodbye!\")\n", | |
" break\n", | |
" for event in graph.stream({\"messages\": (\"user\", user_input)}):\n", | |
" for value in event.values():\n", | |
" print(\"Assistant:\", value[\"messages\"][-1].content)" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "YimJ2Rkq2Ynm", | |
"outputId": "b743af2b-9a2c-45ac-d88e-6314b4a423d0" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"User: Hi\n", | |
"Assistant: Hello! How can I assist you today?\n", | |
"User: My name is David, please remember that\n", | |
"Assistant: Nice to meet you, David! I will remember your name.\n", | |
"User: What is my name?\n", | |
"Assistant: I'm sorry, I do not have access to personal information. Can you please provide me with your name?\n", | |
"User: q\n", | |
"Goodbye!\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"## Enhancing the Chatbot with Tools\n", | |
"\n", | |
"- [DuckDuckGo Search | 🦜️🔗 LangChain](https://python.langchain.com/v0.2/docs/integrations/tools/ddg/)\n", | |
"- [langchain_community.tools.ddg_search.tool.DuckDuckGoSearchRun — 🦜🔗 LangChain 0.2.13](https://api.python.langchain.com/en/latest/tools/langchain_community.tools.ddg_search.tool.DuckDuckGoSearchRun.html)" | |
], | |
"metadata": { | |
"id": "OZRH04e72ud0" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"%%capture --no-stderr\n", | |
"%pip install duckduckgo-search langchain-community" | |
], | |
"metadata": { | |
"id": "pHlud6mk2d5e" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from langchain_community.tools import DuckDuckGoSearchResults\n", | |
"\n", | |
"search = DuckDuckGoSearchResults()\n", | |
"\n", | |
"search.invoke(\"Obama\")" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 157 | |
}, | |
"id": "lOrKaldB3CBt", | |
"outputId": "d3330b8c-3dc9-4630-a57c-8358b3c23a92" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"'[snippet: Mr. Obama\\'s first address to a Democratic convention, in 2004 when he was an Illinois state senator running for the U.S. Senate, made a mark with its rejection of a separate blue America and red ..., title: Barack Obama at DNC: I Am \\'Stupid Enough to Speak After Michelle\\' - The ..., link: https://www.nytimes.com/2024/08/21/us/politics/obamas-convention.html], [snippet: Barack Obama (born August 4, 1961, Honolulu, Hawaii, U.S.) is the 44th president of the United States (2009-17) and the first African American to hold the office. Before winning the presidency, Obama represented Illinois in the U.S. Senate (2005-08). He was the third African American to be elected to that body since the end of ..., title: Barack Obama | Biography, Parents, Education, Presidency, Books ..., link: https://www.britannica.com/biography/Barack-Obama], [snippet: At the Democratic National Convention, former President Barack Obama mocked former President Donald Trump and said he had a \"weird obsession with crowd sizes.\", title: Obama mocks Trump about his \\'weird obsession with crowd sizes\\' - CNN, link: https://www.cnn.com/2024/08/21/politics/video/barack-obama-donald-trump-crowd-size-dnc-digvid], [snippet: Obama\\'s favored phrase back then was \"I don\\'t want to thumb the scale.\") Endorsing too early now would also be a political mistake — fueling criticism that Ms. Harris\\'s nomination ..., title: Why Obama Hasn\\'t Endorsed Harris - The New York Times, link: https://www.nytimes.com/2024/07/21/us/politics/why-obama-hasnt-endorsed-harris.html]'" | |
], | |
"application/vnd.google.colaboratory.intrinsic+json": { | |
"type": "string" | |
} | |
}, | |
"metadata": {}, | |
"execution_count": 24 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"tools = [search]" | |
], | |
"metadata": { | |
"id": "sJSsE6W_3YHZ" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"graph_builder2 = StateGraph(State)\n", | |
"llm2 = ChatOpenAI(model=\"gpt-3.5-turbo-0125\")\n", | |
"llm_with_tools = llm2.bind_tools(tools)\n", | |
"\n", | |
"def chatbot2(state: State):\n", | |
" return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n", | |
"\n", | |
"graph_builder2.add_node(\"chatbot\", chatbot2)" | |
], | |
"metadata": { | |
"id": "Wziwaine3JB3" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"import json\n", | |
"\n", | |
"from langchain_core.messages import ToolMessage\n", | |
"\n", | |
"\n", | |
"class BasicToolNode:\n", | |
" \"\"\"A node that runs the tools requested in the last AIMessage.\"\"\"\n", | |
"\n", | |
" def __init__(self, tools: list) -> None:\n", | |
" self.tools_by_name = {tool.name: tool for tool in tools}\n", | |
"\n", | |
" def __call__(self, inputs: dict):\n", | |
" if messages := inputs.get(\"messages\", []):\n", | |
" message = messages[-1]\n", | |
" else:\n", | |
" raise ValueError(\"No message found in input\")\n", | |
" outputs = []\n", | |
" for tool_call in message.tool_calls:\n", | |
" tool_result = self.tools_by_name[tool_call[\"name\"]].invoke(\n", | |
" tool_call[\"args\"]\n", | |
" )\n", | |
" outputs.append(\n", | |
" ToolMessage(\n", | |
" content=json.dumps(tool_result),\n", | |
" name=tool_call[\"name\"],\n", | |
" tool_call_id=tool_call[\"id\"],\n", | |
" )\n", | |
" )\n", | |
" return {\"messages\": outputs}\n", | |
"\n", | |
"\n", | |
"tool_node = BasicToolNode(tools=[search])\n", | |
"graph_builder2.add_node(\"tools\", tool_node)" | |
], | |
"metadata": { | |
"id": "rS5uKh-G3ZuF" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from typing import Literal\n", | |
"\n", | |
"\n", | |
"def route_tools(\n", | |
" state: State,\n", | |
") -> Literal[\"tools\", \"__end__\"]:\n", | |
" \"\"\"\n", | |
" Use in the conditional_edge to route to the ToolNode if the last message\n", | |
" has tool calls. Otherwise, route to the end.\n", | |
" \"\"\"\n", | |
" if isinstance(state, list):\n", | |
" ai_message = state[-1]\n", | |
" elif messages := state.get(\"messages\", []):\n", | |
" ai_message = messages[-1]\n", | |
" else:\n", | |
" raise ValueError(f\"No messages found in input state to tool_edge: {state}\")\n", | |
" if hasattr(ai_message, \"tool_calls\") and len(ai_message.tool_calls) > 0:\n", | |
" return \"tools\"\n", | |
" return \"__end__\"\n", | |
"\n", | |
"\n", | |
"# The `tools_condition` function returns \"tools\" if the chatbot asks to use a tool, and \"__end__\" if\n", | |
"# it is fine directly responding. This conditional routing defines the main agent loop.\n", | |
"graph_builder2.add_conditional_edges(\n", | |
" \"chatbot\",\n", | |
" route_tools,\n", | |
" # The following dictionary lets you tell the graph to interpret the condition's outputs as a specific node\n", | |
" # It defaults to the identity function, but if you\n", | |
" # want to use a node named something else apart from \"tools\",\n", | |
" # You can update the value of the dictionary to something else\n", | |
" # e.g., \"tools\": \"my_tools\"\n", | |
" {\"tools\": \"tools\", \"__end__\": \"__end__\"},\n", | |
")\n", | |
"# Any time a tool is called, we return to the chatbot to decide the next step\n", | |
"graph_builder2.add_edge(\"tools\", \"chatbot\")\n", | |
"graph_builder2.add_edge(START, \"chatbot\")\n", | |
"graph2 = graph_builder2.compile()\n", | |
"\n", | |
"graph2" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "2NusNLe-3nKd", | |
"outputId": "bda149c8-aa03-44ea-e7d9-04f496766992" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"CompiledStateGraph(nodes={'__start__': PregelNode(config={'tags': ['langsmith:hidden'], 'metadata': {}, 'configurable': {}}, channels=['__start__'], triggers=['__start__'], writers=[ChannelWrite<messages>(recurse=True, writes=[ChannelWriteEntry(channel='messages', value=<object object at 0x7bcf72732040>, skip_none=False, mapper=_get_state_key(recurse=False))], require_at_least_one_of=['messages']), ChannelWrite<start:chatbot>(recurse=True, writes=[ChannelWriteEntry(channel='start:chatbot', value='__start__', skip_none=False, mapper=None)], require_at_least_one_of=None)]), 'chatbot': PregelNode(config={'tags': [], 'metadata': {}, 'configurable': {}}, channels={'messages': 'messages'}, triggers=['tools', 'start:chatbot'], mapper=functools.partial(<function _coerce_state at 0x7bcf7073acb0>, <class '__main__.State'>), writers=[ChannelWrite<chatbot,messages>(recurse=True, writes=[ChannelWriteEntry(channel='chatbot', value='chatbot', skip_none=False, mapper=None), ChannelWriteEntry(channel='messages', value=<object object at 0x7bcf72732040>, skip_none=False, mapper=_get_state_key(recurse=False))], require_at_least_one_of=['messages']), _route(recurse=True, _is_channel_writer=True)]), 'tools': PregelNode(config={'tags': [], 'metadata': {}, 'configurable': {}}, channels={'messages': 'messages'}, triggers=['branch:chatbot:route_tools:tools'], mapper=functools.partial(<function _coerce_state at 0x7bcf7073acb0>, <class '__main__.State'>), writers=[ChannelWrite<tools,messages>(recurse=True, writes=[ChannelWriteEntry(channel='tools', value='tools', skip_none=False, mapper=None), ChannelWriteEntry(channel='messages', value=<object object at 0x7bcf72732040>, skip_none=False, mapper=_get_state_key(recurse=False))], require_at_least_one_of=['messages'])])}, channels={'messages': <langgraph.channels.binop.BinaryOperatorAggregate object at 0x7bcf50671b70>, '__start__': <langgraph.channels.ephemeral_value.EphemeralValue object at 0x7bcf4f76f460>, 'chatbot': <langgraph.channels.ephemeral_value.EphemeralValue object at 0x7bcf4f76f9d0>, 'tools': <langgraph.channels.ephemeral_value.EphemeralValue object at 0x7bcf4f76fcd0>, 'start:chatbot': <langgraph.channels.ephemeral_value.EphemeralValue object at 0x7bcf4f76f550>, 'branch:chatbot:route_tools:tools': <langgraph.channels.ephemeral_value.EphemeralValue object at 0x7bcf4f76e200>}, auto_validate=False, stream_mode='updates', output_channels=['messages'], stream_channels=['messages'], input_channels='__start__', builder=<langgraph.graph.state.StateGraph object at 0x7bcf50673df0>)" | |
] | |
}, | |
"metadata": {}, | |
"execution_count": 29 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from IPython.display import Image, display\n", | |
"\n", | |
"try:\n", | |
" display(Image(graph2.get_graph().draw_mermaid_png()))\n", | |
"except Exception:\n", | |
" # This requires some extra dependencies and is optional\n", | |
" pass" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 236 | |
}, | |
"id": "bP7CQTfL31d8", | |
"outputId": "0eebb6e5-2b62-4d2c-fddf-93a72acd6b57" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "display_data", | |
"data": { | |
"image/jpeg": "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\n", | |
"text/plain": [ | |
"<IPython.core.display.Image object>" | |
] | |
}, | |
"metadata": {} | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from langchain_core.messages import BaseMessage\n", | |
"\n", | |
"while True:\n", | |
" user_input = input(\"User: \")\n", | |
" if user_input.lower() in [\"quit\", \"exit\", \"q\"]:\n", | |
" print(\"Goodbye!\")\n", | |
" break\n", | |
" for event in graph2.stream({\"messages\": [(\"user\", user_input)]}):\n", | |
" for value in event.values():\n", | |
" if isinstance(value[\"messages\"][-1], BaseMessage):\n", | |
" print(\"Assistant:\", value[\"messages\"][-1].content)\n" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "8geNI7JI33ef", | |
"outputId": "145613b2-a546-4a90-c236-f0db5427f936" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"User: What's langgraph all about?\n", | |
"Assistant: \n", | |
"Assistant: \"[snippet: LangGraph is a package for creating LLM workflows with cycles and multi-agent designs. Learn what multi-agent means, why it is useful, and see examples of LangGraph applications and comparisons with other frameworks., title: LangGraph: Multi-Agent Workflows, link: https://blog.langchain.dev/langgraph-multi-agent-workflows/], [snippet: LangGraph is a versatile tool for building complex, stateful applications with LLMs. By understanding its core concepts and working through simple examples, beginners can start to leverage its ..., title: Introduction to LangGraph: A Beginner's Guide - Medium, link: https://medium.com/@cplog/introduction-to-langgraph-a-beginners-guide-14f9be027141], [snippet: LangGraph is a library for building stateful, multi-actor applications with LLMs, used to create agent and multi-agent workflows. Compared to other LLM frameworks, it offers these core benefits: cycles, controllability, and persistence. LangGraph allows you to define flows that involve cycles, essential for most agentic architectures ..., title: langgraph \\u00b7 PyPI, link: https://pypi.org/project/langgraph/], [snippet: StateGraph: In LangGraph, the StateGraph is a fundamental component used to construct and manage stateful & multi-actor workflows. It defines the structure of the graph, including the schema for ..., title: LangGraph: Multi-Agent Collaboration Explained - Medium, link: https://medium.com/@kbdhunga/langgraph-multi-agent-collaboration-explained-c0500b0f2e61]\"\n", | |
"Assistant: LangGraph is a package for creating multi-agent workflows with cycles and multi-agent designs. It is a versatile tool for building complex, stateful applications with LLMs (Large Language Models). LangGraph allows you to define flows that involve cycles, essential for most agentic architectures. It offers core benefits such as cycles, controllability, and persistence. You can learn more about LangGraph and its applications through the following links:\n", | |
"\n", | |
"1. [LangGraph: Multi-Agent Workflows](https://blog.langchain.dev/langgraph-multi-agent-workflows/)\n", | |
"2. [Introduction to LangGraph: A Beginner's Guide](https://medium.com/@cplog/introduction-to-langgraph-a-beginners-guide-14f9be027141)\n", | |
"3. [LangGraph on PyPI](https://pypi.org/project/langgraph/)\n", | |
"4. [LangGraph: Multi-Agent Collaboration Explained](https://medium.com/@kbdhunga/langgraph-multi-agent-collaboration-explained-c0500b0f2e61)\n", | |
"User: What is my last question?\n", | |
"Assistant: I don't have access to your previous questions. How can I assist you today?\n", | |
"User: q\n", | |
"Goodbye!\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"## Adding Memoy to the Chatbot" | |
], | |
"metadata": { | |
"id": "r2TmmXrT4Nm-" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from langgraph.checkpoint.memory import MemorySaver\n", | |
"\n", | |
"memory = MemorySaver()" | |
], | |
"metadata": { | |
"id": "Ps8tPwRp38gt" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from langgraph.prebuilt import ToolNode, tools_condition\n", | |
"\n", | |
"graph_builder3 = StateGraph(State)\n", | |
"llm3 = ChatOpenAI(model=\"gpt-3.5-turbo-0125\")\n", | |
"llm_with_tools2 = llm3.bind_tools(tools)\n", | |
"\n", | |
"def chatbot3(state: State):\n", | |
" return {\"messages\": [llm_with_tools2.invoke(state[\"messages\"])]}\n", | |
"\n", | |
"graph_builder3.add_node(\"chatbot\", chatbot3)\n", | |
"tool_node = ToolNode(tools=tools)\n", | |
"graph_builder3.add_node(\"tools\", tool_node)\n", | |
"graph_builder3.add_conditional_edges(\n", | |
" \"chatbot\",\n", | |
" tools_condition\n", | |
")\n", | |
"# Any time a tool is called, we return to the chatbot to decide the next step\n", | |
"graph_builder3.add_edge(\"tools\", \"chatbot\")\n", | |
"graph_builder3.add_edge(START, \"chatbot\")\n", | |
"graph3 = graph_builder3.compile(checkpointer=memory)\n", | |
"\n", | |
"graph3" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "oYPq1yYf4W7l", | |
"outputId": "ef7ce420-b1c8-4bc7-eb44-3c5a11f30818" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"CompiledStateGraph(nodes={'__start__': PregelNode(config={'tags': ['langsmith:hidden'], 'metadata': {}, 'configurable': {}}, channels=['__start__'], triggers=['__start__'], writers=[ChannelWrite<messages>(recurse=True, writes=[ChannelWriteEntry(channel='messages', value=<object object at 0x7bcf72732040>, skip_none=False, mapper=_get_state_key(recurse=False))], require_at_least_one_of=['messages']), ChannelWrite<start:chatbot>(recurse=True, writes=[ChannelWriteEntry(channel='start:chatbot', value='__start__', skip_none=False, mapper=None)], require_at_least_one_of=None)]), 'chatbot': PregelNode(config={'tags': [], 'metadata': {}, 'configurable': {}}, channels={'messages': 'messages'}, triggers=['tools', 'start:chatbot'], mapper=functools.partial(<function _coerce_state at 0x7bcf7073acb0>, <class '__main__.State'>), writers=[ChannelWrite<chatbot,messages>(recurse=True, writes=[ChannelWriteEntry(channel='chatbot', value='chatbot', skip_none=False, mapper=None), ChannelWriteEntry(channel='messages', value=<object object at 0x7bcf72732040>, skip_none=False, mapper=_get_state_key(recurse=False))], require_at_least_one_of=['messages']), _route(recurse=True, _is_channel_writer=True)]), 'tools': PregelNode(config={'tags': [], 'metadata': {}, 'configurable': {}}, channels={'messages': 'messages'}, triggers=['branch:chatbot:tools_condition:tools'], mapper=functools.partial(<function _coerce_state at 0x7bcf7073acb0>, <class '__main__.State'>), writers=[ChannelWrite<tools,messages>(recurse=True, writes=[ChannelWriteEntry(channel='tools', value='tools', skip_none=False, mapper=None), ChannelWriteEntry(channel='messages', value=<object object at 0x7bcf72732040>, skip_none=False, mapper=_get_state_key(recurse=False))], require_at_least_one_of=['messages'])])}, channels={'messages': <langgraph.channels.binop.BinaryOperatorAggregate object at 0x7bcf4dc5b520>, '__start__': <langgraph.channels.ephemeral_value.EphemeralValue object at 0x7bcf4dc59180>, 'chatbot': <langgraph.channels.ephemeral_value.EphemeralValue object at 0x7bcf4dcb4580>, 'tools': <langgraph.channels.ephemeral_value.EphemeralValue object at 0x7bcf4dcb4730>, 'start:chatbot': <langgraph.channels.ephemeral_value.EphemeralValue object at 0x7bcf4dcb41f0>, 'branch:chatbot:tools_condition:tools': <langgraph.channels.ephemeral_value.EphemeralValue object at 0x7bcf4dcb46d0>}, auto_validate=False, stream_mode='updates', output_channels=['messages'], stream_channels=['messages'], input_channels='__start__', checkpointer=<langgraph.checkpoint.memory.MemorySaver object at 0x7bcf4f76d840>, builder=<langgraph.graph.state.StateGraph object at 0x7bcf4dc592d0>)" | |
] | |
}, | |
"metadata": {}, | |
"execution_count": 35 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from IPython.display import Image, display\n", | |
"\n", | |
"try:\n", | |
" display(Image(graph3.get_graph().draw_mermaid_png()))\n", | |
"except Exception:\n", | |
" # This requires some extra dependencies and is optional\n", | |
" pass" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 236 | |
}, | |
"id": "DUTTmoM943p7", | |
"outputId": "77e23831-77df-4038-b39e-dac086de5429" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "display_data", | |
"data": { | |
"image/jpeg": "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\n", | |
"text/plain": [ | |
"<IPython.core.display.Image object>" | |
] | |
}, | |
"metadata": {} | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"config = {\"configurable\": {\"thread_id\": \"1\"}}" | |
], | |
"metadata": { | |
"id": "mWfEXyO45E0Y" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"user_input = \"Hi there! My name is Will.\"\n", | |
"\n", | |
"# The config is the **second positional argument** to stream() or invoke()!\n", | |
"events = graph3.stream(\n", | |
" {\"messages\": [(\"user\", user_input)]}, config, stream_mode=\"values\"\n", | |
")\n", | |
"for event in events:\n", | |
" event[\"messages\"][-1].pretty_print()" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "xivgxBl65Lbl", | |
"outputId": "7537ea9f-789a-4051-966e-f913c5a6ec54" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"================================\u001b[1m Human Message \u001b[0m=================================\n", | |
"\n", | |
"Hi there! My name is Will.\n", | |
"==================================\u001b[1m Ai Message \u001b[0m==================================\n", | |
"\n", | |
"Hello Will! How can I assist you today?\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"user_input = \"Remember my name?\"\n", | |
"\n", | |
"# The config is the **second positional argument** to stream() or invoke()!\n", | |
"events = graph3.stream(\n", | |
" {\"messages\": [(\"user\", user_input)]}, config, stream_mode=\"values\"\n", | |
")\n", | |
"for event in events:\n", | |
" event[\"messages\"][-1].pretty_print()" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "L3aH5W9P5NVc", | |
"outputId": "0ac31a12-68f4-40f9-b5a6-20d0150083bd" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"================================\u001b[1m Human Message \u001b[0m=================================\n", | |
"\n", | |
"Remember my name?\n", | |
"==================================\u001b[1m Ai Message \u001b[0m==================================\n", | |
"\n", | |
"Yes, Will! I remember your name. How can I help you today?\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# The only difference is we change the `thread_id` here to \"2\" instead of \"1\"\n", | |
"events = graph3.stream(\n", | |
" {\"messages\": [(\"user\", user_input)]},\n", | |
" {\"configurable\": {\"thread_id\": \"2\"}},\n", | |
" stream_mode=\"values\",\n", | |
")\n", | |
"for event in events:\n", | |
" event[\"messages\"][-1].pretty_print()" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "D-YFIele5Twz", | |
"outputId": "5e251b34-98ba-4204-a983-52ea2aa8cf68" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"================================\u001b[1m Human Message \u001b[0m=================================\n", | |
"\n", | |
"Remember my name?\n", | |
"==================================\u001b[1m Ai Message \u001b[0m==================================\n", | |
"\n", | |
"I'm sorry, but I don't have the ability to remember personal information about users. How can I assist you today?\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"snapshot = graph3.get_state(config)\n", | |
"snapshot" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "UdlSJoIM5qhj", | |
"outputId": "8ffe6634-5ba4-43af-c87a-55613499db77" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"StateSnapshot(values={'messages': [HumanMessage(content='Hi there! My name is Will.', id='d18e61f5-9c43-4234-a5c2-841f91b51fc8'), AIMessage(content='Hello Will! How can I assist you today?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 11, 'prompt_tokens': 95, 'total_tokens': 106}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-0e59528b-b05e-4745-9f47-a4bf091b600b-0', usage_metadata={'input_tokens': 95, 'output_tokens': 11, 'total_tokens': 106}), HumanMessage(content='Remember my name?', id='d817b54e-9d10-4305-bbbd-009603118ce6'), AIMessage(content='Yes, Will! I remember your name. How can I help you today?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 17, 'prompt_tokens': 117, 'total_tokens': 134}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-af865234-cdb7-48f0-abc8-5a8930ffc48a-0', usage_metadata={'input_tokens': 117, 'output_tokens': 17, 'total_tokens': 134})]}, next=(), config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef6388f-c1f4-6f1e-8004-73387339be14'}}, metadata={'source': 'loop', 'writes': {'chatbot': {'messages': [AIMessage(content='Yes, Will! I remember your name. How can I help you today?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 17, 'prompt_tokens': 117, 'total_tokens': 134}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-af865234-cdb7-48f0-abc8-5a8930ffc48a-0', usage_metadata={'input_tokens': 117, 'output_tokens': 17, 'total_tokens': 134})]}}, 'step': 4}, created_at='2024-08-26T08:55:46.838694+00:00', parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef6388f-b3d0-6910-8003-10ff5ce3320a'}}, tasks=())" | |
] | |
}, | |
"metadata": {}, | |
"execution_count": 46 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"snapshot.next" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "W_o-BgqT5wU9", | |
"outputId": "48bf1677-0754-4525-f5cc-96fac7551727" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"()" | |
] | |
}, | |
"metadata": {}, | |
"execution_count": 47 | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"## Human-in-the-loop" | |
], | |
"metadata": { | |
"id": "udyC1aAY6Tl8" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from langgraph.prebuilt import ToolNode, tools_condition\n", | |
"\n", | |
"\n", | |
"\n", | |
"graph_builder4 = StateGraph(State)\n", | |
"\n", | |
"graph_builder4.add_node(\"chatbot\", chatbot3)\n", | |
"graph_builder4.add_node(\"tools\", tool_node)\n", | |
"graph_builder4.add_conditional_edges(\n", | |
" \"chatbot\",\n", | |
" tools_condition\n", | |
")\n", | |
"graph_builder4.add_edge(\"tools\", \"chatbot\")\n", | |
"graph_builder4.add_edge(START, \"chatbot\")\n", | |
"\n", | |
"memory2 = MemorySaver()\n", | |
"\n", | |
"graph4 = graph_builder4.compile(\n", | |
" checkpointer=memory2,\n", | |
" # This is new!\n", | |
" interrupt_before=[\"tools\"],\n", | |
" # Note: can also interrupt __after__ tools, if desired.\n", | |
" # interrupt_after=[\"tools\"]\n", | |
")" | |
], | |
"metadata": { | |
"id": "1YS4_N5953Pr" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"user_input = \"I'm learning LangGraph. Could you do some research on it for me?\"\n", | |
"config = {\"configurable\": {\"thread_id\": \"1\"}}\n", | |
"# The config is the **second positional argument** to stream() or invoke()!\n", | |
"events = graph4.stream(\n", | |
" {\"messages\": [(\"user\", user_input)]}, config, stream_mode=\"values\"\n", | |
")\n", | |
"for event in events:\n", | |
" if \"messages\" in event:\n", | |
" event[\"messages\"][-1].pretty_print()" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "8hzT3VXZ7FNc", | |
"outputId": "c53ca906-1cc0-4251-e9d8-591cef8eff31" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"================================\u001b[1m Human Message \u001b[0m=================================\n", | |
"\n", | |
"I'm learning LangGraph. Could you do some research on it for me?\n", | |
"==================================\u001b[1m Ai Message \u001b[0m==================================\n", | |
"Tool Calls:\n", | |
" duckduckgo_results_json (call_DPEZIga1ZoocLNQWAVYxZhaP)\n", | |
" Call ID: call_DPEZIga1ZoocLNQWAVYxZhaP\n", | |
" Args:\n", | |
" query: LangGraph\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"snapshot = graph4.get_state(config)\n", | |
"snapshot.next" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "Tb0g_WYk7LPE", | |
"outputId": "d8b506ff-3b07-4462-d0f7-7a959b5d6c21" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"('tools',)" | |
] | |
}, | |
"metadata": {}, | |
"execution_count": 51 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"existing_message = snapshot.values[\"messages\"][-1]\n", | |
"existing_message.tool_calls" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "35rjPJax7OuM", | |
"outputId": "310a6a81-19d8-4b90-cc8a-c7668844dbfc" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"[{'name': 'duckduckgo_results_json',\n", | |
" 'args': {'query': 'LangGraph'},\n", | |
" 'id': 'call_DPEZIga1ZoocLNQWAVYxZhaP',\n", | |
" 'type': 'tool_call'}]" | |
] | |
}, | |
"metadata": {}, | |
"execution_count": 52 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# `None` will append nothing new to the current state, letting it resume as if it had never been interrupted\n", | |
"events = graph4.stream(None, config, stream_mode=\"values\")\n", | |
"for event in events:\n", | |
" if \"messages\" in event:\n", | |
" event[\"messages\"][-1].pretty_print()" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "Z7A0ib737Sis", | |
"outputId": "aa3fba55-8f4d-4a09-9f36-f646f7c67cb1" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"=================================\u001b[1m Tool Message \u001b[0m=================================\n", | |
"Name: duckduckgo_results_json\n", | |
"\n", | |
"[snippet: LangGraph is a package for creating LLM workflows with cycles and multi-agent designs. Learn what multi-agent means, why it is useful, and see examples of LangGraph applications and comparisons with other frameworks., title: LangGraph: Multi-Agent Workflows, link: https://blog.langchain.dev/langgraph-multi-agent-workflows/], [snippet: LangGraph is a versatile tool for building complex, stateful applications with LLMs. By understanding its core concepts and working through simple examples, beginners can start to leverage its ..., title: Introduction to LangGraph: A Beginner's Guide - Medium, link: https://medium.com/@cplog/introduction-to-langgraph-a-beginners-guide-14f9be027141], [snippet: StateGraph: In LangGraph, the StateGraph is a fundamental component used to construct and manage stateful & multi-actor workflows. It defines the structure of the graph, including the schema for ..., title: LangGraph: Multi-Agent Collaboration Explained - Medium, link: https://medium.com/@kbdhunga/langgraph-multi-agent-collaboration-explained-c0500b0f2e61], [snippet: LangGraph's strength lies in its ability to balance control flow with adaptability. Conditional nodes and the allowance of cycles empower agents to be both flexible and reliable. Similar to a ..., title: A primer on AI Agents with LangGraph, understand all about it, link: https://medium.com/@Shrishml/a-primer-on-ai-agents-with-langgraph-understand-all-about-it-0534345190dc]\n", | |
"==================================\u001b[1m Ai Message \u001b[0m==================================\n", | |
"\n", | |
"I found some information about LangGraph for you:\n", | |
"\n", | |
"1. [LangGraph: Multi-Agent Workflows](https://blog.langchain.dev/langgraph-multi-agent-workflows/): LangGraph is a package for creating LLM workflows with cycles and multi-agent designs. Learn about multi-agent workflows, their usefulness, and see examples of LangGraph applications.\n", | |
"\n", | |
"2. [Introduction to LangGraph: A Beginner's Guide - Medium](https://medium.com/@cplog/introduction-to-langgraph-a-beginners-guide-14f9be027141): LangGraph is a versatile tool for building complex, stateful applications with LLMs. Beginners can understand its core concepts through simple examples.\n", | |
"\n", | |
"3. [LangGraph: Multi-Agent Collaboration Explained - Medium](https://medium.com/@kbdhunga/langgraph-multi-agent-collaboration-explained-c0500b0f2e61): StateGraph in LangGraph is crucial for constructing and managing stateful and multi-actor workflows. It defines the graph's structure and schema.\n", | |
"\n", | |
"4. [A primer on AI Agents with LangGraph, understand all about it](https://medium.com/@Shrishml/a-primer-on-ai-agents-with-langgraph-understand-all-about-it-0534345190dc): LangGraph's strength lies in balancing control flow with adaptability, empowering agents to be flexible and reliable with conditional nodes and cycle allowance.\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"## Manually Updating the State" | |
], | |
"metadata": { | |
"id": "SGHOjz597reJ" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"graph_builder5 = StateGraph(State)\n", | |
"\n", | |
"graph_builder5.add_node(\"chatbot\", chatbot3)\n", | |
"graph_builder5.add_node(\"tools\", tool_node)\n", | |
"graph_builder5.add_conditional_edges(\n", | |
" \"chatbot\",\n", | |
" tools_condition\n", | |
")\n", | |
"graph_builder5.add_edge(\"tools\", \"chatbot\")\n", | |
"graph_builder5.add_edge(START, \"chatbot\")\n", | |
"\n", | |
"memory3 = MemorySaver()\n", | |
"\n", | |
"graph5 = graph_builder4.compile(\n", | |
" checkpointer=memory3,\n", | |
" # This is new!\n", | |
" interrupt_before=[\"tools\"],\n", | |
" # Note: can also interrupt __after__ tools, if desired.\n", | |
" # interrupt_after=[\"tools\"]\n", | |
")\n", | |
"\n", | |
"user_input = \"I'm learning LangGraph. Could you do some research on it for me?\"\n", | |
"config = {\"configurable\": {\"thread_id\": \"1\"}}\n", | |
"# The config is the **second positional argument** to stream() or invoke()!\n", | |
"events = graph5.stream({\"messages\": [(\"user\", user_input)]}, config)\n", | |
"for event in events:\n", | |
" if \"messages\" in event:\n", | |
" event[\"messages\"][-1].pretty_print()" | |
], | |
"metadata": { | |
"id": "eg5L__q57X-e" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"snapshot = graph5.get_state(config)\n", | |
"existing_message = snapshot.values[\"messages\"][-1]\n", | |
"existing_message.pretty_print()" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "xavx9QeO742r", | |
"outputId": "0ffc38e7-420d-4392-9dfb-5af2dcaa6805" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"==================================\u001b[1m Ai Message \u001b[0m==================================\n", | |
"Tool Calls:\n", | |
" duckduckgo_results_json (call_IsktVzsMrWiUbLqbnz8EqzTJ)\n", | |
" Call ID: call_IsktVzsMrWiUbLqbnz8EqzTJ\n", | |
" Args:\n", | |
" query: LangGraph\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from langchain_core.messages import AIMessage\n", | |
"\n", | |
"answer = (\n", | |
" \"LangGraph is a library for building stateful, multi-actor applications with LLMs.\"\n", | |
")\n", | |
"new_messages = [\n", | |
" # The LLM API expects some ToolMessage to match its tool call. We'll satisfy that here.\n", | |
" ToolMessage(content=answer, tool_call_id=existing_message.tool_calls[0][\"id\"]),\n", | |
" # And then directly \"put words in the LLM's mouth\" by populating its response.\n", | |
" AIMessage(content=answer),\n", | |
"]\n", | |
"\n", | |
"new_messages[-1].pretty_print()\n", | |
"graph5.update_state(\n", | |
" # Which state to update\n", | |
" config,\n", | |
" # The updated values to provide. The messages in our `State` are \"append-only\", meaning this will be appended\n", | |
" # to the existing state. We will review how to update existing messages in the next section!\n", | |
" {\"messages\": new_messages},\n", | |
")\n", | |
"\n", | |
"print(\"\\n\\nLast 2 messages;\")\n", | |
"print(graph5.get_state(config).values[\"messages\"][-2:])" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "WIDteLhw78ac", | |
"outputId": "bac50cef-2387-4820-f9da-f3f0e1de6cbf" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"==================================\u001b[1m Ai Message \u001b[0m==================================\n", | |
"\n", | |
"LangGraph is a library for building stateful, multi-actor applications with LLMs.\n", | |
"\n", | |
"\n", | |
"Last 2 messages;\n", | |
"[ToolMessage(content='LangGraph is a library for building stateful, multi-actor applications with LLMs.', id='0d479e1e-367c-4355-a01d-657400694a54', tool_call_id='call_IsktVzsMrWiUbLqbnz8EqzTJ'), AIMessage(content='LangGraph is a library for building stateful, multi-actor applications with LLMs.', id='ed7473e0-9132-4976-9b54-54c819d77899')]\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"graph5.update_state(\n", | |
" config,\n", | |
" {\"messages\": [AIMessage(content=\"I'm an AI expert!\")]},\n", | |
" # Which node for this function to act as. It will automatically continue\n", | |
" # processing as if this node just ran.\n", | |
" as_node=\"chatbot\",\n", | |
")" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "x8PlO1XS8QcY", | |
"outputId": "54ff3fda-b2ef-4585-a318-818d80d41e9f" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"{'configurable': {'thread_id': '1',\n", | |
" 'checkpoint_ns': '',\n", | |
" 'checkpoint_id': '1ef638aa-f74a-622e-8003-8f9e72842e3e'}}" | |
] | |
}, | |
"metadata": {}, | |
"execution_count": 58 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from IPython.display import Image, display\n", | |
"\n", | |
"try:\n", | |
" display(Image(graph5.get_graph().draw_mermaid_png()))\n", | |
"except Exception:\n", | |
" # This requires some extra dependencies and is optional\n", | |
" pass" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 273 | |
}, | |
"id": "cehV6O228CqF", | |
"outputId": "87272211-552e-4820-9c90-d4b8a0082bb5" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "display_data", | |
"data": { | |
"image/jpeg": "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rpJY3Q1Gmx5c2Zp2g6ja7UDRbwQF4V9DT3ShqKOribPS1EboZYn+9exw0c0/QQSF7orEzE3gV/Ba6etx2JlVKZ6ujmmoZpSSTI6GR0e86+VwaHfrVgVY4et6SxT1o12V9dVVce4aaxvmdsOn0s2n9as63Y8RGLVEb5WesREWhBERAREQEREBERAREQEREBERAREQEREBERAREQFVKSZmByOo6rSLH3vL6Sr/AAKQuJJhlP4LNT4j/e6HYdpDN9rX5exsjHMe0Oa4aFpGoIWyivVvE5xKxKpZXwjwbiBcIrlkeJWTIK1sIhjqrhQxTvEYJcGhzgTt1c46fSfjUMe5t4UFob7m+LbQSQO9MGgPl/B+gKwv4fW6JxNuqLhZQf8Ah26rfHEPyREljf1NH/YL4cJqNfhTfvrofZLZqYc9VfOPa5aN72w/h3i3D2GpixjHrZj8VS5rp2W2kZAJSNQC4NA101Pb8asSq/gTUfOq/fXQ+yTwJqPnVfvrofZJs8Pj9JLRvWhFz7kV6yG190viOBw5RdTY7rY6y41DnOiMwlieA3a7o9ANDzGi214E1Hzqv310Psk2eHx+klo3s7LMLsGd2xtuyOy0F9t7ZBM2luNO2eMPAIDtrgRqA4jX6Sqk3ubuFLA4N4cYu0PGjgLTBzGoOh8X4wP2Kf8AAmo+dV++uh9kngTUfOq/fXQ+yTZ4fH6SWjewsa4J8P8ADLxDdrDhVhs1zhDmx1lDbooZWBwLXAOa0EagkH6Cs263E5WZrNaZS+ndrFcLjE7xIGcw6ONw7Zj2cveDVziDta/6MApJz/rC43a6s116KqrniM/lYza1w+hwIVipaSChpo6emhjp6eNoayKJoa1g8gAHIBImjDzpm8+n/vp5rlD7T08VJTxQQRtihiaGMjYNGtaBoAB8QC9ERc/WxEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQc75p/jl4c/wDSly/mNXRC53zT/HLw5/6UuX8xq6IQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQc75p/jl4c/8ASly/mNXRC53zT/HLw5/6UuX8xq6IQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBFU7hllxqayop7HQ01THTSGKWq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\n", | |
"text/plain": [ | |
"<IPython.core.display.Image object>" | |
] | |
}, | |
"metadata": {} | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"snapshot = graph5.get_state(config)\n", | |
"print(snapshot.values[\"messages\"][-3:])\n", | |
"print(snapshot.next)" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "qV2pcykl8ID2", | |
"outputId": "6854a09c-de2f-4e45-cbbe-af25bbf4f685" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"[ToolMessage(content='LangGraph is a library for building stateful, multi-actor applications with LLMs.', id='0d479e1e-367c-4355-a01d-657400694a54', tool_call_id='call_IsktVzsMrWiUbLqbnz8EqzTJ'), AIMessage(content='LangGraph is a library for building stateful, multi-actor applications with LLMs.', id='ed7473e0-9132-4976-9b54-54c819d77899'), AIMessage(content=\"I'm an AI expert!\", id='1597ca4a-3745-46eb-8c17-af32dec4f6a3')]\n", | |
"()\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# Overwrite existing messages\n", | |
"user_input = \"I'm learning LangGraph. Could you do some research on it for me?\"\n", | |
"config = {\"configurable\": {\"thread_id\": \"2\"}} # we'll use thread_id = 2 here\n", | |
"events = graph5.stream(\n", | |
" {\"messages\": [(\"user\", user_input)]}, config, stream_mode=\"values\"\n", | |
")\n", | |
"for event in events:\n", | |
" if \"messages\" in event:\n", | |
" event[\"messages\"][-1].pretty_print()" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "EALMnaMu8Uyf", | |
"outputId": "687ae8a8-ff0f-4ecf-cd05-a9894dd92bde" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"================================\u001b[1m Human Message \u001b[0m=================================\n", | |
"\n", | |
"I'm learning LangGraph. Could you do some research on it for me?\n", | |
"==================================\u001b[1m Ai Message \u001b[0m==================================\n", | |
"Tool Calls:\n", | |
" duckduckgo_results_json (call_wOtsaTi8wPoorlNeHza2xtIe)\n", | |
" Call ID: call_wOtsaTi8wPoorlNeHza2xtIe\n", | |
" Args:\n", | |
" query: LangGraph\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from langchain_core.messages import AIMessage\n", | |
"\n", | |
"snapshot = graph5.get_state(config)\n", | |
"existing_message = snapshot.values[\"messages\"][-1]\n", | |
"print(\"Original\")\n", | |
"print(\"Message ID\", existing_message.id)\n", | |
"print(existing_message.tool_calls[0])\n", | |
"new_tool_call = existing_message.tool_calls[0].copy()\n", | |
"new_tool_call[\"args\"][\"query\"] = \"LangGraph human-in-the-loop workflow\"\n", | |
"new_message = AIMessage(\n", | |
" content=existing_message.content,\n", | |
" tool_calls=[new_tool_call],\n", | |
" # Important! The ID is how LangGraph knows to REPLACE the message in the state rather than APPEND this messages\n", | |
" id=existing_message.id,\n", | |
")\n", | |
"\n", | |
"print(\"Updated\")\n", | |
"print(new_message.tool_calls[0])\n", | |
"print(\"Message ID\", new_message.id)\n", | |
"graph5.update_state(config, {\"messages\": [new_message]})\n", | |
"\n", | |
"print(\"\\n\\nTool calls\")\n", | |
"graph5.get_state(config).values[\"messages\"][-1].tool_calls" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "oznhHSmW8ews", | |
"outputId": "82fb3a6b-c539-4a6d-881f-cbd9ed2ac0fb" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"Original\n", | |
"Message ID run-e97102f4-11a2-42e9-85b1-c5dcf537758f-0\n", | |
"{'name': 'duckduckgo_results_json', 'args': {'query': 'LangGraph'}, 'id': 'call_wOtsaTi8wPoorlNeHza2xtIe', 'type': 'tool_call'}\n", | |
"Updated\n", | |
"{'name': 'duckduckgo_results_json', 'args': {'query': 'LangGraph human-in-the-loop workflow'}, 'id': 'call_wOtsaTi8wPoorlNeHza2xtIe', 'type': 'tool_call'}\n", | |
"Message ID run-e97102f4-11a2-42e9-85b1-c5dcf537758f-0\n", | |
"\n", | |
"\n", | |
"Tool calls\n" | |
] | |
}, | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"[{'name': 'duckduckgo_results_json',\n", | |
" 'args': {'query': 'LangGraph human-in-the-loop workflow'},\n", | |
" 'id': 'call_wOtsaTi8wPoorlNeHza2xtIe',\n", | |
" 'type': 'tool_call'}]" | |
] | |
}, | |
"metadata": {}, | |
"execution_count": 62 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"events = graph5.stream(None, config, stream_mode=\"values\")\n", | |
"for event in events:\n", | |
" if \"messages\" in event:\n", | |
" event[\"messages\"][-1].pretty_print()" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "XNrqGR0Y8nHT", | |
"outputId": "e1da6f1c-842b-411b-a7d8-58e3f1e7f3c8" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"=================================\u001b[1m Tool Message \u001b[0m=================================\n", | |
"Name: duckduckgo_results_json\n", | |
"\n", | |
"[snippet: Implementing a Human-in-the-Loop (HIL) framework in LangGraph with the Streamlit app provides a robust mechanism for user engagement and decision-making. By incorporating breakpoints and ..., title: Implementing Human-in-the-Loop with LangGraph - Medium, link: https://medium.com/@kbdhunga/implementing-human-in-the-loop-with-langgraph-ccfde023385c], [snippet: TLDR; Today we're launching two \"human in the loop\" features in OpenGPTs, Interrupt and Authorize, both powered by LangGraph. We've recently launched LangGraph, a library to help developers build multi-actor, multi-step, stateful LLM applications. That's a lot words packed into a short sentence, let's take it one at a, title: Human-in-the-loop with OpenGPTs and LangGraph, link: https://blog.langchain.dev/human-in-the-loop-with-opengpts-and-langgraph/], [snippet: As a very low-level framework, it provides fine-grained control over both the flow and state of your application, crucial for creating reliable agents. Additionally, LangGraph includes built-in persistence, enabling advanced human-in-the-loop and memory features. LangGraph is inspired by Pregel and Apache Beam., title: langgraph · PyPI, link: https://pypi.org/project/langgraph/], [snippet: LangGraph, as an extension of LangChain, offers powerful tools for building these workflows, making it easier for developers to create highly controllable and collaborative agents., title: Exploring AI Automation: Agentic Workflows with LangGraph and ... - Medium, link: https://medium.com/@LakshmiNarayana_U/exploring-ai-automation-agentic-workflows-with-langgraph-and-tavily-155f5442a999]\n", | |
"==================================\u001b[1m Ai Message \u001b[0m==================================\n", | |
"\n", | |
"I found some information about LangGraph and its human-in-the-loop workflow:\n", | |
"\n", | |
"1. [Implementing Human-in-the-Loop with LangGraph - Medium](https://medium.com/@kbdhunga/implementing-human-in-the-loop-with-langgraph-ccfde023385c): This article discusses implementing a Human-in-the-Loop (HIL) framework in LangGraph with the Streamlit app, providing a robust mechanism for user engagement and decision-making.\n", | |
"\n", | |
"2. [Human-in-the-loop with OpenGPTs and LangGraph](https://blog.langchain.dev/human-in-the-loop-with-opengpts-and-langgraph/): LangGraph is used in OpenGPTs to introduce \"human in the loop\" features like Interrupt and Authorize. LangGraph is a library for building multi-actor, multi-step, stateful LLM applications.\n", | |
"\n", | |
"3. [langgraph · PyPI](https://pypi.org/project/langgraph/): LangGraph is described as a very low-level framework that offers fine-grained control over application flow and state, essential for creating reliable agents. It includes built-in persistence for advanced human-in-the-loop and memory features.\n", | |
"\n", | |
"4. [Exploring AI Automation: Agentic Workflows with LangGraph and Tavily - Medium](https://medium.com/@LakshmiNarayana_U/exploring-ai-automation-agentic-workflows-with-langgraph-and-tavily-155f5442a999): LangGraph, as an extension of LangChain, provides powerful tools for building workflows, enabling developers to create highly controllable and collaborative agents.\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"events = graph5.stream(\n", | |
" {\n", | |
" \"messages\": (\n", | |
" \"user\",\n", | |
" \"Remember what I'm learning about?\",\n", | |
" )\n", | |
" },\n", | |
" config,\n", | |
" stream_mode=\"values\",\n", | |
")\n", | |
"for event in events:\n", | |
" if \"messages\" in event:\n", | |
" event[\"messages\"][-1].pretty_print()" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "3syDbH2n8tuL", | |
"outputId": "f5b54dd7-34e5-467d-a85f-3df81b04b4e4" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"================================\u001b[1m Human Message \u001b[0m=================================\n", | |
"\n", | |
"Remember what I'm learning about?\n", | |
"==================================\u001b[1m Ai Message \u001b[0m==================================\n", | |
"\n", | |
"You are learning about LangGraph and its human-in-the-loop workflow. If you need more information or assistance with LangGraph, feel free to ask!\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"## Customizing State" | |
], | |
"metadata": { | |
"id": "B0EKpOqw823u" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"class State2(TypedDict):\n", | |
" messages: Annotated[list, add_messages]\n", | |
" # This flag is new\n", | |
" ask_human: bool" | |
], | |
"metadata": { | |
"id": "vVQ6x_Xg8zfz" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from langchain_core.pydantic_v1 import BaseModel\n", | |
"\n", | |
"\n", | |
"class RequestAssistance(BaseModel):\n", | |
" \"\"\"Escalate the conversation to an expert. Use this if you are unable to assist directly or if the user requires support beyond your permissions.\n", | |
"\n", | |
" To use this function, relay the user's 'request' so the expert can provide the right guidance.\n", | |
" \"\"\"\n", | |
"\n", | |
" request: str" | |
], | |
"metadata": { | |
"id": "hhsO78K486V6" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"llm_with_tools3 = llm3.bind_tools([search, RequestAssistance])\n", | |
"\n", | |
"def chatbot4(state: State2):\n", | |
" response = llm_with_tools3.invoke(state[\"messages\"])\n", | |
" ask_human = False\n", | |
" if (\n", | |
" response.tool_calls\n", | |
" and response.tool_calls[0][\"name\"] == RequestAssistance.__name__\n", | |
" ):\n", | |
" ask_human = True\n", | |
" return {\"messages\": [response], \"ask_human\": ask_human}" | |
], | |
"metadata": { | |
"id": "g2cXlBRJ89_6" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"graph_builder6 = StateGraph(State2)\n", | |
"\n", | |
"graph_builder6.add_node(\"chatbot\", chatbot4)\n", | |
"graph_builder6.add_node(\"tools\", ToolNode(tools=[search]))" | |
], | |
"metadata": { | |
"id": "Mj6Irtxr9NzK" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from langchain_core.messages import AIMessage, ToolMessage\n", | |
"\n", | |
"\n", | |
"def create_response(response: str, ai_message: AIMessage):\n", | |
" return ToolMessage(\n", | |
" content=response,\n", | |
" tool_call_id=ai_message.tool_calls[0][\"id\"],\n", | |
" )\n", | |
"\n", | |
"\n", | |
"def human_node(state: State2):\n", | |
" new_messages = []\n", | |
" if not isinstance(state[\"messages\"][-1], ToolMessage):\n", | |
" # Typically, the user will have updated the state during the interrupt.\n", | |
" # If they choose not to, we will include a placeholder ToolMessage to\n", | |
" # let the LLM continue.\n", | |
" new_messages.append(\n", | |
" create_response(\"No response from human.\", state[\"messages\"][-1])\n", | |
" )\n", | |
" return {\n", | |
" # Append the new messages\n", | |
" \"messages\": new_messages,\n", | |
" # Unset the flag\n", | |
" \"ask_human\": False,\n", | |
" }\n", | |
"\n", | |
"\n", | |
"graph_builder6.add_node(\"human\", human_node)" | |
], | |
"metadata": { | |
"id": "BQEWdDIH9Tcr" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"def select_next_node(state: State2):\n", | |
" if state[\"ask_human\"]:\n", | |
" return \"human\"\n", | |
" # Otherwise, we can route as before\n", | |
" return tools_condition(state)\n", | |
"\n", | |
"\n", | |
"graph_builder6.add_conditional_edges(\n", | |
" \"chatbot\",\n", | |
" select_next_node,\n", | |
" {\"human\": \"human\", \"tools\": \"tools\", \"__end__\": \"__end__\"},\n", | |
")" | |
], | |
"metadata": { | |
"id": "yASSH9Xx9Ykb" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# The rest is the same\n", | |
"graph_builder6.add_edge(\"tools\", \"chatbot\")\n", | |
"graph_builder6.add_edge(\"human\", \"chatbot\")\n", | |
"graph_builder6.add_edge(START, \"chatbot\")\n", | |
"memory3 = MemorySaver()\n", | |
"graph6 = graph_builder6.compile(\n", | |
" checkpointer=memory3,\n", | |
" # We interrupt before 'human' here instead.\n", | |
" interrupt_before=[\"human\"],\n", | |
")" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "gvwwbYow9d2r", | |
"outputId": "86da7c8c-7970-47a2-fd56-817b34f065fc" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stderr", | |
"text": [ | |
"WARNING:langgraph.graph.graph:Adding an edge to a graph that has already been compiled. This will not be reflected in the compiled graph.\n", | |
"WARNING:langgraph.graph.graph:Adding an edge to a graph that has already been compiled. This will not be reflected in the compiled graph.\n", | |
"WARNING:langgraph.graph.graph:Adding an edge to a graph that has already been compiled. This will not be reflected in the compiled graph.\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from IPython.display import Image, display\n", | |
"\n", | |
"try:\n", | |
" display(Image(graph6.get_graph().draw_mermaid_png()))\n", | |
"except Exception:\n", | |
" # This requires some extra dependencies and is optional\n", | |
" pass" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 273 | |
}, | |
"id": "Cfake3pV9jji", | |
"outputId": "5ff3e82e-5413-458b-eb6e-9fa8123a1e22" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "display_data", | |
"data": { | |
"image/jpeg": "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\n", | |
"text/plain": [ | |
"<IPython.core.display.Image object>" | |
] | |
}, | |
"metadata": {} | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"user_input = \"I need some expert guidance for building this AI agent. Could you request assistance for me?\"\n", | |
"config = {\"configurable\": {\"thread_id\": \"1\"}}\n", | |
"# The config is the **second positional argument** to stream() or invoke()!\n", | |
"events = graph6.stream(\n", | |
" {\"messages\": [(\"user\", user_input)]}, config, stream_mode=\"values\"\n", | |
")\n", | |
"for event in events:\n", | |
" if \"messages\" in event:\n", | |
" event[\"messages\"][-1].pretty_print()" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "ucKxsRvA9mBW", | |
"outputId": "3f1afe92-1161-46e6-94aa-da891c0d4c23" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"================================\u001b[1m Human Message \u001b[0m=================================\n", | |
"\n", | |
"I need some expert guidance for building this AI agent. Could you request assistance for me?\n", | |
"==================================\u001b[1m Ai Message \u001b[0m==================================\n", | |
"Tool Calls:\n", | |
" RequestAssistance (call_TrNIkZta0Ii591rZZONfqaaK)\n", | |
" Call ID: call_TrNIkZta0Ii591rZZONfqaaK\n", | |
" Args:\n", | |
" request: I need expert guidance for building an AI agent.\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"snapshot = graph6.get_state(config)\n", | |
"snapshot.next" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "2ImgMfLK9vcY", | |
"outputId": "e67663a7-b4b5-46d2-e77e-e9cb86d19fda" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"('human',)" | |
] | |
}, | |
"metadata": {}, | |
"execution_count": 78 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"ai_message = snapshot.values[\"messages\"][-1]\n", | |
"human_response = (\n", | |
" \"We, the experts are here to help! We'd recommend you check out LangGraph to build your agent.\"\n", | |
" \" It's much more reliable and extensible than simple autonomous agents.\"\n", | |
")\n", | |
"tool_message = create_response(human_response, ai_message)\n", | |
"graph6.update_state(config, {\"messages\": [tool_message]})" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "hjQgHpxf9zPa", | |
"outputId": "037e1532-bb7d-43d5-cdeb-3b65545e61ff" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"{'configurable': {'thread_id': '1',\n", | |
" 'checkpoint_ns': '',\n", | |
" 'checkpoint_id': '1ef638ba-56a4-67df-8002-6c948efa16af'}}" | |
] | |
}, | |
"metadata": {}, | |
"execution_count": 79 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"graph6.get_state(config).values[\"messages\"]" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "eqr1NpuB923S", | |
"outputId": "cbba2339-1770-4e52-f8dc-538ada9ec4b8" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"[HumanMessage(content='I need some expert guidance for building this AI agent. Could you request assistance for me?', id='26b5e96f-2e3c-40cf-8ece-b6781cf1ec84'),\n", | |
" AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_TrNIkZta0Ii591rZZONfqaaK', 'function': {'arguments': '{\"request\":\"I need expert guidance for building an AI agent.\"}', 'name': 'RequestAssistance'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 24, 'prompt_tokens': 172, 'total_tokens': 196}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-60ba76a2-df68-4b99-a8ad-c9455377032e-0', tool_calls=[{'name': 'RequestAssistance', 'args': {'request': 'I need expert guidance for building an AI agent.'}, 'id': 'call_TrNIkZta0Ii591rZZONfqaaK', 'type': 'tool_call'}], usage_metadata={'input_tokens': 172, 'output_tokens': 24, 'total_tokens': 196}),\n", | |
" ToolMessage(content=\"We, the experts are here to help! We'd recommend you check out LangGraph to build your agent. It's much more reliable and extensible than simple autonomous agents.\", id='5d355c37-70f7-45a1-ab94-9881df565bbd', tool_call_id='call_TrNIkZta0Ii591rZZONfqaaK')]" | |
] | |
}, | |
"metadata": {}, | |
"execution_count": 80 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"events = graph6.stream(None, config, stream_mode=\"values\")\n", | |
"for event in events:\n", | |
" if \"messages\" in event:\n", | |
" event[\"messages\"][-1].pretty_print()" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "8ZHcWyhW95e6", | |
"outputId": "73d4fdbc-35fc-439b-81dc-b4a0235a85c4" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"=================================\u001b[1m Tool Message \u001b[0m=================================\n", | |
"\n", | |
"We, the experts are here to help! We'd recommend you check out LangGraph to build your agent. It's much more reliable and extensible than simple autonomous agents.\n", | |
"==================================\u001b[1m Ai Message \u001b[0m==================================\n", | |
"\n", | |
"I have requested expert assistance for you. The experts recommend checking out LangGraph to build your AI agent as it is more reliable and extensible than simple autonomous agents.\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"## Time Travel" | |
], | |
"metadata": { | |
"id": "dHDhFj5Z-DWX" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"graph_builder7 = StateGraph(State2)\n", | |
"\n", | |
"graph_builder7.add_node(\"chatbot\", chatbot4)\n", | |
"graph_builder7.add_node(\"tools\", ToolNode(tools=[search]))\n", | |
"\n", | |
"graph_builder7.add_conditional_edges(\n", | |
" \"chatbot\",\n", | |
" select_next_node,\n", | |
" {\"human\": \"human\", \"tools\": \"tools\", \"__end__\": \"__end__\"},\n", | |
")\n", | |
"\n", | |
"graph_builder7.add_edge(\"tools\", \"chatbot\")\n", | |
"graph_builder7.add_edge(\"human\", \"chatbot\")\n", | |
"graph_builder7.add_edge(START, \"chatbot\")\n", | |
"memory4 = MemorySaver()\n", | |
"graph7 = graph_builder6.compile(\n", | |
" checkpointer=memory4,\n", | |
" # We interrupt before 'human' here instead.\n", | |
" interrupt_before=[\"human\"],\n", | |
")" | |
], | |
"metadata": { | |
"id": "RhkBegOe99FX" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from IPython.display import Image, display\n", | |
"\n", | |
"try:\n", | |
" display(Image(graph7.get_graph().draw_mermaid_png()))\n", | |
"except Exception:\n", | |
" # This requires some extra dependencies and is optional\n", | |
" pass" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 273 | |
}, | |
"id": "E86fT-JD-qqJ", | |
"outputId": "58816b8f-30fa-4c21-a91f-c3bc0ac3aecb" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "display_data", | |
"data": { | |
"image/jpeg": "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\n", | |
"text/plain": [ | |
"<IPython.core.display.Image object>" | |
] | |
}, | |
"metadata": {} | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"config = {\"configurable\": {\"thread_id\": \"1\"}}\n", | |
"events = graph7.stream(\n", | |
" {\n", | |
" \"messages\": [\n", | |
" (\"user\", \"I'm learning LangGraph. Could you do some research on it for me?\")\n", | |
" ]\n", | |
" },\n", | |
" config,\n", | |
" stream_mode=\"values\",\n", | |
")\n", | |
"for event in events:\n", | |
" if \"messages\" in event:\n", | |
" event[\"messages\"][-1].pretty_print()" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "fP4Lyeox-sb6", | |
"outputId": "5202088e-7735-4613-d5d5-661869330d72" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"================================\u001b[1m Human Message \u001b[0m=================================\n", | |
"\n", | |
"I'm learning LangGraph. Could you do some research on it for me?\n", | |
"==================================\u001b[1m Ai Message \u001b[0m==================================\n", | |
"Tool Calls:\n", | |
" duckduckgo_results_json (call_vO78RvbX37rjknY1IYh0JFQ5)\n", | |
" Call ID: call_vO78RvbX37rjknY1IYh0JFQ5\n", | |
" Args:\n", | |
" query: LangGraph\n", | |
"=================================\u001b[1m Tool Message \u001b[0m=================================\n", | |
"Name: duckduckgo_results_json\n", | |
"\n", | |
"[snippet: LangGraph is a package for creating LLM workflows with cycles and multi-agent designs. Learn what multi-agent means, why it is useful, and see examples of LangGraph applications and comparisons with other frameworks., title: LangGraph: Multi-Agent Workflows, link: https://blog.langchain.dev/langgraph-multi-agent-workflows/], [snippet: LangGraph is a versatile tool for building complex, stateful applications with LLMs. By understanding its core concepts and working through simple examples, beginners can start to leverage its ..., title: Introduction to LangGraph: A Beginner's Guide - Medium, link: https://medium.com/@cplog/introduction-to-langgraph-a-beginners-guide-14f9be027141], [snippet: StateGraph: In LangGraph, the StateGraph is a fundamental component used to construct and manage stateful & multi-actor workflows. It defines the structure of the graph, including the schema for ..., title: LangGraph: Multi-Agent Collaboration Explained - Medium, link: https://medium.com/@kbdhunga/langgraph-multi-agent-collaboration-explained-c0500b0f2e61], [snippet: LangGraph Studio is a desktop app that lets you visualize, interact with, and debug complex agentic applications built with LangGraph, a low-level orchestration framework. Learn how to use it with LangSmith, a platform for creating and managing agents, and see examples of agent graphs and interactions., title: LangGraph Studio: The first agent IDE - blog.langchain.dev, link: https://blog.langchain.dev/langgraph-studio-the-first-agent-ide/]\n", | |
"==================================\u001b[1m Ai Message \u001b[0m==================================\n", | |
"\n", | |
"I found some information on LangGraph for you:\n", | |
"\n", | |
"1. LangGraph is a package for creating LLM workflows with cycles and multi-agent designs. You can learn about multi-agent workflows, their utility, and see examples of LangGraph applications and comparisons with other frameworks. [Read more here](https://blog.langchain.dev/langgraph-multi-agent-workflows/).\n", | |
"\n", | |
"2. LangGraph is a versatile tool for building complex, stateful applications with LLMs. Beginners can start leveraging LangGraph by understanding its core concepts and working through simple examples. [Check out this beginner's guide on Medium](https://medium.com/@cplog/introduction-to-langgraph-a-beginners-guide-14f9be027141).\n", | |
"\n", | |
"3. In LangGraph, the StateGraph is a fundamental component used to construct and manage stateful & multi-actor workflows. It defines the structure of the graph, including the schema for interactions. [Learn more about LangGraph's StateGraph here](https://medium.com/@kbdhunga/langgraph-multi-agent-collaboration-explained-c0500b0f2e61).\n", | |
"\n", | |
"4. LangGraph Studio is a desktop app that allows you to visualize, interact with, and debug complex agentic applications built with LangGraph. It is a low-level orchestration framework that can be used with LangSmith, a platform for creating and managing agents. [Discover more about LangGraph Studio here](https://blog.langchain.dev/langgraph-studio-the-first-agent-ide/).\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"events = graph7.stream(\n", | |
" {\n", | |
" \"messages\": [\n", | |
" (\"user\", \"Ya that's helpful. Maybe I'll build an autonomous agent with it!\")\n", | |
" ]\n", | |
" },\n", | |
" config,\n", | |
" stream_mode=\"values\",\n", | |
")\n", | |
"for event in events:\n", | |
" if \"messages\" in event:\n", | |
" event[\"messages\"][-1].pretty_print()" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "nkUti-oX-yXT", | |
"outputId": "5c7984c6-b3f8-4bf6-9d0f-75bdc0467f5b" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"================================\u001b[1m Human Message \u001b[0m=================================\n", | |
"\n", | |
"Ya that's helpful. Maybe I'll build an autonomous agent with it!\n", | |
"==================================\u001b[1m Ai Message \u001b[0m==================================\n", | |
"\n", | |
"Building an autonomous agent with LangGraph sounds like an exciting project! If you need any guidance or assistance while working on your project, feel free to reach out. Good luck with creating your autonomous agent using LangGraph!\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"to_replay = None\n", | |
"for state in graph7.get_state_history(config):\n", | |
" print(\"Num Messages: \", len(state.values[\"messages\"]), \"Next: \", state.next)\n", | |
" print(\"-\" * 80)\n", | |
" if len(state.values[\"messages\"]) == 6:\n", | |
" # We are somewhat arbitrarily selecting a specific state based on the number of chat messages in the state.\n", | |
" to_replay = state" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "kElesskd-517", | |
"outputId": "479bc2f7-b8ab-4ac2-fb0b-589aa8aeb945" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"Num Messages: 6 Next: ()\n", | |
"--------------------------------------------------------------------------------\n", | |
"Num Messages: 5 Next: ('chatbot',)\n", | |
"--------------------------------------------------------------------------------\n", | |
"Num Messages: 4 Next: ('__start__',)\n", | |
"--------------------------------------------------------------------------------\n", | |
"Num Messages: 4 Next: ()\n", | |
"--------------------------------------------------------------------------------\n", | |
"Num Messages: 3 Next: ('chatbot',)\n", | |
"--------------------------------------------------------------------------------\n", | |
"Num Messages: 2 Next: ('tools',)\n", | |
"--------------------------------------------------------------------------------\n", | |
"Num Messages: 1 Next: ('chatbot',)\n", | |
"--------------------------------------------------------------------------------\n", | |
"Num Messages: 0 Next: ('__start__',)\n", | |
"--------------------------------------------------------------------------------\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"print(to_replay.next)\n", | |
"print(to_replay.config)" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "7UR3kzDC--qK", | |
"outputId": "48600f38-d9c7-49ad-8c86-8edc93d6c877" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"()\n", | |
"{'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef638c4-96a9-6d00-8006-3ac59f4f9ef6'}}\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# The `thread_ts` in the `to_replay.config` corresponds to a state we've persisted to our checkpointer.\n", | |
"for event in graph7.stream(None, to_replay.config, stream_mode=\"values\"):\n", | |
" if \"messages\" in event:\n", | |
" event[\"messages\"][-1].pretty_print()" | |
], | |
"metadata": { | |
"id": "nV4tV62mBci5" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"- [🦜🕸️LangGraph](https://langchain-ai.github.io/langgraph/)\n", | |
"- [Tools | 🦜️🔗 LangChain](https://python.langchain.com/v0.2/docs/integrations/tools/)\n", | |
"\n", | |
"---\n", | |
"\n", | |
"- [Document loaders | 🦜️🔗 LangChain](https://python.langchain.com/v0.2/docs/integrations/document_loaders/)\n", | |
"- [CSV | 🦜️🔗 LangChain](https://python.langchain.com/v0.2/docs/integrations/document_loaders/csv/)\n", | |
"- [How to load CSVs | 🦜️🔗 LangChain](https://python.langchain.com/v0.2/docs/how_to/document_loader_csv/)\n", | |
"\n", | |
"---\n", | |
"\n", | |
"- [Private llama3 langgraph 100% local on windows | by bedy kharisma | Data And Beyond | Medium](https://medium.com/data-and-beyond/private-llama3-langgraph-100-local-on-windows-17b03fd350da)\n", | |
" - [rag-llama3/llama3-rag.ipynb at 93c5808b87b7885c2b4bc7d3b633063dcf72115c · bedy-kharisma/rag-llama3](https://github.com/bedy-kharisma/rag-llama3/blob/93c5808b87b7885c2b4bc7d3b633063dcf72115c/llama3-rag.ipynb)\n", | |
"- [langgraph/examples/code_assistant/langgraph_code_assistant.ipynb at main · langchain-ai/langgraph](https://github.com/langchain-ai/langgraph/blob/main/examples/code_assistant/langgraph_code_assistant.ipynb)" | |
], | |
"metadata": { | |
"id": "wCm4qt-mB4Zv" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [], | |
"metadata": { | |
"id": "G-6bG5HXFPoe" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [], | |
"metadata": { | |
"id": "e7XmvHLqBlw5" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment