and Large Language Models (LLMs)
Large language models (LLMs) are advanced AI systems built on deep neural network akin to transformers and trained on vast amounts of text to generate human-like language. LLMs like ChatGPT, Claude, Gemini and Grok can tackle many difficult tasks and are used across fields akin to science, healthcare, education, and finance.
An AI agent extends the capabilites of LLMs to unravel tasks which might be beyond their pre-trained knowledge. An LLM can write a Python tutorial from what it learned during training. If you happen to ask it to book a flight, the duty requires access to your calendar, web search and the power to take actions, these fall beyond the LLM’s pre-trained knowledge. Among the common actions include:
- The LLM connects to an online search tool to fetch the most recent weather forecast.
- An AI agent that may check a user’s calendar, search the net to go to a booking site like Expedia to seek out available options for flights and hotels, present them to the user for confirmation, and complete the booking on behalf of the user.
How an AI Agent Works
AI agents form a system that uses a Large Language Model to plan, reason, and take steps to interact with its environment using tools suggested from the model’s reasoning to unravel a selected task.
Basic Structure of an AI Agent
- the LLM is the of an AI agent. It takes a user’s prompt, plans and reasons through the request and breaks the issue into steps that determine which tools it should use to finish the duty.
- is the framework that the agent uses to perform an motion based on the plan and reasoning from the Large Language Model. If you happen to ask an LLM to book a table for you at a restaurant, possible tools that shall be used include calendar to envision your availability and an online search tool to access the restaurant website and make a reservation for you.
Ilustrated Decision Making of a Booking AI Agent

AI agents can access different tools depending on the duty. A tool could be an information store, akin to a database. For instance, a customer-support agent could access a customer’s account details and buy history and judge when to retrieve that information to assist resolve a difficulty.
AI agents are used to unravel a wide selection of tasks, and there are a lot of powerful agents available. Coding agents, particularly agentic IDEs akin to Cursor, Windsurf, and GitHub Copilot help engineers write and debug code faster and construct projects quickly. CLI Coding agents like Claude Code and Codex CLI can interact with a user’s desktop and terminal to perform coding tasks. ChatGPT supports agents that may perform actions akin to booking reservations on a user’s behalf. Agents are also integrated into customer support workflows to speak with customers and resolve their issues.
Function Calling
Function calling is a method for connecting a big language model (LLM) to external tools akin to APIs or databases. It’s utilized in creating AI agents to attach LLMs to tools. In function calling, each tool is defined as a code function (for instance, a weather API to fetch the most recent forecast) together with a JSON Schema that specifies the function’s parameters and instructs the LLM on when and the right way to call the function for a given task.
The variety of function defined is dependent upon the duty the agent is designed to perform. For instance, for a customer support agent we will define a function that may extract information from unstructured data, akin to PDFs containing details a couple of business’s products.
On this post I’ll show the right way to use function calling to construct an easy web search agent using GPT-5 as the big language model.
Basic Structure of a Web Search Agent

