| π View Lecture Slides | Full-screen presentation with navigation |
Session 11: Tool Calling & Actions
| Session Duration: 2 Hours | Block: 3 β Agents, Evaluation & Deployment |
Learning Objectives
By the end of this session, students will be able to:
- Explain how function calling enables AI to interact with external systems
- Define tools with clear schemas that the AI model can understand and invoke
- Implement a tool-calling loop in Python
- Add a meaningful tool (search or calculator) to their AI application
Hour 1: Function Calling β Giving AI Hands (Instructor-Led β 60 minutes)
1.1 What Is Tool Calling?
A language model, in its pure form, can only produce text. Tool calling extends this by giving the model the ability to request that specific functions be executed, and then use the results of those functions in its response.
The key insight: the model does not execute the function β it decides to call it and your code executes it.
This is a critical architectural point. The model emits a structured request: βCall the search_web function with query=βcurrent weather in Kathmanduβ.β Your application code then executes the search, retrieves the result, and feeds it back to the model as additional context. The model then incorporates the real-time data into its response.
1.2 The Function Calling Protocol
[Turn 1]
User: "What is the population of Kathmandu?"
Model: [Decides it needs current data] β Emits function call: search_web("population of Kathmandu")
[Your code executes search_web("population of Kathmandu") β returns "1.44 million (2021)"]
[Turn 2 β function result fed back]
Context now includes: [search result: "1.44 million (2021)"]
Model: "The population of Kathmandu is approximately 1.44 million as of the 2021 census."
1.3 Defining Tools
Tools are defined as structured schemas that describe:
- The function name
- What the function does (description β the model reads this to decide when to use it)
- The parameters it accepts (names, types, descriptions)
For Gemini:
import google.generativeai as genai
# Define the tool
calculator_tool = genai.protos.Tool(
function_declarations=[
genai.protos.FunctionDeclaration(
name='calculate',
description='Evaluate a mathematical expression and return the result.',
parameters=genai.protos.Schema(
type=genai.protos.Type.OBJECT,
properties={
'expression': genai.protos.Schema(
type=genai.protos.Type.STRING,
description='The mathematical expression to evaluate, e.g. "2 + 2" or "sqrt(16)"'
)
},
required=['expression']
)
)
]
)
1.4 Implementing the Tool Executor
import ast
import math
import operator as op
_ALLOWED_BINOPS = {
ast.Add: op.add,
ast.Sub: op.sub,
ast.Mult: op.mul,
ast.Div: op.truediv,
ast.Pow: op.pow,
ast.Mod: op.mod,
}
_ALLOWED_UNARYOPS = {
ast.UAdd: op.pos,
ast.USub: op.neg,
}
_ALLOWED_FUNCS = {name: getattr(math, name) for name in (
'sqrt', 'sin', 'cos', 'tan', 'log', 'log10', 'exp', 'fabs', 'floor', 'ceil'
)}
def safe_calculate(expression: str) -> float:
"""Safely evaluate a restricted math expression."""
node = ast.parse(expression, mode='eval').body
def _eval(n):
if isinstance(n, ast.Constant) and isinstance(n.value, (int, float)):
return float(n.value)
if isinstance(n, ast.BinOp) and type(n.op) in _ALLOWED_BINOPS:
return _ALLOWED_BINOPS[type(n.op)](_eval(n.left), _eval(n.right))
if isinstance(n, ast.UnaryOp) and type(n.op) in _ALLOWED_UNARYOPS:
return _ALLOWED_UNARYOPS[type(n.op)](_eval(n.operand))
if isinstance(n, ast.Call) and isinstance(n.func, ast.Name) and n.func.id in _ALLOWED_FUNCS:
args = [_eval(a) for a in n.args]
return float(_ALLOWED_FUNCS[n.func.id](*args))
raise ValueError('Unsupported expression')
return float(_eval(node))
def execute_tool(tool_call) -> str:
"""Execute a tool call from the model and return the result."""
name = tool_call.name
args = dict(tool_call.args)
if name == 'calculate':
try:
result = safe_calculate(args['expression'])
return str(result)
except Exception as e:
return f"Error: {str(e)}"
return f"Unknown tool: {name}"
Security note: Avoid eval() for user/model input. Prefer a strict parser/AST whitelist or a dedicated safe-expression library for expression evaluation.
1.5 The Tool-Calling Loop
def query_with_tools(user_message: str, tools: list) -> str:
"""Handle a query with potential tool calls."""
model = genai.GenerativeModel('gemini-1.5-flash', tools=tools)
chat = model.start_chat()
response = chat.send_message(user_message)
# Handle tool calls
while response.candidates[0].content.parts:
part = response.candidates[0].content.parts[0]
if hasattr(part, 'function_call') and part.function_call.name:
# Execute the tool
result = execute_tool(part.function_call)
# Send the result back to the model
response = chat.send_message(
genai.protos.Content(parts=[
genai.protos.Part(
function_response=genai.protos.FunctionResponse(
name=part.function_call.name,
response={'result': result}
)
)
])
)
else:
break # No more tool calls
return response.text
Hour 2: Practical β Add a Tool to Your Application (60 minutes)
Lab 11.1 β Implement the Calculator Tool
Implement the calculator tool as defined in section 1.3. Test it with:
"What is 15% of Β£2,340?"β should trigger the tool"Explain what an API is"β should NOT trigger the tool"What is the square root of 144 divided by 3?"β multi-step calculation
Verify the model correctly decides when to use the tool and when it is unnecessary.
Lab 11.2 β Add a Search Tool (Simulated)
Implement a simulated search tool (returns hardcoded results for this lab) and connect it to your application:
def search_knowledge_base(query: str) -> str:
"""Search the knowledge base for relevant information."""
# In this lab, call your RAG retrieve function from Session 9
chunks = retrieve_relevant_chunks(query, top_k=2)
if not chunks or chunks[0]['score'] < 0.5:
return "No relevant information found in knowledge base."
return "\n\n".join([f"[{c['file']}]: {c['content'][:500]}" for c in chunks])
This connects your RAG system from Session 9 to the tool-calling framework from this session β the two components now work together.
Lab 11.3 β Relevant Tool for Your Project
Identify one tool that would be genuinely useful for your course project. Some examples:
- Course Assistant:
get_learning_objective(session_number)β returns the objectives for a given session - Document Navigator:
list_documents()β returns the available document names - CV Matcher:
score_cv_match(job_requirements, cv_text)β returns a percentage match
Define the tool schema, implement the function, and integrate it into your application.
Key Takeaways
- Tool calling gives AI the ability to request execution of specific functions with structured arguments
- The model decides when to call a tool; your code decides how to execute it safely
- Tool descriptions are critical β the model reads these to decide when to use each tool
- Security: never expose unrestricted
eval()or system access to tool-calling AI - Tool calling + RAG together create a far more capable application than either alone
Further Reading
- Gemini function calling documentation: ai.google.dev/gemini-api/docs/function-calling
- OpenAI function calling documentation
- βGorilla: Large Language Model Connected with Massive APIsβ (research paper)


