אנו משלבים Function Calling (Tool Use) באפליקציות מובייל — מנגנון שבו מודל ה-AI אינו מנסה לענות על השאלה "מה מזג האוויר מחר" בעצמו, אלא מחזיר JSON מובנה המתאר מה צריך לקרוא: {"name": "get_weather", "arguments": {"city": "Минск", "date": "tomorrow"}}. האפליקציה מבצעת את הקריאה, מעבירה את התוצאה חזרה, והמודל מייצר את התשובה הסופית. עבור OpenAI זה tools, עבור Anthropic — tool_use, עבור Google — function_calling. הניסיון שלנו של 5+ שנים ו-30+ פרויקטים מוצלחים מבטיח אינטגרציה אמינה. בקשו ייעוץ כדי להעריך את התרחיש שלכם.
היכן זה באמת נשבר במובייל
הבעיה הנפוצה ביותר היא תיאור שגוי של JSON Schema עבור כלים. המודל בוחר כלי על סמך התיאור וסכמת הפרמטרים. אם הסכמה מעורפלת ("העבר מה שצריך"), המודל או שלא קורא לכלי כלל או מעביר פרמטרים בסוג שגוי. מקרה קונקרטי: השדה amount שתואר כ-string במקום number — המודל מעביר "150", ה-deserializer מצפה ל-Double, והאפליקציה קורסת עם JsonDataCorruptedException. Gson ו-Moshi כברירת מחדל אינם ממירים מחרוזות למספרים בשקט.
הצוואר בקבוק השני הוא קריאות כלים מקבילות. GPT-4 ו-Claude 3 יכולים להחזיר מספר tool_calls בתשובה אחת. אם מעבדים אותן ברצף, המשתמש ממתין. הגישה הנכונה באנדרואיד היא async/await באמצעות coroutines (async { } + awaitAll()), וב-iOS — async let או TaskGroup. והכי חשוב: יש להחזיר את כל התוצאות למודל בשלב messages[] אחד עם role: "tool" עבור כל קריאה — OpenAI דורש זאת בדיוק, אחרת 400 Invalid request.
הבעיה השלישית היא לולאת קריאה אינסופית. אם הכלי מחזיר שגיאה, המודל לפעמים מנסה לקרוא לו שוב עם אותם פרמטרים. הגבילו את מספר האיטרציות (בדרך כלל 5–10 מספיק) והעבירו במפורש את השגיאה ב-content של תגובת הכלי — זה עוזר למודל לעבור לאסטרטגיה אחרת.
כיצד להימנע מלולאות קריאה אינסופיות?
הגדירו מגבלת איטרציות (לדוגמה, 8) והעבירו את השגיאה ב-content של תגובת הכלי. המודל, עם קבלת הודעת השגיאה, ישנה את האסטרטגיה שלו. כמו כן, כדאי להוסיף דגל בסכמת הכלי כדי למנוע מהמודל לקרוא לו שוב ללא שינוי בפרמטרים.
מה לעשות עם קריאות מקבילות?
השתמשו בביצוע אסינכרוני. באנדרואיד — coroutines עם async ו-awaitAll(), ב-iOS — TaskGroup. אספו את כל התוצאות במערך ושלחו בהודעה אחת עם role: "tool". זה מפחית את זמן ההשהיה ועומד בדרישות ה-API. השוואה: ביצוע אסינכרוני מיושם כראוי מפחית את זמן התגובה פי 3 בהשוואה לעיבוד רציף.
ארכיטקטורת ToolDispatcher
// Android — диспетчер инструментов
class ToolDispatcher {
private val tools = mapOf<String, suspend (JsonObject) -> String>(
"get_weather" to ::handleGetWeather,
"search_flights" to ::handleSearchFlights,
"book_hotel" to ::handleBookHotel
)
suspend fun dispatch(toolName: String, args: JsonObject): String {
return tools[toolName]?.invoke(args) ?: """{"error": "unknown tool: $toolName"}"""
}
}כל handler מחזיר // Android — диспетчер инструментов class ToolDispatcher { private val tools = mapOf<String, suspend (JsonObject) -> String>( "get_weather" to ::handleGetWeather, "search_flights" to ::handleSearchFlights, "book_hotel" to ::handleBookHotel ) suspend fun dispatch(toolName: String, args: JsonObject): String { return tools[toolName]?.invoke(args) ?: """{"error": "unknown tool: $toolName"}""" } } (מחרוזת JSON של התוצאה). המודל מקבל טקסט, לא אובייקט — זה יסודי. אין צורך לסריאליזציה של מבנים מורכבים; מספיק JSON ברור המכיל נתוני מפתח.
תיאורי כלים צריכים להיות ספציפיים ככל האפשר:
{
"name": "search_products",
"description": "Ищет товары в каталоге по названию или категории. Используй когда пользователь спрашивает о конкретном товаре или хочет посмотреть ассортимент.",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Поисковый запрос на языке пользователя"
},
"category": {
"type": "string",
"enum": ["electronics", "clothing", "food"]
},
"limit": {
"type": "integer",
"default": 10,
"maximum": 50
}
},
"required": ["query"]
}
}השדה String משפיע על האם המודל קורא לכלי. "חיפוש" הוא תיאור גרוע. "מחפש מוצרים בקטלוג כאשר המשתמש מזהה מוצר ספציפי" — המודל מבין את ההקשר של השימוש.
ניהול מצב דיאלוג בצד הלקוח
Function Calling דורש שמירת היסטוריית הודעות מלאה: { "name": "search_products", "description": "Ищет товары в каталоге по названию или категории. Используй когда пользователь спрашивает о конкретном товаре или хочет посмотреть ассортимент.", "parameters": { "type": "object", "properties": { "query": {"type": "string", "description": "Поисковый запрос на языке пользователя"}, "category": {"type": "string", "enum": ["electronics", "clothing", "food"]}, "limit": {"type": "integer", "default": 10, "maximum": 50} }, "required": ["query"] } } → description (עם user) → assistant (תוצאה) → tool_calls (תשובה סופית). במובייל זה אומר מודל נתונים מתאים עבור tool:
// iOS enum MessageRole {
case user, assistant, tool
}
struct Message: Codable {
let role: MessageRole
let content: String?
let toolCalls: [ToolCall]? // только для role == .assistant
let toolCallId: String? // только для role == .tool
let name: String? // имя инструмента для role == .tool
}שמרו את כל השרשרת ב-assistant / ViewModel. אם אתם חותכים היסטוריה כדי לחסוך ב-tokens, חתכו רק זוגות Message מוקדמים, אך לעולם אל תחתכו מחזור קריאת כלי לא שלם — המודל יקבל שגיאת הקשר.
השוואת ספקים עבור Function Calling
| ספק | מנגנון | פורמט תיאור | קריאות מקבילות |
|---|---|---|---|
| OpenAI | // iOS enum MessageRole { case user, assistant, tool } struct Message: Codable { let role: MessageRole let content: String? let toolCalls: [ToolCall]? // только для role == .assistant let toolCallId: String? // только для role == .tool let name: String? // имя инструмента для role == .tool } |
JSON Schema | כן |
| Anthropic | @State |
JSON Schema | כן (Claude 3+) |
user/assistant |
JSON Schema | כן (Gemini) |
כל שלושת הספקים משתמשים ב-JSON Schema ( ויקיפדיה: JSON Schema ) לתיאור פרמטרים. ההבדלים הם בשמות השדות ובפורמט התגובה, אך ארכיטקטורת ה-dispatcher היא אוניברסלית.
מה כלול בעבודה
| שלב | משך | תוצאה |
|---|---|---|
| ניתוח ותיאור כלים | 3–5 ימים | JSON Schema עבור כל כלי |
| יישום ToolDispatcher | 5–7 ימים | קוד Dispatcher עם handlers |
| אינטגרציה בלולאת הדיאלוג | 3–4 ימים | שרשרת קריאה מלאה |
| טיפול בקריאות מקבילות | 2–3 ימים | יישום אסינכרוני |
| בדיקת מקרי קצה | 5–7 ימים | ערכת בדיקות (כלי לא ידוע, שגיאת API, timeout) |
| ניטור ותיעוד | 2–3 ימים | לוגים ומדריך הפעלה |
אינטגרציה של Function Calling עבור 3–5 כלים — 2–3 שבועות. עם לוגיקה מורחבת, קריאות מקבילות וניהול מצב מורכב — 4–6 שבועות. בקשו ייעוץ להערכה מדויקת עבור הפרויקט שלכם. קבלו אב-טיפוס עובד תוך 10 ימים.







