آموزش هوش مصنوعی

Function Calling چیست؟ اتصال مدل زبانی به تابع و داده واقعی

متوسط مطالعه در ۱۲ دقیقه بخش ۷ از ۵۰ در مسیر عملی هوش مصنوعی؛ از پرامپت تا ایجنت
mahdyar
· به‌روزرسانی
Function Calling چیست؟ اتصال مدل زبانی به تابع و داده واقعی

Function calling قابلیتی است که مدل زبانی را از «گوینده» به «هماهنگ‌کننده» تبدیل می‌کند. تا اینجا مدل فقط متن تولید می‌کرد. اما اگر کاربر بپرسد «هوای تهران الان چطور است؟»، مدل جوابی ندارد؛ چون دانشش به زمان آموزش محدود است و به داده‌ی زنده دسترسی ندارد.

در این قسمت از مجموعه‌ی «از پرامپت تا دستیار هوش مصنوعی» یاد می‌گیریم چطور مدل تابع مناسب را انتخاب کند، ورودی‌هایش را از پیام کاربر استخراج کند و برنامه‌ی ما با اجرای تابع، داده‌ی واقعی را به گفت‌وگو برگرداند. مثال اصلی، دستیاری است که دوره‌های آموزشی را از یک API واقعی جستجو می‌کند.

Function Calling چیست و چرا به آن نیاز داریم؟

Function calling (فراخوانی تابع) را با یک تصویر آشنا شروع کنیم. در رستوران، پیشخدمت خودش غذا نمی‌پزد؛ سفارش شما را روی برگه‌ای با قالب ثابت می‌نویسد و به آشپزخانه می‌دهد. مدل زبانی همان پیشخدمت است و برنامه‌ی شما آشپزخانه. حد تشبیه هم اینجاست که پیشخدمت گاهی سفارشی می‌نویسد که در منو نیست؛ برای همین برنامه باید هر برگه را پیش از اجرا بررسی کند.

پیش از function calling، پاسخ مدل‌ها متن آزاد بود. توسعه‌دهنده باید کد پیچیده‌ای می‌نوشت تا همه‌ی حالت‌های مختلف پاسخ را تشخیص دهد و پردازش کند. کاربر هم نمی‌توانست از مدل اطلاعات زنده بخواهد.

این قابلیت دو محدودیت اصلی را برطرف می‌کند:

  • قالب پاسخ ثابت: وقتی قالب پاسخ کنترل‌شده باشد، اتصال آن به سیستم‌های دیگر ساده می‌شود.
  • داده‌ی بیرونی: مدل می‌تواند از داده‌ی منابع دیگر، مثل API یا پایگاه داده، داخل گفت‌وگو استفاده کند.

مشکل قالب ناپایدار در یک مثال

فرض کنید می‌خواهیم از توضیح متنی دانشجویان، اطلاعاتشان را استخراج و در پایگاه داده ذخیره کنیم. دو توضیح تقریباً مشابه داریم. دانشجوی اول رشته‌ی کامپیوتر می‌خواند و معدلش ۱۷٫۵ است. دانشجوی دوم هم کامپیوتر می‌خواند و معدلش ۱۸ است.

با یک پرامپت یکسان از مدل می‌خواهیم نام، رشته، دانشگاه، معدل و انجمن دانشجویی را در قالب JSON برگرداند. نتیجه در ظاهر درست است، اما یک جا معدل «17.5» برمی‌گردد و جای دیگر «معدل 18». برای انسان فرقی ندارد، اما کدی که قرار است این عدد را ذخیره کند، با دومی خطا می‌دهد.

دلیلش ساده است. مدل ورودی بی‌ساختار می‌گیرد و خروجی بی‌ساختار هم می‌دهد. در مقابل، function calling با تعریف دقیق ساختار ورودی‌ها این مشکل را حل می‌کند. درست مثل فرم افتتاح حساب بانکی که برای هر خانه نوع داده‌ی مشخصی دارد و جای نوشتن آزاد نمی‌گذارد.

مدل تابع را اجرا نمی‌کند

یک سوءتفاهم رایج این است که مدل خودش تابع را اجرا می‌کند. این‌طور نیست. شما ساختار تابع‌ها را به مدل معرفی می‌کنید و مدل فقط پاسخ ساختاریافته‌ای برمی‌گرداند که می‌گوید کدام تابع با چه ورودی‌هایی باید اجرا شود.

