Multi-Tool Agent Systems with ToolNode
Binding more than one tool costs you nothing extra
Give an agent two tools instead of one, and here's what actually changes in the code:
from langchain_core.tools import tool
from langchain.agents import create_agent
@tool
def search_capital(query: str) -> str:
"""Look up factual information like a country's capital city.
Use this when the user asks a factual fact-lookup question.
Do NOT use this for weather or current conditions."""
return f"Result for: {query}"
@tool
def get_weather(location: str) -> str:
"""Get current weather conditions for a named location.
Use this when the user asks about weather or current conditions.
Do NOT use this for historical or factual lookups."""
return f"Weather for: {location}"
agent = create_agent(
model="anthropic:claude-opus-5",
tools=[search_capital, get_weather],
system_prompt="Answer questions using the appropriate tool.",
)The list passed to tools= just gets longer. That's the entire binding change from lesson 05's one-tool version. What actually changes is that the model now has to choose between two plausible tools instead of deciding whether to call the one it has, and that choice, not the binding mechanism, is where multi-tool systems actually go wrong. This course's own source material spends ten exercises building toward a "complete multi-tool agent system," which makes multi-tool binding sound like it needs proportionally more machinery than the single-tool case. It doesn't.
Prerequisite: Lesson 05 (binding one tool, native tool-calling). This lesson extends that to more than one tool.
After this lesson, you can: bind several tools to one agent, explain what ToolNode (the LangGraph component that executes whichever tool the model picks) actually does, and name the one design discipline (tool naming) that determines whether multi-tool selection works reliably.
The one discipline that decides whether selection works
tools-memory-and-multi-agent-systems lesson 07's four-question test for a tool description applies here with full force, and it's worth citing directly rather than re-deriving: what does it do, when should you use it, what does it return, and when should you NOT use it. That last question is the one multi-tool systems live or die on. Notice both tools above end their docstring with an explicit "Do NOT use this for X" pointing at the other tool. Remove those two lines and a query like "what's it like in Paris right now" becomes ambiguous between the two, because both docstrings otherwise sound plausible for a geography-adjacent question.
ToolNode: still current, and what it actually does
langgraph.prebuilt.create_react_agent was lesson 01's deprecation finding. ToolNode, also in langgraph.prebuilt, is not deprecated, confirmed directly against its current reference documentation. Worth naming explicitly so a "prebuilt is old, avoid it" overcorrection doesn't take hold: only the high-level agent factory moved, not every prebuilt helper.
from langgraph.prebuilt import ToolNode
tool_node = ToolNode([search_capital, get_weather])ToolNode is the piece that turns a model's tool-call output into an actual function execution: it reads the tool_calls on the last message, matches each one against the tools you gave it by name, runs the matching function, and appends a ToolMessage with the result back into state. You rarely write this dispatch logic by hand once you're past a toy example; ToolNode is the current, correct way to do it for a graph built directly on StateGraph rather than through create_agent's own built-in loop.
The model can only pick from what you gave it. A tool added mid-conversation isn't visible retroactively; bind the full set upfront.
If two tools could both reasonably apply to the same question, that's exactly when the disambiguating line earns its place. A tool with no plausible neighbor doesn't need one.
The source material's own rate-limiting exercise adds a request counter to state and checks it before a tool call. That's the same discipline tools-memory-and-multi-agent-systems lesson 09 already named for any external API call: timeout, retry, error map. Rate limiting is that checklist's "don't exceed what the upstream service allows" clause, not a LangGraph-specific concept.
What this buys you before lesson 07
You can now bind multiple tools, explain what ToolNode does with the model's selection, and write descriptions that keep selection reliable as the tool count grows. Lesson 07 turns to what happens when several of those tool calls need to run at once instead of one after another.
Parallel execution and production hardening: running independent tool calls concurrently, and the error-handling patterns this course's source material builds toward in its own "complete system integration" exercise.
Reply here and it goes straight to Rod. Same as replying to one of his emails.