{
"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
}