mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-09-08 18:57:52 +02:00
* add notebook for get update state * cr * Fix bad merge * Update notebook * Update * Fix unbound local bug * Fix duplicate history entries * Update notebook with time travel section * Update notebook * cr * cr --------- Co-authored-by: Nuno Campos <nuno@langchain.dev>
32 KiB
32 KiB
In [1]:
!pip install --quiet -U langchain langchain_openai tavily-python[1m[[0m[34;49mnotice[0m[1;39;49m][0m[39;49m A new release of pip is available: [0m[31;49m23.3.1[0m[39;49m -> [0m[32;49m23.3.2[0m [1m[[0m[34;49mnotice[0m[1;39;49m][0m[39;49m To update, run: [0m[32;49mpip install --upgrade pip[0m
In [2]:
import os
import getpass
os.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API Key:")
os.environ["TAVILY_API_KEY"] = getpass.getpass("Tavily API Key:")OpenAI API Key: ········ Tavily API Key: ········
In [ ]:
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = getpass.getpass("LangSmith API Key:")In [1]:
from langchain_community.tools.tavily_search import TavilySearchResults
tools = [TavilySearchResults(max_results=1)]In [2]:
from langgraph.prebuilt import ToolExecutor
tool_executor = ToolExecutor(tools)In [3]:
from langchain_openai import ChatOpenAI
model = ChatOpenAI(temperature=0)In [4]:
from langchain_core.utils.function_calling import convert_to_openai_function
functions = [convert_to_openai_function(t) for t in tools]
model = model.bind_functions(functions)In [5]:
from langgraph.prebuilt import ToolInvocation
import json
from langchain_core.messages import FunctionMessage
# Define the function that determines whether to continue or not
def should_continue(messages):
last_message = messages[-1]
# If there is no function call, then we finish
if "function_call" not in last_message.additional_kwargs:
return "end"
# Otherwise if there is, we continue
else:
return "continue"
# Define the function that calls the model
def call_model(messages):
response = model.invoke(messages)
# We return a list, because this will get added to the existing list
return response
# Define the function to execute tools
def call_tool(messages):
# Based on the continue condition
# we know the last message involves a function call
last_message = messages[-1]
# We construct an ToolInvocation from the function_call
action = ToolInvocation(
tool=last_message.additional_kwargs["function_call"]["name"],
tool_input=json.loads(
last_message.additional_kwargs["function_call"]["arguments"]
),
)
# We call the tool_executor and get back a response
response = tool_executor.invoke(action)
# We use the response to create a FunctionMessage
function_message = FunctionMessage(content=str(response), name=action.tool)
# We return a list, because this will get added to the existing list
return function_messageIn [6]:
from langgraph.graph import MessageGraph, END
# Define a new graph
workflow = MessageGraph()
# Define the two nodes we will cycle between
workflow.add_node("agent", call_model)
workflow.add_node("action", call_tool)
# Set the entrypoint as `agent`
# This means that this node is the first one called
workflow.set_entry_point("agent")
# We now add a conditional edge
workflow.add_conditional_edges(
# First, we define the start node. We use `agent`.
# This means these are the edges taken after the `agent` node is called.
"agent",
# Next, we pass in the function that will determine which node is called next.
should_continue,
# Finally we pass in a mapping.
# The keys are strings, and the values are other nodes.
# END is a special node marking that the graph should finish.
# What will happen is we will call `should_continue`, and then the output of that
# will be matched against the keys in this mapping.
# Based on which one it matches, that node will then be called.
{
# If `tools`, then we call the tool node.
"continue": "action",
# Otherwise we finish.
"end": END,
},
)
# We now add a normal edge from `tools` to `agent`.
# This means that after `tools` is called, `agent` node is called next.
workflow.add_edge("action", "agent")In [7]:
from langgraph.checkpoint.sqlite import SqliteSaver
memory = SqliteSaver.from_conn_string(":memory:")In [8]:
# Finally, we compile it!
# This compiles it into a LangChain Runnable,
# meaning you can use it as you would any other runnable
app = workflow.compile(checkpointer=memory, interrupt_before=["action"])In [9]:
from langchain_core.messages import HumanMessage
thread = {"configurable": {"thread_id": '3'}}
inputs = [HumanMessage(content="hi! I'm bob")]
for event in app.stream(inputs, thread):
for k, v in event.items():
if k != "__end__":
print(v)content='Hello Bob! How can I assist you today?' response_metadata={'finish_reason': 'stop', 'logprobs': None} id='9467300a-f8ea-47db-9ade-3d9130c9f6d1'
In [10]:
app.get_state(thread)Out [10]:
StateSnapshot(values=[HumanMessage(content="hi! I'm bob", id='5e326da4-44ee-4334-b2e6-869dd6d3218d'), AIMessage(content='Hello Bob! How can I assist you today?', response_metadata={'finish_reason': 'stop', 'logprobs': None}, id='9467300a-f8ea-47db-9ade-3d9130c9f6d1')], next=(), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-03-15T21:24:10.780714+00:00'}})In [11]:
inputs = [HumanMessage(content="what is the weather in sf currently")]
for event in app.stream(inputs, thread):
for k, v in event.items():
if k != "__end__":
print(v)content='' additional_kwargs={'function_call': {'arguments': '{"query":"current weather in San Francisco"}', 'name': 'tavily_search_results_json'}} response_metadata={'finish_reason': 'function_call', 'logprobs': None} id='af48af47-01bc-4099-a7d6-14cc2df5709e'
In [12]:
current_values = app.get_state(thread)
current_values.values[-1].additional_kwargsOut [12]:
{'function_call': {'arguments': '{"query":"current weather in San Francisco"}',
'name': 'tavily_search_results_json'}}In [13]:
current_values.values[-1].additional_kwargs = {'function_call': {'arguments': '{"query":"weather in San Francisco today"}',
'name': 'tavily_search_results_json'}}In [14]:
app.update_state(thread, current_values.values)Out [14]:
{'configurable': {'thread_id': '3',
'thread_ts': '2024-03-15T21:24:37.208417+00:00'}}In [15]:
app.get_state(thread)Out [15]:
StateSnapshot(values=[HumanMessage(content="hi! I'm bob", id='5e326da4-44ee-4334-b2e6-869dd6d3218d'), AIMessage(content='Hello Bob! How can I assist you today?', response_metadata={'finish_reason': 'stop', 'logprobs': None}, id='9467300a-f8ea-47db-9ade-3d9130c9f6d1'), HumanMessage(content='what is the weather in sf currently', id='bc16849a-fa20-4f07-815c-b254c6d77f63'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{"query":"weather in San Francisco today"}', 'name': 'tavily_search_results_json'}}, response_metadata={'finish_reason': 'function_call', 'logprobs': None}, id='af48af47-01bc-4099-a7d6-14cc2df5709e')], next=('agent:edges',), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-03-15T21:24:37.208417+00:00'}})In [16]:
for event in app.stream(None, thread):
for k, v in event.items():
if k != "__end__":
print(v)content='[{\'url\': \'https://weather.com/weather/today/l/San+Francisco+CA+USCA0987:1:US\', \'content\': "Today\'s and tonight\'s San Francisco, CA weather forecast, weather conditions and Doppler radar from The Weather Channel and Weather.com"}]' name='tavily_search_results_json' id='dbba7582-c1b3-4d6a-8727-9421c431f7dc'
content='You can check the current weather in San Francisco by visiting [The Weather Channel](https://weather.com/weather/today/l/San+Francisco+CA+USCA0987:1:US).' response_metadata={'finish_reason': 'stop', 'logprobs': None} id='4a32c94c-63bc-4f65-b9dd-bbaeaff3c54a'
In [17]:
for state in app.get_state_history(thread):
print(state)
print('--')
if len(state.values) == 3:
to_replay = stateStateSnapshot(values=[HumanMessage(content="hi! I'm bob", id='5e326da4-44ee-4334-b2e6-869dd6d3218d'), AIMessage(content='Hello Bob! How can I assist you today?', response_metadata={'finish_reason': 'stop', 'logprobs': None}, id='9467300a-f8ea-47db-9ade-3d9130c9f6d1'), HumanMessage(content='what is the weather in sf currently', id='bc16849a-fa20-4f07-815c-b254c6d77f63'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{"query":"weather in San Francisco today"}', 'name': 'tavily_search_results_json'}}, response_metadata={'finish_reason': 'function_call', 'logprobs': None}, id='af48af47-01bc-4099-a7d6-14cc2df5709e'), FunctionMessage(content='[{\'url\': \'https://weather.com/weather/today/l/San+Francisco+CA+USCA0987:1:US\', \'content\': "Today\'s and tonight\'s San Francisco, CA weather forecast, weather conditions and Doppler radar from The Weather Channel and Weather.com"}]', name='tavily_search_results_json', id='dbba7582-c1b3-4d6a-8727-9421c431f7dc'), AIMessage(content='You can check the current weather in San Francisco by visiting [The Weather Channel](https://weather.com/weather/today/l/San+Francisco+CA+USCA0987:1:US).', response_metadata={'finish_reason': 'stop', 'logprobs': None}, id='4a32c94c-63bc-4f65-b9dd-bbaeaff3c54a')], next=(), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-03-15T21:24:59.635105+00:00'}})
--
StateSnapshot(values=[HumanMessage(content="hi! I'm bob", id='5e326da4-44ee-4334-b2e6-869dd6d3218d'), AIMessage(content='Hello Bob! How can I assist you today?', response_metadata={'finish_reason': 'stop', 'logprobs': None}, id='9467300a-f8ea-47db-9ade-3d9130c9f6d1'), HumanMessage(content='what is the weather in sf currently', id='bc16849a-fa20-4f07-815c-b254c6d77f63'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{"query":"weather in San Francisco today"}', 'name': 'tavily_search_results_json'}}, response_metadata={'finish_reason': 'function_call', 'logprobs': None}, id='af48af47-01bc-4099-a7d6-14cc2df5709e'), FunctionMessage(content='[{\'url\': \'https://weather.com/weather/today/l/San+Francisco+CA+USCA0987:1:US\', \'content\': "Today\'s and tonight\'s San Francisco, CA weather forecast, weather conditions and Doppler radar from The Weather Channel and Weather.com"}]', name='tavily_search_results_json', id='dbba7582-c1b3-4d6a-8727-9421c431f7dc'), AIMessage(content='You can check the current weather in San Francisco by visiting [The Weather Channel](https://weather.com/weather/today/l/San+Francisco+CA+USCA0987:1:US).', response_metadata={'finish_reason': 'stop', 'logprobs': None}, id='4a32c94c-63bc-4f65-b9dd-bbaeaff3c54a')], next=('agent:edges',), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-03-15T21:24:59.629900+00:00'}})
--
StateSnapshot(values=[HumanMessage(content="hi! I'm bob", id='5e326da4-44ee-4334-b2e6-869dd6d3218d'), AIMessage(content='Hello Bob! How can I assist you today?', response_metadata={'finish_reason': 'stop', 'logprobs': None}, id='9467300a-f8ea-47db-9ade-3d9130c9f6d1'), HumanMessage(content='what is the weather in sf currently', id='bc16849a-fa20-4f07-815c-b254c6d77f63'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{"query":"weather in San Francisco today"}', 'name': 'tavily_search_results_json'}}, response_metadata={'finish_reason': 'function_call', 'logprobs': None}, id='af48af47-01bc-4099-a7d6-14cc2df5709e'), FunctionMessage(content='[{\'url\': \'https://weather.com/weather/today/l/San+Francisco+CA+USCA0987:1:US\', \'content\': "Today\'s and tonight\'s San Francisco, CA weather forecast, weather conditions and Doppler radar from The Weather Channel and Weather.com"}]', name='tavily_search_results_json', id='dbba7582-c1b3-4d6a-8727-9421c431f7dc')], next=('agent',), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-03-15T21:24:58.501730+00:00'}})
--
StateSnapshot(values=[HumanMessage(content="hi! I'm bob", id='5e326da4-44ee-4334-b2e6-869dd6d3218d'), AIMessage(content='Hello Bob! How can I assist you today?', response_metadata={'finish_reason': 'stop', 'logprobs': None}, id='9467300a-f8ea-47db-9ade-3d9130c9f6d1'), HumanMessage(content='what is the weather in sf currently', id='bc16849a-fa20-4f07-815c-b254c6d77f63'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{"query":"weather in San Francisco today"}', 'name': 'tavily_search_results_json'}}, response_metadata={'finish_reason': 'function_call', 'logprobs': None}, id='af48af47-01bc-4099-a7d6-14cc2df5709e'), FunctionMessage(content='[{\'url\': \'https://weather.com/weather/today/l/San+Francisco+CA+USCA0987:1:US\', \'content\': "Today\'s and tonight\'s San Francisco, CA weather forecast, weather conditions and Doppler radar from The Weather Channel and Weather.com"}]', name='tavily_search_results_json', id='dbba7582-c1b3-4d6a-8727-9421c431f7dc')], next=('action:edges',), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-03-15T21:24:58.498596+00:00'}})
--
StateSnapshot(values=[HumanMessage(content="hi! I'm bob", id='5e326da4-44ee-4334-b2e6-869dd6d3218d'), AIMessage(content='Hello Bob! How can I assist you today?', response_metadata={'finish_reason': 'stop', 'logprobs': None}, id='9467300a-f8ea-47db-9ade-3d9130c9f6d1'), HumanMessage(content='what is the weather in sf currently', id='bc16849a-fa20-4f07-815c-b254c6d77f63'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{"query":"weather in San Francisco today"}', 'name': 'tavily_search_results_json'}}, response_metadata={'finish_reason': 'function_call', 'logprobs': None}, id='af48af47-01bc-4099-a7d6-14cc2df5709e')], next=('action',), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-03-15T21:24:57.092121+00:00'}})
--
StateSnapshot(values=[HumanMessage(content="hi! I'm bob", id='5e326da4-44ee-4334-b2e6-869dd6d3218d'), AIMessage(content='Hello Bob! How can I assist you today?', response_metadata={'finish_reason': 'stop', 'logprobs': None}, id='9467300a-f8ea-47db-9ade-3d9130c9f6d1'), HumanMessage(content='what is the weather in sf currently', id='bc16849a-fa20-4f07-815c-b254c6d77f63'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{"query":"weather in San Francisco today"}', 'name': 'tavily_search_results_json'}}, response_metadata={'finish_reason': 'function_call', 'logprobs': None}, id='af48af47-01bc-4099-a7d6-14cc2df5709e')], next=('agent:edges',), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-03-15T21:24:37.208417+00:00'}})
--
StateSnapshot(values=[HumanMessage(content="hi! I'm bob", id='5e326da4-44ee-4334-b2e6-869dd6d3218d'), AIMessage(content='Hello Bob! How can I assist you today?', response_metadata={'finish_reason': 'stop', 'logprobs': None}, id='9467300a-f8ea-47db-9ade-3d9130c9f6d1'), HumanMessage(content='what is the weather in sf currently', id='bc16849a-fa20-4f07-815c-b254c6d77f63'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{"query":"current weather in San Francisco"}', 'name': 'tavily_search_results_json'}}, response_metadata={'finish_reason': 'function_call', 'logprobs': None}, id='af48af47-01bc-4099-a7d6-14cc2df5709e')], next=('agent:edges',), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-03-15T21:24:20.413423+00:00'}})
--
StateSnapshot(values=[HumanMessage(content="hi! I'm bob", id='5e326da4-44ee-4334-b2e6-869dd6d3218d'), AIMessage(content='Hello Bob! How can I assist you today?', response_metadata={'finish_reason': 'stop', 'logprobs': None}, id='9467300a-f8ea-47db-9ade-3d9130c9f6d1'), HumanMessage(content='what is the weather in sf currently', id='bc16849a-fa20-4f07-815c-b254c6d77f63')], next=('agent',), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-03-15T21:24:19.721216+00:00'}})
--
StateSnapshot(values=[HumanMessage(content="hi! I'm bob", id='5e326da4-44ee-4334-b2e6-869dd6d3218d'), AIMessage(content='Hello Bob! How can I assist you today?', response_metadata={'finish_reason': 'stop', 'logprobs': None}, id='9467300a-f8ea-47db-9ade-3d9130c9f6d1'), HumanMessage(content='what is the weather in sf currently', id='bc16849a-fa20-4f07-815c-b254c6d77f63')], next=('__start__:edges',), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-03-15T21:24:19.717873+00:00'}})
--
StateSnapshot(values=[HumanMessage(content="hi! I'm bob", id='5e326da4-44ee-4334-b2e6-869dd6d3218d'), AIMessage(content='Hello Bob! How can I assist you today?', response_metadata={'finish_reason': 'stop', 'logprobs': None}, id='9467300a-f8ea-47db-9ade-3d9130c9f6d1')], next=(), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-03-15T21:24:10.780714+00:00'}})
--
StateSnapshot(values=[HumanMessage(content="hi! I'm bob", id='5e326da4-44ee-4334-b2e6-869dd6d3218d'), AIMessage(content='Hello Bob! How can I assist you today?', response_metadata={'finish_reason': 'stop', 'logprobs': None}, id='9467300a-f8ea-47db-9ade-3d9130c9f6d1')], next=('agent:edges',), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-03-15T21:24:10.773938+00:00'}})
--
StateSnapshot(values=[HumanMessage(content="hi! I'm bob", id='5e326da4-44ee-4334-b2e6-869dd6d3218d')], next=('agent',), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-03-15T21:24:10.163843+00:00'}})
--
StateSnapshot(values=[HumanMessage(content="hi! I'm bob", id='5e326da4-44ee-4334-b2e6-869dd6d3218d')], next=('__start__:edges',), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-03-15T21:24:10.162581+00:00'}})
--
In [18]:
to_replayOut [18]:
StateSnapshot(values=[HumanMessage(content="hi! I'm bob", id='5e326da4-44ee-4334-b2e6-869dd6d3218d'), AIMessage(content='Hello Bob! How can I assist you today?', response_metadata={'finish_reason': 'stop', 'logprobs': None}, id='9467300a-f8ea-47db-9ade-3d9130c9f6d1'), HumanMessage(content='what is the weather in sf currently', id='bc16849a-fa20-4f07-815c-b254c6d77f63')], next=('__start__:edges',), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-03-15T21:24:19.717873+00:00'}})In [19]:
for event in app.stream(None, to_replay.config):
for k, v in event.items():
if k != "__end__":
print(v)content='' additional_kwargs={'function_call': {'arguments': '{"query":"current weather in San Francisco"}', 'name': 'tavily_search_results_json'}} response_metadata={'finish_reason': 'function_call', 'logprobs': None} id='3a853de3-bdd9-4186-9f10-56bd151f63da'
In [ ]: