mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-08-24 00:22:25 +02:00
Merge pull request #63 from langchain-ai/harrison/notebook-for-streaming
update notebook for streaming
This commit is contained in:
+43
-112
@@ -198,40 +198,6 @@
|
||||
"model = model.bind_functions(functions)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8e8b9211-93d0-4ad5-aa7a-9c09099c53ff",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Define the agent state\n",
|
||||
"\n",
|
||||
"The main type of graph in `langgraph` is the `StatefulGraph`.\n",
|
||||
"This graph is parameterized by a state object that it passes around to each node.\n",
|
||||
"Each node then returns operations to update that state.\n",
|
||||
"These operations can either SET specific attributes on the state (e.g. overwrite the existing values) or ADD to the existing attribute.\n",
|
||||
"Whether to set or add is denoted by annotating the state object you construct the graph with.\n",
|
||||
"\n",
|
||||
"For this example, the state we will track will just be a list of messages.\n",
|
||||
"We want each node to just add messages to that list.\n",
|
||||
"Therefore, we will use a `TypedDict` with one key (`messages`) and annotate it so that the `messages` attribute is always added to.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "ea793afa-2eab-4901-910d-6eed90cd6564",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import TypedDict, Annotated, Sequence\n",
|
||||
"import operator\n",
|
||||
"from langchain_core.messages import BaseMessage\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class AgentState(TypedDict):\n",
|
||||
" messages: Annotated[Sequence[BaseMessage], operator.add]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e03c5094-9297-4d19-a04e-3eedc75cefb4",
|
||||
@@ -265,7 +231,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"execution_count": 5,
|
||||
"id": "3b541bb9-900c-40d0-964d-7b5dfee30667",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -275,8 +241,7 @@
|
||||
"from langchain_core.messages import FunctionMessage\n",
|
||||
"\n",
|
||||
"# Define the function that determines whether to continue or not\n",
|
||||
"def should_continue(state):\n",
|
||||
" messages = state['messages']\n",
|
||||
"def should_continue(messages):\n",
|
||||
" last_message = messages[-1]\n",
|
||||
" # If there is no function call, then we finish\n",
|
||||
" if \"function_call\" not in last_message.additional_kwargs:\n",
|
||||
@@ -286,15 +251,13 @@
|
||||
" return \"continue\"\n",
|
||||
"\n",
|
||||
"# Define the function that calls the model\n",
|
||||
"async def call_model(state):\n",
|
||||
" messages = state['messages']\n",
|
||||
"async def call_model(messages):\n",
|
||||
" response = await model.ainvoke(messages)\n",
|
||||
" # We return a list, because this will get added to the existing list\n",
|
||||
" return {\"messages\": [response]}\n",
|
||||
" return response\n",
|
||||
"\n",
|
||||
"# Define the function to execute tools\n",
|
||||
"async def call_tool(state):\n",
|
||||
" messages = state['messages']\n",
|
||||
"async def call_tool(messages):\n",
|
||||
" # Based on the continue condition\n",
|
||||
" # we know the last message involves a function call\n",
|
||||
" last_message = messages[-1]\n",
|
||||
@@ -308,7 +271,7 @@
|
||||
" # We use the response to create a FunctionMessage\n",
|
||||
" function_message = FunctionMessage(content=str(response), name=action.tool)\n",
|
||||
" # We return a list, because this will get added to the existing list\n",
|
||||
" return {\"messages\": [function_message]}"
|
||||
" return function_message"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -323,14 +286,14 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"execution_count": 6,
|
||||
"id": "813ae66c-3b58-4283-a02a-36da72a2ab90",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langgraph.graph import StateGraph, END\n",
|
||||
"from langgraph.graph import MessageGraph, END\n",
|
||||
"# Define a new graph\n",
|
||||
"workflow = StateGraph(AgentState)\n",
|
||||
"workflow = MessageGraph()\n",
|
||||
"\n",
|
||||
"# Define the two nodes we will cycle between\n",
|
||||
"workflow.add_node(\"agent\", call_model)\n",
|
||||
@@ -385,84 +348,52 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"execution_count": 7,
|
||||
"id": "cfd140f0-a5a6-4697-8115-322242f197b5",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"/Users/harrisonchase/workplace/langchain/libs/core/langchain_core/_api/beta_decorator.py:86: LangChainBetaWarning: This API is in beta and may change in the future.\n",
|
||||
" warn_beta(\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"content='' additional_kwargs={'function_call': {'arguments': '', 'name': 'tavily_search_results_json'}}\n",
|
||||
"content='' additional_kwargs={'function_call': {'arguments': '{\\n', 'name': ''}}\n",
|
||||
"content='' additional_kwargs={'function_call': {'arguments': ' ', 'name': ''}}\n",
|
||||
"content='' additional_kwargs={'function_call': {'arguments': ' \"', 'name': ''}}\n",
|
||||
"content='' additional_kwargs={'function_call': {'arguments': 'query', 'name': ''}}\n",
|
||||
"content='' additional_kwargs={'function_call': {'arguments': '\":', 'name': ''}}\n",
|
||||
"content='' additional_kwargs={'function_call': {'arguments': ' \"', 'name': ''}}\n",
|
||||
"content='' additional_kwargs={'function_call': {'arguments': 'weather', 'name': ''}}\n",
|
||||
"content='' additional_kwargs={'function_call': {'arguments': ' in', 'name': ''}}\n",
|
||||
"content='' additional_kwargs={'function_call': {'arguments': ' San', 'name': ''}}\n",
|
||||
"content='' additional_kwargs={'function_call': {'arguments': ' Francisco', 'name': ''}}\n",
|
||||
"content='' additional_kwargs={'function_call': {'arguments': '\"\\n', 'name': ''}}\n",
|
||||
"content='' additional_kwargs={'function_call': {'arguments': '}', 'name': ''}}\n",
|
||||
"content=''\n",
|
||||
"content=''\n",
|
||||
"content='I'\n",
|
||||
"content=\"'m\"\n",
|
||||
"content=' sorry'\n",
|
||||
"content=','\n",
|
||||
"content=' but'\n",
|
||||
"content=' I'\n",
|
||||
"content=' couldn'\n",
|
||||
"content=\"'t\"\n",
|
||||
"content=' find'\n",
|
||||
"content=' the'\n",
|
||||
"content=' current'\n",
|
||||
"content=' weather'\n",
|
||||
"content=' in'\n",
|
||||
"content=' San'\n",
|
||||
"content=' Francisco'\n",
|
||||
"content='.'\n",
|
||||
"content=' However'\n",
|
||||
"content=','\n",
|
||||
"content=' you'\n",
|
||||
"content=' can'\n",
|
||||
"content=' check'\n",
|
||||
"content=' the'\n",
|
||||
"content=' weather'\n",
|
||||
"content=' forecast'\n",
|
||||
"content=' for'\n",
|
||||
"content=' San'\n",
|
||||
"content=' Francisco'\n",
|
||||
"content=' on'\n",
|
||||
"content=' websites'\n",
|
||||
"content=' like'\n",
|
||||
"content=' Weather'\n",
|
||||
"content='.com'\n",
|
||||
"content=' or'\n",
|
||||
"content=' Acc'\n",
|
||||
"content='u'\n",
|
||||
"content='Weather'\n",
|
||||
"content='.'\n",
|
||||
"content=''\n"
|
||||
"--\n",
|
||||
"Starting tool: tavily_search_results_json with inputs: {'query': 'weather in San Francisco'}\n",
|
||||
"Done tool: tavily_search_results_json\n",
|
||||
"Tool output was: [{'url': 'https://www.whereandwhen.net/when/north-america/california/san-francisco-ca/january/', 'content': 'Best time to go to San Francisco? Weather in San Francisco in january 2024 How was the weather last january? Here is the day by day recorded weather in San Francisco in january 2023: Seasonal average climate and temperature of San Francisco in january 8% 46% 29% 12% 8% Evolution of daily average temperature and precipitation in San Francisco in januaryWeather in San Francisco in january 2024. The weather in San Francisco in january comes from statistical datas on the past years. You can view the weather statistics the entire month, but also by using the tabs for the beginning, the middle and the end of the month. ... 23-01-2023 47°F to 61°F. 24-01-2023 43°F to 58°F. 25-01-2023 47°F to ...'}]\n",
|
||||
"--\n",
|
||||
"I|'m| sorry|,| but| I| couldn|'t| find| the| current| weather| in| San| Francisco|.| However|,| you| can| check| the| weather| in| San| Francisco| for| the| month| of| January| on| this| website|:| [|San| Francisco| Weather| in| January|](|https|://|www|.where|and|when|.net|/|when|/n|orth|-|amer|ica|/cal|ifornia|/s|an|-fr|anc|isco|-ca|/j|an|uary|/|).|"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from langchain_core.messages import HumanMessage\n",
|
||||
"inputs = {\"messages\": [HumanMessage(content=\"what is the weather in sf\")]}\n",
|
||||
"async for output in app.astream_log(inputs, include_types=[\"llm\"]):\n",
|
||||
" # astream_log() yields the requested logs (here LLMs) in JSONPatch format\n",
|
||||
" for op in output.ops:\n",
|
||||
" if op[\"path\"] == \"/streamed_output/-\":\n",
|
||||
" # this is the output from .stream()\n",
|
||||
" ...\n",
|
||||
" elif op[\"path\"].startswith(\"/logs/\") and op[\"path\"].endswith(\n",
|
||||
" \"/streamed_output/-\"\n",
|
||||
" ):\n",
|
||||
" # because we chose to only include LLMs, these are LLM tokens\n",
|
||||
" print(op[\"value\"])"
|
||||
"inputs = [HumanMessage(content=\"what is the weather in sf\")]\n",
|
||||
"async for event in app.astream_events(inputs, version=\"v1\"):\n",
|
||||
" kind = event[\"event\"]\n",
|
||||
" if kind == \"on_chat_model_stream\":\n",
|
||||
" content = event[\"data\"][\"chunk\"].content\n",
|
||||
" if content:\n",
|
||||
" # Empty content in the context of OpenAI means\n",
|
||||
" # that the model is asking for a tool to be invoked.\n",
|
||||
" # So we only print non-empty content\n",
|
||||
" print(content, end=\"|\")\n",
|
||||
" elif kind == \"on_tool_start\":\n",
|
||||
" print(\"--\")\n",
|
||||
" print(\n",
|
||||
" f\"Starting tool: {event['name']} with inputs: {event['data'].get('input')}\"\n",
|
||||
" )\n",
|
||||
" elif kind == \"on_tool_end\":\n",
|
||||
" print(f\"Done tool: {event['name']}\")\n",
|
||||
" print(f\"Tool output was: {event['data'].get('output')}\")\n",
|
||||
" print(\"--\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user