%pip install -q -U langchain langchain-google-genai langgraph langchain-corePractice 1.2 β Tools: Giving Your Agent Hands
Unit 1, Lesson 2
This practice builds on and goes beyond what you did in class. You will read tools, fix broken ones, build your own, and wire them into agents.
You will practice: - Reading and evaluating existing tools - Fixing broken tool definitions - Building custom tools from scratch - Converting existing Python code into tools - Understanding why docstrings drive agent behavior
# YOUR CODE HEREβ replace with your own code
# YOUR ANSWER HEREβ write your answer as a comment or string
Run every cell in order
π Setup
import os
from google.colab import userdata
from langchain.chat_models import init_chat_model
from langchain.agents import create_react_agent
from langchain_core.tools import tool
os.environ['GOOGLE_API_KEY'] = userdata.get('GOOGLE_API_KEY')
model = init_chat_model(
model="google_genai:gemini-2.5-flash",
temperature=0
)
print("Ready!")Part 1 β Read and Evaluate
Below are three tools. For each one, answer the questions before running the code.
Tool A
@tool
def word_counter(text: str) -> str:
"""
Counts the number of words in a given text and returns the result.
Use this tool when the user asks how many words are in a sentence,
paragraph, or any piece of text.
Args:
text: The text to count words in
"""
count = len(text.split())
return f"The text contains {count} words."tool_a_evaluation = """
# 1. What does this tool do?
# 2. When would the agent call it?
# 3. Is the docstring clear enough? What would you change?
# 4. What edge case might break this tool? (hint: what if text is empty?)
# YOUR ANSWER HERE
"""
print(tool_a_evaluation)
# Now test it
print(word_counter.invoke({"text": "The quick brown fox jumps over the lazy dog"}))
print(word_counter.invoke({"text": ""}))Tool B
@tool
def temperature_converter(celsius: float) -> str:
"""
Converts a temperature from Celsius to Fahrenheit.
Use this when the user gives a temperature in Celsius and wants
to know the Fahrenheit equivalent.
Args:
celsius: Temperature in Celsius as a number
"""
fahrenheit = (celsius * 9/5) + 32
return f"{celsius}Β°C is {fahrenheit:.1f}Β°F"tool_b_evaluation = """
# 1. What does this tool do?
# 2. What would happen if a user asked to convert Fahrenheit to Celsius?
# Would the agent use this tool? Why or why not?
# 3. How would you expand this tool to handle both directions?
# YOUR ANSWER HERE
"""
print(tool_b_evaluation)
# Test it
print(temperature_converter.invoke({"celsius": 100}))
print(temperature_converter.invoke({"celsius": 0}))
print(temperature_converter.invoke({"celsius": -40}))Tool C β Something is wrong here
@tool
def get_info(x: str) -> str:
"""Gets info."""
return f"Here is the info you requested about {x}."tool_c_problems = """
# List everything wrong with Tool C:
# 1.
# 2.
# 3.
# Would an agent ever reliably use this tool? Why or why not?
# YOUR ANSWER HERE
"""
print(tool_c_problems)Part 2 β Fix the Broken Tools
Below are two broken tools. Each has a different kind of problem. Find the problem, fix it, and explain what was wrong.
Broken Tool 1 β The agent never calls it
# DO NOT EDIT THIS CELL β just read it
@tool
def reverse_string(text: str) -> str:
"""Does something with text."""
return text[::-1]# Fix the tool here β rewrite the whole thing correctly
@tool
def reverse_string(text: str) -> str:
# YOUR FIXED DOCSTRING HERE
return text[::-1]
# Test it
print(reverse_string.invoke({"text": "hello world"}))broken1_explanation = """
# What was wrong with the original tool?
# What did you change and why?
# YOUR ANSWER HERE
"""
print(broken1_explanation)Broken Tool 2 β The function crashes
# DO NOT EDIT THIS CELL β just read it
@tool
def divide_numbers(a: float, b: float) -> str:
"""
Divides two numbers and returns the result.
Use this when the user asks you to divide one number by another.
Args:
a: The numerator
b: The denominator
"""
result = a / b
return f"{a} divided by {b} is {result}"# Fix the tool β it needs to handle the case that would crash it
@tool
def divide_numbers(a: float, b: float) -> str:
"""
Divides two numbers and returns the result.
Use this when the user asks you to divide one number by another.
Args:
a: The numerator
b: The denominator
"""
# YOUR FIX HERE
result = a / b
return f"{a} divided by {b} is {result}"
# Test with a normal case and the case that would crash
print(divide_numbers.invoke({"a": 10, "b": 2}))
print(divide_numbers.invoke({"a": 10, "b": 0})) # This should not crash anymorePart 3 β Convert Existing Code to Tools
Below is regular Python code that does useful things. Convert each one into a tool the agent can use. Remember: add @tool, type hints, and a strong docstring.
Convert 1
# Original code β do not edit
def is_palindrome(word):
cleaned = word.lower().replace(" ", "")
return cleaned == cleaned[::-1]# YOUR TOOL VERSION HERE
# Requirements:
# - @tool decorator
# - Type hints on parameters and return
# - Clear docstring with Args section
# - Returns a readable string (not just True/False)
# Test it
# print(is_palindrome.invoke({"word": "racecar"}))
# print(is_palindrome.invoke({"word": "hello"}))
# print(is_palindrome.invoke({"word": "A man a plan a canal Panama"}))Convert 2
# Original code β do not edit
def days_until_event(event_date_str):
from datetime import datetime
event_date = datetime.strptime(event_date_str, "%Y-%m-%d")
today = datetime.today()
delta = event_date - today
return delta.days# YOUR TOOL VERSION HERE
# Extra challenge: handle the case where the date has already passed
# and return a helpful message instead of a negative number
# Test it
# print(days_until_event.invoke({"event_date_str": "2026-12-25"}))
# print(days_until_event.invoke({"event_date_str": "2020-01-01"})) # Already passedPart 4 β Build From Scratch and Wire Into an Agent
Build two tools of your own choice. They should be different enough that the agent can clearly tell when to use each one. Then wire both into a single agent and test it.
Requirements: - Both tools must do something useful (not just return a hardcoded string) - Both docstrings must clearly say when to use the tool AND when not to - Test each tool directly with .invoke() before adding to the agent - Ask the agent at least 4 questions β 2 that trigger Tool 1, 2 that trigger Tool 2
# Tool 1
# YOUR CODE HERE# Tool 2
# YOUR CODE HERE# Wire both tools into an agent and test with 4 questions
# YOUR CODE HEREpart4_reflection = """
# Did the agent always pick the right tool?
# If it ever picked the wrong one, what did you change to fix it?
# What made writing the docstrings harder than you expected?
# YOUR ANSWER HERE
"""
print(part4_reflection)Part 5 β Stretch Challenge π₯
This is optional.
The challenge: Build a tool that takes a list of numbers as input and returns basic statistics about them β min, max, mean, and median. Then wire it into an agent with the calculator tool from class and ask it questions that require both tools together.
For example: - βHere are my test scores: 78, 92, 85, 60, 95. What is my average, and what would my average be if my lowest score was dropped?β
This requires the stats tool AND the calculator tool to work together.
# YOUR CODE HERE