V předchozích lekcích jste se už hodně naučili. Přesto se můžeme ještě zlepšit. Některé věci, které můžeme řešit, jsou například, jak získat konzistentnější formát odpovědi, aby bylo snazší s ní dále pracovat. Také bychom mohli chtít přidat data z jiných zdrojů, abychom naši aplikaci ještě více obohatili.
Výše zmíněné problémy jsou tím, čemu se tato kapitola věnuje.
Tato lekce pokryje:
- Vysvětlení, co je volání funkcí a k čemu se používá.
- 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í funkce pomocí Azure OpenAI Service.
- Navrhnout efektivní volání funkcí pro konkrétní použití vaší aplikace.
Pro tuto lekci chceme vytvořit funkci pro náš vzdělávací startup, která uživatelům umožní pomocí chatbota najít technické kurzy. Doporučíme kurzy, které odpovídají jejich úrovni dovedností, aktuální roli a zájmu o technologii.
K dokončení tohoto scénáře použijeme kombinaci:
Azure OpenAIpro 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ů.Function Callingk převzetí dotazu uživatele a jeho odeslání do funkce, která provede API požadavek.
Pro začátek se podívejme, proč bychom vůbec chtěli používat volání funkcí:
Před voláním funkcí byly odpovědi z LLM nestrukturované a nekonzistentní. Vývojáři museli psát složitý validační kód, aby zvládli všechny možné varianty odpovědí. Uživatelé nemohli získat odpovědi na otázky jako „Jaké je aktuální počasí ve Stockholmu?“. To proto, že modely byly omezené na data, na kterých byly trénovány.
Volání funkcí je funkce Azure OpenAI Service, která pomáhá překonat následující omezení:
- Konzistentní formát odpovědi. Pokud můžeme lépe kontrolovat formát odpovědi, můžeme ji snáze integrovat do dalších systémů.
- Externí data. Možnost využít data z jiných zdrojů aplikace v kontextu chatu.
Doporučujeme použít přiložený notebook, pokud chcete scénář vyzkoušet. Můžete také jen číst dál, protože se snažíme ukázat problém, který funkce mohou pomoci vyřešit.
Podívejme se na příklad, který ilustruje problém s formátem odpovědi:
Řekněme, že chceme vytvořit databázi studentských dat, abychom jim mohli doporučit správný kurz. Níže máme dva popisy studentů, které jsou si datově velmi podobné.
-
Vytvoříme připojení k našemu Azure OpenAI zdroji:
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 Python kód pro konfiguraci připojení k Azure OpenAI, kde nastavujeme
api_type,api_base,api_versionaapi_key. -
Vytvoříme dva popisy 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 tyto popisy studentů poslat do LLM, aby data rozparsoval. Tato data pak můžeme použít v aplikaci, odeslat do API nebo uložit do databáze.
-
Vytvoříme dva stejné prompti, 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é prompty instruují LLM, aby extrahoval informace a vrátil odpověď ve formátu JSON.
-
Po nastavení promptů a připojení k Azure OpenAI nyní pošleme prompty do LLM pomocí
openai.ChatCompletion. Prompt uložíme do proměnnémessagesa přiřadíme roliuser. Tím simulujeme zprávu od uživatele psanou do chatbota.# 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 odeslat oba požadavky do LLM a zkontrolovat odpověď, kterou obdržíme, například takto: openai_response1['choices'][0]['message']['content'].
-
Nakonec můžeme odpověď převést do JSON formátu zavoláním
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 prompty stejné a popisy podobné, vidíme, že hodnoty vlastnosti
Gradesjsou formátovány různě, například někdy ve formátu3.7a jindy3.7 GPA.Tento výsledek je způsoben tím, že LLM přijímá nestrukturovaná data ve formě psaného promptu a také vrací 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šit problém s formátováním? Pomocí volání funkcí můžeme zajistit, že dostaneme zpět strukturovaná data. Při volání funkcí LLM ve skutečnosti žádné funkce nespouští. Místo toho vytvoříme strukturu, kterou má LLM při odpovědích dodržovat. Tyto strukturované odpovědi pak použijeme k rozhodnutí, kterou funkci v aplikaci spustíme.
Výsledek z funkce pak můžeme poslat zpět do LLM. LLM následně odpoví přirozeným jazykem na dotaz uživatele.
Existuje mnoho různých případů, kdy volání funkcí může zlepšit vaši aplikaci, například:
-
Volání externích nástrojů. Chatboti jsou skvělí v poskytování odpovědí na otázky uživatelů. Pomocí volání funkcí mohou chatboti využít zprávy od uživatelů k dokončení určitých úkolů. Například student může požádat chatbota: „Pošli e-mail mému lektorovi, že potřebuji více pomoci s tímto předmětem.“ To může vyvolat volání funkce
send_email(to: string, body: string). -
Vytváření API nebo databázových dotazů. Uživatelé mohou najít informace pomocí přirozeného jazyka, který se převede na formátovaný dotaz nebo API požadavek. Příkladem může být učitel, který se zeptá: „Kteří studenti dokončili poslední úkol?“, což může vyvolat funkci
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í. Například student může převést článek z Wikipedie o mírových dohodách na AI flashkarty. To lze provést pomocí funkce
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 pro provedení akce, tj. spuštění funkce nebo API volání.
- Vytvoření dalšího volání na Chat Completions API s odpovědí z vaší funkce, abyste použili tyto informace k vytvoření odpovědi uživateli.
Prvním krokem je vytvořit zprávu od uživatele. Ta může být dynamicky přiřazena z hodnoty textového vstupu, nebo ji můžete zde přímo zadat. Pokud pracujete s Chat Completions API poprvé, musíme definovat role a content zprávy.
role může být system (nastavení pravidel), assistant (model) nebo user (koncový uživatel). Pro volání funkcí přiřadíme roli user a uvedeme 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 pro LLM jasné, zda něco říká systém nebo uživatel, což pomáhá budovat historii konverzace, na kterou se LLM může odkazovat.
Dále definujeme funkci a její parametry. Použijeme zde pouze jednu funkci s názvem search_courses, ale můžete vytvořit i více funkcí.
Důležité : Funkce jsou zahrnuty do systémové zprávy pro LLM a započítávají se 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"
]
}
}
]Popíšeme si jednotlivé vlastnosti funkce podrobněji:
name- Název funkce, kterou chceme volat.description- Popis, jak funkce funguje. Je důležité být konkrétní a jasný.parameters- Seznam hodnot a formát, který chcete, aby model ve své odpovědi použil. Pole parametrů obsahuje položky s následujícími vlastnostmi:type- Datový typ, ve kterém budou vlastnosti uloženy.properties- Seznam konkrétních hodnot, které model použije ve své odpovědi.name- Klíč je název vlastnosti, kterou model použije ve formátované 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 musíme zahrnout do volání Chat Completion API. Uděláme to přidáním functions do požadavku, v tomto případě functions=functions.
Je také možnost nastavit function_call na auto. To znamená, že necháme LLM rozhodnout, kterou funkci má zavolat na základě zprávy uživatele, místo abychom to určovali my.
Níže je kód, kde voláme ChatCompletion.create, všimněte si, jak nastavujeme functions=functions a function_call="auto", čí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ěď, kterou nyní dostaneme, vypadá takto:
{
"role": "assistant",
"function_call": {
"name": "search_courses",
"arguments": "{\n \"role\": \"student\",\n \"product\": \"Azure\",\n \"level\": \"beginner\"\n}"
}
}Vidíme, že byla zavolána funkce search_courses a s jakými argumenty, které jsou uvedeny ve vlastnosti arguments v JSON odpovědi.
Závěr je, že LLM dokázal najít data odpovídající argumentům funkce, protože je extrahoval z hodnoty předané do parametru messages v chat completion volání. 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 z promptu extrahovat informace, ale také jak dát LLM strukturu a mít znovupoužitelnou funkcionalitu.
Nyní se podíváme, jak to můžeme použít v naší aplikaci.
Po otestování formátované odpovědi z LLM ji nyní můžeme integrovat do aplikace.
Pro integraci do aplikace postupujme následovně:
-
Nejprve zavoláme OpenAI služby a uložíme zprávu do proměnné
response_message.response_message = response.choices[0].message
-
Nyní definujeme funkci, která zavolá Microsoft Learn API a získá seznam 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, že nyní vytváříme skutečnou Python funkci, která odpovídá názvům funkcí uvedeným v proměnné
functions. Také provádíme skutečná externí API volání pro získání potřebných dat. V tomto případě voláme Microsoft Learn API pro vyhledání výukových modulů.
Dobře, vytvořili jsme proměnnou functions a odpovídající Python funkci, jak ale LLM řekneme, jak tyto dvě věci propojit, aby byla naše Python funkce zavolána?
-
Abychom zjistili, zda máme zavolat Python funkci, musíme se podívat do odpovědi LLM a zjistit, zda obsahuje
function_call, a podle toho zavolat příslušnou funkci. Níže je ukázka, jak tuto kontrolu provést:# 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 zajistí, ž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
messageszpět do LLM, abychom mohli získat odpověď v přirozeném jazyce místo JSON formátu z 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 studiu Azure OpenAI Function Calling můžete vytvořit:
- Více parametrů funkce, které by mohly pomoci studentům najít více kurzů.
- Další volání funkce, které vezme více informací od studenta, například jeho rodný jazyk.
- Ošetření chyb v případě, že volání funkce a/nebo API nevrátí žádné vhodné kurzy.
Po dokončení této lekce si prohlédněte naši kolekci Generative AI Learning, kde můžete dále rozvíjet své znalosti o Generative AI!
Přejděte k Lekci 12, kde se podíváme na to, jak navrhovat UX pro AI aplikace!
Prohlášení o vyloučení odpovědnosti:
Tento dokument byl přeložen pomocí AI překladatelské služby Co-op Translator. I když usilujeme 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 mateřské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. Nejsme odpovědní za jakékoliv nedorozumění nebo nesprávné výklady vyplývající z použití tohoto překladu.


