ai-agents-for-beginners

Hvordan man designer gode AI-agenter

(Klik på billedet ovenfor for at se videoen til denne lektion)

Mønster for brug af værktøjer

Værktøjer er interessante, fordi de giver AI-agenter en bredere vifte af muligheder. I stedet for at agenten har et begrænset sæt handlinger, den kan udføre, kan agenten nu udføre en bred vifte af handlinger ved at tilføje et værktøj. I dette kapitel vil vi se nærmere på mønsteret for brug af værktøjer, som beskriver, hvordan AI-agenter kan bruge specifikke værktøjer til at nå deres mål.

Introduktion

I denne lektion vil vi besvare følgende spørgsmål:

Læringsmål

Efter at have gennemført denne lektion vil du kunne:

Hvad er mønsteret for brug af værktøjer?

Mønstret for brug af værktøjer fokuserer på at give LLM’er mulighed for at interagere med eksterne værktøjer for at opnå specifikke mål. Værktøjer er kode, der kan udføres af en agent for at udføre handlinger. Et værktøj kan være en simpel funktion som en lommeregner eller et API-kald til en tredjepartstjeneste som aktiekursopslag eller vejrudsigt. I forbindelse med AI-agenter er værktøjer designet til at blive udført af agenter som svar på modelgenererede funktionskald.

Hvilke anvendelsestilfælde kan det anvendes på?

AI-agenter kan udnytte værktøjer til at udføre komplekse opgaver, hente information eller træffe beslutninger. Mønstret for brug af værktøjer anvendes ofte i scenarier, der kræver dynamisk interaktion med eksterne systemer som databaser, webtjenester eller kodefortolkere. Denne evne er nyttig for flere forskellige anvendelsestilfælde, herunder:

Hvilke elementer/opbygningsblokke er nødvendige for at implementere mønsteret for brug af værktøjer?

Disse opbygningsblokke tillader AI-agenten at udføre en bred vifte af opgaver. Lad os se på nøgleelementerne, der er nødvendige for at implementere mønsteret for brug af værktøjer:

Lad os nu se nærmere på Funktions-/værktøjskald.

Funktions-/værktøjskald

Funktionskald er den primære måde, hvorpå vi gør det muligt for store sprogmodeller (LLM’er) at interagere med værktøjer. Man vil ofte se ‘Funktion’ og ‘Værktøj’ brugt i flæng, fordi ‘funktioner’ (blokke af genanvendelig kode) er de ‘værktøjer’, agenter bruger til at udføre opgaver. For at en funktions kode kan påkaldes, skal LLM’en sammenligne brugerens anmodning med funktionens beskrivelse. Til dette sendes et skema indeholdende beskrivelser af alle tilgængelige funktioner til LLM’en. LLM’en vælger så den mest passende funktion til opgaven og returnerer dens navn og argumenter. Den valgte funktion påkaldes, og dens svar sendes tilbage til LLM’en, som bruger informationen til at svare på brugerens anmodning.

For at udviklere kan implementere funktionskald for agenter, skal følgende være på plads:

  1. En LLM-model, der understøtter funktionskald
  2. Et skema indeholdende funktionsbeskrivelser
  3. Koden til hver beskrevet funktion

