Tools: a travel search the agent can call
Tools are Python functions the model can ask the agent to run; a tool's name, arguments and docstring tell the model what it does and when to call it.
Last updated: 29 Sep, 2026 · Deep Agents 0.7
The video's web_search tool
The video's first tool searches the internet. It creates a TavilyClient with the Tavily key, then writes web_search: a query string, max_results with a default of 5, a topic that must be one of a few fixed words, written with Literal, and include_raw_content. The parameters are the ones the Tavily client's search method takes, read from its documentation. The docstring, "Run a web search", is what the model reads to decide when to use it.
Installing tavily-python
web_search needs the Tavily client, tavily-python, which the video installs with the other packages. Add it next to the ones from Installation and setup:
pip install "tavily-python==0.8.4"Getting a free Tavily keyOptional
Sign up at app.tavily.com. The API key is on the dashboard and starts with tvly-. The free Researcher plan gives 1,000 API credits a month and needs no card; a basic search, the kind web_search runs, costs one credit. Set the key the same way as the Groq key:
export TAVILY_API_KEY=tvly-...Or add it to the .env file under the Groq key; load_dotenv() loads both:
GROQ_API_KEY=gsk_...
# optional, only the web search examples use it
TAVILY_API_KEY=tvly-...The key is optional. The course's own examples, from the catalog tool below to the finished trip planner, search a small travel catalog and run with the Groq key alone. web_search is the real-web version of the same idea: the examples from the video that search the internet, and the live search in Integrations: taking the trip planner to production, need this key.
The web_search function
Save the function as research.py. It is the video's code with two changes that keep each request inside the 8,000 tokens a minute that Groq's free tier allows: include_raw_content is left out, because one page's full text can be larger than that on its own, and max_results is capped at 5, because the model sometimes asks for 10. On a paid tier you can put both back. If your keys live in .env, the two load_dotenv lines from Installation and setup go at the very top, above tavily_client, because the client reads the key as soon as the file runs.
import os
from tavily import TavilyClient
from typing import Literal
tavily_client = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
def web_search(query: str, max_results: int = 5,
topic: Literal["general", "sports", "news", "finance"] = "general"):
"""Run a web search"""
return tavily_client.search(query, max_results=min(max_results, 5), topic=topic)It runs in the next lesson, create_deep_agent: your first deep agent, where the video hands it to its first deep agent. The trip planner on these pages uses a tool that searches a small travel catalog instead, so every answer can be checked against the data. Web search results change every day; a catalog does not.
The search_travel tool
The catalog is a dictionary: one city, and for each kind of entry, a list of lines with rupee prices. The prices are the ones the trip planner uses in every later lesson.
The travel catalog
CATALOG = {
"paris": {
"flight": ["Return flight Delhi to Paris: 42,000 rupees"],
"hotel": ["Seine Budget Inn, Latin Quarter: 5,200 rupees a night",
"Hotel Lumiere, Montmartre: 7,500 rupees a night",
"Le Grand Opera Hotel: 16,000 rupees a night"],
"sight": ["Eiffel Tower summit: 3,100 rupees", "Louvre Museum: 2,000 rupees",
"Seine river cruise: 1,500 rupees", "Versailles day trip: 2,600 rupees",
"Montmartre walking tour: free"],
"food": ["Cafe breakfast and bistro dinner: 3,000 rupees a day"],
},
}Turning a function into a tool with @tool
@tool from langchain.tools reads the function's name, type hints and docstring and builds the description the model sees. Deep Agents also accepts a plain function, as the video's web_search shows; @tool makes the conversion explicit and lets you call the tool yourself with .invoke. A city that is not in the catalog gets a clear sentence back, so the model can say so instead of guessing.
@tool
def search_travel(city: str, kind: str) -> str:
"""Search the travel catalog. kind is "flight", "hotel", "sight" or "food". Prices are in rupees."""
entries = CATALOG.get(city.lower(), {}).get(kind)
return "\n".join(entries) if entries else f"The catalog has no {kind} entries for {city}."Calling search_travel directly
The file so far; save it as trip.py; later lessons start from it.
from langchain.tools import tool
CATALOG = {
"paris": {
"flight": ["Return flight Delhi to Paris: 42,000 rupees"],
"hotel": ["Seine Budget Inn, Latin Quarter: 5,200 rupees a night",
"Hotel Lumiere, Montmartre: 7,500 rupees a night",
"Le Grand Opera Hotel: 16,000 rupees a night"],
"sight": ["Eiffel Tower summit: 3,100 rupees", "Louvre Museum: 2,000 rupees",
"Seine river cruise: 1,500 rupees", "Versailles day trip: 2,600 rupees",
"Montmartre walking tour: free"],
"food": ["Cafe breakfast and bistro dinner: 3,000 rupees a day"],
},
}
@tool
def search_travel(city: str, kind: str) -> str:
"""Search the travel catalog. kind is "flight", "hotel", "sight" or "food". Prices are in rupees."""
entries = CATALOG.get(city.lower(), {}).get(kind)
return "\n".join(entries) if entries else f"The catalog has no {kind} entries for {city}."Add two calls to the end of trip.py. A tool made with @tool takes its arguments as a dictionary. No model is involved yet, so this runs without a key:
print(search_travel.invoke({"city": "Paris", "kind": "hotel"}))
print(search_travel.invoke({"city": "Tokyo", "kind": "hotel"}))Seine Budget Inn, Latin Quarter: 5,200 rupees a night Hotel Lumiere, Montmartre: 7,500 rupees a night Le Grand Opera Hotel: 16,000 rupees a night The catalog has no hotel entries for Tokyo.
What the two calls returned
- Paris hotels came back as three lines, cheapest first, exactly as the catalog stores them.
- Tokyo is not in the catalog, so the tool returned a sentence saying so. An agent that reads it can tell the traveller the city is missing.
A web search tool vs the catalog tool
| web_search (the video) | search_travel (this course) | |
|---|---|---|
| Data | Live results from the internet | A fixed catalog in the file |
| Keys | Tavily and a model key | A model key only |
| Same question tomorrow | May return different pages | Returns the same lines |
| Good for | Research on current topics | Learning, testing and checking answers |
Where custom tools fit
- Your own data: a booking system, a price list, a database query.
- Actions: sending a message, making a booking, which later lessons put behind a person's approval.
- Anything the model cannot know on its own, such as today's prices.
kind values tells the model how to call it.Related
- Previous: Installation and setup
- Next: create_deep_agent: your first deep agent
- Reference: Deep Agents tools
- Call
search_travelwithkind="sight"and count the free entries. - Add a
"rome"city with one hotel and call the tool for it. - Call it with
kind="train"and read the sentence it returns.
You understood something today that you didn't yesterday.