The major logic behind the net search agent:
- Define a code function to handle the net search.
- Define custom instructions that guide the big language model in determining when to call the net search function based on the query. For instance, if the query asks in regards to the current weather, the net search agent will recognize the necessity to go looking the web to get the most recent weather reports. Nonetheless, if the query asks it to jot down a tutorial a couple of programming language like Python, something it could actually answer from its pre-trained knowledge it’ll not call the net search function and can respond directly as an alternative.
Prerequisite
Create an OpenAI account and generate an API key
1: Create an OpenAI Account in case you don’t have one
2: Generate an API Key
Arrange and Activate Environment
python3 -m venv env
source env/bin/activate
Export OpenAI API Key
export OPENAI_API_KEY="Your Openai API Key"
Setup Tavily for Web Search
Tavily is a specialized web-search tool for AI agents. Create an account on Tavily.com, and once your profile is about up, an API key shall be generated which you can copy into your environment. Recent accounta receive 1000 free credits that might be used for as much as 1000 web searches.
Export TAVILY API Key
export TAVILY_API_KEY="Your Tavily API Key"
Install Packages
pip3 install openai
pip3 install tavily-python
Constructing a Web Search Agent with Function Calling Step by Step
Step 1: Create Web Search Function with Tavily
An internet search function is implemented using Tavily, serving because the tool for function calling in the net search agent.
from tavily import TavilyClient
import os
tavily = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
def web_search(query: str, num_results: int = 10):
try:
result = tavily.search(
query=query,
search_depth="basic",
max_results=num_results,
include_answer=False,
include_raw_content=False,
include_images=False
)
results = result.get("results", [])
return {
"query": query,
"results": results,
"sources": [
{"title": r.get("title", ""), "url": r.get("url", "")}
for r in results
]
}
except Exception as e:
return {
"error": f"Search error: {e}",
"query": query,
"results": [],
"sources": [],
}
Web function code breakdown
Tavily is initialized with its API key. Within the web_search
function, the next steps are performed:
- Tavily search function is named to go looking the web and retrieve the highest 10 results.
- The search results and their corresponding sources are returned.
This returned output will function relevant context for the net search agent: which we are going to define later in this text, to fetch up-to-date information for queries (prompts) that require real-time data akin to weather forecasts.
Step 2: Create Tool Schema
The tool schema defines custom instructions for an AI model on when it should call a tool, on this case the tool that shall be utilized in an online search function. It also specifies the conditions and actions to be taken when the model calls a tool. A json tool schema is defined below based on the OpenAI tool schema structure.
tool_schema = [
{
"type": "function",
"name": "web_search",
"description": """Execute a web search to fetch up to date information. Synthesize a concise,
self-contained answer from the content of the results of the visited pages.
Fetch pages, extract text, and provide the best available result while citing 1-3 sources (title + URL).
If sources conflict, surface the uncertainty and prefer the most recent evidence.
""",
"strict": True,
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Query to be searched on the web.",
},
},
"required": ["query"],
"additionalProperties": False
},
},
]
Tool schema’s Properties
- Specifies that the variety of tool is a function.
- the name of the function that shall be used for tool call, which is .
- Describes what the AI model should do when calling the net search tool. It instructs the model to go looking the web using the function to fetch up-to-date information and extract relevant details to generate the most effective response.
- It is about to true, this property instructs the LLM to strictly follow the tool schema’s instructions.
- Defines the parameters that shall be passed into the function. On this case, there is just one parameter: which represents the search term to look up on the web.
- Instructs the LLM that question is a compulsory parameter for the function.
- it is about to false, meaning that the tool’s cannot include any parameters aside from those defined under
Step 3: Create the Web Search Agent Using GPT-5 and Function Calling
Finally I’ll construct an agent that we will chat with, which may search the net when it needs up-to-date information. I’ll use GPT-5-mini, a quick and accurate model from OpenAI, together with function calling to invoke the and the already defined.
from datetime import datetime, timezone
import json
from openai import OpenAI
import os
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
# tracker for the last model's response id to keep up conversation's state
prev_response_id = None
# an inventory for storing tool's results from the function call
tool_results = []
while True:
# if the tool results is empty prompt message
if len(tool_results) == 0:
user_message = input("User: ")
""" commands for exiting chat """
if isinstance(user_message, str) and user_message.strip().lower() in {"exit", "q"}:
print("Exiting chat. Goodbye!")
break
else:
user_message = tool_results.copy()
# clear the tool results for the following call
tool_results = []
# obtain current's date to be passed into the model as an instruction to help in decision making
today_date = datetime.now(timezone.utc).date().isoformat()
response = client.responses.create(
model = "gpt-5-mini",
input = user_message,
instructions=f"Current date is {today_date}.",
tools = tool_schema,
previous_response_id=prev_response_id,
text = {"verbosity": "low"},
reasoning={
"effort": "low",
},
store=True,
)
prev_response_id = response.id
# Handles model response's output
for output in response.output:
if output.type == "reasoning":
print("Assistant: ","Reasoning ....")
for reasoning_summary in output.summary:
print("Assistant: ",reasoning_summary)
elif output.type == "message":
for item in output.content:
print("Assistant: ",item.text)
elif output.type == "function_call":
# obtain function name
function_name = globals().get(output.name)
# loads function arguments
args = json.loads(output.arguments)
function_response = function_name(**args)
tool_results.append(
{
"type": "function_call_output",
"call_id": output.call_id,
"output": json.dumps(function_response)
}
)
Step by Step Code Breakdown
from openai import OpenAI
import os
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
prev_response_id = None
tool_results = []
- Initialized the OpenAI model API with an API key.
- Initialized two variables and . keeps track of the model’s response to keep up conversation state, and is an inventory that stores outputs returned from the function call.
The chat runs contained in the. A user enters a message and the model called with tool schema accepts the message, reasons over it, decides whether to call the net search tool, after which the tool’s output is passed back to the model. The model generates a context-aware response. This continues until the user exits the chat.
Code Walkthrough of the Loop
if len(tool_results) == 0:
user_message = input("User: ")
if isinstance(user_message, str) and user_message.strip().lower() in {"exit", "q"}:
print("Exiting chat. Goodbye!")
break
else:
user_message = tool_results.copy()
tool_results = []
today_date = datetime.now(timezone.utc).date().isoformat()
response = client.responses.create(
model = "gpt-5-mini",
input = user_message,
instructions=f"Current date is {today_date}.",
tools = tool_schema,
previous_response_id=prev_response_id,
text = {"verbosity": "low"},
reasoning={
"effort": "low",
},
store=True,
)
prev_response_id = response.id
- Checks if the is empty. Whether it is, the user shall be prompted to type in a message, with an choice to quit using or .
- If the is just not empty, shall be set to the collected tool outputs to be sent to the model. is cleared to avoid resending the identical on the following loop iteration.
- The present date () is obtained to be utilized by the model to make time-aware decisions.
- Calls to generate the model’s response and it accepts the next parameters:
- model: set to .
- input: accepts the user’s message.
- instructions: set to current’s date (today_date).
- tools: set to the tool schema that was defined earlier.
- previous_response_id: set to the previous response’s id so the model can maintain conversation state.
- text: verbosity is about to low to maintain model’s response concise.
- reasoning: GPT-5-mini is a reasoning model, set the reasoning’s effort to low for faster’s response. For more complex tasks we will set it to high.
- store: tells the model to store the present’s response so it could actually be retrieved later and helps with conversation continuity.
for output in response.output:
if output.type == "reasoning":
print("Assistant: ","Reasoning ....")
for reasoning_summary in output.summary:
print("Assistant: ",reasoning_summary)
elif output.type == "message":
for item in output.content:
print("Assistant: ",item.text)
elif output.type == "function_call":
# obtain function name
function_name = globals().get(output.name)
# loads function arguments
args = json.loads(output.arguments)
function_response = function_name(**args)
# append tool results list with the the function call's id and performance's response
tool_results.append(
{
"type": "function_call_output",
"call_id": output.call_id,
"output": json.dumps(function_response)
}
)
This processes the model’s response output and does the next;
- If the output type is reasoning, print each item within the reasoning summary.
- If the output type is message, iterate through the content and print each text item.
- If the output type is a function call, obtain the function’s name, parse its arguments, and pass them to the function () to generate a response. On this case, the net search response accommodates up-to-date information relevant to the user’s message. Finally appends the function call’s response and performance call id to . This lets the following loop send the tool result back to the model.
Full Code for the Web Search Agent
from datetime import datetime, timezone
import json
from openai import OpenAI
import os
from tavily import TavilyClient
tavily = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
def web_search(query: str, num_results: int = 10):
try:
result = tavily.search(
query=query,
search_depth="basic",
max_results=num_results,
include_answer=False,
include_raw_content=False,
include_images=False
)
results = result.get("results", [])
return {
"query": query,
"results": results,
"sources": [
{"title": r.get("title", ""), "url": r.get("url", "")}
for r in results
]
}
except Exception as e:
return {
"error": f"Search error: {e}",
"query": query,
"results": [],
"sources": [],
}
tool_schema = [
{
"type": "function",
"name": "web_search",
"description": """Execute a web search to fetch up to date information. Synthesize a concise,
self-contained answer from the content of the results of the visited pages.
Fetch pages, extract text, and provide the best available result while citing 1-3 sources (title + URL). "
If sources conflict, surface the uncertainty and prefer the most recent evidence.
""",
"strict": True,
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Query to be searched on the web.",
},
},
"required": ["query"],
"additionalProperties": False
},
},
]
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
# tracker for the last model's response id to keep up conversation's state
prev_response_id = None
# an inventory for storing tool's results from the function call
tool_results = []
while True:
# if the tool results is empty prompt message
if len(tool_results) == 0:
user_message = input("User: ")
""" commands for exiting chat """
if isinstance(user_message, str) and user_message.strip().lower() in {"exit", "q"}:
print("Exiting chat. Goodbye!")
break
else:
# set the user's messages to the tool results to be sent to the model
user_message = tool_results.copy()
# clear the tool results for the following call
tool_results = []
# obtain current's date to be passed into the model as an instruction to help in decision making
today_date = datetime.now(timezone.utc).date().isoformat()
response = client.responses.create(
model = "gpt-5-mini",
input = user_message,
instructions=f"Current date is {today_date}.",
tools = tool_schema,
previous_response_id=prev_response_id,
text = {"verbosity": "low"},
reasoning={
"effort": "low",
},
store=True,
)
prev_response_id = response.id
# Handles model response's output
for output in response.output:
if output.type == "reasoning":
print("Assistant: ","Reasoning ....")
for reasoning_summary in output.summary:
print("Assistant: ",reasoning_summary)
elif output.type == "message":
for item in output.content:
print("Assistant: ",item.text)
# checks if the output type is a function call and append the function call's results to the tool results list
elif output.type == "function_call":
# obtain function name
function_name = globals().get(output.name)
# loads function arguments
args = json.loads(output.arguments)
function_response = function_name(**args)
# append tool results list with the the function call's id and performance's response
tool_results.append(
{
"type": "function_call_output",
"call_id": output.call_id,
"output": json.dumps(function_response)
}
)
If you run the code, you possibly can easily chat with the agent to ask questions that require the most recent information, akin to the present weather or the most recent product releases. The agent responds with up-to-date information together with the corresponding sources from the web. Below is a sample output from the terminal.
User: What's the weather like in London today?
Assistant: Reasoning ....
Assistant: Reasoning ....
Assistant: Right away in London: overcast, about 18°C (64°F), humidity ~88%, light SW wind ~16 km/h, no precipitation reported. Source: WeatherAPI (current conditions) — https://www.weatherapi.com/
User: What's the most recent iPhone model?
Assistant: Reasoning ....
Assistant: Reasoning ....
Assistant: The most recent iPhone models are the iPhone 17 lineup (including iPhone 17, iPhone 17 Pro, iPhone 17 Pro Max) and the brand new iPhone Air — announced by Apple on Sept 9, 2025. Source: Apple Newsroom — https://www.apple.com/newsroom/2025/09/apple-debuts-iphone-17/
User: Multiply 500 by 12.
Assistant: Reasoning ....
Assistant: 6000
User: exit
Exiting chat. Goodbye!
You possibly can see the outcomes with their corresponding web sources. If you ask it to perform a task that doesn’t require up-to-date information, akin to maths calculations or writing code the agent responds directly with none web search.
Note: The net search agent is an easy, single-tool agent. Advanced agentic systems orchestrate multiple specialized tools and use efficient memory to keep up context, plan, and solve more complex tasks.
Conclusion
On this post I explained how an AI agent works and the way it extends the capabilities of a giant language model to interact with its environment, perform actions and solve tasks through using tools. I also explained function calling and the way it enables LLMs to call tools. I demonstrated the right way to create a tool schema for function calling that defines when and the way an LLM should call a tool to perform an motion. I defined an online search function using Tavily to fetch information from the net after which showed step-by-step the right way to construct an online search agent using function calling and GPT-5-mini because the LLM. In the long run, we built an online search agent able to retrieving up-to-date information from the web to reply user queries.
Take a look at my GitHub repo, where I even have published more courses on various Generative AI topics. It also features a guide on constructing an Agentic RAG using function calling.
Reach out to me via:
Email: [email protected]
Linkedin: https://www.linkedin.com/in/ayoola-olafenwa-003b901a9/
References
https://platform.openai.com/docs/guides/function-calling?api-mode=responses
https://docs.tavily.com/documentation/api-reference/endpoint/search