Lad os bruge eksemplet med at hente det aktuelle klokkeslæt i en by som illustration:

  1. Initier en LLM, der understøtter funktionskald:

    Ikke alle modeller understøtter funktionskald, så det er vigtigt at tjekke, at den LLM, du bruger, gør det. Azure OpenAI understøtter funktionskald. Vi kan starte med at initialisere Azure OpenAI klienten.

     # Initialiser Azure OpenAI-klienten
     client = AzureOpenAI(
         azure_endpoint = os.getenv("AZURE_AI_PROJECT_ENDPOINT"), 
         api_key=os.getenv("AZURE_OPENAI_API_KEY"),  
         api_version="2024-05-01-preview"
     )
    
  2. Opret et funktionsskema:

    Dernæst definerer vi et JSON-skema, der indeholder funktionsnavnet, beskrivelse af hvad funktionen gør, samt navne og beskrivelser af funktionsparametrene. Vi sender så dette skema til klienten, som vi tidligere oprettede, sammen med brugerens anmodning om at finde tiden i San Francisco. Det vigtige at bemærke er, at et værktøjskald er det, der returneres, ikke det endelige svar på spørgsmålet. Som nævnt tidligere returnerer LLM navnet på den funktion, den har valgt til opgaven, og argumenterne, der skal sendes til den.

     # Funktionsbeskrivelse til modellen at læse
     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"],
                 },
             }
         }
     ]
    
      
     # Indledende brugermeddelelse
     messages = [{"role": "user", "content": "What's the current time in San Francisco"}] 
      
     # Første API-opkald: Bed modellen om at bruge funktionen
       response = client.chat.completions.create(
           model=deployment_name,
           messages=messages,
           tools=tools,
           tool_choice="auto",
       )
      
       # Behandl modellens svar
       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. Funktionskoden, der kræves for at udføre opgaven:

    Nu hvor LLM’en har valgt, hvilken funktion der skal køres, skal koden, der udfører opgaven, implementeres og eksekveres. Vi kan implementere koden til at hente det aktuelle klokkeslæt i Python. Vi skal også skrive koden til at udtrække navn og argumenter fra response_message for at få det endelige resultat.

       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"})
    
      # Håndter funktionskald
       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.")  
      
       # Andet API-kald: Få det endelige svar fra modellen
       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.
    

Funktionskald er kerneelementet i de fleste, hvis ikke alle agentværktøjsbrugsmønstre, men det kan nogle gange være udfordrende at implementere fra bunden.
Som vi lærte i Lektion 2 leverer agentiske rammer præbyggede opbygningsblokke til implementering af værktøjsbrug.

Eksempler på brug af værktøjer med agentiske rammer

Her er nogle eksempler på, hvordan du kan implementere mønsteret for brug af værktøjer ved hjælp af forskellige agentiske rammer:

Microsoft Agent Framework

Microsoft Agent Framework er en open source AI-ramme til opbygning af AI-agenter. Det forenkler processen med funktionskald ved at give dig mulighed for at definere værktøjer som Python-funktioner med @tool-dekorationen. Frameworket håndterer kommunikationen frem og tilbage mellem modellen og din kode. Det giver også adgang til forudbyggede værktøjer som fil- og kodefortolkning gennem AzureAIProjectAgentProvider.

Følgende diagram illustrerer processen ved funktionskald med Microsoft Agent Framework:

function calling

I Microsoft Agent Framework defineres værktøjer som dekorerede funktioner. Vi kan konvertere get_current_time-funktionen, vi så tidligere, til et værktøj ved at bruge @tool-dekorationen. Frameworket vil automatisk serialisere funktionen og dens parametre, hvilket skaber det skema, der sendes til LLM’en.

from agent_framework import tool
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity import AzureCliCredential

@tool
def get_current_time(location: str) -> str:
    """Get the current time for a given location"""
    ...

# Opret klienten
provider = AzureAIProjectAgentProvider(credential=AzureCliCredential())

# Opret en agent og kør med værktøjet
agent = await provider.create_agent(name="TimeAgent", instructions="Use available tools to answer questions.", tools=get_current_time)
response = await agent.run("What time is it?")

Azure AI Agent Service

Azure AI Agent Service er en nyere agentisk ramme, der er designet til at give udviklere mulighed for sikkert at opbygge, implementere og skalere AI-agenter af høj kvalitet og med udvidelsesmuligheder uden at skulle håndtere de underliggende compute- og lagringsressourcer. Det er særligt nyttigt for enterprise-applikationer, da det er en fuldt administreret tjeneste med enterprise-sikkerhed i topklasse.

