ai-agents-for-beginners

Hur man designar bra AI-agenter

(Klicka på bilden ovan för att se videon av denna lektion)

Designmönster för verktygsanvändning

Verktyg är intressanta eftersom de tillåter AI-agenter att ha en bredare uppsättning möjligheter. Istället för att agenten har en begränsad mängd åtgärder den kan utföra, kan agenten nu utföra ett stort antal åtgärder genom att lägga till ett verktyg. I detta kapitel ska vi titta på designmönstret för verktygsanvändning, som beskriver hur AI-agenter kan använda specifika verktyg för att uppnå sina mål.

Introduktion

I denna lektion vill vi besvara följande frågor:

Lärandemål

Efter att ha slutfört denna lektion kommer du att kunna:

Vad är designmönstret för verktygsanvändning?

Designmönstret för verktygsanvändning fokuserar på att ge LLM:er möjligheten att interagera med externa verktyg för att nå specifika mål. Verktyg är kod som kan köras av en agent för att utföra åtgärder. Ett verktyg kan vara en enkel funktion som en räknare, eller ett API-anrop till en tredjepartstjänst som att slå upp aktiekurser eller väderprognos. I sammanhanget AI-agenter är verktyg designade för att köras av agenter som svar på modellgenererade funktionsanrop.

Vilka användningsfall kan det tillämpas på?

AI-agenter kan använda verktyg för att slutföra komplexa uppgifter, hämta information eller fatta beslut. Designmönstret för verktygsanvändning används ofta i scenarier som kräver dynamisk interaktion med externa system, såsom databaser, webbtjänster eller kodtolkare. Denna förmåga är användbar för flera olika användningsfall, bland annat:

Vilka element/byggstenar behövs för att implementera designmönstret för verktygsanvändning?

Dessa byggstenar tillåter AI-agenten att utföra en rad olika uppgifter. Låt oss titta på de viktigaste elementen som behövs för att implementera designmönstret för verktygsanvändning:

Nästa steg är att titta närmare på funktions- och verktygsanrop.

Funktions-/Verktygsanrop

Funktionsanrop är det primära sättet vi gör det möjligt för stora språkmodeller (LLM) att interagera med verktyg. Du kommer ofta att se “funktion” och “verktyg” användas synonymt eftersom “funktioner” (återanvändbara kodblock) är de “verktyg” som agenter använder för att utföra uppgifter. För att kunna anropa en funktions kod måste en LLM jämföra användarens förfrågan med funktionens beskrivning. För att göra detta skickas ett schema som innehåller beskrivningarna av alla tillgängliga funktioner till LLM:n. LLM väljer sedan den mest lämpliga funktionen för uppgiften och returnerar dess namn och argument. Den valda funktionen anropas, dess svar skickas tillbaka till LLM:n som använder informationen för att svara på användarens fråga.

För utvecklare som vill implementera funktionsanrop för agenter krävs:

  1. En LLM-modell som stöder funktionsanrop
  2. Ett schema som innehåller funktionsbeskrivningar
  3. Koden för varje beskrivna funktion

Låt oss använda exemplet att ta reda på aktuell tid i en stad för att illustrera:

  1. Initiera en LLM som stöder funktionsanrop:

    Inte alla modeller stödjer funktionsanrop, så det är viktigt att kontrollera att den LLM du använder gör det. Azure OpenAI stöder funktionsanrop. Vi kan börja med att initiera Azure OpenAI-klienten.

     # Initiera 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. Skapa ett funktionsschema:

    Nästa steg är att definiera ett JSON-schema som innehåller funktionsnamnet, beskrivningen av vad funktionen gör och namnen och beskrivningarna av funktionsparametrarna. Vi skickar sedan detta schema till klienten som vi skapade tidigare, tillsammans med användarens förfrågan att ta reda på tiden i San Francisco. Det viktiga att notera är att det som returneras är ett verktygsanrop, inte det slutgiltiga svaret på frågan. Som nämnts tidigare returnerar LLM namnet på den funktion den valt för uppgiften och argumenten som ska skickas till den.

     # Funktionsbeskrivning för modellen att läsa
     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"],
                 },
             }
         }
     ]
    
      
     # Inledande användarmeddelande
     messages = [{"role": "user", "content": "What's the current time in San Francisco"}] 
      
     # Första API-anropet: Be modellen använda funktionen
       response = client.chat.completions.create(
           model=deployment_name,
           messages=messages,
           tools=tools,
           tool_choice="auto",
       )
      
       # Bearbeta 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 som krävs för att utföra uppgiften:

    Nu när LLM har valt vilken funktion som måste köras behöver koden som utför uppgiften implementeras och köras. Vi kan implementera koden för att hämta aktuell tid i Python. Vi behöver också skriva koden för att extrahera namn och argument från response_message för att få det slutgiltiga resultatet.

       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"})
    
      # Hantera funktionsanrop
       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.")  
      
       # Andra API-anropet: Hämta det slutgiltiga svaret från 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.
    

Funktionsanrop är kärnan i de flesta, om inte alla, agenters verktygsanvändningsdesign men att implementera det från grunden kan ibland vara utmanande. Som vi lärde oss i Lektion 2 erbjuder agentbaserade ramverk oss förbyggda byggstenar för att implementera verktygsanvändning.

