Skip to content

Latest commit

 

History

History
468 lines (338 loc) · 22.7 KB

File metadata and controls

468 lines (338 loc) · 22.7 KB

Integration med funktionskald

Du har lært en del i de tidligere lektioner. Men vi kan stadig forbedre os. Noget af det, vi kan tage fat på, er, hvordan vi kan få et mere konsistent responsformat, så det bliver lettere at arbejde med svaret nedstrøms. Derudover kan vi have lyst til at tilføje data fra andre kilder for yderligere at berige vores applikation.

De ovennævnte problemer er, hvad dette kapitel søger at adressere.

Introduktion

Denne lektion vil dække:

  • Forklare, hvad funktionskald er, og dets anvendelsestilfælde.
  • Oprette et funktionskald ved hjælp af Azure OpenAI.
  • Hvordan man integrerer et funktionskald i en applikation.

Læringsmål

Ved slutningen af denne lektion vil du være i stand til at:

  • Forklare formålet med at bruge funktionskald.
  • Opsætte Funktionskald ved hjælp af Azure OpenAI Service.
  • Designe effektive funktionskald til din applikations brugstilfælde.

Scenarie: Forbedring af vores chatbot med funktioner

For denne lektion ønsker vi at bygge en funktion til vores uddannelses-startup, der giver brugerne mulighed for at bruge en chatbot til at finde tekniske kurser. Vi vil anbefale kurser, der passer til deres færdighedsniveau, nuværende rolle og interesse for teknologi.

For at fuldføre dette scenarie vil vi bruge en kombination af:

  • Azure OpenAI til at skabe en chatoplevelse for brugeren.
  • Microsoft Learn Catalog API til at hjælpe brugere med at finde kurser baseret på brugerens anmodning.
  • Function Calling til at tage brugerens forespørgsel og sende den til en funktion for at lave API-anmodningen.

For at komme i gang, lad os se på, hvorfor vi overhovedet vil bruge funktionskald:

Hvorfor Funktionskald

Før funktionskald var svar fra en LLM ustrukturerede og inkonsistente. Udviklere var nødt til at skrive kompleks valideringskode for at sikre, at de kunne håndtere hver variation af et svar. Brugere kunne ikke få svar som "Hvad er det nuværende vejr i Stockholm?". Dette skyldes, at modeller var begrænset til den tid, dataene blev trænet på.

Funktionskald er en funktion i Azure OpenAI Service til at overvinde følgende begrænsninger:

  • Konsistent responsformat. Hvis vi bedre kan kontrollere responsformatet, kan vi lettere integrere svaret nedstrøms til andre systemer.
  • Eksterne data. Mulighed for at bruge data fra andre kilder i en applikation i en chatkontekst.

Illustrere problemet gennem et scenarie

Vi anbefaler, at du bruger den medfølgende notebook, hvis du vil køre nedenstående scenarie. Du kan også blot læse med, da vi forsøger at illustrere et problem, hvor funktioner kan hjælpe med at adressere problemet.

Lad os se på eksemplet, der illustrerer problemet med responsformat:

Lad os sige, at vi ønsker at oprette en database over studentdata, så vi kan foreslå det rigtige kursus til dem. Nedenfor har vi to beskrivelser af studerende, der er meget ens i de data, de indeholder.

  1. Opret en forbindelse til vores Azure OpenAI-ressource:

    import os
    import json
    from openai import AzureOpenAI
    from dotenv import load_dotenv
    load_dotenv()
    
    client = AzureOpenAI(
    api_key=os.environ['AZURE_OPENAI_API_KEY'],  # this is also the default, it can be omitted
    api_version = "2023-07-01-preview"
    )
    
    deployment=os.environ['AZURE_OPENAI_DEPLOYMENT']

    Nedenfor er noget Python-kode til at konfigurere vores forbindelse til Azure OpenAI, hvor vi indstiller api_type, api_base, api_version and api_key.

  2. Creating two student descriptions using variables student_1_description and student_2_description.

    student_1_description="Emily Johnson is a sophomore majoring in computer science at Duke University. She has a 3.7 GPA. Emily is an active member of the university's Chess Club and Debate Team. She hopes to pursue a career in software engineering after graduating."
    
    student_2_description = "Michael Lee is a sophomore majoring in computer science at Stanford University. He has a 3.8 GPA. Michael is known for his programming skills and is an active member of the university's Robotics Club. He hopes to pursue a career in artificial intelligence after finishing his studies."

    Vi ønsker at sende de ovenstående studenterbeskrivelser til en LLM for at analysere dataene. Disse data kan senere bruges i vores applikation og sendes til en API eller gemmes i en database.

  3. Lad os oprette to identiske prompts, hvor vi instruerer LLM om, hvilke oplysninger vi er interesserede i:

    prompt1 = f'''
    Please extract the following information from the given text and return it as a JSON object:
    
    name
    major
    school
    grades
    club
    
    This is the body of text to extract the information from:
    {student_1_description}
    '''
    
    prompt2 = f'''
    Please extract the following information from the given text and return it as a JSON object:
    
    name
    major
    school
    grades
    club
    
    This is the body of text to extract the information from:
    {student_2_description}
    '''

    De ovenstående prompts instruerer LLM om at udtrække oplysninger og returnere svaret i JSON-format.

  4. Efter opsætning af prompts og forbindelsen til Azure OpenAI vil vi nu sende prompts til LLM ved hjælp af openai.ChatCompletion. We store the prompt in the messages variable and assign the role to user. Dette er for at efterligne en besked fra en bruger, der skrives til en chatbot.

    # response from prompt one
    openai_response1 = client.chat.completions.create(
    model=deployment,
    messages = [{'role': 'user', 'content': prompt1}]
    )
    openai_response1.choices[0].message.content
    
    # response from prompt two
    openai_response2 = client.chat.completions.create(
    model=deployment,
    messages = [{'role': 'user', 'content': prompt2}]
    )
    openai_response2.choices[0].message.content

