mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-09-27 03:55:00 +02:00
[Docs] Update notebooks to use START (#902)
This commit is contained in:
@@ -22,10 +22,7 @@
|
||||
"id": "c04a3f8e-0bc9-430b-85db-3edfa026d2cd",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%capture --no-stderr\n",
|
||||
"%pip install -U langgraph langchain-openai"
|
||||
]
|
||||
"source": ["%%capture --no-stderr\n%pip install -U langgraph langchain-openai"]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -41,18 +38,7 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"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\")"
|
||||
]
|
||||
"source": ["import getpass\nimport os\n\n\ndef _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",
|
||||
@@ -68,35 +54,7 @@
|
||||
"id": "1d51c35c-dbf2-4c01-932d-c5d308ea37d2",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Literal\n",
|
||||
"from langchain_community.tools.tavily_search import TavilySearchResults\n",
|
||||
"from langchain_core.runnables import ConfigurableField\n",
|
||||
"from langchain_core.tools import tool\n",
|
||||
"from langchain_openai import ChatOpenAI\n",
|
||||
"from langgraph.prebuilt import create_react_agent\n",
|
||||
"from langgraph.prebuilt import ToolNode\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"@tool\n",
|
||||
"def get_weather(city: Literal[\"nyc\", \"sf\"]):\n",
|
||||
" \"\"\"Use this to get weather information.\"\"\"\n",
|
||||
" if city == \"nyc\":\n",
|
||||
" return \"It might be cloudy in nyc\"\n",
|
||||
" elif city == \"sf\":\n",
|
||||
" return \"It's always sunny in sf\"\n",
|
||||
" else:\n",
|
||||
" raise AssertionError(\"Unknown city\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"tools = [get_weather]\n",
|
||||
"model = ChatOpenAI(model_name=\"gpt-3.5-turbo\", temperature=0)\n",
|
||||
"final_model = ChatOpenAI(model_name=\"gpt-3.5-turbo\", temperature=0)\n",
|
||||
"\n",
|
||||
"model = model.bind_tools(tools)\n",
|
||||
"# NOTE: this is where we're adding a tag that we'll be using later to filter the outputs of the final node\n",
|
||||
"final_model = final_model.with_config(tags=[\"final_node\"])"
|
||||
]
|
||||
"source": ["from typing import Literal\nfrom langchain_community.tools.tavily_search import TavilySearchResults\nfrom langchain_core.runnables import ConfigurableField\nfrom langchain_core.tools import tool\nfrom langchain_openai import ChatOpenAI\nfrom langgraph.prebuilt import create_react_agent\nfrom langgraph.prebuilt import ToolNode\n\n\n@tool\ndef get_weather(city: Literal[\"nyc\", \"sf\"]):\n \"\"\"Use this to get weather information.\"\"\"\n if city == \"nyc\":\n return \"It might be cloudy in nyc\"\n elif city == \"sf\":\n return \"It's always sunny in sf\"\n else:\n raise AssertionError(\"Unknown city\")\n\n\ntools = [get_weather]\nmodel = ChatOpenAI(model_name=\"gpt-3.5-turbo\", temperature=0)\nfinal_model = ChatOpenAI(model_name=\"gpt-3.5-turbo\", temperature=0)\n\nmodel = model.bind_tools(tools)\n# NOTE: this is where we're adding a tag that we'll be using later to filter the outputs of the final node\nfinal_model = final_model.with_config(tags=[\"final_node\"])"]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -104,9 +62,7 @@
|
||||
"id": "0af37212-e592-484d-9194-35d53fa79678",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"tool_node = ToolNode(tools=tools)"
|
||||
]
|
||||
"source": ["tool_node = ToolNode(tools=tools)"]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -114,13 +70,7 @@
|
||||
"id": "ac9d4f5b-655a-48f3-b514-a4a0815714a6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import TypedDict, Annotated\n",
|
||||
"\n",
|
||||
"from langgraph.graph import END, StateGraph\n",
|
||||
"from langgraph.graph.message import MessagesState\n",
|
||||
"from langchain_core.messages import BaseMessage"
|
||||
]
|
||||
"source": ["from typing import TypedDict, Annotated\n\nfrom langgraph.graph import END, StateGraph, START\nfrom langgraph.graph.message import MessagesState\nfrom langchain_core.messages import BaseMessage"]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -136,9 +86,7 @@
|
||||
"id": "3948c6b8-0317-4001-b699-32b25306a023",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain_core.messages import SystemMessage, HumanMessage"
|
||||
]
|
||||
"source": ["from langchain_core.messages import SystemMessage, HumanMessage"]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -146,35 +94,7 @@
|
||||
"id": "2efe9fb4-c6c2-4171-becd-d45bbf899209",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def should_continue(state: MessagesState) -> Literal[\"tools\", \"final\"]:\n",
|
||||
" messages = state['messages']\n",
|
||||
" last_message = messages[-1]\n",
|
||||
" # If the LLM makes a tool call, then we route to the \"tools\" node\n",
|
||||
" if last_message.tool_calls:\n",
|
||||
" return \"tools\"\n",
|
||||
" # Otherwise, we stop (reply to the user)\n",
|
||||
" return \"final\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def call_model(state: MessagesState):\n",
|
||||
" messages = state['messages']\n",
|
||||
" response = model.invoke(messages)\n",
|
||||
" # We return a list, because this will get added to the existing list\n",
|
||||
" return {\"messages\": [response]}\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def call_final_model(state: MessagesState):\n",
|
||||
" messages = state['messages']\n",
|
||||
" last_ai_message = messages[-1]\n",
|
||||
" response = final_model.invoke([\n",
|
||||
" SystemMessage(\"Rewrite this in the voice of Al Roker\"),\n",
|
||||
" HumanMessage(last_ai_message.content)\n",
|
||||
" ])\n",
|
||||
" # overwrite the last AI message from the agent\n",
|
||||
" response.id = last_ai_message.id\n",
|
||||
" return {\"messages\": [response]}"
|
||||
]
|
||||
"source": ["def should_continue(state: MessagesState) -> Literal[\"tools\", \"final\"]:\n messages = state['messages']\n last_message = messages[-1]\n # If the LLM makes a tool call, then we route to the \"tools\" node\n if last_message.tool_calls:\n return \"tools\"\n # Otherwise, we stop (reply to the user)\n return \"final\"\n\n\ndef call_model(state: MessagesState):\n messages = state['messages']\n response = model.invoke(messages)\n # We return a list, because this will get added to the existing list\n return {\"messages\": [response]}\n\n\ndef call_final_model(state: MessagesState):\n messages = state['messages']\n last_ai_message = messages[-1]\n response = final_model.invoke([\n SystemMessage(\"Rewrite this in the voice of Al Roker\"),\n HumanMessage(last_ai_message.content)\n ])\n # overwrite the last AI message from the agent\n response.id = last_ai_message.id\n return {\"messages\": [response]}"]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -182,23 +102,7 @@
|
||||
"id": "b1a9a981-8629-4d25-a0e1-d666c3968b30",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"workflow = StateGraph(MessagesState)\n",
|
||||
"\n",
|
||||
"workflow.add_node(\"agent\", call_model)\n",
|
||||
"workflow.add_node(\"tools\", tool_node)\n",
|
||||
"# add a separate final node\n",
|
||||
"workflow.add_node(\"final\", call_final_model)\n",
|
||||
"\n",
|
||||
"workflow.set_entry_point(\"agent\")\n",
|
||||
"workflow.add_conditional_edges(\n",
|
||||
" \"agent\",\n",
|
||||
" should_continue,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"workflow.add_edge(\"tools\", 'agent')\n",
|
||||
"workflow.add_edge(\"final\", END)"
|
||||
]
|
||||
"source": ["workflow = StateGraph(MessagesState)\n\nworkflow.add_node(\"agent\", call_model)\nworkflow.add_node(\"tools\", tool_node)\n# add a separate final node\nworkflow.add_node(\"final\", call_final_model)\n\nworkflow.add_edge(START, \"agent\")\nworkflow.add_conditional_edges(\n \"agent\",\n should_continue,\n)\n\nworkflow.add_edge(\"tools\", 'agent')\nworkflow.add_edge(\"final\", END)"]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -206,9 +110,7 @@
|
||||
"id": "a7b0251f-dcee-49d6-8133-af50d4a55e22",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"app = workflow.compile()"
|
||||
]
|
||||
"source": ["app = workflow.compile()"]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -216,9 +118,7 @@
|
||||
"id": "f8b77e74-17e9-4fee-a164-4637013b55ff",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from IPython.display import display, Image"
|
||||
]
|
||||
"source": ["from IPython.display import display, Image"]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -237,9 +137,7 @@
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"display(Image(app.get_graph().draw_mermaid_png()))"
|
||||
]
|
||||
"source": ["display(Image(app.get_graph().draw_mermaid_png()))"]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -271,19 +169,7 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"inputs = {\"messages\": [(\"human\", \"what's the weather in nyc?\")]}\n",
|
||||
"async for event in app.astream_events(inputs, version=\"v2\"):\n",
|
||||
" kind = event[\"event\"]\n",
|
||||
" tags = event.get(\"tags\", [])\n",
|
||||
" if kind == \"on_chat_model_stream\" and \"final_node\" in tags:\n",
|
||||
" data = event[\"data\"]\n",
|
||||
" if data[\"chunk\"].content:\n",
|
||||
" # Empty content in the context of OpenAI or Anthropic usually means\n",
|
||||
" # that the model is asking for a tool to be invoked.\n",
|
||||
" # So we only print non-empty content\n",
|
||||
" print(data[\"chunk\"].content, end=\"|\")"
|
||||
]
|
||||
"source": ["inputs = {\"messages\": [(\"human\", \"what's the weather in nyc?\")]}\nasync for event in app.astream_events(inputs, version=\"v2\"):\n kind = event[\"event\"]\n tags = event.get(\"tags\", [])\n if kind == \"on_chat_model_stream\" and \"final_node\" in tags:\n data = event[\"data\"]\n if data[\"chunk\"].content:\n # Empty content in the context of OpenAI or Anthropic usually means\n # that the model is asking for a tool to be invoked.\n # So we only print non-empty content\n print(data[\"chunk\"].content, end=\"|\")"]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
Reference in New Issue
Block a user