Exempel på verktygsanvändning med agentbaserade ramverk

Här är några exempel på hur du kan implementera designmönstret för verktygsanvändning med olika agentbaserade ramverk:

Microsoft Agent Framework

Microsoft Agent Framework är ett open source-ramverk för att bygga AI-agenter. Det förenklar processen med funktionsanrop genom att låta dig definiera verktyg som Python-funktioner med @tool-dekorationen. Ramverket hanterar kommunikationen fram och tillbaka mellan modellen och din kod. Det erbjuder också tillgång till förbyggda verktyg som Fil-sökning och Kodtolkare via AzureAIProjectAgentProvider.

Följande diagram illustrerar processen för funktionsanrop med Microsoft Agent Framework:

funktionsanrop

I Microsoft Agent Framework definieras verktyg som dekorerade funktioner. Vi kan konvertera funktionen get_current_time som vi såg tidigare till ett verktyg genom att använda @tool-dekorationen. Ramverket serialiserar automatiskt funktionen och dess parametrar, och skapar schemat som skickas till LLM.

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"""
    ...

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

# Skapa en agent och kör med verktyget
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 är ett nyare agentbaserat ramverk designat för att ge utvecklare möjlighet att säkert bygga, distribuera och skala högkvalitativa och utbyggbara AI-agenter utan att behöva hantera underliggande dator- och lagringsresurser. Det är särskilt användbart för företagsapplikationer eftersom det är en helt hanterad tjänst med företagsklassad säkerhet.

Jämfört med att utveckla direkt med LLM API erbjuder Azure AI Agent Service vissa fördelar, inklusive:

Verktygen som finns tillgängliga i Azure AI Agent Service kan delas in i två kategorier:

  1. Kunskapsverktyg:
  2. Åtgärdsverktyg:

Agenttjänsten gör det möjligt för oss att använda dessa verktyg tillsammans som ett toolset. Den använder även threads som håller reda på historiken av meddelanden från ett särskilt samtal.

Föreställ dig att du är en säljagent på ett företag som heter Contoso. Du vill utveckla en konverserande agent som kan svara på frågor om din försäljningsdata.

Följande bild illustrerar hur du kan använda Azure AI Agent Service för att analysera din försäljningsdata:

Agenttjänsten i aktion

För att använda något av dessa verktyg med tjänsten kan vi skapa en klient och definiera ett verktyg eller verktygssats. För att praktiskt genomföra detta kan vi använda följande Python-kod. LLM:n kan titta på verktygssatsen och avgöra om den ska använda den användarskapade funktionen fetch_sales_data_using_sqlite_query eller den förbyggda Kodtolkaren, beroende på användarförfrågan.

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 hittas i filen fetch_sales_data_functions.py.
from azure.ai.projects.models import ToolSet, FunctionTool, CodeInterpreterTool

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

# Initiera verktygssats
toolset = ToolSet()

# Initiera agent för funktionsanrop med funktionen fetch_sales_data_using_sqlite_query och lägg till den i verktygssatsen
fetch_data_function = FunctionTool(fetch_sales_data_using_sqlite_query)
toolset.add(fetch_data_function)

# Initiera kodtolkningsverktyg och lägg till det i verktygssatsen.
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
)

Vilka är de särskilda övervägandena för att använda designmönstret för verktygsanvändning för att bygga pålitliga AI-agenter?

En vanlig oro med SQL som dynamiskt genereras av LLM:er är säkerhet, särskilt risken för SQL-injektion eller illvilliga åtgärder, som att ta bort eller manipulera databasen. Även om dessa farhågor är giltiga kan de effektivt mildras genom att korrekt konfigurera databastillgångsrättigheter. För de flesta databaser innebär detta att databasen konfigureras som skrivskyddad. För databastjänster som PostgreSQL eller Azure SQL bör appen tilldelas en skrivskyddad (SELECT) roll.

Att köra appen i en säker miljö förbättrar skyddet ytterligare. I företagsmiljöer extraheras och omvandlas data vanligtvis från operativa system till en skrivskyddad databas eller datalager med ett användarvänligt schema. Denna metod säkerställer att data är säker, optimerad för prestanda och tillgänglighet, samt att appen har begränsad, skrivskyddad åtkomst.

Exempelkoder

Fler frågor om designmönstren för verktygsanvändning?

Gå med i Microsoft Foundry Discord för att träffa andra som lär sig, delta i kontorstider och få svar på dina frågor om AI-agenter.

Ytterligare resurser

Föregående lektion

Förståelse för agentbaserade designmönster

Nästa lektion

Agentic RAG


Ansvarsfriskrivning: Detta dokument har översatts med hjälp av AI-översättningstjänsten Co-op Translator. Även om vi strävar efter noggrannhet, var vänlig notera att automatiska översättningar kan innehålla fel eller brister. Det ursprungliga dokumentet på dess modersmål bör betraktas som den auktoritativa källan. För kritisk information rekommenderas professionell mänsklig översättning. Vi ansvarar inte för några missförstånd eller feltolkningar som uppstår till följd av användningen av denna översättning.