{ "cells": [ { "cell_type": "markdown", "id": "8bcd1a3d-7c50-4f58-be4e-1ed654aa33be", "metadata": {}, "source": [ "# Visualization\n", "\n", "This notebook walks through how to visualize the graphs you create. For this example we will use a prebuilt graph, but this works with ANY graphs." ] }, { "cell_type": "markdown", "id": "e130cf70-a30e-47d7-8fd5-464f1a92e374", "metadata": {}, "source": [ "## Set up the chat model and tools\n", "\n", "Here we will define the chat model and tools that we want to use.\n", "Importantly, this model MUST support OpenAI function calling." ] }, { "cell_type": "code", "execution_count": 1, "id": "efb7e3c0-c63f-40f6-93ce-19681d650fc2", "metadata": { "ExecuteTime": { "start_time": "2024-04-19T11:25:28.531482Z", "end_time": "2024-04-19T11:25:30.217991Z" } }, "outputs": [], "source": [ "from langchain_openai import ChatOpenAI\n", "from langchain_community.tools.tavily_search import TavilySearchResults\n", "from langgraph.prebuilt import chat_agent_executor" ] }, { "cell_type": "code", "execution_count": 2, "id": "a7025f33-3160-41cf-868b-17ebc916fb1d", "metadata": { "ExecuteTime": { "start_time": "2024-04-19T11:25:32.168821Z", "end_time": "2024-04-19T11:25:32.431922Z" } }, "outputs": [], "source": [ "# Optional to not need .env\n", "# import os\n", "# os.environ['TAVILY_API_KEY'] = 'foo'\n", "# os.environ['OPENAI_API_KEY'] = 'foo'\n", "\n", "tools = [TavilySearchResults(max_results=1)]\n", "model = ChatOpenAI()" ] }, { "cell_type": "markdown", "id": "43064805-2ac9-4b5a-850c-a68dd7282350", "metadata": { "ExecuteTime": { "start_time": "2024-04-18T12:18:30.469100Z", "end_time": "2024-04-18T12:18:30.586216Z" } }, "source": [ "## Create executor\n", "\n", "We can now use the high level interface to create the executor" ], "outputs": [], "execution_count": 3 }, { "cell_type": "code", "execution_count": 3, "id": "32b4ae66-f667-4a8b-a602-503fd0effcd9", "metadata": { "ExecuteTime": { "start_time": "2024-04-19T11:25:36.098462Z", "end_time": "2024-04-19T11:25:36.231169Z" } }, "outputs": [], "source": [ "app = chat_agent_executor.create_function_calling_executor(model, tools)" ] }, { "cell_type": "markdown", "id": "f4fc9378-b141-4b65-b86c-3afba77f7161", "metadata": { "ExecuteTime": { "start_time": "2024-04-18T12:18:30.587191Z", "end_time": "2024-04-18T12:18:30.605220Z" } }, "source": [ "## Ascii\n", "\n", "We can easily visualize this graph in ascii" ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " +-----------+ \n", " | __start__ | \n", " +-----------+ \n", " * \n", " * \n", " * \n", " +-------+ \n", " | agent | \n", " +-------+* \n", " *** *** \n", " * * \n", " ** *** \n", "+-----------------+ * \n", "| should_continue | * \n", "+-----------------+. * \n", " . ..... * \n", " . ... * \n", " . ... * \n", " +---------+ +--------+ \n", " | __end__ | | action | \n", " +---------+ +--------+ \n" ] } ], "execution_count": 4 }, { "cell_type": "code", "execution_count": 4, "id": "ca9b980d-1f0a-4286-9157-a870e3d55134", "metadata": { "ExecuteTime": { "start_time": "2024-04-19T11:25:37.273032Z", "end_time": "2024-04-19T11:25:37.303260Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " +-----------+ \n", " | __start__ | \n", " +-----------+ \n", " * \n", " * \n", " * \n", " +-------+ \n", " | agent | \n", " +-------+* \n", " *** *** \n", " * * \n", " ** *** \n", "+-----------------+ * \n", "| should_continue | * \n", "+-----------------+. * \n", " . ..... * \n", " . ... * \n", " . ... * \n", " +---------+ +--------+ \n", " | __end__ | | action | \n", " +---------+ +--------+ \n" ] } ], "source": [ "app.get_graph().print_ascii()" ] }, { "cell_type": "markdown", "id": "edcd9ad2", "metadata": { "ExecuteTime": { "start_time": "2024-04-18T12:18:30.609323Z", "end_time": "2024-04-18T12:18:30.629307Z" } }, "source": [ "## Mermaid\n", "\n", "We can also convert a graph class into Mermaid syntax." ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "%%{init: {'flowchart': {'curve': 'linear'}}}%%\n", "graph TD;\n", "\t__start__[__start__]:::startclass;\n", "\t__end__[__end__]:::endclass;\n", "\tagent([agent]):::otherclass;\n", "\taction([action]):::otherclass;\n", "\tshould_continue([should_continue]):::otherclass;\n", "\t__start__ --> agent;\n", "\taction --> agent;\n", "\tagent --> should_continue;\n", "\tshould_continue -. continue .-> action;\n", "\tshould_continue -. end .-> __end__;\n", "\tclassDef startclass fill:#ffdfba;\n", "\tclassDef endclass fill:#baffc9;\n", "\tclassDef otherclass fill:#fad7de;\n", "\n" ] } ], "execution_count": 5 }, { "cell_type": "code", "execution_count": 5, "id": "66007b2d", "metadata": { "ExecuteTime": { "start_time": "2024-04-19T11:25:38.726838Z", "end_time": "2024-04-19T11:25:38.733126Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "%%{init: {'flowchart': {'curve': 'linear'}}}%%\n", "graph TD;\n", "\t__start__[__start__]:::startclass;\n", "\t__end__[__end__]:::endclass;\n", "\tagent([agent]):::otherclass;\n", "\taction([action]):::otherclass;\n", "\tshould_continue([should_continue]):::otherclass;\n", "\t__start__ --> agent;\n", "\taction --> agent;\n", "\tagent --> should_continue;\n", "\tshould_continue -. continue .-> action;\n", "\tshould_continue -. end .-> __end__;\n", "\tclassDef startclass fill:#ffdfba;\n", "\tclassDef endclass fill:#baffc9;\n", "\tclassDef otherclass fill:#fad7de;\n", "\n" ] } ], "source": [ "print(app.get_graph().draw_mermaid())" ] }, { "cell_type": "markdown", "id": "324d40ed-b665-4416-88f1-5df161546cd9", "metadata": { "ExecuteTime": { "start_time": "2024-04-18T12:18:30.615432Z", "end_time": "2024-04-18T12:18:30.629548Z" } }, "source": [ "## PNG\n", "\n", "If prefered, we could render the Graph into a `.png`. Here we could use three options:\n", "\n", "- Using graphviz (which requires `pip install graphviz`)\n", "- Using Mermaid + Pyppeteer (requires `pip install pyppeteer`)\n", "- Using Mermaid.ink API (does not require additional packages)" ], "outputs": [], "execution_count": 6 }, { "cell_type": "code", "execution_count": 6, "outputs": [], "source": [ "from IPython.display import display, HTML\n", "import base64\n", "\n", "def display_image(image_bytes: bytes, width=300):\n", " decoded_img_bytes = base64.b64encode(image_bytes).decode('utf-8')\n", " html = f''\n", " display(HTML(html))" ], "metadata": { "collapsed": false, "ExecuteTime": { "start_time": "2024-04-19T11:25:40.351636Z", "end_time": "2024-04-19T11:25:40.358604Z" } } }, { "cell_type": "markdown", "id": "d821b2f6", "metadata": { "ExecuteTime": { "start_time": "2024-04-18T12:18:30.620092Z", "end_time": "2024-04-18T12:18:30.629629Z" } }, "source": [ "### Using Graphviz" ], "outputs": [], "execution_count": 7 }, { "cell_type": "code", "execution_count": 7, "id": "d4234400-75cd-4b13-aeff-828f7fb68ab1", "metadata": { "ExecuteTime": { "start_time": "2024-04-19T11:25:42.019017Z", "end_time": "2024-04-19T11:25:42.057704Z" } }, "outputs": [], "source": [ "#!pip install pygraphviz" ] }, { "cell_type": "code", "execution_count": 8, "id": "ee026342-f560-4ce0-ab43-1718bd19a366", "metadata": { "ExecuteTime": { "start_time": "2024-04-19T11:25:42.452377Z", "end_time": "2024-04-19T11:25:42.631675Z" } }, "outputs": [ { "data": { "text/plain": "", "text/html": "" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display_image(app.get_graph().draw_png())" ] }, { "cell_type": "markdown", "id": "b9e767fc", "metadata": { "ExecuteTime": { "start_time": "2024-04-18T12:18:30.871750Z", "end_time": "2024-04-18T12:18:30.873950Z" } }, "source": [ "### Using Mermaid + Pyppeteer" ], "outputs": [], "execution_count": 9 }, { "cell_type": "code", "execution_count": 9, "id": "d403e1e7", "metadata": { "ExecuteTime": { "start_time": "2024-04-19T11:25:44.793438Z", "end_time": "2024-04-19T11:25:44.798703Z" } }, "outputs": [], "source": [ "# !pip install pyppeteer\n", "# !pip install nest_asyncio" ] }, { "cell_type": "code", "execution_count": 10, "id": "058546ee", "metadata": { "ExecuteTime": { "start_time": "2024-04-19T11:25:45.405158Z", "end_time": "2024-04-19T11:25:47.412695Z" } }, "outputs": [ { "data": { "text/plain": "", "text/html": "" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import nest_asyncio\n", "from langchain_core.runnables.graph import CurveStyle, NodeColors, MermaidDrawMethod\n", "\n", "nest_asyncio.apply() # Required for Jupyter Notebook to run async functions\n", "\n", "display_image(app.get_graph().draw_mermaid_png(\n", " curve_style=CurveStyle.LINEAR,\n", " node_colors=NodeColors(start=\"#ffdfba\", end=\"#baffc9\", other=\"#fad7de\"),\n", " wrap_label_n_words=9,\n", " output_file_path=None,\n", " draw_method=MermaidDrawMethod.PYPPETEER,\n", " background_color=\"white\",\n", " padding=10\n", "))" ] }, { "cell_type": "markdown", "id": "2dd71a7c", "metadata": { "ExecuteTime": { "start_time": "2024-04-18T12:16:57.852988Z", "end_time": "2024-04-18T12:16:58.610115Z" } }, "source": [ "### Using Mermaid.Ink" ], "outputs": [ { "data": { "text/plain": "", "text/html": "" }, "metadata": {}, "output_type": "display_data" } ], "execution_count": 12 }, { "cell_type": "code", "execution_count": 11, "id": "be37d419", "metadata": { "ExecuteTime": { "start_time": "2024-04-19T11:25:51.640462Z", "end_time": "2024-04-19T11:25:51.865932Z" } }, "outputs": [ { "data": { "text/plain": "", "text/html": "" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display_image(app.get_graph().draw_mermaid_png(\n", " draw_method=MermaidDrawMethod.API,\n", "))" ] }, { "cell_type": "markdown", "id": "e3079261", "metadata": { "ExecuteTime": { "start_time": "2024-04-18T12:18:34.010816Z", "end_time": "2024-04-18T12:18:35.651423Z" } }, "source": [ "## Excluding condition nodes\n", "By default, condition nods like 'should_continue' will be added. In case you have a big graph and want to exclude these or simplicity, you can use add_condition_nodes parameter" ], "outputs": [ { "data": { "text/plain": "", "text/html": "" }, "metadata": {}, "output_type": "display_data" } ], "execution_count": 13 }, { "cell_type": "code", "execution_count": 21, "id": "9f2773dd", "metadata": { "ExecuteTime": { "start_time": "2024-04-19T17:28:35.404649Z", "end_time": "2024-04-19T17:28:37.844424Z" } }, "outputs": [ { "data": { "text/plain": "", "text/html": "" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display_image(app.get_graph(add_condition_nodes=False).draw_mermaid_png(\n", " draw_method=MermaidDrawMethod.PYPPETEER,\n", "))\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.1" } }, "nbformat": 4, "nbformat_minor": 5 }