ai-agents-for-beginners

How to Design Good AI Agents

(Click di image wey dey up to watch di video for dis lesson)

Tool Use Design Pattern

Tools dey interesting because dem dey allow AI agents fit do plenty things. Instead make di agent get only small actions wey e fit perform, if you add tool, di agent go fit perform plenty actions. For dis chapter, we go look di Tool Use Design Pattern, wey dey explain how AI agents fit use specific tools to achieve wetin dem wan do.

Introduction

For dis lesson, we wan answer di following questions:

Learning Goals

After you finish dis lesson, you go fit:

Wetin be Tool Use Design Pattern?

Di Tool Use Design Pattern dey focus on how LLMs fit interact with external tools to achieve specific goals. Tools na code wey agent fit run to perform actions. Tool fit be simple function like calculator, or API call to third-party service like stock price lookup or weather forecast. For AI agents, tools dey designed make agents fit run dem when dem need am based on model-generated function calls.

Wetin be di use cases wey e fit work for?

AI Agents fit use tools to complete hard tasks, find information, or make decisions. Tool use design pattern dey useful for situations wey need dynamic interaction with external systems like databases, web services, or code interpreters. E dey useful for plenty use cases like:

Wetin be di elements/building blocks wey we need to implement di tool use design pattern?

Dis building blocks dey help AI agent perform plenty tasks. Make we look di key elements wey we need to implement di Tool Use Design Pattern:

Next, make we look Function/Tool Calling well.

Function/Tool Calling

Function calling na di main way we dey make Large Language Models (LLMs) interact with tools. You go often see ‘Function’ and ‘Tool’ dey used interchangeably because ‘functions’ (blocks of reusable code) na di ‘tools’ wey agents dey use to do tasks. For function code to run, LLM go compare wetin di user ask with di function description. To do dis, schema wey get di descriptions of all di available functions go dey sent to di LLM. Di LLM go then choose di function wey fit di task and return di name and arguments. Di selected function go run, e response go go back to di LLM, wey go use di information to answer di user.

For developers to implement function calling for agents, you go need:

  1. LLM model wey support function calling
  2. Schema wey get function descriptions
  3. Di code for each function wey dem describe

Make we use example of getting di current time for one city to explain:

  1. Initialize LLM wey support function calling:

    No be all models dey support function calling, so e dey important to check say di LLM wey you dey use dey support am. Azure OpenAI dey support function calling. We fit start by initiating di Azure OpenAI client.

     # Initialize the Azure OpenAI client
     client = AzureOpenAI(
         azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT"), 
         api_key=os.getenv("AZURE_OPENAI_API_KEY"),  
         api_version="2024-05-01-preview"
     )
    
  2. Create Function Schema:

    Next, we go define JSON schema wey get di function name, description of wetin di function dey do, and di names plus descriptions of di function parameters. We go then take dis schema pass am to di client wey we create before, plus di user request to find di time for San Francisco. Wetin dey important na say wetin dey returned na tool call, no be di final answer to di question. As we talk before, di LLM go return di name of di function wey e choose for di task, and di arguments wey go dey passed to am.

     # Function description for the model to read
     tools = [
         {
             "type": "function",
             "function": {
                 "name": "get_current_time",
                 "description": "Get the current time in a given location",
                 "parameters": {
                     "type": "object",
                     "properties": {
                         "location": {
                             "type": "string",
                             "description": "The city name, e.g. San Francisco",
                         },
                     },
                     "required": ["location"],
                 },
             }
         }
     ]
    
      
     # Initial user message
     messages = [{"role": "user", "content": "What's the current time in San Francisco"}] 
      
     # First API call: Ask the model to use the function
       response = client.chat.completions.create(
           model=deployment_name,
           messages=messages,
           tools=tools,
           tool_choice="auto",
       )
      
       # Process the model's response
       response_message = response.choices[0].message
       messages.append(response_message)
      
       print("Model's response:")  
    
       print(response_message)
      
    
     Model's response:
     ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_pOsKdUlqvdyttYB67MOj434b', function=Function(arguments='{"location":"San Francisco"}', name='get_current_time'), type='function')])
    
  3. Di function code wey go do di task:

    Now wey di LLM don choose di function wey need to run, di code wey go do di task go need to dey implemented and executed. We fit write di code to get di current time for Python. We go also need write di code to extract di name and arguments from di response_message to get di final result.

       def get_current_time(location):
         """Get the current time for a given location"""
         print(f"get_current_time called with location: {location}")  
         location_lower = location.lower()
            
         for key, timezone in TIMEZONE_DATA.items():
             if key in location_lower:
                 print(f"Timezone found for {key}")  
                 current_time = datetime.now(ZoneInfo(timezone)).strftime("%I:%M %p")
                 return json.dumps({
                     "location": location,
                     "current_time": current_time
                 })
          
         print(f"No timezone data found for {location_lower}")  
         return json.dumps({"location": location, "current_time": "unknown"})
    
      # Handle function calls
       if response_message.tool_calls:
           for tool_call in response_message.tool_calls:
               if tool_call.function.name == "get_current_time":
         
                   function_args = json.loads(tool_call.function.arguments)
         
                   time_response = get_current_time(
                       location=function_args.get("location")
                   )
         
                   messages.append({
                       "tool_call_id": tool_call.id,
                       "role": "tool",
                       "name": "get_current_time",
                       "content": time_response,
                   })
       else:
           print("No tool calls were made by the model.")  
      
       # Second API call: Get the final response from the model
       final_response = client.chat.completions.create(
           model=deployment_name,
           messages=messages,
       )
      
       return final_response.choices[0].message.content
    
       get_current_time called with location: San Francisco
       Timezone found for san francisco
       The current time in San Francisco is 09:24 AM.
    