اجرای واقعی کار برنامه‌ی شماست. نتیجه‌ی تابع دوباره به مدل برمی‌گردد و مدل با زبان طبیعی به کاربر جواب می‌دهد. این چرخه را در تصویر زیر می‌بینید.

چرخه‌ی function calling از پیام کاربر تا اجرای تابع و پاسخ نهایی مدل

کاربردهای Function Calling

فراخوانی تابع درِ بسیاری از قابلیت‌ها را باز می‌کند. سه دسته‌ی اصلی کاربرد این‌هاست:

  • استفاده از ابزار بیرونی: کاربر می‌گوید «به استادم ایمیل بزن که در این درس کمک بیشتری لازم دارم» و مدل تابع send_email(to, body) را با ورودی مناسب فراخوانی می‌کند.
  • ساخت پرس‌وجوی پایگاه داده یا API: معلم می‌پرسد «چه کسانی تکلیف آخر را تحویل داده‌اند؟» و درخواست به فراخوانی تابعی مثل get_completed(assignment, status) تبدیل می‌شود.
  • تولید داده‌ی ساختاریافته: از یک مقاله‌ی طولانی، نکته‌های کلیدی مثل تاریخ، طرف‌ها و نتیجه در قالب ثابت برای ساخت کارت مرور استخراج می‌شود.

در هر سه حالت، مدل زبان طبیعی کاربر را به یک فراخوانی دقیق و قابل اجرا تبدیل می‌کند. همین قابلیت پایه‌ی ایجنت‌هایی است که در قسمت‌های بعد می‌سازیم.

function calling و RAG اغلب کنار هم به کار می‌روند؛ یکی داده‌ی زنده می‌آورد و دیگری دانش اسناد. اگر RAG را ندیده‌اید، قسمت قبل را بخوانید.

بیشتر بخوانید: RAG چیست؟ آموزش ساخت دستیار پاسخ‌گو از روی اسناد با پایتون

ساخت اولین Function Calling در سه مرحله

فرایند کلی سه مرحله دارد. اول درخواست را همراه فهرست تابع‌ها می‌فرستید. بعد پاسخ مدل را می‌خوانید و تابع خواسته‌شده را اجرا می‌کنید. در پایان نتیجه را به مدل برمی‌گردانید تا پاسخ نهایی را بنویسد.

مرحله‌ی اول؛ پیام کاربر

پیام‌ها همان ساختار آشنای قسمت چت‌بات را دارند. هر پیام یک نقش (role) و یک محتوا (content) دارد. نقش می‌تواند system، user یا assistant باشد. اینجا یک پیام کاربر ساده می‌سازیم:

python
messages = [{"role": "user", "content": "یک دوره‌ی خوب برای دانشجوی مبتدی که می‌خواهد Azure یاد بگیرد پیدا کن."}]

در برنامه‌ی واقعی این پیام از ورودی کاربر می‌آید. نقش‌ها به مدل کمک می‌کنند تشخیص دهد چه کسی چه گفته است و تاریخچه‌ی گفت‌وگو را درست دنبال کند.

مرحله‌ی دوم؛ تعریف تابع

حالا تابع را معرفی می‌کنیم. هر تابع یک نام، یک توضیح و فهرست پارامترها با قالب JSON Schema (استانداردی برای توصیف شکل داده‌ی JSON) دارد. توضیح‌ها مهم‌ترین بخش‌اند، چون مدل بر اساس همین متن تصمیم می‌گیرد کی و چطور تابع را صدا بزند:

python
functions = [{
    "type": "function",
    "name": "search_courses",
    "description": "دوره‌های آموزشی را بر اساس نقش، محصول و سطح یادگیرنده جستجو می‌کند",
    "parameters": {
        "type": "object",
        "properties": {
            "role": {"type": "string", "description": "نقش یادگیرنده؛ مثلاً developer یا student"},
            "product": {"type": "string", "description": "محصول یا فناوری؛ مثلاً Azure یا Power BI"},
            "level": {"type": "string", "description": "سطح تجربه: beginner، intermediate یا advanced"},
        },
        "required": ["role"],
    },
}]

فیلد required مشخص می‌کند کدام پارامترها اجباری‌اند. یادتان باشد تعریف تابع‌ها بخشی از ورودی مدل است و توکن مصرف می‌کند. پس توضیح‌ها را دقیق اما کوتاه بنویسید.

تصویر زیر نشان می‌دهد در این مرحله دقیقاً چه چیزی به مدل می‌رسد: پیام کاربر در کنار نام، توضیح و پارامترهای تابع.

ورودی مدل در function calling شامل پیام کاربر و تعریف تابع search_courses