Nu kan vi sende begge anmodninger til LLM og undersøge det svar, vi modtager ved at finde det sådan openai_response1['choices'][0]['message']['content'].

  1. Lastly, we can convert the response to JSON format by calling json.loads:

    # Loading the response as a JSON object
    json_response1 = json.loads(openai_response1.choices[0].message.content)
    json_response1

    Svar 1:

    {
      "name": "Emily Johnson",
      "major": "computer science",
      "school": "Duke University",
      "grades": "3.7",
      "club": "Chess Club"
    }

    Svar 2:

    {
      "name": "Michael Lee",
      "major": "computer science",
      "school": "Stanford University",
      "grades": "3.8 GPA",
      "club": "Robotics Club"
    }

    Selvom prompts er de samme, og beskrivelserne er ens, ser vi værdierne af Grades property formatted differently, as we can sometimes get the format 3.7 or 3.7 GPA for example.

    This result is because the LLM takes unstructured data in the form of the written prompt and returns also unstructured data. We need to have a structured format so that we know what to expect when storing or using this data

So how do we solve the formatting problem then? By using functional calling, we can make sure that we receive structured data back. When using function calling, the LLM does not actually call or run any functions. Instead, we create a structure for the LLM to follow for its responses. We then use those structured responses to know what function to run in our applications.

function flow

We can then take what is returned from the function and send this back to the LLM. The LLM will then respond using natural language to answer the user's query.

Use Cases for using function calls

There are many different use cases where function calls can improve your app like:

  • Calling External Tools. Chatbots are great at providing answers to questions from users. By using function calling, the chatbots can use messages from users to complete certain tasks. For example, a student can ask the chatbot to "Send an email to my instructor saying I need more assistance with this subject". This can make a function call to send_email(to: string, body: string)

  • Create API or Database Queries. Users can find information using natural language that gets converted into a formatted query or API request. An example of this could be a teacher who requests "Who are the students that completed the last assignment" which could call a function named get_completed(student_name: string, assignment: int, current_status: string)

  • Creating Structured Data. Users can take a block of text or CSV and use the LLM to extract important information from it. For example, a student can convert a Wikipedia article about peace agreements to create AI flashcards. This can be done by using a function called get_important_facts(agreement_name: string, date_signed: string, parties_involved: list)

Creating Your First Function Call

The process of creating a function call includes 3 main steps:

  1. Calling the Chat Completions API with a list of your functions and a user message.
  2. Reading the model's response to perform an action i.e. execute a function or API Call.
  3. Making another call to Chat Completions API with the response from your function to use that information to create a response to the user.

LLM Flow

Step 1 - creating messages

The first step is to create a user message. This can be dynamically assigned by taking the value of a text input or you can assign a value here. If this is your first time working with the Chat Completions API, we need to define the role and the content of the message.

The role can be either system (creating rules), assistant (the model) or user (the end-user). For function calling, we will assign this as user og et eksempelspørgsmål.

messages= [ {"role": "user", "content": "Find me a good course for a beginner student to learn Azure."} ]

Ved at tildele forskellige roller bliver det klart for LLM, om det er systemet, der siger noget, eller brugeren, hvilket hjælper med at opbygge en samtalehistorik, som LLM kan bygge videre på.

Trin 2 - oprette funktioner

Derefter vil vi definere en funktion og parametrene for den funktion. Vi vil kun bruge en funktion her kaldet search_courses but you can create multiple functions.

