Tools and Agents
Give models functions to call and let them decide when.
What you will learn
- Define a tool
- Bind tools to a model
- Run an agent loop safely
A chain follows steps you decided in advance. An agent lets the model decide which steps to take, calling tools (ordinary functions) when it needs facts or actions. Tools are how a model gets fresh data, does exact math and changes the world.
Defining a tool
Decorate a function with @tool. The name, type hints and docstring become the description the model reads, so write them clearly.
from langchain_core.tools import tool
@tool
def get_weather(city: str) -> str:
"""Get the current weather for a city."""
data = {"Paris": "18C, cloudy", "Delhi": "34C, sunny"}
return data.get(city, "unknown city")
@tool
def multiply(a: float, b: float) -> float:
"""Multiply two numbers exactly."""
return a * bllm_with_tools = llm.bind_tools([get_weather, multiply])
response = llm_with_tools.invoke("What is the weather in Paris?")
print(response.tool_calls)[{'name': 'get_weather', 'args': {'city': 'Paris'}, 'id': 'call_1'}]The model does not run the function. It requests a call with arguments; your code executes it and sends the result back so the model can write the final answer. An agent loop automates that exchange.
from langgraph.prebuilt import create_react_agent
agent = create_react_agent(llm, [get_weather, multiply])
result = agent.invoke({"messages": [("user", "What is the weather in Delhi, and what is 12.5 times 8?")]})
print(result["messages"][-1].content)The agent calls both tools (possibly in parallel), reads their results and composes the answer. Use agent.stream(...) to watch each step.
Writing good tools
- One clear purpose per tool, with a precise description of when to use it.
- Simple, typed arguments; return short, useful strings or JSON.
- Return errors as readable messages so the model can recover and retry.
- Keep the tool list small. Too many similar tools confuse the model.
Safety for agents
- Least privilege: give read-only tools where possible.
- Confirm dangerous actions (sending email, deleting, spending money) with a human before executing.
- Limit loops: cap the number of steps and total cost.
- Validate arguments exactly as you would any user input.
- Prompt injection: text from web pages or emails may try to instruct the agent. Never let untrusted content authorize actions.
If the steps are known in advance, a plain chain is cheaper, faster and more predictable. Reach for agents when the number and order of steps genuinely depends on the input.
Try it yourself
Write a word_count(text: str) tool and a current_time() tool, give them to an agent, and ask it how many words are in a sentence you supply.
Show solution
from datetime import datetime
@tool
def word_count(text: str) -> int:
"""Count the words in a piece of text."""
return len(text.split())
@tool
def current_time() -> str:
"""Return the current UTC time in ISO format."""
return datetime.utcnow().isoformat()
agent = create_react_agent(llm, [word_count, current_time])
print(agent.invoke({"messages": [("user", "How many words are in: the quick brown fox?")]})["messages"][-1].content)