مرحله‌ی سوم؛ فراخوانی مدل با ابزارها

تابع‌ها را با پارامتر tools به درخواست اضافه می‌کنیم. با tool_choice="auto" هم تصمیم را به مدل می‌سپاریم؛ خودش تشخیص می‌دهد تابعی لازم است یا نه. چون store=False است، پاسخ مدل استدلالی آیتم‌های استدلال را به شکل رمزنگاری‌شده برمی‌گرداند تا در درخواست دوم دوباره بفرستیم:

python
from openai import OpenAI

client = OpenAI()  # کلید از OPENAI_API_KEY خوانده می‌شود
response = client.responses.create(
    model="gpt-5-mini",
    input=messages,
    tools=functions,
    tool_choice="auto",
    store=False,
)

در خروجی، به‌جای متن، یک آیتم از نوع function_call می‌بینید. نام تابع search_courses است و آرگومان‌هایش role: student، product: Azure و level: beginner. مدل هر سه مقدار را از جمله‌ی کاربر استخراج کرده است؛ بی‌آنکه کاربر آن‌ها را جداگانه وارد کرده باشد.

در مقابل، اگر کاربر فقط سلام کرده بود، مدل احتمالاً هیچ تابعی صدا نمی‌زد و مستقیم جواب می‌داد. شما فکر می‌کنید برای جمله‌ی «دوره‌ی Power BI برای مدیران» کدام آرگومان‌ها پر می‌شوند؟

پنج قدم function calling؛ از پیام کاربر و تعریف تابع تا اجرای تابع و پاسخ نهایی

اتصال Function Calling به برنامه

خروجی ساختاریافته را داریم. حالا باید آن را به تابع واقعی وصل کنیم و نتیجه را به مدل برگردانیم تا پاسخی قابل‌فهم برای کاربر بنویسد.

نوشتن تابع واقعی

تابع پایتونی زیر هم‌نام تابعی است که به مدل معرفی کردیم. این تابع API کاتالوگ آموزشی مایکروسافت را صدا می‌زند و پنج نتیجه‌ی اول را برمی‌گرداند. پیش از اجرا pip install requests را بزنید:

python
import requests

def search_courses(role, product=None, level=None):
    params = {"role": role, "product": product, "level": level}
    modules = requests.get("https://learn.microsoft.com/api/catalog/", params=params, timeout=20).json()["modules"]
    return str([{"title": m["title"], "url": m["url"]} for m in modules[:5]])

در پروژه‌ی واقعی این تابع می‌تواند پایگاه داده‌ی دوره‌های سایت شما را جستجو کند. مهم این است که نام و پارامترهایش دقیقاً با تعریفی که به مدل دادید یکی باشد.

اجرای تابع و برگرداندن نتیجه

حالا همه‌ی آیتم‌های خروجی مدل را به تاریخچه اضافه می‌کنیم. این آیتم‌ها شامل فراخوانی تابع و استدلال مدل‌اند و مستندات OpenAI می‌گوید در مدل‌های استدلالی باید همراه خروجی تابع برگردند. بعد تابع متناظر هر function_call را اجرا می‌کنیم و خروجی‌اش را اضافه می‌کنیم:

python
import json

available = {"search_courses": search_courses}
messages += response.output
for call in [item for item in response.output if item.type == "function_call"]:
    if call.name not in available:  # فقط تابع‌های مجاز
        result = "خطا: این تابع وجود ندارد."
    else:
        result = available[call.name](**json.loads(call.arguments))
    messages.append({"type": "function_call_output", "call_id": call.call_id, "output": result})

final = client.responses.create(model="gpt-5-mini", input=messages, tools=functions, store=False)
print(final.output_text)

در درخواست دوم، مدل نتیجه‌ی تابع را می‌بیند و فهرست دوره‌ها را با زبان طبیعی و همراه لینک به کاربر ارائه می‌دهد. call_id هم ارتباط هر خروجی را با فراخوانی خودش حفظ می‌کند؛ به‌خصوص وقتی مدل چند تابع را همزمان صدا بزند.

نکته‌های امنیتی و خطا

مدل ممکن است نام تابعی را بدهد که وجود ندارد یا آرگومانی نامعتبر بسازد. پس همیشه نام تابع را با فهرست مجاز مقایسه کنید و آرگومان‌ها را پیش از اجرا اعتبارسنجی کنید. تابع‌هایی که کار حساس انجام می‌دهند، مثل پرداخت یا حذف داده، باید تأیید کاربر را هم بگیرند.