Sammenlignet med direkte udvikling med LLM API, giver Azure AI Agent Service flere fordele, herunder:

Værktøjerne i Azure AI Agent Service kan opdeles i to kategorier:

  1. Vidensværktøjer:
  2. Handlingsværktøjer:

Agent Service giver os mulighed for at bruge disse værktøjer sammen som et værktøjssæt. Det benytter også tråde, der holder styr på historikken af beskeder fra en bestemt samtale.

Forestil dig, at du er en salgsagent hos et firma, der hedder Contoso. Du ønsker at udvikle en samtaleagent, der kan besvare spørgsmål om dine salgsdata.

Følgende billede illustrerer, hvordan du kan bruge Azure AI Agent Service til at analysere dine salgsdata:

Agentic Service In Action

For at bruge nogle af disse værktøjer med tjenesten kan vi oprette en klient og definere et værktøj eller et værktøjssæt. For at implementere dette praktisk kan vi bruge følgende Python-kode. LLM’en vil kunne se på værktøjssættet og beslutte, om den skal bruge den brugeroprettede funktion, fetch_sales_data_using_sqlite_query, eller den forudbyggede Kodefortolker afhængigt af brugerens anmodning.

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 funktion, som kan findes i en fetch_sales_data_functions.py fil.
from azure.ai.projects.models import ToolSet, FunctionTool, CodeInterpreterTool

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

# Initialiser værktøjssæt
toolset = ToolSet()

# Initialiser funktion kaldende agent med fetch_sales_data_using_sqlite_query funktionen og tilføj den til værktøjssættet
fetch_data_function = FunctionTool(fetch_sales_data_using_sqlite_query)
toolset.add(fetch_data_function)

# Initialiser Code Interpreter værktøj og tilføj det til værktøjssættet.
code_interpreter = code_interpreter = CodeInterpreterTool()
toolset.add(code_interpreter)

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

Hvilke særlige overvejelser er der ved brug af mønsteret for brug af værktøjer til at opbygge pålidelige AI-agenter?

En almindelig bekymring ved SQL dynamisk genereret af LLM’er er sikkerhed, især risikoen for SQL-injektion eller ondsindede handlinger som at slette eller manipulere databasen. Selvom disse bekymringer er gyldige, kan de effektivt afbødes ved korrekt konfiguration af databaseadgangstilladelser. For de fleste databaser indebærer det at konfigurere databasen som skrivebeskyttet. For databaser som PostgreSQL eller Azure SQL bør appen tildeles en skrivebeskyttet (SELECT) rolle.

At køre appen i et sikkert miljø øger yderligere beskyttelsen. I enterprise-scenarier bliver data typisk udtrukket og transformeret fra operationelle systemer til en skrivebeskyttet database eller datalager med et brugervenligt skema. Denne tilgang sikrer, at dataene er sikre, optimeret til ydeevne og tilgængelighed, og at appen har begrænset, skrivebeskyttet adgang.

Eksempelkoder

Har du flere spørgsmål om mønstrene for brug af værktøjer?

Deltag i Microsoft Foundry Discord for at møde andre lærende, deltage i kontortimer og få svar på dine spørgsmål om AI-agenter.

Yderligere ressourcer

Forrige lektion

Forstå agentiske designmønstre

Næste lektion

Agentic RAG


Ansvarsfraskrivelse: Dette dokument er blevet oversat ved hjælp af AI-oversættelsestjenesten Co-op Translator. Selvom vi bestræber os på nøjagtighed, bedes du være opmærksom på, at automatiserede oversættelser kan indeholde fejl eller unøjagtigheder. Det oprindelige dokument på originalsproget bør betragtes som den autoritative kilde. For kritiske oplysninger anbefales professionel menneskelig oversættelse. Vi påtager os intet ansvar for misforståelser eller misfortolkninger, der opstår som følge af brugen af denne oversættelse.