V předchozích lekcích jste se již naučili poměrně dost. Nicméně stále je prostor pro zlepšení. Některé věci, které můžeme řešit, zahrnují získání konzistentnějšího formátu odpovědí, což usnadní práci s odpověďmi v dalších krocích. Také bychom mohli přidat data z jiných zdrojů, abychom naši aplikaci dále obohatili.
Tento kapitola se zaměřuje na řešení výše zmíněných problémů.
Tato lekce pokryje:
- Vysvětlení, co je volání funkcí a jeho využití.
- Vytvoření volání funkce pomocí Azure OpenAI.
- Jak integrovat volání funkce do aplikace.
Na konci této lekce budete schopni:
- Vysvětlit účel používání volání funkcí.
- Nastavit volání funkcí pomocí služby Azure OpenAI.
- Navrhnout efektivní volání funkcí pro potřeby vaší aplikace.
V této lekci chceme vytvořit funkci pro náš startup zaměřený na vzdělávání, která umožní uživatelům používat chatbot k vyhledávání technických kurzů. Budeme doporučovat kurzy, které odpovídají jejich úrovni dovedností, aktuální roli a zájmu o technologie.
K dokončení tohoto scénáře použijeme kombinaci:
Azure OpenAIk vytvoření chatovacího zážitku pro uživatele.Microsoft Learn Catalog APIk pomoci uživatelům najít kurzy na základě jejich požadavků.Volání funkcík přijetí dotazu uživatele a jeho odeslání do funkce pro provedení požadavku na API.
Než začneme, podívejme se, proč bychom vůbec chtěli používat volání funkcí:
Před voláním funkcí byly odpovědi od LLM nestrukturované a nekonzistentní. Vývojáři museli psát složitý validační kód, aby zajistili, že budou schopni zpracovat každou variaci odpovědi. Uživatelé nemohli získat odpovědi jako například "Jaké je aktuální počasí ve Stockholmu?". To proto, že modely byly omezeny na data, na kterých byly vyškoleny.
Volání funkcí je funkce služby Azure OpenAI, která překonává následující omezení:
- Konzistentní formát odpovědí. Pokud můžeme lépe kontrolovat formát odpovědí, můžeme je snadněji integrovat do dalších systémů.
- Externí data. Možnost využívat data z jiných zdrojů aplikace v kontextu chatu.
Doporučujeme použít přiložený notebook, pokud chcete spustit níže uvedený scénář. Můžete také jen číst dál, protože se snažíme ilustrovat problém, kde mohou funkce pomoci s jeho řešením.
Podívejme se na příklad, který ilustruje problém s formátem odpovědí:
Řekněme, že chceme vytvořit databázi údajů o studentech, abychom jim mohli doporučit správný kurz. Níže máme dva popisy studentů, které jsou velmi podobné v datech, která obsahují.
-
Vytvořte připojení k našemu zdroji Azure OpenAI:
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']
Níže je uveden kód v Pythonu pro konfiguraci našeho připojení k Azure OpenAI, kde nastavujeme
api_type,api_base,api_versionaapi_key. -
Vytvoření dvou popisů studentů pomocí proměnných
student_1_descriptionastudent_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."
Chceme poslat výše uvedené popisy studentů do LLM, aby data analyzoval. Tato data mohou být později použita v naší aplikaci a odeslána do API nebo uložena do databáze.
-
Vytvořme dva identické výzvy, ve kterých LLM instruujeme, jaké informace nás zajímají:
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} '''
Výše uvedené výzvy instruují LLM, aby extrahoval informace a vrátil odpověď ve formátu JSON.
-
Po nastavení výzev a připojení k Azure OpenAI nyní pošleme výzvy do LLM pomocí
openai.ChatCompletion. Výzvu uložíme do proměnnémessagesa přiřadíme roliuser. To simuluje zprávu od uživatele napsanou chatbotu.# 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
Nyní můžeme poslat oba požadavky do LLM a zkoumat odpověď, kterou obdržíme, například takto: openai_response1['choices'][0]['message']['content'].
-
Nakonec můžeme odpověď převést do formátu JSON pomocí volání
json.loads:# Loading the response as a JSON object json_response1 = json.loads(openai_response1.choices[0].message.content) json_response1
Odpověď 1:
{ "name": "Emily Johnson", "major": "computer science", "school": "Duke University", "grades": "3.7", "club": "Chess Club" }Odpověď 2:
{ "name": "Michael Lee", "major": "computer science", "school": "Stanford University", "grades": "3.8 GPA", "club": "Robotics Club" }I když jsou výzvy stejné a popisy podobné, vidíme, že hodnoty vlastnosti
Gradesjsou formátovány odlišně, například někdy dostaneme formát3.7nebo3.7 GPA.Tento výsledek je způsoben tím, že LLM přijímá nestrukturovaná data ve formě psané výzvy a vrací také nestrukturovaná data. Potřebujeme mít strukturovaný formát, abychom věděli, co očekávat při ukládání nebo používání těchto dat.
Jak tedy vyřešíme problém s formátováním? Použitím volání funkcí můžeme zajistit, že dostaneme zpět strukturovaná data. Při použití volání funkcí LLM ve skutečnosti žádné funkce nevolá ani nespouští. Místo toho vytvoříme strukturu, kterou LLM bude následovat při generování odpovědí. Poté použijeme tyto strukturované odpovědi k určení, jakou funkci spustit v našich aplikacích.
Poté můžeme vzít to, co je vráceno z funkce, a poslat to zpět do LLM. LLM pak odpoví přirozeným jazykem na dotaz uživatele.
Existuje mnoho různých případů použití, kde volání funkcí může zlepšit vaši aplikaci, například:
-
Volání externích nástrojů. Chatboty jsou skvělé pro poskytování odpovědí na otázky uživatelů. Použitím volání funkcí mohou chatboty použít zprávy od uživatelů k provádění určitých úkolů. Například student může požádat chatbot, aby "Poslal e-mail mému instruktorovi, že potřebuji více pomoci s tímto předmětem". To může provést volání funkce
send_email(to: string, body: string). -
Vytváření dotazů na API nebo databázi. Uživatelé mohou najít informace pomocí přirozeného jazyka, který se převede na formátovaný dotaz nebo požadavek na API. Příkladem může být učitel, který se ptá "Kteří studenti dokončili poslední úkol", což by mohlo vyvolat funkci nazvanou
get_completed(student_name: string, assignment: int, current_status: string). -
Vytváření strukturovaných dat. Uživatelé mohou vzít blok textu nebo CSV a použít LLM k extrakci důležitých informací z něj. Například student může převést článek z Wikipedie o mírových dohodách na vytvoření AI kartiček. To lze provést pomocí funkce nazvané
get_important_facts(agreement_name: string, date_signed: string, parties_involved: list).
Proces vytvoření volání funkce zahrnuje 3 hlavní kroky:
- Volání API Chat Completions s seznamem vašich funkcí a zprávou od uživatele.
- Čtení odpovědi modelu k provedení akce, tj. spuštění funkce nebo API požadavku.
- Vytvoření dalšího volání API Chat Completions s odpovědí z vaší funkce, aby se tato informace použila k vytvoření odpovědi pro uživatele.
Prvním krokem je vytvoření zprávy od uživatele. To může být dynamicky přiřazeno pomocí hodnoty textového vstupu nebo můžete hodnotu přiřadit zde. Pokud je to vaše první práce s API Chat Completions, musíme definovat role a content zprávy.
Role může být buď system (vytváření pravidel), assistant (model) nebo user (koncový uživatel). Pro volání funkcí ji přiřadíme jako user a příklad otázky.
messages= [ {"role": "user", "content": "Find me a good course for a beginner student to learn Azure."} ]Přiřazením různých rolí je LLM jasné, zda něco říká systém nebo uživatel, což pomáhá budovat historii konverzace, na které může LLM stavět.
Dále definujeme funkci a parametry této funkce. Použijeme zde pouze jednu funkci nazvanou search_courses, ale můžete vytvořit více funkcí.
Důležité: Funkce jsou zahrnuty do systémové zprávy pro LLM a budou zahrnuty do dostupného počtu tokenů.
Níže vytvoříme funkce jako pole položek. Každá položka je funkce a má vlastnosti name, description a 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"
]
}
}
]Pojďme si podrobněji popsat každou instanci funkce níže:
name- Název funkce, kterou chceme volat.description- Popis, jak funkce funguje. Zde je důležité být konkrétní a jasný.parameters- Seznam hodnot a formát, který chceme, aby model vytvořil ve své odpovědi. Pole parametrů se skládá z položek, kde položky mají následující vlastnosti:type- Datový typ, ve kterém budou vlastnosti uloženy.properties- Seznam konkrétních hodnot, které model použije pro svou odpověď.name- Klíč je název vlastnosti, kterou model použije ve svém formátovaném odpovědi, napříkladproduct.type- Datový typ této vlastnosti, napříkladstring.description- Popis konkrétní vlastnosti.
Existuje také volitelná vlastnost required - povinná vlastnost pro dokončení volání funkce.
Po definování funkce ji nyní musíme zahrnout do volání API Chat Completion. To provedeme přidáním functions do požadavku. V tomto případě functions=functions.
Existuje také možnost nastavit function_call na auto. To znamená, že necháme LLM rozhodnout, kterou funkci by měl volat na základě zprávy uživatele, místo abychom ji sami přiřadili.
Níže je uveden kód, kde voláme ChatCompletion.create, všimněte si, jak nastavujeme functions=functions a function_call="auto" a tím dáváme LLM možnost rozhodnout, kdy volat poskytnuté funkce:
response = client.chat.completions.create(model=deployment,
messages=messages,
functions=functions,
function_call="auto")
print(response.choices[0].message)Odpověď, která se nyní vrací, vypadá takto:
{
"role": "assistant",
"function_call": {
"name": "search_courses",
"arguments": "{\n \"role\": \"student\",\n \"product\": \"Azure\",\n \"level\": \"beginner\"\n}"
}
}Zde vidíme, jak byla funkce search_courses volána a s jakými argumenty, jak je uvedeno ve vlastnosti arguments v odpovědi JSON.
LLM dokázal najít data, která odpovídají argumentům funkce, protože je extrahoval z hodnoty poskytnuté parametru messages ve volání chat completion. Níže je připomenutí hodnoty messages:
messages= [ {"role": "user", "content": "Find me a good course for a beginner student to learn Azure."} ]Jak vidíte, student, Azure a beginner byly extrahovány z messages a nastaveny jako vstup do funkce. Používání funkcí tímto způsobem je skvělý způsob, jak extrahovat informace z výzvy, ale také poskytnout strukturu LLM a mít opakovaně použitelné funkce.
Dále musíme zjistit, jak to můžeme použít v naší aplikaci.
Poté, co jsme otestovali formátovanou odpověď od LLM, můžeme ji nyní integrovat do aplikace.
Pro integraci do naší aplikace postupujme podle následujících kroků:
-
Nejprve proveďme volání služeb OpenAI a uložme zprávu do proměnné nazvané
response_message.response_message = response.choices[0].message
-
Nyní definujeme funkci, která bude volat Microsoft Learn API k získání seznamu kurzů:
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)
Všimněte si, jak nyní vytváříme skutečnou Python funkci, která odpovídá názvům funkcí představeným v proměnné
functions. Také provádíme skutečné externí API volání k získání dat, která potřebujeme. V tomto případě se obracíme na Microsoft Learn API k vyhledání vzdělávacích modulů.
Dobře, vytvořili jsme proměnnou functions a odpovídající Python funkci, jak řekneme LLM, jak tyto dvě propojit, aby byla naše Python funkce volána?
-
Abychom zjistili, zda potřebujeme volat Python funkci, musíme se podívat do odpovědi LLM a zjistit, zda obsahuje
function_call, a volat určenou funkci. Zde je, jak můžete provést zmíněnou kontrolu níže:# 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, } )
Tyto tři řádky zajišťují, že extrahujeme název funkce, argumenty a provedeme volání:
function_to_call = available_functions[function_name] function_args = json.loads(response_message.function_call.arguments) function_response = function_to_call(**function_args)
Níže je výstup z běhu našeho kódu:
Výstup
{ "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'> -
Nyní pošleme aktualizovanou zprávu,
messages, do LLM, abychom mohli obdržet odpověď v přirozeném jazyce místo odpovědi ve formátu JSON API.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)
Výstup
{ "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." }
Pro pokračování ve vašem učení o Azure OpenAI Function Calling můžete vytvořit:
- Více parametrů funkce, které by mohly pomoci studentům najít více kurzů.
- Vytvořit další volání funkce, které by bralo více informací od studenta, například jeho rodný jazyk.
- Vytvořte zpracování chyb pro případ, kdy volání funkce a/nebo API nevrátí žádné vhodné kurzy.
Tip: Podívejte se na stránku Learn API referenční dokumentace, kde zjistíte, jak a kde jsou tato data dostupná.
Po dokončení této lekce se podívejte na naši kolekci učení o generativní AI, abyste dále rozvíjeli své znalosti o generativní AI!
Přejděte na lekci 12, kde se podíváme na to, jak navrhnout UX pro AI aplikace!
Prohlášení:
Tento dokument byl přeložen pomocí služby AI pro překlady Co-op Translator. I když se snažíme o přesnost, mějte prosím na paměti, že automatizované překlady mohou obsahovat chyby nebo nepřesnosti. Původní dokument v jeho rodném jazyce by měl být považován za autoritativní zdroj. Pro důležité informace se doporučuje profesionální lidský překlad. Neodpovídáme za žádná nedorozumění nebo nesprávné interpretace vyplývající z použití tohoto překladu.