Function Calling na di main thing for most agent tool use design, but to implement am from scratch fit dey hard sometimes. As we learn for Lesson 2 agentic frameworks dey give us pre-built building blocks to implement tool use.

Tool Use Examples with Agentic Frameworks

Here be some examples of how you fit implement di Tool Use Design Pattern using different agentic frameworks:

Semantic Kernel

Semantic Kernel na open-source AI framework for .NET, Python, and Java developers wey dey work with Large Language Models (LLMs). E dey make di process of using function calling easy by automatically describing your functions and their parameters to di model through one process wey dem dey call serializing. E dey also handle di back-and-forth communication between di model and your code. Another advantage of using agentic framework like Semantic Kernel na say e dey allow you access pre-built tools like File Search and Code Interpreter.

Di diagram wey dey below dey show di process of function calling with Semantic Kernel:

function calling

For Semantic Kernel, functions/tools dey called Plugins. We fit turn di get_current_time function wey we see before into plugin by turning am into class wey get di function inside. We fit also import di kernel_function decorator, wey dey take di description of di function. When you create kernel with di GetCurrentTimePlugin, di kernel go automatically serialize di function and its parameters, creating di schema to send to di LLM for di process.

from semantic_kernel.functions import kernel_function

class GetCurrentTimePlugin:
    async def __init__(self, location):
        self.location = location

    @kernel_function(
        description="Get the current time for a given location"
    )
    def get_current_time(location: str = ""):
        ...

from semantic_kernel import Kernel

# Create the kernel
kernel = Kernel()

# Create the plugin
get_current_time_plugin = GetCurrentTimePlugin(location)

# Add the plugin to the kernel
kernel.add_plugin(get_current_time_plugin)

Azure AI Agent Service

Azure AI Agent Service na new agentic framework wey dey designed to help developers build, deploy, and scale high-quality, and extensible AI agents without needing to manage di underlying compute and storage resources. E dey useful for enterprise applications because e na fully managed service with enterprise grade security.

When you compare am to developing with di LLM API directly, Azure AI Agent Service dey give some advantages, like:

Di tools wey dey available for Azure AI Agent Service fit dey divided into two categories:

  1. Knowledge Tools:
  2. Action Tools:

Di Agent Service dey allow us use all dis tools together as toolset. E dey also use threads wey dey keep track of di history of messages from one particular conversation.

Imagine say you be sales agent for one company wey dem call Contoso. You wan develop one conversational agent wey fit answer questions about your sales data.

Di image wey dey below dey show how you fit use Azure AI Agent Service to analyze your sales data:

Agentic Service In Action

To use any of dis tools with di service, we fit create client and define tool or toolset. To implement dis practically, we fit use di Python code wey dey below. Di LLM go fit look di toolset and decide whether to use di user-created function, fetch_sales_data_using_sqlite_query, or di pre-built Code Interpreter based on wetin di user ask.

import os
from azure.ai.projects import AIProjectClient
from azure.identity import DefaultAzureCredential
from fetch_sales_data_functions import fetch_sales_data_using_sqlite_query # fetch_sales_data_using_sqlite_query function which can be found in a fetch_sales_data_functions.py file.
from azure.ai.projects.models import ToolSet, FunctionTool, CodeInterpreterTool

project_client = AIProjectClient.from_connection_string(
    credential=DefaultAzureCredential(),
    conn_str=os.environ["PROJECT_CONNECTION_STRING"],
)

# Initialize function calling agent with the fetch_sales_data_using_sqlite_query function and adding it to the toolset
fetch_data_function = FunctionTool(fetch_sales_data_using_sqlite_query)
toolset = ToolSet()
toolset.add(fetch_data_function)

# Initialize Code Interpreter tool and adding it to the toolset. 
code_interpreter = code_interpreter = CodeInterpreterTool()
toolset = ToolSet()
toolset.add(code_interpreter)

agent = project_client.agents.create_agent(
    model="gpt-4o-mini", name="my-agent", instructions="You are helpful agent", 
    toolset=toolset
)

Wetin be di special things we need to think about when we dey use Tool Use Design Pattern to build AI agents wey people go trust?

One common concern with SQL wey LLMs dey generate dynamically na security, especially di risk of SQL injection or bad actions, like dropping or tampering with di database. Even though dis concern dey valid, e fit dey managed well if we configure di database access permissions properly. For most databases, dis go mean configuring di database as read-only. For database services like PostgreSQL or Azure SQL, di app go need dey assigned read-only (SELECT) role. To run di app for secure environment go make di protection strong well well. For enterprise matter, dem dey usually carry data comot from operational systems, change am small, then put am for read-only database or data warehouse wey get schema wey easy to use. Dis kind method go make sure say di data dey secure, e go dey perform well, e go easy to access, and di app go get restricted, read-only access.

You get more questions about di Tool Use Design Patterns?

Join di Azure AI Foundry Discord to meet other learners, attend office hours, and make dem answer your AI Agents questions.

Extra Resources

Previous Lesson

Understanding Agentic Design Patterns

Next Lesson

Agentic RAG


Disclaimer:
Dis dokyument don use AI transleto service Co-op Translator do di translation. Even as we dey try make am correct, abeg sabi say machine translation fit get mistake or no dey accurate well. Di original dokyument wey dey for im native language na di main source wey you go trust. For important mata, e good make professional human transleto check am. We no go fit take blame for any misunderstanding or wrong interpretation wey fit happen because you use dis translation.