mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-09-30 05:25:05 +02:00
88 KiB
88 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, AIMessage
# 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 to execute tools
def call_tool(messages, config):
# 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, config)
# 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", 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)In [9]:
from IPython.display import Image
Image(app.get_graph().draw_png())Out [9]:
In [10]:
from langchain_core.messages import HumanMessage
thread = {"configurable": {"thread_id": '3'}}
for event in app.stream("hi! I'm bob", thread):
for v in event.values():
print(v)content='Hello Bob! How can I assist you today?' response_metadata={'token_usage': {'completion_tokens': 11, 'prompt_tokens': 86, 'total_tokens': 97}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None} id='run-b5f3758d-1e41-4c18-9ea4-628a5dc9304a-0'
In [11]:
app.get_state(thread).valuesOut [11]:
[HumanMessage(content="hi! I'm bob", id='9d441d6c-8e75-4fb1-b8d7-142d97f445f7'),
AIMessage(content='Hello Bob! How can I assist you today?', response_metadata={'token_usage': {'completion_tokens': 11, 'prompt_tokens': 86, 'total_tokens': 97}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None}, id='run-b5f3758d-1e41-4c18-9ea4-628a5dc9304a-0')]In [12]:
for event in app.stream("what is the weather in sf currently", thread):
for v in event.values():
print(v)content='' additional_kwargs={'function_call': {'arguments': '{"query":"current weather in San Francisco"}', 'name': 'tavily_search_results_json'}} response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 111, 'total_tokens': 133}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None} id='run-86030ee6-69eb-4399-9ffb-cf31103ed095-0'
content='[{\'url\': \'https://weather.com/weather/hourbyhour/l/USCA0987:1:US\', \'content\': "recents\\nSpecialty Forecasts\\nHourly Weather-San Francisco, CA\\nBeach Hazard Statement\\nSaturday, November 25\\n5 pm\\nClear\\n6 pm\\nClear\\n7 pm\\nClear\\n8 pm\\nMostly Clear\\n9 pm\\nPartly Cloudy\\n10 pm\\nPartly Cloudy\\n11 pm\\nPartly Cloudy\\nSunday, November 26\\n12 am\\nPartly Cloudy\\n1 am\\nMostly Cloudy\\n2 am\\nMostly Cloudy\\n3 am\\nMostly Cloudy\\n4 am\\nCloudy\\n5 am\\nCloudy\\n6 am\\nMostly Cloudy\\n7 am\\nMostly Cloudy\\n8 am\\nMostly Cloudy\\n9 am\\nMostly Cloudy\\n10 am\\nPartly Cloudy\\n11 am\\nPartly Cloudy\\n12 pm\\nPartly Cloudy\\n1 pm\\nPartly Cloudy\\n2 pm\\nPartly Cloudy\\n3 pm\\nPartly Cloudy\\n4 pm\\nPartly Cloudy\\n5 pm\\nPartly Cloudy\\n6 pm\\nPartly Cloudy\\n7 pm\\nPartly Cloudy\\n8 pm\\nPartly Cloudy\\n9 pm\\nMostly Clear\\n10 pm\\nMostly Clear\\n11 pm\\nMostly Clear\\nMonday, November 27\\n12 am\\nClear\\n1 am\\nMostly Clear\\n2 am\\nMostly Clear\\n3 am\\nPartly Cloudy\\n4 am\\nMostly Clear\\n5 am\\nMostly Clear\\n6 am\\nClear\\n7 am\\nClear\\n8 am\\nSunny\\n9 am\\nSunny\\n10 am\\nSunny\\n11 am\\nSunny\\n12 pm\\nMostly Sunny\\n1 pm\\nPartly Cloudy\\n2 pm\\nMostly Sunny\\n3 pm\\nMostly Sunny\\n4 pm\\nPartly Cloudy\\nRadar\\nSafety First!\\n Don\'t Miss\\nIrresistible\\nWeather Wonders\\nOur Amazing World\\nCelestial Symphony\\nFried Turkey Fail\\nLook At That!\\n Health & Activities\\nSeasonal Allergies and Pollen Count Forecast\\nNo pollen detected in your area\\nCold & Flu Forecast\\nFlu risk is low in your area\\nWe recognize our responsibility to use data and technology for good. Changes For Critters\\nHurricane Tracker\\nStay Safe\\nAir Quality Index\\nAir quality is considered satisfactory, and air pollution poses little or no risk.\\n Take control of your data.\\n"}]' name='tavily_search_results_json' id='89c58552-0092-4169-bff6-e1cb6c8fe321'
content='The current weather in San Francisco is as follows:\n- 5 pm: Clear\n- 6 pm: Clear\n- 7 pm: Clear\n- 8 pm: Mostly Clear\n- 9 pm: Partly Cloudy\n- 10 pm: Partly Cloudy\n\nFor more detailed weather information, you can visit [this link](https://weather.com/weather/hourbyhour/l/USCA0987:1:US).' response_metadata={'token_usage': {'completion_tokens': 93, 'prompt_tokens': 684, 'total_tokens': 777}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None} id='run-11318f28-a516-4b5c-85f6-8d9775205db9-0'
In [16]:
app_w_interrupt = workflow.compile(checkpointer=memory, interrupt_before=["action"])In [14]:
thread = {"configurable": {"thread_id": '4'}}
for event in app_w_interrupt.stream("what is the weather in sf currently", thread):
for v in event.values():
print(v)content='' additional_kwargs={'function_call': {'arguments': '{"query":"current weather in San Francisco"}', 'name': 'tavily_search_results_json'}} response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 88, 'total_tokens': 110}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None} id='run-966f6180-3c8f-42d5-af89-906650c46ab5-0'
In [17]:
current_values = app_w_interrupt.get_state(thread)
current_values.values[-1].additional_kwargsOut [17]:
{'function_call': {'arguments': '{"query":"current weather in San Francisco"}',
'name': 'tavily_search_results_json'}}In [18]:
current_values.values[-1].additional_kwargs = {'function_call': {'arguments': '{"query":"weather in San Francisco today"}',
'name': 'tavily_search_results_json'}}In [19]:
app_w_interrupt.update_state(thread, current_values.values)Out [19]:
{'configurable': {'thread_id': '4',
'thread_ts': '2024-04-02T23:05:41.595778+00:00'}}In [22]:
app_w_interrupt.get_state(thread).valuesOut [22]:
[HumanMessage(content='what is the weather in sf currently', id='06076c4e-40fe-4f44-978a-612fed60849c'),
AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{"query":"weather in San Francisco today"}', 'name': 'tavily_search_results_json'}}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 88, 'total_tokens': 110}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None}, id='run-966f6180-3c8f-42d5-af89-906650c46ab5-0')]In [23]:
app_w_interrupt.get_state(thread).nextOut [23]:
('action',)In [24]:
for event in app_w_interrupt.stream(None, thread):
for v in event.values():
print(v)content='[{\'url\': \'https://weather.com/weather/hourbyhour/l/USCA0987:1:US\', \'content\': "recents\\nSpecialty Forecasts\\nHourly Weather-San Francisco, CA\\nBeach Hazard Statement\\nSaturday, November 25\\n5 pm\\nClear\\n6 pm\\nClear\\n7 pm\\nClear\\n8 pm\\nMostly Clear\\n9 pm\\nPartly Cloudy\\n10 pm\\nPartly Cloudy\\n11 pm\\nPartly Cloudy\\nSunday, November 26\\n12 am\\nPartly Cloudy\\n1 am\\nMostly Cloudy\\n2 am\\nMostly Cloudy\\n3 am\\nMostly Cloudy\\n4 am\\nCloudy\\n5 am\\nCloudy\\n6 am\\nMostly Cloudy\\n7 am\\nMostly Cloudy\\n8 am\\nMostly Cloudy\\n9 am\\nMostly Cloudy\\n10 am\\nPartly Cloudy\\n11 am\\nPartly Cloudy\\n12 pm\\nPartly Cloudy\\n1 pm\\nPartly Cloudy\\n2 pm\\nPartly Cloudy\\n3 pm\\nPartly Cloudy\\n4 pm\\nPartly Cloudy\\n5 pm\\nPartly Cloudy\\n6 pm\\nPartly Cloudy\\n7 pm\\nPartly Cloudy\\n8 pm\\nPartly Cloudy\\n9 pm\\nMostly Clear\\n10 pm\\nMostly Clear\\n11 pm\\nMostly Clear\\nMonday, November 27\\n12 am\\nClear\\n1 am\\nMostly Clear\\n2 am\\nMostly Clear\\n3 am\\nPartly Cloudy\\n4 am\\nMostly Clear\\n5 am\\nMostly Clear\\n6 am\\nClear\\n7 am\\nClear\\n8 am\\nSunny\\n9 am\\nSunny\\n10 am\\nSunny\\n11 am\\nSunny\\n12 pm\\nMostly Sunny\\n1 pm\\nPartly Cloudy\\n2 pm\\nMostly Sunny\\n3 pm\\nMostly Sunny\\n4 pm\\nPartly Cloudy\\nRadar\\nSafety First!\\n Don\'t Miss\\nIrresistible\\nWeather Wonders\\nOur Amazing World\\nCelestial Symphony\\nFried Turkey Fail\\nLook At That!\\n Health & Activities\\nSeasonal Allergies and Pollen Count Forecast\\nNo pollen detected in your area\\nCold & Flu Forecast\\nFlu risk is low in your area\\nWe recognize our responsibility to use data and technology for good. Changes For Critters\\nHurricane Tracker\\nStay Safe\\nAir Quality Index\\nAir quality is considered satisfactory, and air pollution poses little or no risk.\\n Take control of your data.\\n"}]' name='tavily_search_results_json' id='97fa7a07-399e-4c5d-8175-624be906c574'
content='The current weather in San Francisco is partly cloudy. The temperature is expected to remain consistent with partly cloudy conditions throughout the day.' response_metadata={'token_usage': {'completion_tokens': 26, 'prompt_tokens': 661, 'total_tokens': 687}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None} id='run-b99e4fd0-7688-4db7-a677-bf8ba9b8698e-0'
In [25]:
for state in app_w_interrupt.get_state_history(thread):
print(state)
print('--')
if len(state.values) == 2:
to_replay = stateStateSnapshot(values=[HumanMessage(content='what is the weather in sf currently', id='06076c4e-40fe-4f44-978a-612fed60849c'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{"query":"weather in San Francisco today"}', 'name': 'tavily_search_results_json'}}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 88, 'total_tokens': 110}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None}, id='run-966f6180-3c8f-42d5-af89-906650c46ab5-0'), FunctionMessage(content='[{\'url\': \'https://weather.com/weather/hourbyhour/l/USCA0987:1:US\', \'content\': "recents\\nSpecialty Forecasts\\nHourly Weather-San Francisco, CA\\nBeach Hazard Statement\\nSaturday, November 25\\n5 pm\\nClear\\n6 pm\\nClear\\n7 pm\\nClear\\n8 pm\\nMostly Clear\\n9 pm\\nPartly Cloudy\\n10 pm\\nPartly Cloudy\\n11 pm\\nPartly Cloudy\\nSunday, November 26\\n12 am\\nPartly Cloudy\\n1 am\\nMostly Cloudy\\n2 am\\nMostly Cloudy\\n3 am\\nMostly Cloudy\\n4 am\\nCloudy\\n5 am\\nCloudy\\n6 am\\nMostly Cloudy\\n7 am\\nMostly Cloudy\\n8 am\\nMostly Cloudy\\n9 am\\nMostly Cloudy\\n10 am\\nPartly Cloudy\\n11 am\\nPartly Cloudy\\n12 pm\\nPartly Cloudy\\n1 pm\\nPartly Cloudy\\n2 pm\\nPartly Cloudy\\n3 pm\\nPartly Cloudy\\n4 pm\\nPartly Cloudy\\n5 pm\\nPartly Cloudy\\n6 pm\\nPartly Cloudy\\n7 pm\\nPartly Cloudy\\n8 pm\\nPartly Cloudy\\n9 pm\\nMostly Clear\\n10 pm\\nMostly Clear\\n11 pm\\nMostly Clear\\nMonday, November 27\\n12 am\\nClear\\n1 am\\nMostly Clear\\n2 am\\nMostly Clear\\n3 am\\nPartly Cloudy\\n4 am\\nMostly Clear\\n5 am\\nMostly Clear\\n6 am\\nClear\\n7 am\\nClear\\n8 am\\nSunny\\n9 am\\nSunny\\n10 am\\nSunny\\n11 am\\nSunny\\n12 pm\\nMostly Sunny\\n1 pm\\nPartly Cloudy\\n2 pm\\nMostly Sunny\\n3 pm\\nMostly Sunny\\n4 pm\\nPartly Cloudy\\nRadar\\nSafety First!\\n Don\'t Miss\\nIrresistible\\nWeather Wonders\\nOur Amazing World\\nCelestial Symphony\\nFried Turkey Fail\\nLook At That!\\n Health & Activities\\nSeasonal Allergies and Pollen Count Forecast\\nNo pollen detected in your area\\nCold & Flu Forecast\\nFlu risk is low in your area\\nWe recognize our responsibility to use data and technology for good. Changes For Critters\\nHurricane Tracker\\nStay Safe\\nAir Quality Index\\nAir quality is considered satisfactory, and air pollution poses little or no risk.\\n Take control of your data.\\n"}]', name='tavily_search_results_json', id='97fa7a07-399e-4c5d-8175-624be906c574'), AIMessage(content='The current weather in San Francisco is partly cloudy. The temperature is expected to remain consistent with partly cloudy conditions throughout the day.', response_metadata={'token_usage': {'completion_tokens': 26, 'prompt_tokens': 661, 'total_tokens': 687}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None}, id='run-b99e4fd0-7688-4db7-a677-bf8ba9b8698e-0')], next=(), config={'configurable': {'thread_id': '4', 'thread_ts': '2024-04-02T23:07:42.012426+00:00'}}, parent_config=None)
--
StateSnapshot(values=[HumanMessage(content='what is the weather in sf currently', id='06076c4e-40fe-4f44-978a-612fed60849c'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{"query":"weather in San Francisco today"}', 'name': 'tavily_search_results_json'}}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 88, 'total_tokens': 110}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None}, id='run-966f6180-3c8f-42d5-af89-906650c46ab5-0')], next=('action',), config={'configurable': {'thread_id': '4', 'thread_ts': '2024-04-02T23:05:41.595778+00:00'}}, parent_config=None)
--
StateSnapshot(values=[HumanMessage(content='what is the weather in sf currently', id='06076c4e-40fe-4f44-978a-612fed60849c'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{"query":"current weather in San Francisco"}', 'name': 'tavily_search_results_json'}}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 88, 'total_tokens': 110}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None}, id='run-966f6180-3c8f-42d5-af89-906650c46ab5-0')], next=('action',), config={'configurable': {'thread_id': '4', 'thread_ts': '2024-04-02T23:01:11.296458+00:00'}}, parent_config=None)
--
In [26]:
to_replay.valuesOut [26]:
[HumanMessage(content='what is the weather in sf currently', id='06076c4e-40fe-4f44-978a-612fed60849c'),
AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{"query":"current weather in San Francisco"}', 'name': 'tavily_search_results_json'}}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 88, 'total_tokens': 110}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None}, id='run-966f6180-3c8f-42d5-af89-906650c46ab5-0')]In [27]:
to_replay.nextOut [27]:
('action',)In [28]:
for event in app_w_interrupt.stream(None, to_replay.config):
for v in event.values():
print(v)content="[{'url': 'https://www.accuweather.com/en/us/san-francisco/94103/current-weather/347629', 'content': 'Get the latest weather conditions and forecast for San Francisco, CA. See the temperature, humidity, wind, pressure, cloud cover, and alerts for the current hour and the next few days.'}]" name='tavily_search_results_json' id='82d6c2ac-260c-4d5d-9541-21ac4fab8916'
content='You can check the current weather conditions and forecast for San Francisco, CA on [AccuWeather](https://www.accuweather.com/en/us/san-francisco/94103/current-weather/347629). It will provide you with information on temperature, humidity, wind, pressure, cloud cover, and alerts for the current hour and the next few days.' response_metadata={'token_usage': {'completion_tokens': 75, 'prompt_tokens': 194, 'total_tokens': 269}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None} id='run-b4ab153a-266f-44c2-ad37-5fd2a869003a-0'
In [29]:
branch_config = app_w_interrupt.update_state(to_replay.config, AIMessage(content='All done here!', id=to_replay.values[-1].id))In [30]:
branch_state = app_w_interrupt.get_state(branch_config)In [31]:
branch_state.valuesOut [31]:
[HumanMessage(content='what is the weather in sf currently', id='06076c4e-40fe-4f44-978a-612fed60849c'), AIMessage(content='All done here!', id='run-966f6180-3c8f-42d5-af89-906650c46ab5-0')]
In [32]:
branch_state.nextOut [32]:
()
In [ ]: