Update How-to Guides (#417)

- reduce the number of API keys needed (Use simple tool)
- make everything "tool use" oriented rather than split across agent executor, function calling, tool use, etc.
- Reorg navbar and index
- Fixup some docstrings
- Add more links to ref docs
- Mix up models used
- Simplify a few examples
This commit is contained in:
William FH
2024-05-07 23:09:17 -07:00
committed by GitHub
parent f49e8dbc98
commit 991d35be08
31 changed files with 6734 additions and 1996 deletions
@@ -8,7 +8,7 @@
"# Chat Agent Executor with Anthropic\n",
"\n",
"\n",
"In this example we will build a chat executor that uses tool calling and the prebuilt ToolNode with Anthropic."
"In this example we will build a ReAct Agent that uses tool calling and the prebuilt ToolNode with Anthropic."
]
},
{
@@ -7,7 +7,7 @@
"source": [
"# Chat Agent Executor\n",
"\n",
"In this example we will build a chat executor that uses function calling from scratch."
"In this example we will build a ReAct Agent that uses function calling from scratch."
]
},
{
@@ -175,7 +175,7 @@
"source": [
"## Define the agent state\n",
"\n",
"The main type of graph in `langgraph` is the `StatefulGraph`.\n",
"The main type of graph in `langgraph` is the [StateGraph](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph).\n",
"This graph is parameterized by a state object that it passes around to each node.\n",
"Each node then returns operations to update that state.\n",
"These operations can either SET specific attributes on the state (e.g. overwrite the existing values) or ADD to the existing attribute.\n",
@@ -204,7 +204,7 @@
"source": [
"## Define the agent state\n",
"\n",
"The main type of graph in `langgraph` is the `StatefulGraph`.\n",
"The main type of graph in `langgraph` is the [StateGraph](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph).\n",
"This graph is parameterized by a state object that it passes around to each node.\n",
"Each node then returns operations to update that state.\n",
"These operations can either SET specific attributes on the state (e.g. overwrite the existing values) or ADD to the existing attribute.\n",
@@ -32,7 +32,7 @@
"outputs": [],
"source": [
"%%capture --no-stderr\n",
"%pip install --quiet -U langchain langchain_openai tavily-python"
"%pip install --quiet -U langgraph langchain_openai tavily-python"
]
},
{
@@ -45,7 +45,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 1,
"id": "c903a1cf-2977-4e2d-ad7d-8b3946821d89",
"metadata": {},
"outputs": [],
@@ -53,8 +53,13 @@
"import os\n",
"import getpass\n",
"\n",
"os.environ[\"OPENAI_API_KEY\"] = getpass.getpass(\"OpenAI API Key:\")\n",
"os.environ[\"TAVILY_API_KEY\"] = getpass.getpass(\"Tavily API Key:\")"
"\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\")"
]
},
{
@@ -67,13 +72,13 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 2,
"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:\")"
"_set_env(\"LANGCHAIN_API_KEY\")"
]
},
{
@@ -90,14 +95,22 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": 5,
"id": "d7ef57dd-5d6e-4ad3-9377-a92201c1310e",
"metadata": {},
"outputs": [],
"source": [
"from langchain_community.tools.tavily_search import TavilySearchResults\n",
"from langchain_core.tools import tool\n",
"\n",
"tools = [TavilySearchResults(max_results=1)]"
"\n",
"@tool\n",
"def search(query: str):\n",
" \"\"\"Call to surf the web.\"\"\"\n",
" # This is a placeholder, but don't tell the LLM that...\n",
" return [\"The answer to your question lies within.\"]\n",
"\n",
"\n",
"tools = [search]"
]
},
{
@@ -112,7 +125,7 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 6,
"id": "5cf3331e-ccb3-41c8-aeb9-a840a94d41e7",
"metadata": {},
"outputs": [],
@@ -133,23 +146,21 @@
"Importantly, this should satisfy two criteria:\n",
"\n",
"1. It should work with messages. We will represent all agent state in the form of messages, so it needs to be able to work well with them.\n",
"2. It should work with OpenAI function calling. This means it should either be an OpenAI model or a model that exposes a similar interface.\n",
"2. The model should support tool calling. Model providers like Anthropic, Google, OpenAI, Cohere, Fireworks, Mistral, and Groq should all work. You can reference [this list](https://python.langchain.com/docs/integrations/chat/) for more up-to-date compatibility.\n",
"\n",
"Note: these model requirements are not requirements for using LangGraph - they are just requirements for this one example.\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 7,
"id": "892b54b9-75f0-4804-9ed0-88b5e5532989",
"metadata": {},
"outputs": [],
"source": [
"from langchain_openai import ChatOpenAI\n",
"\n",
"# We will set streaming=True so that we can stream tokens\n",
"# See the streaming section for more information on this.\n",
"model = ChatOpenAI(temperature=0, streaming=True)"
"model = ChatOpenAI(temperature=0)"
]
},
{
@@ -164,7 +175,7 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 8,
"id": "cd3cbae5-d92c-4559-a4aa-44721b80d107",
"metadata": {},
"outputs": [],
@@ -192,7 +203,7 @@
},
{
"cell_type": "code",
"execution_count": 10,
"execution_count": 9,
"id": "ea793afa-2eab-4901-910d-6eed90cd6564",
"metadata": {},
"outputs": [],
@@ -235,7 +246,7 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 10,
"id": "3b541bb9-900c-40d0-964d-7b5dfee30667",
"metadata": {},
"outputs": [],
@@ -245,7 +256,7 @@
"\n",
"\n",
"# Define the function that determines whether to continue or not\n",
"def should_continue(state):\n",
"def should_continue(state: AgentState):\n",
" messages = state[\"messages\"]\n",
" last_message = messages[-1]\n",
" # If there is no function call, then we finish\n",
@@ -257,7 +268,7 @@
"\n",
"\n",
"# Define the function that calls the model\n",
"def call_model(state):\n",
"def call_model(state: AgentState):\n",
" messages = state[\"messages\"]\n",
" response = model.invoke(messages)\n",
" # We return a list, because this will get added to the existing list\n",
@@ -265,7 +276,10 @@
"\n",
"\n",
"# Define the function to execute tools\n",
"def call_tool(state):\n",
"# We recommend you use ToolNode\n",
"# for this, but we are showing the\n",
"# manual way here for clarity\n",
"def call_tool(state: AgentState):\n",
" messages = state[\"messages\"]\n",
" # Based on the continue condition\n",
" # we know the last message involves a function call\n",
@@ -311,7 +325,7 @@
},
{
"cell_type": "code",
"execution_count": 16,
"execution_count": 11,
"id": "1bfd2b22-292a-4f4d-91a0-46bb704f5e38",
"metadata": {},
"outputs": [],
@@ -320,7 +334,7 @@
"from langchain_core.messages import AIMessage\n",
"\n",
"\n",
"def first_model(state):\n",
"def first_model(state: AgentState):\n",
" human_input = state[\"messages\"][-1].content\n",
" return {\n",
" \"messages\": [\n",
@@ -356,7 +370,7 @@
},
{
"cell_type": "code",
"execution_count": 17,
"execution_count": 12,
"id": "813ae66c-3b58-4283-a02a-36da72a2ab90",
"metadata": {},
"outputs": [],
@@ -413,7 +427,7 @@
},
{
"cell_type": "code",
"execution_count": 18,
"execution_count": 15,
"id": "a8afd6ef",
"metadata": {},
"outputs": [
@@ -431,11 +445,7 @@
"source": [
"from IPython.display import Image, display\n",
"\n",
"try:\n",
" display(Image(app.get_graph(xray=True).draw_mermaid_png()))\n",
"except:\n",
" # This requires some extra dependencies and is optional\n",
" pass"
"display(Image(app.get_graph(xray=True).draw_mermaid_png()))"
]
},
{
@@ -451,7 +461,7 @@
},
{
"cell_type": "code",
"execution_count": 19,
"execution_count": 17,
"id": "8edb04b9-40b6-46f1-a7a8-4b2d8aba7752",
"metadata": {},
"outputs": [
@@ -459,21 +469,199 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Output from node 'first_agent':\n",
"---\n",
"{'messages': [AIMessage(content='', tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': 'what is the weather in sf'}, 'id': 'tool_abcd123'}])]}\n",
"================================\u001b[1m Human Message \u001b[0m=================================\n",
"\n",
"what is the weather in sf\n",
"\n",
"---\n",
"\n",
"Output from node 'action':\n",
"---\n",
"{'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\\': 1714808650, \\'localtime\\': \\'2024-05-04 0:44\\'}, \\'current\\': {\\'last_updated_epoch\\': 1714807800, \\'last_updated\\': \\'2024-05-04 00:30\\', \\'temp_c\\': 12.8, \\'temp_f\\': 55.0, \\'is_day\\': 0, \\'condition\\': {\\'text\\': \\'Overcast\\', \\'icon\\': \\'//cdn.weatherapi.com/weather/64x64/night/122.png\\', \\'code\\': 1009}, \\'wind_mph\\': 11.9, \\'wind_kph\\': 19.1, \\'wind_degree\\': 240, \\'wind_dir\\': \\'WSW\\', \\'pressure_mb\\': 1013.0, \\'pressure_in\\': 29.9, \\'precip_mm\\': 0.0, \\'precip_in\\': 0.0, \\'humidity\\': 96, \\'cloud\\': 100, \\'feelslike_c\\': 11.4, \\'feelslike_f\\': 52.4, \\'vis_km\\': 16.0, \\'vis_miles\\': 9.0, \\'uv\\': 1.0, \\'gust_mph\\': 14.9, \\'gust_kph\\': 23.9}}\"}]', name='tavily_search_results_json', tool_call_id='tool_abcd123')]}\n",
"================================\u001b[1m Human Message \u001b[0m=================================\n",
"\n",
"what is the weather in sf\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"Tool Calls:\n",
" tavily_search_results_json (tool_abcd123)\n",
" Call ID: tool_abcd123\n",
" Args:\n",
" query: what is the weather in sf\n",
"\n",
"---\n",
"\n",
"Output from node 'agent':\n",
"================================\u001b[1m Human Message \u001b[0m=================================\n",
"\n",
"what is the weather in sf\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"Tool Calls:\n",
" tavily_search_results_json (tool_abcd123)\n",
" Call ID: tool_abcd123\n",
" Args:\n",
" query: what is the weather in sf\n",
"=================================\u001b[1m Tool Message \u001b[0m=================================\n",
"Name: tavily_search_results_json\n",
"\n",
"tavily_search_results_json is not a valid tool, try one of [search].\n",
"\n",
"---\n",
"{'messages': [AIMessage(content='The current weather in San Francisco is as follows:\\n- Temperature: 12.8°C (55.0°F)\\n- Condition: Overcast\\n- Wind: 11.9 mph from WSW\\n- Humidity: 96%\\n- Cloud Cover: 100%\\n- Visibility: 16.0 km (9.0 miles)\\n- UV Index: 1.0\\n\\nFor more details, you can visit [Weather API](https://www.weatherapi.com/).', response_metadata={'finish_reason': 'stop'}, id='run-57b5d14c-08c3-481d-9875-fc3a9472475c-0')]}\n",
"\n",
"================================\u001b[1m Human Message \u001b[0m=================================\n",
"\n",
"what is the weather in sf\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"Tool Calls:\n",
" tavily_search_results_json (tool_abcd123)\n",
" Call ID: tool_abcd123\n",
" Args:\n",
" query: what is the weather in sf\n",
"=================================\u001b[1m Tool Message \u001b[0m=================================\n",
"Name: tavily_search_results_json\n",
"\n",
"tavily_search_results_json is not a valid tool, try one of [search].\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"Tool Calls:\n",
" search (call_P0Ce1Jg9jUF1hcQpkAfHZo0P)\n",
" Call ID: call_P0Ce1Jg9jUF1hcQpkAfHZo0P\n",
" Args:\n",
" query: weather in San Francisco\n",
"\n",
"---\n",
"\n",
"================================\u001b[1m Human Message \u001b[0m=================================\n",
"\n",
"what is the weather in sf\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"Tool Calls:\n",
" tavily_search_results_json (tool_abcd123)\n",
" Call ID: tool_abcd123\n",
" Args:\n",
" query: what is the weather in sf\n",
"=================================\u001b[1m Tool Message \u001b[0m=================================\n",
"Name: tavily_search_results_json\n",
"\n",
"tavily_search_results_json is not a valid tool, try one of [search].\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"Tool Calls:\n",
" search (call_P0Ce1Jg9jUF1hcQpkAfHZo0P)\n",
" Call ID: call_P0Ce1Jg9jUF1hcQpkAfHZo0P\n",
" Args:\n",
" query: weather in San Francisco\n",
"=================================\u001b[1m Tool Message \u001b[0m=================================\n",
"Name: search\n",
"\n",
"['The answer to your question lies within.']\n",
"\n",
"---\n",
"\n",
"================================\u001b[1m Human Message \u001b[0m=================================\n",
"\n",
"what is the weather in sf\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"Tool Calls:\n",
" tavily_search_results_json (tool_abcd123)\n",
" Call ID: tool_abcd123\n",
" Args:\n",
" query: what is the weather in sf\n",
"=================================\u001b[1m Tool Message \u001b[0m=================================\n",
"Name: tavily_search_results_json\n",
"\n",
"tavily_search_results_json is not a valid tool, try one of [search].\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"Tool Calls:\n",
" search (call_P0Ce1Jg9jUF1hcQpkAfHZo0P)\n",
" Call ID: call_P0Ce1Jg9jUF1hcQpkAfHZo0P\n",
" Args:\n",
" query: weather in San Francisco\n",
"=================================\u001b[1m Tool Message \u001b[0m=================================\n",
"Name: search\n",
"\n",
"['The answer to your question lies within.']\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"\n",
"I found some information related to the weather in San Francisco. Let me retrieve the details for you.\n",
"Tool Calls:\n",
" search (call_8XR90INYwh5A7eOTAXsaak5Q)\n",
" Call ID: call_8XR90INYwh5A7eOTAXsaak5Q\n",
" Args:\n",
" query: weather in San Francisco\n",
"\n",
"---\n",
"\n",
"================================\u001b[1m Human Message \u001b[0m=================================\n",
"\n",
"what is the weather in sf\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"Tool Calls:\n",
" tavily_search_results_json (tool_abcd123)\n",
" Call ID: tool_abcd123\n",
" Args:\n",
" query: what is the weather in sf\n",
"=================================\u001b[1m Tool Message \u001b[0m=================================\n",
"Name: tavily_search_results_json\n",
"\n",
"tavily_search_results_json is not a valid tool, try one of [search].\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"Tool Calls:\n",
" search (call_P0Ce1Jg9jUF1hcQpkAfHZo0P)\n",
" Call ID: call_P0Ce1Jg9jUF1hcQpkAfHZo0P\n",
" Args:\n",
" query: weather in San Francisco\n",
"=================================\u001b[1m Tool Message \u001b[0m=================================\n",
"Name: search\n",
"\n",
"['The answer to your question lies within.']\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"\n",
"I found some information related to the weather in San Francisco. Let me retrieve the details for you.\n",
"Tool Calls:\n",
" search (call_8XR90INYwh5A7eOTAXsaak5Q)\n",
" Call ID: call_8XR90INYwh5A7eOTAXsaak5Q\n",
" Args:\n",
" query: weather in San Francisco\n",
"=================================\u001b[1m Tool Message \u001b[0m=================================\n",
"Name: search\n",
"\n",
"['The answer to your question lies within.']\n",
"\n",
"---\n",
"\n",
"================================\u001b[1m Human Message \u001b[0m=================================\n",
"\n",
"what is the weather in sf\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"Tool Calls:\n",
" tavily_search_results_json (tool_abcd123)\n",
" Call ID: tool_abcd123\n",
" Args:\n",
" query: what is the weather in sf\n",
"=================================\u001b[1m Tool Message \u001b[0m=================================\n",
"Name: tavily_search_results_json\n",
"\n",
"tavily_search_results_json is not a valid tool, try one of [search].\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"Tool Calls:\n",
" search (call_P0Ce1Jg9jUF1hcQpkAfHZo0P)\n",
" Call ID: call_P0Ce1Jg9jUF1hcQpkAfHZo0P\n",
" Args:\n",
" query: weather in San Francisco\n",
"=================================\u001b[1m Tool Message \u001b[0m=================================\n",
"Name: search\n",
"\n",
"['The answer to your question lies within.']\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"\n",
"I found some information related to the weather in San Francisco. Let me retrieve the details for you.\n",
"Tool Calls:\n",
" search (call_8XR90INYwh5A7eOTAXsaak5Q)\n",
" Call ID: call_8XR90INYwh5A7eOTAXsaak5Q\n",
" Args:\n",
" query: weather in San Francisco\n",
"=================================\u001b[1m Tool Message \u001b[0m=================================\n",
"Name: search\n",
"\n",
"['The answer to your question lies within.']\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"\n",
"I found some information related to the weather in San Francisco. Let me retrieve the details for you.\n",
"I found some information related to the weather in San Francisco. Let me retrieve the details for you.\n",
"\n",
"---\n",
"\n"
@@ -484,12 +672,11 @@
"from langchain_core.messages import HumanMessage\n",
"\n",
"inputs = {\"messages\": [HumanMessage(content=\"what is the weather in sf\")]}\n",
"for output in app.stream(inputs):\n",
"for output in app.stream(inputs, stream_mode=\"values\"):\n",
" # stream() yields dictionaries with output keyed by node name\n",
" for key, value in output.items():\n",
" print(f\"Output from node '{key}':\")\n",
" print(\"---\")\n",
" print(value)\n",
" messages = output[\"messages\"]\n",
" for message in messages:\n",
" message.pretty_print()\n",
" print(\"\\n---\\n\")"
]
},
@@ -7,7 +7,7 @@
"source": [
"# Chat Executor: with tool calling\n",
"\n",
"This notebook walks through an example creating a chat executor that uses tool calling.\n",
"This notebook walks through an example creating a ReAct Agent that uses tool calling.\n",
"This is useful for getting started quickly.\n",
"However, it is highly likely you will want to customize the logic - for information on that, check out the other examples in this folder."
]
@@ -7,7 +7,7 @@
"source": [
"# Human-in-the-loop\n",
"\n",
"In this example we will build a chat executor that has a human in the loop. We will use the human to approve specific actions.\n",
"In this example we will build a ReAct Agent that has a human in the loop. We will use the human to approve specific actions.\n",
"\n",
"This examples builds off the base chat executor. It is highly recommended you learn about that executor before going through this notebook. You can find documentation for that example [here](./base.ipynb).\n",
"\n",
@@ -196,7 +196,7 @@
"source": [
"## Define the agent state\n",
"\n",
"The main type of graph in `langgraph` is the `StatefulGraph`.\n",
"The main type of graph in `langgraph` is the [StateGraph](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph).\n",
"This graph is parameterized by a state object that it passes around to each node.\n",
"Each node then returns operations to update that state.\n",
"These operations can either SET specific attributes on the state (e.g. overwrite the existing values) or ADD to the existing attribute.\n",
@@ -179,7 +179,7 @@
"source": [
"## Define the agent state\n",
"\n",
"The main type of graph in `langgraph` is the `StatefulGraph`.\n",
"The main type of graph in `langgraph` is the [StateGraph](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph).\n",
"This graph is parameterized by a state object that it passes around to each node.\n",
"Each node then returns operations to update that state.\n",
"These operations can either SET specific attributes on the state (e.g. overwrite the existing values) or ADD to the existing attribute.\n",
@@ -8,7 +8,7 @@
"# Chat Agent Executor using prebuilt Tool Node\n",
"\n",
"\n",
"In this example we will build a chat executor that uses tool calling and the prebuilt ToolNode."
"In this example we will build a ReAct Agent that uses tool calling and the prebuilt ToolNode."
]
},
{
@@ -156,7 +156,7 @@
"source": [
"## Define the agent state\n",
"\n",
"The main type of graph in `langgraph` is the `StatefulGraph`.\n",
"The main type of graph in `langgraph` is the [StateGraph](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph).\n",
"This graph is parameterized by a state object that it passes around to each node.\n",
"Each node then returns operations to update that state.\n",
"These operations can either SET specific attributes on the state (e.g. overwrite the existing values) or ADD to the existing attribute.\n",
@@ -194,7 +194,7 @@
"source": [
"## Define the agent state\n",
"\n",
"The main type of graph in `langgraph` is the `StatefulGraph`.\n",
"The main type of graph in `langgraph` is the [StateGraph](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph).\n",
"This graph is parameterized by a state object that it passes around to each node.\n",
"Each node then returns operations to update that state.\n",
"These operations can either SET specific attributes on the state (e.g. overwrite the existing values) or ADD to the existing attribute.\n",