07 Oct LangGraph Tools and Tool Calling
An LLM can only produce text. It can’t check today’s weather, do exact math, or read your database. Tools fix this by giving the model functions it can ask your code to run.
The key idea
The model never runs the tool itself. The flow is:
- You tell the model which tools exist
- The model replies: “please call multiply with a=6, b=7”
- Your code runs the function
- You send the result back, and the model writes the final answer
Understanding this flow makes Chapter 11 much easier.
Step 1: Create a tool
A tool is a normal Python function with the @tool decorator:
from langchain_core.tools import tool
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
Three things matter here:
- The docstring is what the model reads to decide when to use the tool, so write it clearly
- Type hints tell the model what inputs are expected
- The function name becomes the tool name
Try it directly:
print(multiply.name)
print(multiply.description)
print(multiply.invoke({"a": 6, "b": 7}))
Output:
multiply Multiply two numbers. 42
Step 2: Add a second tool
@tool
def get_weather(city: str) -> str:
"""Get the current weather for a city."""
# Fake data for learning. A real tool would call a weather API.
data = {"delhi": "34°C, sunny", "london": "15°C, cloudy"}
return data.get(city.lower(), "Weather data not available")
This tool returns made-up data so you can focus on the mechanics. Later, you can swap in a real API without changing anything else.
Step 3: Tell the model about the tools
Use bind_tools():
from dotenv import load_dotenv from langchain_anthropic import ChatAnthropic load_dotenv() llm = ChatAnthropic(model="claude-sonnet-5-5") tools = [multiply, get_weather] llm_with_tools = llm.bind_tools(tools)
Step 4: See a tool call
response = llm_with_tools.invoke("What is 6 times 7?")
print("Text:", response.content)
print("Tool calls:", response.tool_calls)
Sample output (ids will differ):
Text:
Tool calls: [{'name': 'multiply', 'args': {'a': 6, 'b': 7}, 'id': 'call_abc123', 'type': 'tool_call'}]
The model didn’t answer 42. It returned a request to call multiply with a=6 and b=7. The text may be empty or contain a short sentence, depending on the model.
When the model doesn’t need a tool
response = llm_with_tools.invoke("What is Python?")
print(response.tool_calls)
print(response.content)
Sample output:
[] Python is a popular programming language...
An empty tool_calls list means the model answered directly. The model decides for itself whether a tool is needed.
Step 5: Run the tool and send back the result
from langchain_core.messages import HumanMessage, ToolMessage
tools_by_name = {"multiply": multiply, "get_weather": get_weather}
messages = [HumanMessage("What is 6 times 7?")]
# 1. Model asks for a tool
ai_message = llm_with_tools.invoke(messages)
messages.append(ai_message)
# 2. We run each requested tool
for call in ai_message.tool_calls:
result = tools_by_name[call["name"]].invoke(call["args"])
messages.append(ToolMessage(content=str(result), tool_call_id=call["id"]))
# 3. Model writes the final answer
final = llm_with_tools.invoke(messages)
print(final.content)
Sample output:
6 times 7 is 42.
How it works:
- ai_message contains the tool request, and we add it to the history
- We look up the requested tool by name and run it with the model’s arguments
- A ToolMessage carries the result back. Its tool_call_id must match the request’s id, so the model knows which call it answers.
- The second invoke() sees the whole conversation, including the result, and writes a natural reply
Message types, updated
- HumanMessage: what the user said
- AIMessage: the model’s reply, which may include tool_calls
- ToolMessage: the result of a tool your code ran
Multiple tool calls at once
response = llm_with_tools.invoke("What's the weather in Delhi and London?")
for call in response.tool_calls:
print(call["name"], call["args"])
Sample output:
get_weather {'city': 'Delhi'}
get_weather {'city': 'London'}
Models can request several calls in one reply, which is why our code loops over tool_calls.
Writing good tools
- Clear docstring: “Get the current weather for a city” beats “weather function”
- Simple inputs: strings and numbers work best
- Return text or simple values: the result goes back to the model as text
- One job per tool: small, focused tools get chosen more accurately
- Handle errors gently: return a message like “City not found” instead of crashing
Common mistakes
- Missing docstring: the tool may fail to register, or the model won’t know when to use it
- Forgetting bind_tools(): the model can’t request tools it doesn’t know about
- Mismatched tool_call_id: the model can’t match the result to its request
- Forgetting to append the AIMessage: the history must include the tool request before the ToolMessage
- Treating tool_calls as the answer: it is only a request, and your code still has to run the tool
- Trusting tool arguments blindly: the model chooses them, so validate inputs before touching files, databases, or paid APIs
Summary
- Tools are Python functions the model can ask your code to run
- @tool plus a clear docstring and type hints creates one
- bind_tools() tells the model which tools exist
- The model returns tool_calls. Your code runs them and replies with ToolMessages.
Practice
- Write a tool word_count(text: str) -> int and check that the model calls it for “How many words are in ‘LangGraph is fun to learn’?”
- Add a get_time tool that returns a fixed string, and ask a question that needs both get_weather and get_time
- Ask a question that needs no tool and confirm tool_calls is empty
If you liked the tutorial, spread the word and share the link and our website, Studyopedia, with others.
For Videos, Join Our YouTube Channel:Â Join Now
Read More:
- Generative AI Tutorial
- AI Ethics
- Machine Learning Tutorial
- Deep Learning Tutorial
- Ollama Tutorial
- Retrieval Augmented Generation (RAG) Tutorial
- ChatGPT Tutorial
- Microsoft Copilot Tutorial
No Comments