Files
langgraph/examples/streaming-events-from-within-tools.ipynb
T

296 lines
9.1 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"id": "b23ced4e-dc29-43be-9f94-0c36bb181b8a",
"metadata": {},
"source": [
"# How to stream events from within a tool"
]
},
{
"cell_type": "markdown",
"id": "7044eeb8-4074-4f9c-8a62-962488744557",
"metadata": {},
"source": [
"If your LangGraph graph needs to use tools that call LLMs (or any other LangChain `Runnable` objects -- other graphs, LCEL chains, retrievers, etc.), you might want to stream events from the underlying `Runnable`. This guide shows how you can do that."
]
},
{
"cell_type": "markdown",
"id": "a37f60af-43ea-4aa6-847a-df8cc47065f5",
"metadata": {},
"source": [
"## Setup"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "47f79af8-58d8-4a48-8d9a-88823d88701f",
"metadata": {},
"outputs": [],
"source": [
"%%capture --no-stderr\n",
"%pip install -U langgraph langchain-openai"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "0cf6b41d-7fcb-40b6-9a72-229cdd00a094",
"metadata": {},
"outputs": [
{
"name": "stdin",
"output_type": "stream",
"text": [
"OPENAI_API_KEY: ········\n"
]
}
],
"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\")"
]
},
{
"cell_type": "markdown",
"id": "e3d02ebb-c2e1-4ef7-b187-810d55139317",
"metadata": {},
"source": [
"## Define graph and tools"
]
},
{
"cell_type": "markdown",
"id": "d74a1760-a063-4d05-8c6f-9d16bc31fa82",
"metadata": {},
"source": [
"We'll use a prebuilt ReAct agent for this guide"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "083757a9-26d7-481e-8f3d-3e34bcba154b",
"metadata": {},
"outputs": [],
"source": [
"from langchain_core.callbacks import Callbacks\n",
"from langchain_core.prompts import ChatPromptTemplate\n",
"from langchain_core.tools import tool\n",
"\n",
"from langgraph.prebuilt import create_react_agent\n",
"from langchain_openai import ChatOpenAI"
]
},
{
"cell_type": "markdown",
"id": "9378fd4a-69e4-49e2-b34c-a98a0505ea35",
"metadata": {},
"source": [
"<div class=\"admonition warning\">\n",
" <p class=\"admonition-title\">ASYNC IN PYTHON<=3.10</p>\n",
" <p>\n",
"Any Langchain RunnableLambda, a RunnableGenerator, or Tool that invokes other runnables and is running async in python<=3.10, will have to propagate callbacks to child objects manually. This is because LangChain cannot automatically propagate callbacks to child objects in this case.\n",
" \n",
"This is a common reason why you may fail to see events being emitted from custom runnables or tools.\n",
" </p>\n",
"</div>"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "2cb38dd9-74d8-456d-9e39-4655f2bf3f37",
"metadata": {},
"outputs": [],
"source": [
"@tool\n",
"async def get_items(\n",
" place: str, callbacks: Callbacks\n",
") -> str: # <--- Accept callbacks (Python <= 3.10)\n",
" \"\"\"Use this tool to look up which items are in the given place.\"\"\"\n",
" template = ChatPromptTemplate.from_messages(\n",
" [\n",
" (\n",
" \"human\",\n",
" \"Can you tell me what kind of items i might find in the following place: '{place}'. \"\n",
" \"List at least 3 such items separating them by a comma. And include a brief description of each item..\",\n",
" )\n",
" ]\n",
" )\n",
" chain = template | llm.with_config(\n",
" {\n",
" \"run_name\": \"Get Items LLM\",\n",
" \"tags\": [\"tool_llm\"],\n",
" \"callbacks\": callbacks, # <-- Propagate callbacks (Python <= 3.10)\n",
" }\n",
" )\n",
" chunks = [chunk async for chunk in chain.astream({\"place\": place})]\n",
" return \"\".join(chunk.content for chunk in chunks)"
]
},
{
"cell_type": "markdown",
"id": "17279b8a-049d-483d-af63-8a875098e71f",
"metadata": {},
"source": [
"We're adding a custom tag (`tool_llm`) to our LLM runnable within the tool. This will allow us to filter events that we'll stream from the compiled graph (`agent`) Runnable below"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "7254310e-7016-45f7-9795-6d52a1160086",
"metadata": {},
"outputs": [],
"source": [
"llm = ChatOpenAI(model_name=\"gpt-3.5-turbo\")\n",
"tools = [get_items]\n",
"agent = create_react_agent(llm, tools=tools)"
]
},
{
"cell_type": "markdown",
"id": "b7d88960-a66b-4699-adee-c12d40b4318a",
"metadata": {},
"source": [
"## Stream events from the graph"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "31fe94ab-80de-4729-843e-5a0fe1bb52c0",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/vadymbarda/.virtualenvs/langgraph/lib/python3.12/site-packages/langchain_core/_api/beta_decorator.py:87: LangChainBetaWarning: This API is in beta and may change in the future.\n",
" warn_beta(\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"1. Books - A collection of written or printed works bound together with covers. They can be fiction or non-fiction and come in various genres.\n",
"\n",
"2. Picture frames - A decorative border for a photograph or artwork, typically made of wood, metal, or plastic. Picture frames are used to display and protect a picture or painting.\n",
"\n",
"3. Candles - A cylinder of wax with a central wick that is lit to produce light or fragrance. Candles are often used for decoration, ambiance, or religious ceremonies."
]
}
],
"source": [
"async for event in agent.astream_events(\n",
" {\"messages\": [(\"human\", \"what items are on the shelf?\")]}, version=\"v2\"\n",
"):\n",
" tags = event.get(\"tags\", [])\n",
" if event[\"event\"] == \"on_chat_model_stream\" and \"tool_llm\" in tags:\n",
" print(event[\"data\"][\"chunk\"].content, end=\"\", flush=True)"
]
},
{
"cell_type": "markdown",
"id": "ebd8902e-935b-4724-8b5d-551b7674fd34",
"metadata": {},
"source": [
"Let's inspect the last event to get the final list of messages from the agent"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "ca382c1f-b1c7-4c8a-bd9b-7a873b891b3e",
"metadata": {},
"outputs": [],
"source": [
"final_messages = event[\"data\"][\"output\"][\"messages\"]"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "3fa7d768-5a84-475a-950e-fd351a44841b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"================================\u001b[1m Human Message \u001b[0m=================================\n",
"\n",
"what items are on the shelf?\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"Tool Calls:\n",
" get_items (call_5CAMZ3asoLsZm9ocMbCOWxYQ)\n",
" Call ID: call_5CAMZ3asoLsZm9ocMbCOWxYQ\n",
" Args:\n",
" place: shelf\n",
"=================================\u001b[1m Tool Message \u001b[0m=================================\n",
"Name: get_items\n",
"\n",
"1. Books - A collection of written or printed works bound together with covers. They can be fiction or non-fiction and come in various genres.\n",
"\n",
"2. Picture frames - A decorative border for a photograph or artwork, typically made of wood, metal, or plastic. Picture frames are used to display and protect a picture or painting.\n",
"\n",
"3. Candles - A cylinder of wax with a central wick that is lit to produce light or fragrance. Candles are often used for decoration, ambiance, or religious ceremonies.\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"\n",
"The items on the shelf are:\n",
"1. Books\n",
"2. Picture frames\n",
"3. Candles\n"
]
}
],
"source": [
"for message in final_messages:\n",
" message.pretty_print()"
]
},
{
"cell_type": "markdown",
"id": "d7f9457c-5665-4cd5-9a99-d54c84270616",
"metadata": {},
"source": [
"You can see that the content of the `ToolMessage` is the same as the output we streamed above"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "langgraph",
"language": "python",
"name": "langgraph"
},
"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.12.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}