علاوه بر این، خطاها را هم مدیریت کنید. اگر API پاسخ نداد یا نتیجه‌ای پیدا نشد، یک پیام روشن به‌عنوان خروجی تابع برگردانید. مدل می‌تواند همین پیام را به زبان ساده به کاربر توضیح دهد؛ به‌جای اینکه برنامه متوقف شود.

تمرین عملی؛ دستیار دوره‌ها با تابع جستجو

دستیار پروژه‌ی مشترک را به یک تابع جستجو مجهز کنید. به‌جای API مایکروسافت، یک فهرست ساده از دوره‌ها در پایتون بسازید و تابع search_courses را روی آن بنویسید. بعد این قابلیت‌ها را اضافه کنید:

  1. پارامتر تازه‌ای مثل زبان دوره یا حداکثر مدت اضافه کنید.
  2. تابع دومی بسازید که مشخصات کامل یک دوره را با نامش برمی‌گرداند.
  3. برای حالتی که هیچ دوره‌ای پیدا نمی‌شود، پیام خطای روشن برگردانید.

با چند پرسش متفاوت بررسی کنید مدل کدام تابع را انتخاب می‌کند. اگر انتخاب‌ها اشتباه بود، قبل از هر چیز توضیح تابع‌ها را دقیق‌تر کنید.

سخن پایانی

Function calling دو مشکل قدیمی مدل‌های زبانی را حل می‌کند: خروجی ناپایدار و بی‌خبری از داده‌ی زنده. مدل تصمیم می‌گیرد چه تابعی با چه ورودی‌هایی لازم است و برنامه‌ی شما آن را اجرا می‌کند. سپس مدل نتیجه را برای کاربر توضیح می‌دهد. توضیح دقیق تابع، اعتبارسنجی آرگومان‌ها و مدیریت خطا سه اصلی‌اند که این همکاری را قابل‌اعتماد می‌کنند.

در قسمت هشتم وارد دنیای ایجنت‌ها می‌شویم؛ سیستم‌هایی که با همین ابزارها برنامه‌ریزی می‌کنند و چند قدم را پشت‌سرهم پیش می‌برند.

این آموزش بر پایه‌ی درس Integrating with Function Calling از مجموعه‌ی آزاد Generative AI for Beginners مایکروسافت (مجوز MIT) به فارسی بازنویسی و تکمیل شده است.

برای مطالعه بیشتر

برای دنبال کردن عمیق‌تر این بحث، منابع زیر را به ترتیب از ساده به تخصصی بخوانید.

پرسش‌های پرتکرار

آیا در function calling خود مدل تابع را اجرا می‌کند؟

نه. مدل فقط تصمیم می‌گیرد کدام تابع با چه آرگومان‌هایی فراخوانی شود و این را در قالب JSON برمی‌گرداند. اجرای واقعی تابع و ارسال نتیجه به مدل بر عهده‌ی برنامه‌ی شماست.

فرق function calling با خواستن JSON در پرامپت چیست؟

وقتی فقط در پرامپت JSON می‌خواهید، قالب خروجی ممکن است هر بار کمی فرق کند. در function calling ساختار دقیق ورودی‌ها با JSON Schema تعریف می‌شود و مدل آرگومان‌ها را مطابق همان ساختار برمی‌گرداند.

tool_choice روی auto یعنی چه؟

یعنی خود مدل بر اساس پیام کاربر تصمیم می‌گیرد تابعی را فراخوانی کند یا مستقیم جواب دهد و اگر چند تابع دارید، کدام را انتخاب کند.

تعریف تابع‌ها توکن مصرف می‌کند؟

بله. نام، توضیح و پارامترهای همه‌ی تابع‌ها جزو ورودی مدل حساب می‌شوند. پس توضیح‌ها را دقیق اما مختصر بنویسید و فقط تابع‌هایی را بفرستید که در آن درخواست لازم‌اند.

دیدگاه‌ها

هنوز دیدگاهی ثبت نشده است. شروع‌کننده باشید — پرسش و اصلاح را با آغوش باز می‌پذیریم.

دیدگاه بگذارید

برای **پررنگ**، *مورب*، `کد` و لینک از Markdown استفاده کنید. لینک‌ها nofollow هستند.

پنج رقم داخل تصویر را وارد کنید. اعداد فارسی و انگلیسی پذیرفته می‌شوند.

تصویر کد امنیتی پنج‌رقمی

در حال دریافت کد امنیتی…

مهلت کد تمام شد. روی «کد جدید» بزنید.