Important : Functions are included in the system message to the LLM and will be included in the amount of available tokens you have available.

Below, we create the functions as an array of items. Each item is a function and has properties name, description and parameters:

functions = [
   {
      "name":"search_courses",
      "description":"Retrieves courses from the search index based on the parameters provided",
      "parameters":{
         "type":"object",
         "properties":{
            "role":{
               "type":"string",
               "description":"The role of the learner (i.e. developer, data scientist, student, etc.)"
            },
            "product":{
               "type":"string",
               "description":"The product that the lesson is covering (i.e. Azure, Power BI, etc.)"
            },
            "level":{
               "type":"string",
               "description":"The level of experience the learner has prior to taking the course (i.e. beginner, intermediate, advanced)"
            }
         },
         "required":[
            "role"
         ]
      }
   }
]

Lad os beskrive hver funktionseksempel mere detaljeret nedenfor:

  • name - The name of the function that we want to have called.
  • description - This is the description of how the function works. Here it's important to be specific and clear.
  • parameters - A list of values and format that you want the model to produce in its response. The parameters array consists of items where the items have the following properties:
    1. type - The data type of the properties will be stored in.
    2. properties - List of the specific values that the model will use for its response
      1. name - The key is the name of the property that the model will use in its formatted response, for example, product.
      2. type - The data type of this property, for example, string.
      3. description - Description of the specific property.

There's also an optional property required - required property for the function call to be completed.

Step 3 - Making the function call

After defining a function, we now need to include it in the call to the Chat Completion API. We do this by adding functions to the request. In this case functions=functions.

There is also an option to set function_call to auto. This means we will let the LLM decide which function should be called based on the user message rather than assigning it ourselves.

Here's some code below where we call ChatCompletion.create, note how we set functions=functions and function_call="auto" og dermed give LLM valget om, hvornår de skal kalde de funktioner, vi giver det:

response = client.chat.completions.create(model=deployment,
                                        messages=messages,
                                        functions=functions,
                                        function_call="auto")

print(response.choices[0].message)

Svaret, der kommer tilbage, ser nu sådan ud:

{
  "role": "assistant",
  "function_call": {
    "name": "search_courses",
    "arguments": "{\n  \"role\": \"student\",\n  \"product\": \"Azure\",\n  \"level\": \"beginner\"\n}"
  }
}

Her kan vi se, hvordan funktionen search_courses was called and with what arguments, as listed in the arguments property in the JSON response.

The conclusion the LLM was able to find the data to fit the arguments of the function as it was extracting it from the value provided to the messages parameter in the chat completion call. Below is a reminder of the messages værdi:

messages= [ {"role": "user", "content": "Find me a good course for a beginner student to learn Azure."} ]

Som du kan se, student, Azure and beginner was extracted from messages and set as input to the function. Using functions this way is a great way to extract information from a prompt but also to provide structure to the LLM and have reusable functionality.

Next, we need to see how we can use this in our app.

Integrating Function Calls into an Application

After we have tested the formatted response from the LLM, we can now integrate this into an application.

Managing the flow

To integrate this into our application, let's take the following steps:

  1. First, let's make the call to the OpenAI services and store the message in a variable called response_message.

    response_message = response.choices[0].message
  2. Nu vil vi definere den funktion, der vil kalde Microsoft Learn API for at få en liste over kurser:

    import requests
    
    def search_courses(role, product, level):
      url = "https://learn.microsoft.com/api/catalog/"
      params = {
         "role": role,
         "product": product,
         "level": level
      }
      response = requests.get(url, params=params)
      modules = response.json()["modules"]
      results = []
      for module in modules[:5]:
         title = module["title"]
         url = module["url"]
         results.append({"title": title, "url": url})
      return str(results)

    Bemærk, hvordan vi nu opretter en faktisk Python-funktion, der kortlægger de funktionsnavne, der blev introduceret i functions variable. We're also making real external API calls to fetch the data we need. In this case, we go against the Microsoft Learn API to search for training modules.

