mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-08-17 21:25:46 +02:00
32 KiB
32 KiB
In [1]:
!pip install --quiet -U langchain langchain_openai tavily-pythonIn [ ]:
import os
import getpass
os.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API Key:")
os.environ["TAVILY_API_KEY"] = getpass.getpass("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 langchain_openai import ChatOpenAI
model = ChatOpenAI(temperature=0)In [3]:
model = model.bind_tools(tools)In [4]:
from typing import TypedDict, Annotated, Sequence
import operator
from langchain_core.messages import BaseMessage
class AgentState(TypedDict):
messages: Annotated[Sequence[BaseMessage], operator.add]In [11]:
from langgraph.prebuilt import ToolNode
import json
from langchain_core.messages import FunctionMessage
# Define the function that determines whether to continue or not
def should_continue(state):
messages = state["messages"]
last_message = messages[-1]
# If there are no tool calls, then we finish
if not last_message.tool_calls:
return "end"
# Otherwise if there is, we continue
else:
return "continue"
# Define the function that calls the model
def call_model(state):
messages = state["messages"]
response = model.invoke(messages)
# We return a list, because this will get added to the existing list
return {"messages": [response]}
# Define the function to execute tools
tool_node = ToolNode(tools)In [12]:
from langgraph.graph import StateGraph, END
# Define a new graph
workflow = StateGraph(AgentState)
# Define the two nodes we will cycle between
workflow.add_node("agent", call_model)
workflow.add_node("action", tool_node)
# 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")
# 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()In [14]:
from langchain_core.messages import HumanMessage
inputs = {"messages": [HumanMessage(content="what is the weather in sf")]}
app.invoke(inputs)Out [14]:
/Users/nuno/dev/langgraph/.venv/lib/python3.11/site-packages/langchain_core/messages/ai.py:52: UserWarning: New langchain packages are available that more efficiently handle tool calling. Please upgrade your packages to versions that set message tool calls. e.g., `pip install --upgrade langchain-anthropic`, pip install--upgrade langchain-openai`, etc. warnings.warn(
{'messages': [HumanMessage(content='what is the weather in sf'),
AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_Q7l0TopyJxaly7xM9Vq2aGxO', 'function': {'arguments': '{"query":"weather in San Francisco"}', 'name': 'tavily_search_results_json'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 21, 'prompt_tokens': 87, 'total_tokens': 108}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-d39a73db-e37a-46ce-9476-73fe9eb84b2e-0', tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': 'weather in San Francisco'}, 'id': 'call_Q7l0TopyJxaly7xM9Vq2aGxO'}]),
ToolMessage(content='[{"url": "https://www.weatherapi.com/", "content": "{\'location\': {\'name\': \'San Francisco\', \'region\': \'California\', \'country\': \'United States of America\', \'lat\': 37.78, \'lon\': -122.42, \'tz_id\': \'America/Los_Angeles\', \'localtime_epoch\': 1712797953, \'localtime\': \'2024-04-10 18:12\'}, \'current\': {\'last_updated_epoch\': 1712797200, \'last_updated\': \'2024-04-10 18:00\', \'temp_c\': 21.1, \'temp_f\': 70.0, \'is_day\': 1, \'condition\': {\'text\': \'Partly cloudy\', \'icon\': \'//cdn.weatherapi.com/weather/64x64/day/116.png\', \'code\': 1003}, \'wind_mph\': 10.5, \'wind_kph\': 16.9, \'wind_degree\': 300, \'wind_dir\': \'WNW\', \'pressure_mb\': 1017.0, \'pressure_in\': 30.04, \'precip_mm\': 0.0, \'precip_in\': 0.0, \'humidity\': 59, \'cloud\': 75, \'feelslike_c\': 21.1, \'feelslike_f\': 70.0, \'vis_km\': 16.0, \'vis_miles\': 9.0, \'uv\': 5.0, \'gust_mph\': 16.0, \'gust_kph\': 25.8}}"}]', name='tavily_search_results_json', tool_call_id='call_Q7l0TopyJxaly7xM9Vq2aGxO'),
AIMessage(content='The current weather in San Francisco is partly cloudy with a temperature of 21.1°C (70.0°F). The wind speed is 10.5 mph (16.9 kph) coming from the west-northwest direction. The humidity is at 59% with a visibility of 16.0 km (9.0 miles).', response_metadata={'token_usage': {'completion_tokens': 72, 'prompt_tokens': 466, 'total_tokens': 538}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None}, id='run-091dcb4c-9424-40fc-aab6-58968d9929a2-0')]}In [15]:
inputs = {"messages": [HumanMessage(content="what is the weather in sf")]}
for output in app.stream(inputs):
# stream() yields dictionaries with output keyed by node name
for key, value in output.items():
print(f"Output from node '{key}':")
print("---")
print(value)
print("\n---\n")/Users/nuno/dev/langgraph/.venv/lib/python3.11/site-packages/langchain_core/messages/ai.py:52: UserWarning: New langchain packages are available that more efficiently handle tool calling. Please upgrade your packages to versions that set message tool calls. e.g., `pip install --upgrade langchain-anthropic`, pip install--upgrade langchain-openai`, etc. warnings.warn(
Output from node 'agent':
---
{'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_VgzsFE5Cf3sdlrIudeijqVsp', 'function': {'arguments': '{"query":"weather in San Francisco"}', 'name': 'tavily_search_results_json'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 21, 'prompt_tokens': 87, 'total_tokens': 108}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-b3acca13-ccbf-4761-9d0c-1410d5f4f0a9-0', tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': 'weather in San Francisco'}, 'id': 'call_VgzsFE5Cf3sdlrIudeijqVsp'}])]}
---
Output from node 'action':
---
{'messages': [ToolMessage(content='[{"url": "https://www.weatherapi.com/", "content": "{\'location\': {\'name\': \'San Francisco\', \'region\': \'California\', \'country\': \'United States of America\', \'lat\': 37.78, \'lon\': -122.42, \'tz_id\': \'America/Los_Angeles\', \'localtime_epoch\': 1712797953, \'localtime\': \'2024-04-10 18:12\'}, \'current\': {\'last_updated_epoch\': 1712797200, \'last_updated\': \'2024-04-10 18:00\', \'temp_c\': 21.1, \'temp_f\': 70.0, \'is_day\': 1, \'condition\': {\'text\': \'Partly cloudy\', \'icon\': \'//cdn.weatherapi.com/weather/64x64/day/116.png\', \'code\': 1003}, \'wind_mph\': 10.5, \'wind_kph\': 16.9, \'wind_degree\': 300, \'wind_dir\': \'WNW\', \'pressure_mb\': 1017.0, \'pressure_in\': 30.04, \'precip_mm\': 0.0, \'precip_in\': 0.0, \'humidity\': 59, \'cloud\': 75, \'feelslike_c\': 21.1, \'feelslike_f\': 70.0, \'vis_km\': 16.0, \'vis_miles\': 9.0, \'uv\': 5.0, \'gust_mph\': 16.0, \'gust_kph\': 25.8}}"}]', name='tavily_search_results_json', tool_call_id='call_VgzsFE5Cf3sdlrIudeijqVsp')]}
---
Output from node 'agent':
---
{'messages': [AIMessage(content='The current weather in San Francisco is partly cloudy with a temperature of 70°F (21.1°C). The wind speed is 10.5 mph (16.9 kph) coming from the west-northwest direction. The humidity is at 59%, and the visibility is 9.0 miles.', response_metadata={'token_usage': {'completion_tokens': 65, 'prompt_tokens': 466, 'total_tokens': 531}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None}, id='run-fa95b6d0-34bb-41e7-8cfd-87b6af69064f-0')]}
---
In [16]:
inputs = {"messages": [HumanMessage(content="what is the weather in sf?")]}
async for output in app.astream_log(inputs, include_types=["llm"]):
# astream_log() yields the requested logs (here LLMs) in JSONPatch format
for op in output.ops:
if op["path"] == "/streamed_output/-":
# this is the output from .stream()
...
elif op["path"].startswith("/logs/") and op["path"].endswith(
"/streamed_output/-"
):
# because we chose to only include LLMs, these are LLM tokens
print(op["value"])/Users/nuno/dev/langgraph/.venv/lib/python3.11/site-packages/langchain_core/messages/ai.py:52: UserWarning: New langchain packages are available that more efficiently handle tool calling. Please upgrade your packages to versions that set message tool calls. e.g., `pip install --upgrade langchain-anthropic`, pip install--upgrade langchain-openai`, etc. warnings.warn(
content='' additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_TyyKAi2L0Uymjr3YW2d3ZnIm', 'function': {'arguments': '', 'name': 'tavily_search_results_json'}, 'type': 'function'}]} id='run-7106791e-464e-4aa1-aaee-5d4674fe49e1' invalid_tool_calls=[{'name': 'tavily_search_results_json', 'args': '', 'id': 'call_TyyKAi2L0Uymjr3YW2d3ZnIm', 'error': 'Malformed args.'}] tool_call_chunks=[{'name': 'tavily_search_results_json', 'args': '', 'id': 'call_TyyKAi2L0Uymjr3YW2d3ZnIm', 'index': 0}]
content='' additional_kwargs={'tool_calls': [{'index': 0, 'id': None, 'function': {'arguments': '{"', 'name': None}, 'type': None}]} id='run-7106791e-464e-4aa1-aaee-5d4674fe49e1' tool_calls=[{'name': '', 'args': {}, 'id': None}] tool_call_chunks=[{'name': None, 'args': '{"', 'id': None, 'index': 0}]
content='' additional_kwargs={'tool_calls': [{'index': 0, 'id': None, 'function': {'arguments': 'query', 'name': None}, 'type': None}]} id='run-7106791e-464e-4aa1-aaee-5d4674fe49e1' invalid_tool_calls=[{'name': None, 'args': 'query', 'id': None, 'error': 'Malformed args.'}] tool_call_chunks=[{'name': None, 'args': 'query', 'id': None, 'index': 0}]
content='' additional_kwargs={'tool_calls': [{'index': 0, 'id': None, 'function': {'arguments': '":"', 'name': None}, 'type': None}]} id='run-7106791e-464e-4aa1-aaee-5d4674fe49e1' invalid_tool_calls=[{'name': None, 'args': '":"', 'id': None, 'error': 'Malformed args.'}] tool_call_chunks=[{'name': None, 'args': '":"', 'id': None, 'index': 0}]
content='' additional_kwargs={'tool_calls': [{'index': 0, 'id': None, 'function': {'arguments': 'weather', 'name': None}, 'type': None}]} id='run-7106791e-464e-4aa1-aaee-5d4674fe49e1' invalid_tool_calls=[{'name': None, 'args': 'weather', 'id': None, 'error': 'Malformed args.'}] tool_call_chunks=[{'name': None, 'args': 'weather', 'id': None, 'index': 0}]
content='' additional_kwargs={'tool_calls': [{'index': 0, 'id': None, 'function': {'arguments': ' in', 'name': None}, 'type': None}]} id='run-7106791e-464e-4aa1-aaee-5d4674fe49e1' invalid_tool_calls=[{'name': None, 'args': ' in', 'id': None, 'error': 'Malformed args.'}] tool_call_chunks=[{'name': None, 'args': ' in', 'id': None, 'index': 0}]
content='' additional_kwargs={'tool_calls': [{'index': 0, 'id': None, 'function': {'arguments': ' San', 'name': None}, 'type': None}]} id='run-7106791e-464e-4aa1-aaee-5d4674fe49e1' invalid_tool_calls=[{'name': None, 'args': ' San', 'id': None, 'error': 'Malformed args.'}] tool_call_chunks=[{'name': None, 'args': ' San', 'id': None, 'index': 0}]
content='' additional_kwargs={'tool_calls': [{'index': 0, 'id': None, 'function': {'arguments': ' Francisco', 'name': None}, 'type': None}]} id='run-7106791e-464e-4aa1-aaee-5d4674fe49e1' invalid_tool_calls=[{'name': None, 'args': ' Francisco', 'id': None, 'error': 'Malformed args.'}] tool_call_chunks=[{'name': None, 'args': ' Francisco', 'id': None, 'index': 0}]
content='' additional_kwargs={'tool_calls': [{'index': 0, 'id': None, 'function': {'arguments': '"}', 'name': None}, 'type': None}]} id='run-7106791e-464e-4aa1-aaee-5d4674fe49e1' invalid_tool_calls=[{'name': None, 'args': '"}', 'id': None, 'error': 'Malformed args.'}] tool_call_chunks=[{'name': None, 'args': '"}', 'id': None, 'index': 0}]
content='' response_metadata={'finish_reason': 'tool_calls'} id='run-7106791e-464e-4aa1-aaee-5d4674fe49e1'
content='' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='The' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' current' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' weather' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' in' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' San' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' Francisco' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' is' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' as' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' follows' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=':\n' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='-' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' Temperature' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=':' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' ' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='21' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='.' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='1' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='°C' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' (' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='70' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='.' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='0' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='°F' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=')\n' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='-' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' Condition' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=':' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' Part' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='ly' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' cloudy' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='\n' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='-' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' Wind' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=':' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' ' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='10' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='.' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='5' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' mph' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' from' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' W' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='NW' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='\n' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='-' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' Pressure' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=':' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' ' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='101' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='7' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='.' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='0' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' mb' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='\n' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='-' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' Hum' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='idity' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=':' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' ' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='59' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='%\n' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='-' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' Cloud' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' Cover' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=':' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' ' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='75' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='%\n' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='-' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' Visibility' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=':' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' ' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='16' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='.' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='0' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' km' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' (' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='9' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='.' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='0' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' miles' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=')\n' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='-' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' UV' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' Index' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=':' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' ' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='5' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='.' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='0' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='\n\n' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='For' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' more' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' details' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=',' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' you' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' can' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' visit' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' [' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='Weather' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=' API' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='](' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='https' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='://' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='www' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='.weather' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='api' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='.com' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='/' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content=').' id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
content='' response_metadata={'finish_reason': 'stop'} id='run-9000bee8-10fe-4712-852b-e043aecb42ec'
In [ ]: