تا اینجا در درسهای قبلی مطالب زیادی یاد گرفتهاید. اما میتوانیم بهتر هم بشویم. برخی مواردی که میتوانیم بهبود دهیم، نحوه دریافت پاسخ با قالبی یکنواختتر است تا کار با پاسخ در مراحل بعدی آسانتر شود. همچنین ممکن است بخواهیم دادههایی از منابع دیگر اضافه کنیم تا برنامهمان غنیتر شود.
مشکلات ذکر شده در بالا، موضوعی است که این فصل به آن میپردازد.
این درس شامل موارد زیر است:
- توضیح اینکه فراخوانی تابع چیست و کاربردهای آن.
- ایجاد یک فراخوانی تابع با استفاده از Azure OpenAI.
- نحوه ادغام فراخوانی تابع در یک برنامه.
در پایان این درس، شما قادر خواهید بود:
- هدف استفاده از فراخوانی تابع را توضیح دهید.
- راهاندازی فراخوانی تابع با استفاده از سرویس Azure OpenAI.
- طراحی فراخوانیهای تابع مؤثر برای کاربرد برنامه خود.
برای این درس، میخواهیم ویژگیای برای استارتاپ آموزشی خود بسازیم که به کاربران اجازه میدهد با استفاده از چتبات، دورههای فنی را پیدا کنند. ما دورههایی را پیشنهاد میدهیم که متناسب با سطح مهارت، نقش فعلی و فناوری مورد علاقه آنها باشد.
برای تکمیل این سناریو، از ترکیبی استفاده خواهیم کرد از:
Azure OpenAIبرای ایجاد تجربه چت برای کاربر.Microsoft Learn Catalog APIبرای کمک به کاربران در یافتن دورهها بر اساس درخواست آنها.Function Callingبرای دریافت پرسش کاربر و ارسال آن به تابعی برای انجام درخواست API.
برای شروع، بیایید ببینیم چرا اصلاً میخواهیم از فراخوانی تابع استفاده کنیم:
قبل از فراخوانی تابع، پاسخهای یک مدل زبان بزرگ (LLM) ساختارمند و یکنواخت نبودند. توسعهدهندگان مجبور بودند کدهای اعتبارسنجی پیچیدهای بنویسند تا بتوانند هر نوع پاسخ را مدیریت کنند. کاربران نمیتوانستند پاسخهایی مانند «وضعیت آب و هوای فعلی در استکهلم چیست؟» دریافت کنند. چون مدلها محدود به دادههای زمان آموزش بودند.
فراخوانی تابع ویژگیای از سرویس Azure OpenAI است که برای غلبه بر محدودیتهای زیر طراحی شده است:
- قالب پاسخ یکنواخت. اگر بتوانیم قالب پاسخ را بهتر کنترل کنیم، میتوانیم پاسخ را راحتتر در سیستمهای دیگر استفاده کنیم.
- دادههای خارجی. امکان استفاده از دادههای منابع دیگر برنامه در زمینه چت.
توصیه میکنیم اگر میخواهید سناریوی زیر را اجرا کنید، از دفترچه یادداشت همراه استفاده کنید. همچنین میتوانید فقط مطالعه کنید چون هدف ما نشان دادن مشکلی است که توابع میتوانند به حل آن کمک کنند.
بیایید مثالی را ببینیم که مشکل قالب پاسخ را نشان میدهد:
فرض کنید میخواهیم یک پایگاه داده از اطلاعات دانشآموزان بسازیم تا بتوانیم دوره مناسب را به آنها پیشنهاد دهیم. در زیر دو توصیف از دانشآموزان داریم که دادههای مشابهی دارند.
-
ایجاد اتصال به منبع 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']
در زیر کد پایتون برای پیکربندی اتصال به Azure OpenAI آمده است که در آن
api_type،api_base،api_versionوapi_keyتنظیم شدهاند. -
ایجاد دو توصیف دانشآموز با استفاده از متغیرهای
student_1_descriptionو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."
میخواهیم این توصیفات دانشآموزان را به یک LLM ارسال کنیم تا دادهها را تجزیه کند. این دادهها بعداً میتوانند در برنامه ما استفاده شده و به API ارسال یا در پایگاه داده ذخیره شوند.
-
بیایید دو درخواست مشابه بسازیم که در آنها به LLM میگوییم به چه اطلاعاتی علاقهمندیم:
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} '''
درخواستهای بالا به LLM دستور میدهند اطلاعات را استخراج کرده و پاسخ را در قالب JSON بازگرداند.
-
پس از تنظیم درخواستها و اتصال به Azure OpenAI، حالا درخواستها را با استفاده از
openai.ChatCompletionبه LLM ارسال میکنیم. درخواست را در متغیرmessagesذخیره کرده و نقش راuserتعیین میکنیم. این کار برای شبیهسازی پیامی است که کاربر به چتبات میفرستد.# 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
حالا میتوانیم هر دو درخواست را به LLM ارسال کرده و پاسخ دریافتی را با استفاده از openai_response1['choices'][0]['message']['content'] بررسی کنیم.
-
در نهایت، میتوانیم پاسخ را با فراخوانی
json.loadsبه قالب JSON تبدیل کنیم:# Loading the response as a JSON object json_response1 = json.loads(openai_response1.choices[0].message.content) json_response1
پاسخ ۱:
{ "name": "Emily Johnson", "major": "computer science", "school": "Duke University", "grades": "3.7", "club": "Chess Club" }پاسخ ۲:
{ "name": "Michael Lee", "major": "computer science", "school": "Stanford University", "grades": "3.8 GPA", "club": "Robotics Club" }با اینکه درخواستها یکسان و توصیفات مشابه هستند، میبینیم که مقادیر ویژگی
Gradesبه شکلهای متفاوتی قالببندی شدهاند، مثلاً گاهی به صورت3.7و گاهی3.7 GPA.این نتیجه به این دلیل است که LLM دادههای بدون ساختار را به صورت متن دریافت کرده و دادههای بدون ساختار هم بازمیگرداند. ما نیاز به قالبی ساختارمند داریم تا بدانیم هنگام ذخیره یا استفاده از این دادهها چه انتظاری باید داشته باشیم.
پس چگونه مشکل قالببندی را حل کنیم؟ با استفاده از فراخوانی تابع، میتوانیم مطمئن شویم که دادههای ساختارمند دریافت میکنیم. هنگام استفاده از فراخوانی تابع، LLM در واقع هیچ تابعی را اجرا نمیکند. بلکه ساختاری برای پاسخهای LLM تعریف میکنیم تا آنها را دنبال کند. سپس از این پاسخهای ساختارمند برای تعیین تابعی که باید در برنامه اجرا شود، استفاده میکنیم.
سپس میتوانیم خروجی تابع را گرفته و دوباره به LLM ارسال کنیم. LLM سپس با زبان طبیعی به پرسش کاربر پاسخ میدهد.
موارد مختلفی وجود دارد که فراخوانی توابع میتواند برنامه شما را بهبود بخشد، مانند:
-
فراخوانی ابزارهای خارجی. چتباتها در پاسخ به سوالات کاربران عالی هستند. با استفاده از فراخوانی تابع، چتباتها میتوانند پیامهای کاربران را برای انجام کارهای خاصی استفاده کنند. مثلاً دانشآموز میتواند از چتبات بخواهد «برای استاد ایمیل بفرست که به کمک بیشتری در این موضوع نیاز دارم». این میتواند یک فراخوانی تابع به
send_email(to: string, body: string)باشد. -
ایجاد پرسوجوهای API یا پایگاه داده. کاربران میتوانند با زبان طبیعی اطلاعاتی را پیدا کنند که به پرسوجویی قالببندی شده یا درخواست API تبدیل میشود. مثلاً معلمی میتواند بپرسد «کدام دانشآموزان آخرین تکلیف را انجام دادهاند» که میتواند تابعی به نام
get_completed(student_name: string, assignment: int, current_status: string)را فراخوانی کند. -
ایجاد دادههای ساختارمند. کاربران میتوانند یک متن یا فایل CSV را گرفته و از LLM بخواهند اطلاعات مهم را استخراج کند. مثلاً دانشآموزی میتواند مقاله ویکیپدیا درباره توافقات صلح را به کارتهای فلش هوش مصنوعی تبدیل کند. این کار با استفاده از تابعی به نام
get_important_facts(agreement_name: string, date_signed: string, parties_involved: list)انجام میشود.
فرآیند ایجاد فراخوانی تابع شامل ۳ مرحله اصلی است:
- فراخوانی API تکمیل چت با لیستی از توابع شما و پیام کاربر.
- خواندن پاسخ مدل برای انجام عملی مانند اجرای تابع یا فراخوانی API.
- انجام فراخوانی دیگری به API تکمیل چت با پاسخ تابع برای استفاده از آن اطلاعات در پاسخ به کاربر.
اولین مرحله ایجاد پیام کاربر است. این پیام میتواند به صورت پویا از ورودی متنی گرفته شود یا میتوانید مقدار آن را اینجا تعیین کنید. اگر برای اولین بار با API تکمیل چت کار میکنید، باید role و content پیام را تعریف کنیم.
role میتواند یکی از system (ایجاد قوانین)، assistant (مدل) یا user (کاربر نهایی) باشد. برای فراخوانی تابع، این را user تعیین میکنیم و یک سوال نمونه مینویسیم.
messages= [ {"role": "user", "content": "Find me a good course for a beginner student to learn Azure."} ]با تعیین نقشهای مختلف، به LLM مشخص میکنیم که آیا سیستم چیزی میگوید یا کاربر، که به ساخت تاریخچه مکالمه کمک میکند.
سپس تابع و پارامترهای آن را تعریف میکنیم. در اینجا فقط یک تابع به نام search_courses تعریف میکنیم اما میتوانید چندین تابع بسازید.
مهم: توابع در پیام سیستم به LLM گنجانده میشوند و در تعداد توکنهای در دسترس شما محاسبه میشوند.
در زیر، توابع را به صورت آرایهای از آیتمها ایجاد میکنیم. هر آیتم یک تابع است و ویژگیهای name، description و 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"
]
}
}
]بیایید هر مورد تابع را دقیقتر توضیح دهیم:
name- نام تابعی که میخواهیم فراخوانی شود.description- توضیحی درباره عملکرد تابع. در اینجا باید واضح و دقیق باشید.parameters- لیستی از مقادیر و قالبی که میخواهید مدل در پاسخ خود تولید کند. آرایه پارامترها شامل آیتمهایی است که ویژگیهای زیر را دارند:type- نوع دادهای که ویژگیها در آن ذخیره میشوند.properties- لیستی از مقادیر خاصی که مدل برای پاسخ خود استفاده میکند:name- کلید نام ویژگی است که مدل در پاسخ قالببندی شده استفاده میکند، مثلاًproduct.type- نوع داده این ویژگی، مثلاًstring.description- توضیح ویژگی خاص.
همچنین ویژگی اختیاری required وجود دارد که مشخص میکند کدام ویژگیها برای تکمیل فراخوانی تابع ضروری هستند.
پس از تعریف تابع، باید آن را در فراخوانی API تکمیل چت وارد کنیم. این کار با افزودن functions به درخواست انجام میشود. در اینجا functions=functions است.
همچنین گزینهای برای تنظیم function_call به auto وجود دارد. این یعنی اجازه میدهیم LLM تصمیم بگیرد کدام تابع باید بر اساس پیام کاربر فراخوانی شود، نه اینکه خودمان تعیین کنیم.
کد زیر را ببینید که در آن ChatCompletion.create فراخوانی شده است، توجه کنید که چگونه functions=functions و function_call="auto" تنظیم شدهاند و به LLM اجازه داده شده که زمان فراخوانی توابع را انتخاب کند:
response = client.chat.completions.create(model=deployment,
messages=messages,
functions=functions,
function_call="auto")
print(response.choices[0].message)پاسخ دریافتی اکنون به این شکل است:
{
"role": "assistant",
"function_call": {
"name": "search_courses",
"arguments": "{\n \"role\": \"student\",\n \"product\": \"Azure\",\n \"level\": \"beginner\"\n}"
}
}در اینجا میبینیم که تابع search_courses فراخوانی شده و با چه آرگومانهایی، که در ویژگی arguments در پاسخ JSON آمده است.
نتیجه این است که LLM توانسته دادهها را استخراج کند تا با آرگومانهای تابع مطابقت داشته باشد، چون آنها را از مقدار messages در فراخوانی تکمیل چت گرفته است. در زیر یادآوری مقدار messages آمده است:
messages= [ {"role": "user", "content": "Find me a good course for a beginner student to learn Azure."} ]همانطور که میبینید، student، Azure و beginner از messages استخراج شده و به عنوان ورودی به تابع داده شدهاند. استفاده از توابع به این شکل، راهی عالی برای استخراج اطلاعات از یک درخواست است و همچنین ساختاردهی به LLM و داشتن قابلیت استفاده مجدد را فراهم میکند.
حالا باید ببینیم چگونه میتوانیم این را در برنامه خود استفاده کنیم.
پس از آزمایش پاسخ قالببندی شده از LLM، حالا میتوانیم آن را در یک برنامه ادغام کنیم.
برای ادغام این در برنامه، مراحل زیر را انجام میدهیم:
-
ابتدا فراخوانی به سرویسهای OpenAI را انجام داده و پیام را در متغیری به نام
response_messageذخیره میکنیم.response_message = response.choices[0].message
-
حالا تابعی تعریف میکنیم که API Microsoft Learn را برای دریافت لیست دورهها فراخوانی میکند:
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)
توجه کنید که اکنون یک تابع واقعی پایتون ایجاد میکنیم که به نامهای توابع معرفی شده در متغیر
functionsنگاشت میشود. همچنین فراخوانیهای واقعی API خارجی برای دریافت دادهها انجام میدهیم. در این مورد، به API Microsoft Learn مراجعه میکنیم تا ماژولهای آموزشی را جستجو کنیم.
خب، متغیر functions و تابع پایتون مربوطه را ساختیم، حالا چگونه به LLM میگوییم که این دو را به هم مرتبط کند تا تابع پایتون ما فراخوانی شود؟
-
برای اینکه ببینیم آیا باید تابع پایتون را فراخوانی کنیم، باید پاسخ LLM را بررسی کنیم و ببینیم آیا
function_callدر آن وجود دارد و تابع مشخص شده را فراخوانی کنیم. در زیر نحوه انجام این بررسی آمده است:# 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, } )
این سه خط تضمین میکند که نام تابع، آرگومانها استخراج شده و فراخوانی انجام شود:
function_to_call = available_functions[function_name] function_args = json.loads(response_message.function_call.arguments) function_response = function_to_call(**function_args)
در زیر خروجی اجرای کد ما آمده است:
خروجی
{ "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'> -
حالا پیام بهروزشده،
messagesرا به LLM ارسال میکنیم تا پاسخ به زبان طبیعی دریافت کنیم، نه پاسخ قالببندی شده 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)
خروجی
{ "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." }
برای ادامه یادگیری فراخوانی تابع Azure OpenAI میتوانید موارد زیر را بسازید:
- افزودن پارامترهای بیشتر به تابع که ممکن است به یادگیرندگان کمک کند دورههای بیشتری پیدا کنند.
- ایجاد فراخوانی تابع دیگری که اطلاعات بیشتری از یادگیرنده مانند زبان مادری او دریافت کند.
- ایجاد مدیریت خطا زمانی که فراخوانی تابع و/یا فراخوانی API هیچ دوره مناسبی بازنگرداند.
پس از اتمام این درس، مجموعه یادگیری هوش مصنوعی مولد ما را بررسی کنید تا دانش خود در زمینه هوش مصنوعی مولد را ارتقا دهید!
به درس ۱۲ بروید، جایی که به بررسی نحوه طراحی تجربه کاربری برای برنامههای هوش مصنوعی میپردازیم!
سلب مسئولیت:
این سند با استفاده از سرویس ترجمه هوش مصنوعی Co-op Translator ترجمه شده است. در حالی که ما در تلاش برای دقت هستیم، لطفاً توجه داشته باشید که ترجمههای خودکار ممکن است حاوی خطاها یا نادرستیهایی باشند. سند اصلی به زبان بومی خود باید به عنوان منبع معتبر در نظر گرفته شود. برای اطلاعات حیاتی، ترجمه حرفهای انسانی توصیه میشود. ما مسئول هیچ گونه سوءتفاهم یا تفسیر نادرستی که از استفاده این ترجمه ناشی شود، نیستیم.