Ok, so we created functions variables and a corresponding Python function, how do we tell the LLM how to map these two together so our Python function is called?

  1. To see if we need to call a Python function, we need to look into the LLM response and see if function_call, er en del af det og kalder den påpegede funktion. Her er, hvordan du kan lave den nævnte kontrol nedenfor:

    # Check if the model wants to call a function
    if response_message.function_call.name:
     print("Recommended Function call:")
     print(response_message.function_call.name)
     print()
    
     # Call the function.
     function_name = response_message.function_call.name
    
     available_functions = {
             "search_courses": search_courses,
     }
     function_to_call = available_functions[function_name]
    
     function_args = json.loads(response_message.function_call.arguments)
     function_response = function_to_call(**function_args)
    
     print("Output of function call:")
     print(function_response)
     print(type(function_response))
    
    
     # Add the assistant response and function response to the messages
     messages.append( # adding assistant response to messages
         {
             "role": response_message.role,
             "function_call": {
                 "name": function_name,
                 "arguments": response_message.function_call.arguments,
             },
             "content": None
         }
     )
     messages.append( # adding function response to messages
         {
             "role": "function",
             "name": function_name,
             "content":function_response,
         }
     )

    Disse tre linjer sikrer, at vi udtrækker funktionsnavnet, argumenterne og foretager kaldet:

    function_to_call = available_functions[function_name]
    
    function_args = json.loads(response_message.function_call.arguments)
    function_response = function_to_call(**function_args)

    Nedenfor er outputtet fra at køre vores kode:

    Output

    {
      "name": "search_courses",
      "arguments": "{\n  \"role\": \"student\",\n  \"product\": \"Azure\",\n  \"level\": \"beginner\"\n}"
    }
    
    Output of function call:
    [{'title': 'Describe concepts of cryptography', 'url': 'https://learn.microsoft.com/training/modules/describe-concepts-of-cryptography/?
    WT.mc_id=api_CatalogApi'}, {'title': 'Introduction to audio classification with TensorFlow', 'url': 'https://learn.microsoft.com/en-
    us/training/modules/intro-audio-classification-tensorflow/?WT.mc_id=api_CatalogApi'}, {'title': 'Design a Performant Data Model in Azure SQL
    Database with Azure Data Studio', 'url': 'https://learn.microsoft.com/training/modules/design-a-data-model-with-ads/?
    WT.mc_id=api_CatalogApi'}, {'title': 'Getting started with the Microsoft Cloud Adoption Framework for Azure', 'url':
    'https://learn.microsoft.com/training/modules/cloud-adoption-framework-getting-started/?WT.mc_id=api_CatalogApi'}, {'title': 'Set up the
    Rust development environment', 'url': 'https://learn.microsoft.com/training/modules/rust-set-up-environment/?WT.mc_id=api_CatalogApi'}]
    <class 'str'>
    
  2. Nu vil vi sende den opdaterede besked, messages, til LLM, så vi kan modtage et naturligt sprogrespons i stedet for et API JSON-formateret svar.

    print("Messages in next request:")
    print(messages)
    print()
    
    second_response = client.chat.completions.create(
       messages=messages,
       model=deployment,
       function_call="auto",
       functions=functions,
       temperature=0
          )  # get a new response from GPT where it can see the function response
    
    
    print(second_response.choices[0].message)

    Output

    {
      "role": "assistant",
      "content": "I found some good courses for beginner students to learn Azure:\n\n1. [Describe concepts of cryptography] (https://learn.microsoft.com/training/modules/describe-concepts-of-cryptography/?WT.mc_id=api_CatalogApi)\n2. [Introduction to audio classification with TensorFlow](https://learn.microsoft.com/training/modules/intro-audio-classification-tensorflow/?WT.mc_id=api_CatalogApi)\n3. [Design a Performant Data Model in Azure SQL Database with Azure Data Studio](https://learn.microsoft.com/training/modules/design-a-data-model-with-ads/?WT.mc_id=api_CatalogApi)\n4. [Getting started with the Microsoft Cloud Adoption Framework for Azure](https://learn.microsoft.com/training/modules/cloud-adoption-framework-getting-started/?WT.mc_id=api_CatalogApi)\n5. [Set up the Rust development environment](https://learn.microsoft.com/training/modules/rust-set-up-environment/?WT.mc_id=api_CatalogApi)\n\nYou can click on the links to access the courses."
    }

Opgave

For at fortsætte din læring om Azure OpenAI Funktionskald kan du bygge:

  • Flere parametre for funktionen, der kan hjælpe eleverne med at finde flere kurser.
  • Oprette et andet funktionskald, der tager mere information fra eleven som deres modersmål.
  • Oprette fejlhåndtering, når funktionskaldet og/eller API-kaldet ikke returnerer nogen passende kurser.

Hint: Følg siden Learn API reference documentation for at se, hvordan og hvor disse data er tilgængelige.

Godt arbejde! Fortsæt rejsen

Efter at have afsluttet denne lektion, tjek vores Generative AI Learning collection for at fortsætte med at opgradere din viden om Generativ AI!

Gå videre til Lektion 12, hvor vi vil se på, hvordan man designer UX til AI-applikationer!

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 originale dokument på dets oprindelige sprog bør betragtes som den autoritative kilde. For kritisk information anbefales professionel menneskelig oversættelse. Vi er ikke ansvarlige for eventuelle misforståelser eller fejltolkninger, der måtte opstå som følge af brugen af denne oversættelse.