mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-09-30 13:35:09 +02:00
[Docs] Update notebooks to use START (#902)
This commit is contained in:
+24
-218
@@ -38,9 +38,7 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"!%pip install --quiet -U langgraph langchain langchain_openai tavily-pythonvily-python"
|
||||
]
|
||||
"source": ["!%pip install --quiet -U langgraph langchain langchain_openai tavily-pythonvily-python"]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -65,13 +63,7 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import getpass\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"os.environ[\"OPENAI_API_KEY\"] = getpass.getpass(\"OpenAI API Key:\")\n",
|
||||
"os.environ[\"TAVILY_API_KEY\"] = getpass.getpass(\"Tavily API Key:\")"
|
||||
]
|
||||
"source": ["import getpass\nimport os\n\nos.environ[\"OPENAI_API_KEY\"] = getpass.getpass(\"OpenAI API Key:\")\nos.environ[\"TAVILY_API_KEY\"] = getpass.getpass(\"Tavily API Key:\")"]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -87,10 +79,7 @@
|
||||
"id": "95e25aec-7c9f-4a63-b143-225d0e9a79c3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n",
|
||||
"os.environ[\"LANGCHAIN_API_KEY\"] = getpass.getpass(\"LangSmith API Key:\")"
|
||||
]
|
||||
"source": ["os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\nos.environ[\"LANGCHAIN_API_KEY\"] = getpass.getpass(\"LangSmith API Key:\")"]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -110,11 +99,7 @@
|
||||
"id": "d7ef57dd-5d6e-4ad3-9377-a92201c1310e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain_community.tools.tavily_search import TavilySearchResults\n",
|
||||
"\n",
|
||||
"tools = [TavilySearchResults(max_results=1)]"
|
||||
]
|
||||
"source": ["from langchain_community.tools.tavily_search import TavilySearchResults\n\ntools = [TavilySearchResults(max_results=1)]"]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -131,11 +116,7 @@
|
||||
"id": "5cf3331e-ccb3-41c8-aeb9-a840a94d41e7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langgraph.prebuilt import ToolNode\n",
|
||||
"\n",
|
||||
"tool_node = ToolNode(tools)"
|
||||
]
|
||||
"source": ["from langgraph.prebuilt import ToolNode\n\ntool_node = ToolNode(tools)"]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -159,11 +140,7 @@
|
||||
"id": "892b54b9-75f0-4804-9ed0-88b5e5532989",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain_openai import ChatOpenAI\n",
|
||||
"\n",
|
||||
"model = ChatOpenAI(temperature=0)"
|
||||
]
|
||||
"source": ["from langchain_openai import ChatOpenAI\n\nmodel = ChatOpenAI(temperature=0)"]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -180,9 +157,7 @@
|
||||
"id": "cd3cbae5-d92c-4559-a4aa-44721b80d107",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"model = model.bind_tools(tools)"
|
||||
]
|
||||
"source": ["model = model.bind_tools(tools)"]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -217,17 +192,7 @@
|
||||
"id": "3b541bb9-900c-40d0-964d-7b5dfee30667",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Define the function that determines whether to continue or not\n",
|
||||
"def should_continue(state):\n",
|
||||
" last_message = state[\"messages\"][-1]\n",
|
||||
" # If there is no function call, then we finish\n",
|
||||
" if not last_message.tool_calls:\n",
|
||||
" return \"end\"\n",
|
||||
" # Otherwise if there is, we continue\n",
|
||||
" else:\n",
|
||||
" return \"continue\""
|
||||
]
|
||||
"source": ["# Define the function that determines whether to continue or not\ndef should_continue(state):\n last_message = state[\"messages\"][-1]\n # If there is no function call, then we finish\n if not last_message.tool_calls:\n return \"end\"\n # Otherwise if there is, we continue\n else:\n return \"continue\""]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -245,107 +210,7 @@
|
||||
"id": "812b4e70-4956-4415-8880-db48b3dcbad2",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Annotated, TypedDict\n",
|
||||
"\n",
|
||||
"from langchain_core.messages import (\n",
|
||||
" AIMessage,\n",
|
||||
" AnyMessage,\n",
|
||||
" HumanMessage,\n",
|
||||
" SystemMessage,\n",
|
||||
" ToolMessage,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"from langgraph.graph import END, StateGraph\n",
|
||||
"from langgraph.graph.message import add_messages\n",
|
||||
"from langgraph.managed.few_shot import FewShotExamples\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class BaseState(TypedDict):\n",
|
||||
" messages: Annotated[list[AnyMessage], add_messages]\n",
|
||||
" examples: Annotated[list, FewShotExamples]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def _render_message(m):\n",
|
||||
" if isinstance(m, HumanMessage):\n",
|
||||
" return \"Human: \" + m.content\n",
|
||||
" elif isinstance(m, AIMessage):\n",
|
||||
" _m = \"AI: \" + m.content\n",
|
||||
" if len(m.tool_calls) > 0:\n",
|
||||
" _m += f\" Tools: {m.tool_calls}\"\n",
|
||||
" return _m\n",
|
||||
" elif isinstance(m, ToolMessage):\n",
|
||||
" return \"Tool Result: ...\"\n",
|
||||
" else:\n",
|
||||
" raise ValueError\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def _render_messages(ms):\n",
|
||||
" m_string = [_render_message(m) for m in ms]\n",
|
||||
" return \"\\n\".join(m_string)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Define a new graph\n",
|
||||
"workflow = StateGraph(BaseState)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def _agent(state: BaseState):\n",
|
||||
" if len(state[\"examples\"]) > 0:\n",
|
||||
" _examples = \"\\n\\n\".join(\n",
|
||||
" [\n",
|
||||
" f\"Example {i}: \" + _render_messages(e[\"messages\"])\n",
|
||||
" for i, e in enumerate(state[\"examples\"])\n",
|
||||
" ]\n",
|
||||
" )\n",
|
||||
" system_message = \"\"\"You are a helpful assistant. Below are some examples of interactions you had with users. \\\n",
|
||||
"These were good interactions where the final result they got was the desired one. As much as possible, you should learn from these interactions and mimic them in the future. \\\n",
|
||||
"Pay particularly close attention to when tools are called, and what the inputs are.!\n",
|
||||
"\n",
|
||||
"{examples}\n",
|
||||
"\n",
|
||||
"Assist the user as they require!\"\"\".format(\n",
|
||||
" examples=_examples\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" else:\n",
|
||||
" system_message = \"\"\"You are a helpful assistant\"\"\"\n",
|
||||
" output = model.invoke([SystemMessage(content=system_message)] + state[\"messages\"])\n",
|
||||
" return {\"messages\": [output]}\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Define the two nodes we will cycle between\n",
|
||||
"workflow.add_node(\"agent\", _agent)\n",
|
||||
"workflow.add_node(\"action\", tool_node)\n",
|
||||
"\n",
|
||||
"# Set the entrypoint as `agent`\n",
|
||||
"# This means that this node is the first one called\n",
|
||||
"workflow.set_entry_point(\"agent\")\n",
|
||||
"\n",
|
||||
"# We now add a conditional edge\n",
|
||||
"workflow.add_conditional_edges(\n",
|
||||
" # First, we define the start node. We use `agent`.\n",
|
||||
" # This means these are the edges taken after the `agent` node is called.\n",
|
||||
" \"agent\",\n",
|
||||
" # Next, we pass in the function that will determine which node is called next.\n",
|
||||
" should_continue,\n",
|
||||
" # Finally we pass in a mapping.\n",
|
||||
" # The keys are strings, and the values are other nodes.\n",
|
||||
" # END is a special node marking that the graph should finish.\n",
|
||||
" # What will happen is we will call `should_continue`, and then the output of that\n",
|
||||
" # will be matched against the keys in this mapping.\n",
|
||||
" # Based on which one it matches, that node will then be called.\n",
|
||||
" {\n",
|
||||
" # If `tools`, then we call the tool node.\n",
|
||||
" \"continue\": \"action\",\n",
|
||||
" # Otherwise we finish.\n",
|
||||
" \"end\": END,\n",
|
||||
" },\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# We now add a normal edge from `tools` to `agent`.\n",
|
||||
"# This means that after `tools` is called, `agent` node is called next.\n",
|
||||
"workflow.add_edge(\"action\", \"agent\")"
|
||||
]
|
||||
"source": ["from typing import Annotated, TypedDict\n\nfrom langchain_core.messages import (\n AIMessage,\n AnyMessage,\n HumanMessage,\n SystemMessage,\n ToolMessage,\n)\n\nfrom langgraph.graph import END, StateGraph, START\nfrom langgraph.graph.message import add_messages\nfrom langgraph.managed.few_shot import FewShotExamples\n\n\nclass BaseState(TypedDict):\n messages: Annotated[list[AnyMessage], add_messages]\n examples: Annotated[list, FewShotExamples]\n\n\ndef _render_message(m):\n if isinstance(m, HumanMessage):\n return \"Human: \" + m.content\n elif isinstance(m, AIMessage):\n _m = \"AI: \" + m.content\n if len(m.tool_calls) > 0:\n _m += f\" Tools: {m.tool_calls}\"\n return _m\n elif isinstance(m, ToolMessage):\n return \"Tool Result: ...\"\n else:\n raise ValueError\n\n\ndef _render_messages(ms):\n m_string = [_render_message(m) for m in ms]\n return \"\\n\".join(m_string)\n\n\n# Define a new graph\nworkflow = StateGraph(BaseState)\n\n\ndef _agent(state: BaseState):\n if len(state[\"examples\"]) > 0:\n _examples = \"\\n\\n\".join(\n [\n f\"Example {i}: \" + _render_messages(e[\"messages\"])\n for i, e in enumerate(state[\"examples\"])\n ]\n )\n system_message = \"\"\"You are a helpful assistant. Below are some examples of interactions you had with users. \\\nThese were good interactions where the final result they got was the desired one. As much as possible, you should learn from these interactions and mimic them in the future. \\\nPay particularly close attention to when tools are called, and what the inputs are.!\n\n{examples}\n\nAssist the user as they require!\"\"\".format(\n examples=_examples\n )\n\n else:\n system_message = \"\"\"You are a helpful assistant\"\"\"\n output = model.invoke([SystemMessage(content=system_message)] + state[\"messages\"])\n return {\"messages\": [output]}\n\n\n# Define the two nodes we will cycle between\nworkflow.add_node(\"agent\", _agent)\nworkflow.add_node(\"action\", tool_node)\n\n# Set the entrypoint as `agent`\n# This means that this node is the first one called\nworkflow.add_edge(START, \"agent\")\n\n# We now add a conditional edge\nworkflow.add_conditional_edges(\n # First, we define the start node. We use `agent`.\n # This means these are the edges taken after the `agent` node is called.\n \"agent\",\n # Next, we pass in the function that will determine which node is called next.\n should_continue,\n # Finally we pass in a mapping.\n # The keys are strings, and the values are other nodes.\n # END is a special node marking that the graph should finish.\n # What will happen is we will call `should_continue`, and then the output of that\n # will be matched against the keys in this mapping.\n # Based on which one it matches, that node will then be called.\n {\n # If `tools`, then we call the tool node.\n \"continue\": \"action\",\n # Otherwise we finish.\n \"end\": END,\n },\n)\n\n# We now add a normal edge from `tools` to `agent`.\n# This means that after `tools` is called, `agent` node is called next.\nworkflow.add_edge(\"action\", \"agent\")"]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -363,11 +228,7 @@
|
||||
"id": "6845ed6a-d155-4105-9160-28849877248b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langgraph.checkpoint.sqlite import SqliteSaver\n",
|
||||
"\n",
|
||||
"memory = SqliteSaver.from_conn_string(\":memory:\")"
|
||||
]
|
||||
"source": ["from langgraph.checkpoint.sqlite import SqliteSaver\n\nmemory = SqliteSaver.from_conn_string(\":memory:\")"]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -375,12 +236,7 @@
|
||||
"id": "79d29875-8aa8-434c-9f20-1c58346a6249",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Finally, we compile it!\n",
|
||||
"# This compiles it into a LangChain Runnable,\n",
|
||||
"# meaning you can use it as you would any other runnable\n",
|
||||
"app = workflow.compile(checkpointer=memory, interrupt_before=[\"action\"])"
|
||||
]
|
||||
"source": ["# Finally, we compile it!\n# This compiles it into a LangChain Runnable,\n# meaning you can use it as you would any other runnable\napp = workflow.compile(checkpointer=memory, interrupt_before=[\"action\"])"]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -408,11 +264,7 @@
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from IPython.display import Image\n",
|
||||
"\n",
|
||||
"Image(app.get_graph().draw_png())"
|
||||
]
|
||||
"source": ["from IPython.display import Image\n\nImage(app.get_graph().draw_png())"]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -438,14 +290,7 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"thread = {\"configurable\": {\"thread_id\": \"1\"}}\n",
|
||||
"for event in app.stream(\n",
|
||||
" {\"messages\": [HumanMessage(content=\"what's the weather in sf?\")]}, thread\n",
|
||||
"):\n",
|
||||
" for v in event.values():\n",
|
||||
" print(v)"
|
||||
]
|
||||
"source": ["thread = {\"configurable\": {\"thread_id\": \"1\"}}\nfor event in app.stream(\n {\"messages\": [HumanMessage(content=\"what's the weather in sf?\")]}, thread\n):\n for v in event.values():\n print(v)"]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -465,10 +310,7 @@
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"current_values = app.get_state(thread)\n",
|
||||
"current_values.values"
|
||||
]
|
||||
"source": ["current_values = app.get_state(thread)\ncurrent_values.values"]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -476,11 +318,7 @@
|
||||
"id": "1a0cdb78-40c6-4550-8c27-8f1b02d9e678",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"current_values.values[\"messages\"][-1].tool_calls[0][\"args\"][\n",
|
||||
" \"query\"\n",
|
||||
"] = \"weather in San Francisco, Accuweather\""
|
||||
]
|
||||
"source": ["current_values.values[\"messages\"][-1].tool_calls[0][\"args\"][\n \"query\"\n] = \"weather in San Francisco, Accuweather\""]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -500,9 +338,7 @@
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"app.update_state(thread, current_values.values)"
|
||||
]
|
||||
"source": ["app.update_state(thread, current_values.values)"]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -521,9 +357,7 @@
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"app.get_state(thread)"
|
||||
]
|
||||
"source": ["app.get_state(thread)"]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -540,11 +374,7 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"for event in app.stream(None, thread):\n",
|
||||
" for v in event.values():\n",
|
||||
" print(v)"
|
||||
]
|
||||
"source": ["for event in app.stream(None, thread):\n for v in event.values():\n print(v)"]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -552,16 +382,7 @@
|
||||
"id": "84748206-975e-4a33-a178-d43df683298c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"chkpnt_tuple = memory.get_tuple({\"configurable\": {\"thread_id\": \"1\"}})\n",
|
||||
"config = chkpnt_tuple.config\n",
|
||||
"checkpoint = chkpnt_tuple.checkpoint\n",
|
||||
"metadata = chkpnt_tuple.metadata\n",
|
||||
"\n",
|
||||
"# mark as \"good\"\n",
|
||||
"metadata[\"score\"] = 1\n",
|
||||
"memory.put(config, checkpoint, metadata)"
|
||||
]
|
||||
"source": ["chkpnt_tuple = memory.get_tuple({\"configurable\": {\"thread_id\": \"1\"}})\nconfig = chkpnt_tuple.config\ncheckpoint = chkpnt_tuple.checkpoint\nmetadata = chkpnt_tuple.metadata\n\n# mark as \"good\"\nmetadata[\"score\"] = 1\nmemory.put(config, checkpoint, metadata)"]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -569,9 +390,7 @@
|
||||
"id": "ce7fa228-8c37-4001-afd4-0001b268e1db",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"examples = list(memory.search({\"score\": 1}))"
|
||||
]
|
||||
"source": ["examples = list(memory.search({\"score\": 1}))"]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -590,9 +409,7 @@
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"examples"
|
||||
]
|
||||
"source": ["examples"]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -608,14 +425,7 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"thread = {\"configurable\": {\"thread_id\": \"7\"}}\n",
|
||||
"for event in app.stream(\n",
|
||||
" {\"messages\": [HumanMessage(content=\"what's the weather in la?\")]}, thread\n",
|
||||
"):\n",
|
||||
" for v in event.values():\n",
|
||||
" print(v)"
|
||||
]
|
||||
"source": ["thread = {\"configurable\": {\"thread_id\": \"7\"}}\nfor event in app.stream(\n {\"messages\": [HumanMessage(content=\"what's the weather in la?\")]}, thread\n):\n for v in event.values():\n print(v)"]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -632,11 +442,7 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"for event in app.stream(None, thread):\n",
|
||||
" for v in event.values():\n",
|
||||
" print(v)"
|
||||
]
|
||||
"source": ["for event in app.stream(None, thread):\n for v in event.values():\n print(v)"]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -644,7 +450,7 @@
|
||||
"id": "9ab115de-9b11-4e8b-8ace-c23e1369300b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
"source": [""]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
Reference in New Issue
Block a user