Мазмұнға өту
2026 ж. 16 ақп.·7 мин оқу

Бірнеше провайдер арқылы құрал шақыру: күтпеген мәселелерсіз

Бірнеше провайдер арқылы құрал шақыру көбіне схемаларда, типтерде және қате кодтарында бұзылады. Продакшенге шығар алдында нені тексеру керегін талдаймыз.

Бірнеше провайдер арқылы құрал шақыру: күтпеген мәселелерсіз

Неліктен бір шақыру әр провайдерде бұзылады

Бірдей сұрау бір құралмен бір провайдерде өтеді де, екіншісінде сәтсіздікке ұшырайды, тіпті екеуі де OpenAI API-мен үйлесімдімін деп айтса да. Форматы ұқсас, бірақ ұсақ-түйек әртүрлі: модель схеманы қалай оқиды, аргументтерді қалай жинайды, провайдер қатені қалай қайтарады және журналға не түседі.

Продакшенде бұл бірден көрінеді. Команда модельге find_customer және create_ticket сияқты екі құрал береді де, бір ұқыпты tool_call күтеді. Бірінші провайдерде модель find_customer-ді жарамды JSON-мен шақырады. Екіншісінде сандарды жолдарға салып жібереді, артық өріс қосады немесе функцияны шақырудың орнына кәдімгі мәтінмен жауап береді. Үшіншісінде сұрау тіпті бұдан ертерек құлайды, өйткені схема сіздің SDK үшін формалды түрде дұрыс болғанымен, провайдер басқа формат күтеді.

Ортақ қабат тез бастауға көмектеседі, бірақ көбіне ақау қай жерде шыққанын жасырып қояды. Егер адаптер барлық істен шығуды "tool call failed" сияқты хабарға дейін қысқартса, команда ең маңызды нәрседен айырылады: модель нақты нені көрді, қандай аргументтер қайтарды және қате қай жерде пайда болды.

Көбіне мәселе төрт жерде жатады:

  • құрал схемасында, бір провайдер параметрлердің дәл емес сипаттамасына көне салса, ал екіншісі типтер мен міндетті өрістерді қатаң тексерсе
  • аргументтерде, модель JSON-жолын, объектіні, бос өрістер жиынын немесе артық деректерді қайтарғанда
  • қателерді өңдеуде, бір жерде сізге шынайы 400 келсе, ал басқа жерде 200 ішіндегі бұзылған мазмұн келуі мүмкін
  • журналдарда, егер шикі сұрау мен шикі жауапты сақтамасаңыз

Шынайы интеграцияларда бұзылу сирек әдемі көрінеді. Модель дұрыс емес құралды таңдауы мүмкін, ретрайдан кейін бір құралды екі рет шақыруы мүмкін, customer_id-ді client_id-мен шатастыруы немесе өріс міндетті бола тұра null жіберуі мүмкін. Кейде бәрі он тест сұрауда жұмыс істейді де, содан кейін контекст үлкейген ұзақ диалогтарда быт-шыт болады, өйткені модель аргументтердің дәлдігін үнемдей бастайды.

Сондықтан бірнеше провайдер арқылы құрал шақыруды "бәрінің API-і бірдей" деген ойға сыйғызуға болмайды. Қағаз жүзінде үйлесімділік бар. Іс жүзінде мінез-құлық ұсақ-түйекте өзгеше, ал жүйені дәл солар бұзады.

Егер команда бірінші күннен бастап журналға құрал схемасын, шикі tool_call-ды, талдаудан кейінгі JSON-ды және провайдердің қате кодын жазып отырса, талдау он минутта бітеді. Онсыз қарапайым ақаудың өзі жарты күнді жұтып қоюы мүмкін.

Құрал схемаларында не өзгереді

Один и тот же инструмент редко выглядит одинаково у всех провайдеров. Even if the team sends requests through an OpenAI-compatible gateway, differences still show up in the tools description, JSON Schema rules, and the way the model returns the tool choice.

Қай жерде форматтар алшақтайды

Көбіне функцияның логикасы емес, оны орау тәсілі бұзылады. Бір провайдерде құрал tools ішінде type: "function" және ішкі function бар объект ретінде тұрады. Басқасында сол деректер name, description және input_schema өрістерінде, артық қабатсыз күтіледі.

Өріс атаулары да бірдей емес. Бір жерде аргументтер схемасы parameters деп аталады, бір жерде input_schema, ал бір жерде тек қысқартылған JSON Schema түрі ғана қолдау табады. Егер қабат осы айырмашылықтарды жасырып жіберсе, ол ережелердің бір бөлігін үнсіз алып тастауы мүмкін, содан кейін модель аргументтерді еркін түрде ойлап таба бастайды.

Әдетте enum, default және nullable қолдауы, additionalProperties-ке қатынасы, nested объектілер мен массивтер, required ішіндегі міндетті өрістер, ал кейде тіпті функция атауындағы ұзындық пен рұқсат етілген таңбалар да өзгеше болады.

JSON Schema-ны да бәріне ортақ стандарт деп ойламаған дұрыс. Көп модельдер type, properties және required-пен сенімді жұмыс істейді, бірақ oneOf, anyOf, жолдарға арналған күрделі шектеулерді немесе терең nested құрылымды нашар түсінеді. Егер схема тапсырысты заңгер жазғандай сипаттаса, модель әдетте әлдеқайда нашар жауап береді, ал провайдер кейде қолдаусыз бөліктерді жай ғана кесіп тастайды.

Enum әсіресе айлакер. Бір провайдер тізімдегі мәндердің бірін қатаң таңдауға мәжбүрлейді, екіншісі кез келген мәтінді өткізе береді, ал үшіншісі enum-дағы мәндер тип бойынша сәйкес келмесе, қате қайтарады. Міндетті өрістерде де ұқсас жағдай: кей жүйе оларды модельге дейін тексереді, кейі тек кейін, ал кейбірі мүлде сіздің тарапыңызға қалдырады.

Модель не қайтарады

Құралды таңдағандағы жауап та ортақ емес. Бір провайдер tool_calls-пен функция атауы мен arguments ішіндегі JSON-жолын қайтарады, екіншісі аргументтері уже талданып қойылған құрылымды объект жібереді, ал үшіншісі шақырудың қасында кәдімгі мәтінді қосып береді.

Сондықтан парсерді бір ғана сәтті мысалға қарап жазуға болмайды. Егер сізде get_weather(city, units) және find_order(order_id) болса, тек сәтті шақыруды емес, келесі оғаш жағдайларды да тексеріңіз: бос аргументтер, артық өріс, enum-нан тыс мән, бірден екі құралды шақыру талпынысы. Дәл солар абстракция айырмашылықты жасырып тұр ма, әлде оны ашық көрсетіп тұр ма — соны байқатады.

Провайдерлер аргументтерді қалай оқиды

Бірдей схема бірдей нәтиже береді дегенді білдірмейді. Бір модель {\"count\": 3} қайтарады, ал екіншісі {\"count\": \"3\"} жібереді. Код үшін бұл айырмашылық қағаз жүзінде ғана ұсақ көрінеді. Іс жүзінде сүзгі, калькулятор немесе тапсырысты іздеу басқа тармаққа түсіп кетуі мүмкін.

Жол, сан және boolean арасындағы шатасу ең жиі кездеседі. string-ті көп жағдайда шамадан тыс кең қолданады: күн, сома, клиент id-і және кәдімгі мәтіннің бәрі бір типпен келеді, ал олар үшін ережелер әртүрлі. number да оңай емес: кей модельдер \"00125\"-ті 125-ке айналдырып, идентификаторды бұзады, басқалары 12.00-ді 12 деп дөңгелектейді. boolean-мен де солай: true мен false орнына модель \"true\", \"yes\", 1 немесе мүлде бос жол қайтара алады.

Nullable өрістерде де айырмашылық байқалады. Бір провайдер null-ді еркін қабылдайды, басқасы өрістің мүлде жоғалғанын қалайды. Массивтерде де ұқсас жағдай: бір жерде [] — "ештеңе жоқ", ал басқа жерде модель null немесе жолдар массивінің орнына жалғыз жол қояды. Nested объектілерде ақау тез жиналады, өйткені модель ішіндегі міндетті өрісті өткізіп жіберуі мүмкін, ал сыртқы жауап бәрібір бір қарағанда дұрыс сияқты көрінеді.

Жауап формасы да бөлек мәселе. Кей модельдер аргументтерді бірден JSON объектісі ретінде қайтарады, басқалары JSON-ды әлі де парсингтен өткізу керек жолға салады. Кейде жол дерлік жарамды, бірақ ішінде артық үтір, түсініктеме немесе тырнақшадағы сандар бар. Егер қабат мұндай жауаптарды үнсіз түзете берсе, команда кейін біртүрлі мінездің себебін ұзақ іздейді.

Әдетте ең жиі бұзылатын өрістер үшін мынадай қатаң келісім көп көмектеседі:

  • күндерді бір форматта сақтаңыз, мысалы \"2025-04-27\", және модельге \"27/04\" немесе \"келесі дүйсенбі\" деп еркін жаздырмаңыз
  • сомаларды валютасы бар жол түрінде немесе минимал бірлікпен сан ретінде беріңіз
  • идентификаторларды көбіне жол ретінде сақтаған дұрыс, тіпті олар тек цифрлардан тұрса да
  • бос мән үшін бір нұсқаны ғана таңдаңыз: null, \"\" немесе өрістің болмауы

Жақсы абстракция бұл айырмашылықтарды жасырмайды, керісінше кірісте де, шығыста да тексереді. Егер құрал қатаң JSON күтсе, әр аргументті модель жауап бергеннен кейін валидациядан өткізіп, шикі жауапты толығымен сақтаңыз. Әйтпесе ыңғайлы қабат провайдерлер арасындағы жай ғана айырманы продакшендегі дыбыссыз қатеге айналдырады.

Ортақ қабатты кезең-кезеңімен қалай құруға болады

Егер команда сұрауларды бір шлюз арқылы жіберсе, үйлесімділік мәселесі жабылды деп ойлау оңай. Іс жүзінде ортақ endpoint рутинасының бір бөлігін алып тастағанымен, LLM-дегі tool calling айырмасын жоймайды. Жақсы қабат бұл айырмашылықтарды жасырып тастамайды, керісінше бақылауда ұстайды.

Алдымен құрал үшін ең қарапайым контракттан бастаңыз. Ішкі nested объектілерді, nested ішіндегі массивтерді және ұзын міндетті емес өрістерді, онсыз да бола тұрса, қоспаңыз. Схема неғұрлым қарапайым болса, модель аргумент атауларын соғұрлым сирек шатастырады және шақыру қай жерде бұзылғанын соғұрлым оңай түсінесіз.

Содан кейін бір ішкі жұмыс тәртібін бекітіңіз.

  1. Әр құралды түсінікті типтер мен міндетті өрістерден тұратын қысқа JSON схемасымен сипаттаңыз. Егер құралға city керек болса, бұл өрісті бірде location, бірде query, бірде text деп атамаңыз.
  2. Аргументтерді модельге жіберер алдында тексеріңіз. Егер схема сан талап етсе, жолды өткізбеңіз. Егер өріс міндетті болса, сұрауды бірден тоқтатып, провайдерге емес, өз кодыңызға түсінікті қате қайтарыңыз.
  3. Модель жауаптарын бір ішкі форматқа келтіріңіз. Мысалы, өзіңізде tool_name, arguments, call_id, finish_reason сақтаңыз, тіпті провайдер бұл өрістерді басқаша атап, басқа JSON деңгейіне салса да.
  4. Шикі сұрау мен шикі жауапты сақтаңыз. Әйтпесе бір күннен кейін ешкім модель құралды көрмеді ме, JSON-ды бұзды ма, әлде провайдер өз қате форматын қайтарды ма — есіне түсіре алмайды.
  5. Қате маппингін бөлек қабатқа шығарыңыз. Бір провайдер артық өріс үшін 400 қайтарады, екіншісі 422 береді, үшіншісі құрылымсыз мәтін жібереді. Қолданбаңыз қателердің зообағын емес, INVALID_TOOL_SCHEMA, BAD_ARGUMENTS немесе PROVIDER_TIMEOUT сияқты өз кодтарын көруі керек.

Мұндай тәсіл ақауларды талдауға кететін уақытты үнемдейді. Айтайық, модель get_customer-ді шақырып, customerId: \"abc\" жіберді, ал сіз сан күтесіз. Егер валидация жауаптан кейін бірден тұрса, қате бір жерде көрінеді. Егер ол жоқ болса, сіз бөгде 400 аласыз да, кінәлі кім екенін — схема ма, модель ме, SDK ма, әлде провайдердің өзі ме — жорамалдай бастайсыз.

Мұндағы пайдалы әдет қарапайым: алдымен қабатты жалықтыратындай қатаң етіңіз. Содан кейін ғана ыңғайлылық, retry және сирек өрістерді қосыңыз.

Екі құралмен қарапайым сценарий

Схеманы қатаң ұстаңыз
Типтерді, required өрістерді және enum-ды продакшенге шығармай тұрып тексеріңіз.

Интернет-дүкеннің қолдау чат-ботын алайық. Ол екі нәрсе істей алады: тапсырысты нөмірі бойынша табу және клиентке көмек керек болса, өтініш ашу. Сырттай қарағанда бәрі оңай, бірақ дәл осындай жағдайда провайдерлердің әртүрлі мінезі жиі байқалады.

Құралдарды былай сипаттауға болады:

[
  {
    "name": "find_order",
    "description": "Найти заказ по номеру",
    "parameters": {
      "type": "object",
      "properties": {
        "order_id": { "type": "string" }
      },
      "required": ["order_id"]
    }
  },
  {
    "name": "create_ticket",
    "description": "Создать заявку в поддержку",
    "parameters": {
      "type": "object",
      "properties": {
        "order_id": { "type": "string" },
        "reason": { "type": "string" },
        "urgent": { "type": "boolean" }
      },
      "required": ["order_id", "reason"]
    }
  }
]

Пайдаланушы: "Менің 45128 тапсырысым қайда? Егер жоғалса, өтініш ашыңыз" деп жазады. Бір провайдер find_order-дың ұқыпты шақыруын, мысалы {\"order_id\":\"45128\"} түрінде қайтаруы мүмкін. Қолданба тапсырысты іздеп, жеткізуге қатысты мәселені көреді де, келесі қадамда екінші дұрыс шақыруды алады: {\"order_id\":\"45128\",\"reason\":\"жеткізу кешікті\",\"urgent\":true}.

Енді жағымсыз нұсқаны көрейік. Сол prompt-та басқа провайдер ұқсас жауап береді, бірақ типтерді бұзады: {\"order_id\":45128,\"reason\":\"жеткізу кешікті\",\"urgent\":\"true\"}. Адам үшін айырмашылық шамалы. Код үшін бұл екі қауіп: тапсырыс нөмірі санға айналды, ал шұғылдық жалаушасы жол болып кетті.

Команда бір OpenAI-үйлесімді шлюз арқылы жұмыс істесе де, мұндай айырмашылықтарды бәрібір қолданбада ұстау керек. Шлюз модельдерге қолжетімділікті жеңілдетеді, бірақ ішкі жүйелерді шақырғанға дейін аргументтерді тексеруді алып тастамайды.

Бірінші жағдайда бәрі түсінікті: JSON-ды тексересіз, құралды шақырасыз және нәтижені журналға жазасыз. Екінші жағдайда қолданба бұзылған деректі үнсіз әрі қарай жібермеуі тиіс. Тәртіп қарапайым:

  • құрал атауын және аргумент схемасын тексеру
  • тек анық ереже бойынша қауіпсіз типтерге түрлендіру
  • қауіпті немесе екіұшты мәндерді қабылдамау
  • модельге түсінікті қате қайтару немесе нақтылау сұрау

order_id-ді қауіпсіз болса жолға айналдыруға болады. Ал urgent: \"true\" мәнін болжаған дұрыс емес, әсіресе ол кезек приоритетіне немесе қызметкерге хабарлама жіберуге әсер етсе. Ондайда қолданба модельге: "urgent өрісі boolean болуы керек" деген сияқты хабар беріп, құрал шақыруын қайталауды сұрай алады.

Қорытындысы қарапайым: ортақ қабат ыңғайлы, бірақ кірісте қатаң болуы керек. Әйтпесе бір провайдер жұмыс істейтін JSON береді, ал екіншісі CRM-ге немесе ticket жүйесіне қате деректі үнсіз өткізіп жібереді.

Командалар көбіне қай жерде қателеседі

Бірінші қате қарапайым: команда OpenAI-үйлесімді API көріп, мінез-құлық та бірдей болады деп ойлайды. Шын мәнінде сұраудың пішіні ғана ұқсас, ал орындалу егжей-тегжейі түгел сәйкес келмейді. Бір провайдер артық өрісті үнсіз өткізіп жібереді, екіншісі қате қайтарады. Бірі ұқыпты tool_calls береді, екіншісі JSON-ы аздап бұзылған аргументтерді жол ретінде жібереді.

Бұл көбіне бірегей шлюз бар жерде байқалады. Мысалы, AI Router бір OpenAI-үйлесімді endpoint береді, сондықтан бұрынғы SDK, код және prompt-тарды қалдыруға болады. Бірақ провайдерлер арасындағы айырмашылық жоғалып кетпейді, сондықтан схеманы, аргументтерді және жауаптарды бәрібір ашық тексеру керек.

Екінші жиі қате — provider-specific өрістерді ортақ қабатқа тым ерте тығып тастау. Команда тек құрал атауы мен аргументтерді қалдырады да, қалғанын "шу" деп кесіп тастайды. Содан кейін қатаң схема баптаулары, құрал таңдау режимі, аргументтерді қайтару форматы және мінез-құлықты қайталайтын басқа детальдар жоғалады.

Әдетте екі қабатты ұстаған дұрыс. Біріншісі — құрал атауы, схема және трассировка үшін ортақ контракт. Екіншісі — сіз әзірге нормализацияламаған провайдер өрістері. Және міндетті түрде өңдеуге дейін шикі жауапты сақтап, қай адаптер сұрау мен жауапты өзгерткенін белгілеңіз.

Үшінші қате debugging-ті ауырлатады. Командалар барлық сәтсіздікті TOOL_CALL_FAILED сияқты бір кодқа жинап тастайды. Содан кейін қай жерде бұзылғанын тез түсіну мүмкін болмай қалады: модель JSON жинай алмады ма, провайдер схеманы кері қайтарды ма, сіздің backend аргументтерді қабылдамады ма, әлде құралдың өзі timeout алды ма.

Тағы бір тұзақ — модельге міндетті аргументтерді тексеруді сеніп тапсыру. Модель customer_id-ді ұмытуы, санның орнына жол қоюы немесе жүйеңізде жоқ enum мәнін ойлап табуы мүмкін. Мұны сіздің кодыңыз құралды шақырмай тұрып тексеруі керек, біртүрлі backend жауабынан кейін емес.

Кәдімгі мысал: get_invoice құралы customer_id мен month күтеді. Бір провайдер екі өрісті де береді. Екіншісі customer_id-ді "контексттен түсінуге болады" деп, оны өткізіп жіберуі мүмкін. Егер backend сұрауды тексермесе, сіз түсініксіз 500 алып, себебін бір сағат іздейсіз.

Соңғы жиі қате — продқа сынақ шақырулар жиынтығынсыз шығару. Кем дегенде мына кейстер болуы керек: қалыпты сұрау, жетіспейтін міндетті өріс, артық өріс, қате тип және ұзын аргумент. Мұндай жинақты схема, SDK немесе провайдер өзгерген сайын қайта іске қосып отырған дұрыс.

Болжамсыз қалай талдауға болады

Шотты теңгемен алыңыз
B2B есеп айырысуды провайдер тарифтерімен, API үстемесіз жүргізіңіз.

Егер LLM-дегі бір tool calling кейде өтсе, кейде әр провайдерде бұзылса, мәселе көбіне "модельдің сиқырында" емес, себептерді дұрыс ажыратпауында. Барлық қателерді "болмады" деген бір бумаға салу — апталап қате жерді жөндеудің ең оңай жолы.

Әуелі ақауларды үш түрге бөліңіз. Схема қателері құрал сипаттамасы немесе аргумент форматы провайдер не сіздің валидаторыңыз күтетін нәрсеге сай келмегенде пайда болады. Модель қателері басқа түрде көрінеді: схема формалды түрде дұрыс, бірақ модель дұрыс емес құралды таңдайды, міндетті өрісті қалдырып кетеді немесе оғаш мән қояды. Желілік ақауларды таймаут, 429, 5xx және қосылымның үзілуі арқылы тану оңай.

Бұл бөлу есеп беру үшін емес, әрекет ету үшін керек. Схема қатесін қайта жіберіп емдемейді. Модель қатесін кәдімгі retry сирек түзетеді, бірақ қатаңырақ схема, нақты мысалдар және міндетті өрістерді жеке тексеру көмектеседі. Желілік ақауға әдетте retry, backoff немесе басқа провайдерге ауысу керек.

Минималды логтар жиыны шағын: құрал атауы, нормализацияға дейінгі және кейінгі аргументтер, provider id, request id және қате мәтінімен валидация нәтижесі. Осыларсыз талдау көз жұмып жасаумен тең.

Әсіресе сәтсіздіктің жай ғана болғанын емес, нақты қай жерде шыққанын көрсету маңызды. "invalid arguments" сияқты хабардың пайдасы аз. Ал "field: customer_id, expected: integer, got: "12A"" деген хабарды әзірлеушіге бірден беруге немесе түзету тізбегіне салуға болады.

Жақсы тәжірибе — сәтсіз шақыруларды регрессия үшін бөлек мысал ретінде сақтау. Тек модельдің шикі жауабы емес, толық контекстті де: құрал сипаттамасын, prompt-ты, провайдер жауабын, нормаланған аргументтерді және тексеру нәтижесін. Сонда қабатты түзегеннен кейін бұрынғы құлауларды қайта іске қосып, шынымен жақсарғанын бірден көресіз.

Кішкентай мысал: модель get_balance-ты шақырып, account=\"00125\" берді, ал валидаторыңыз сан күтеді. Егер бұл схема қатесі болса, типті не жолды санға нормалауды өзгертесіз. Егер сол сценарийде басқа провайдер мүлде search_customer таңдап кетсе, бұл модель қатесі. Егер екі нұсқа да кейде таймауттан құласа, мәселе желіде, аргументтерде емес.

Сұраулар AI Router сияқты шлюз арқылы өтсе, журналға тек ішкі id емес, шақыру қай провайдерге жіберілгенін де қосқан пайдалы. Әйтпесе сырттай бірдей екі ақау бір қате сияқты көрінеді, ал себебі әртүрлі болуы мүмкін. Іс жүзінде бұл көп сағатты үнемдейді.

Іске қоспас бұрын қысқа тексеру тізімі

Бір endpoint-ті қолданыңыз
Бірнеше адаптер мен артық кодсыз провайдерлердің айырмасын тексеріңіз.

Релиз алдында бәрін қамтитын тағы ондаған тест жазғаннан гөрі, бірнеше қиын сценарийді қолмен де, автотестпен де өткізу пайдалырақ. Дәл солар арқылы бірнеше провайдердегі tool calling жиі бұзылады, тіпті сұраулар үйлесімді болып көрінсе де.

Бірдей құрал барлық жерде бірдей аталуы керек, get_user, getUser және fetch_user сияқты үнсіз айырмашылықтарға жол жоқ. Модель үшін олар — әртүрлі функциялар. Егер сізде ортақ шлюз арқылы маршруттау болса, атаудағы қате жоғалып кетпейді, тек кейінірек шығып, талдауды шатастырады.

Іске қоспас бұрын мына бес нәрсені тексеріңіз:

  • продқа баратын барлық провайдерде құрал атауларын, enum мәндерін және аргумент сипаттамаларын салыстырыңыз
  • міндетті өрістер мен әдепкі мәндерді тексеріңіз
  • жүйе бос tool call-ды көтере алатынына көз жеткізіңіз
  • артық өріс пен қате типке қалай жауап беретінін қараңыз
  • логтар арқылы кіріс prompt-тен модельдің финалдық жауабына дейінгі бүкіл тізбекті қайта құра алатыныңызға көз жеткізіңіз

Кішкентай мысал: check_order құралы order_id-ді жол ретінде күтеді. Бір провайдер 12345 санын үнсіз өткізіп жібереді, екіншісі schema қатесін қайтарады, үшіншісі бос аргументтері бар tool call береді. Егер қосымша типті алдын ала нормализациялап, бос шақыруды ұстап, шикі payload-ты журналға жазса, ақау жарты күн емес, 10 минутта жөнделеді.

Бөлек бір тексеретін нәрсе — логтардың ретрайлар арасында контекст жоғалтпауы. Әйтпесе сіз тек финалдық қатені көресіз де, модель схеманы бұзды ма, прокси өрісті қиып тастады ма, әлде кодыңыз аргументтерді қате жинады ма — түсінбей қаласыз.

Келесі не істеу керек

Теориядан кейін бірден барлық жағдайға арналған "әмбебап" қабат жазуға асықпаңыз. Алдымен шын мәнінде қолданатын 2-3 провайдерді алып, бірдей тест жиынын өткізіңіз. Әйтпесе өте тез әдемі көрінетін, бірақ нақты LLM-дегі бірінші tool calling-та-ақ бұзылатын код пайда болады.

Жақсы бастапқы жиын қарапайым: міндетті өрісі жоқ бір құрал, аргументтерінде nested объектісі бар бір құрал және модель шақырудан бас тартуы тиіс бір сценарий. Соның өзі функция аргументтері схемаларындағы, өріс атауларындағы, хабарлама реттеріндегі және қате мәтіндеріндегі айырманы көруге жетеді. Көбіне мәселе функцияның өзінде емес, провайдердің JSON Schema-ны қалай сипаттауды күтетінінде немесе жарамсыз аргументтерді қалай қайтаратынында.

Қасында қысқа кесте құрып, оны жазбаларда емес, кодтың жанында ұстаған пайдалы. Әдетте оған бес баған жеткілікті: провайдер құрал сипаттамасын қалай қабылдайды, модель аргументтерді қалай қайтарады, жарамсыз JSON келгенде не түседі, құралды шақырудан бас тарту қалай көрінеді және қандай өрістерді өзіңізде нормализациялау керек.

Мұндай кесте қай жерде жалпы контракт барын, ал қай жерде жеке тармақ қалдырған дұрыс екенін тез көрсетеді. Бір абстракция тек маңызды айырмашылықтарды жасырмай тұрған кезде ғана пайдалы.

Сосын нормализация ережелерін команданың кодына тікелей бекітіңіз. Басда ғана емес, wiki-де де емес, тесттерде және бір адаптер қабатында. Мысалы, кез келген құралды шақырар алдында әрдайым үш нәрсе істелсін деп келісіңіз: аргументтерді бір форматқа келтіру, міндетті өрістерді валидациялау және ақауларды талдау үшін провайдердің шикі жауабын сақтау.

Егер сізге әртүрлі модельдер үшін бір OpenAI-үйлесімді кіріс керек болса, оны алдын ала өз трафигіңізде тексерген дұрыс. AI Router жағдайында ыңғайлысы — тек base_url-ды api.airouter.kz-ке ауыстырып, үйреншікті SDK-лармен жұмыс істей беруіңізге болады. Бірақ іске қоспай тұрып, шлюз арқылы әр провайдердің tool call-дары қалай өтетінін, аудит логтарында не көрінетінін және кілт деңгейінде rate limits қай жерде іске қосылатынын бәрібір тексеру керек.

Егер осы мақаладан кейін бір ғана практикалық әрекет жасасаңыз, ол бірдей prompt-тар мен бірдей құралдармен жалпы тесттік прогон болсын. Сонда бірнеше провайдер арқылы құрал шақыру лотерея болудан қалады да, жүйенің болжамды бөлігіне айналады.

Жиі қойылатын сұрақтар

Неге бірдей құрал шақыруы барлық провайдерде жұмыс істемейді?

Өйткені API-дің тек жалпы пішіні ғана сәйкес келеді, ал ұсақ детальдары әр провайдерде бөлек. Бір провайдер схеманы қатаң тексереді, екіншісі tool_call-ды басқаша орайды, үшіншісі 200 қайтарып, ішінде бұзылған мазмұн жібереді, сондықтан сіздің кодыңыз мүлде басқа жағдаймен беттеседі.

Қай жерден бұзылғанын тез табу үшін нені логтау керек?

Ең алдымен құрал схемасын, шикі сұрауды, шикі жауапты, парсингке дейінгі tool_call-ды және парсингтен кейінгі валидация нәтижесін сақтаңыз. Осы деректерсіз команда ақаудың қай жерде шыққанын: схема ма, модель ме, адаптер ме, әлде провайдер ме — тек болжап отырады.

Құрал схемасының қай бөліктері жиі проблема туғызады?

Көбіне required, өріс типтері, enum, nullable және артық өрістер қиындық тудырады. Сюрпризді азайтқыңыз келсе, ең алдымен type, properties және required сияқты қарапайым бөліктерден бастаңыз, ал oneOf сияқты күрделі құрылымдар мен терең nested объектілерді тек шынымен қажет болса ғана қосыңыз.

Модель аргументтерді аз шатастыруы үшін құралды қалай сипаттаған дұрыс?

Схеманы қысқа әрі анық етіңіз. Егер өріс order_id деп аталса, оны id немесе customer_order деп ауыстырмаңыз және модельге күн, сома мен идентификатор пішінін өз бетінше болжауға ерік бермеңіз.

Егер модель санның орнына жол, не `boolean` орнына жол қайтарса, не істеу керек?

Мұндай жауаптарды үнсіз түземеңіз. Модельден келген әр аргументті міндетті түрде валидациядан өткізіңіз және тек нақты ереже болса ғана типті түрлендіріңіз, мысалы 45128-ді order_id үшін жолға айналдыру қауіпсіз болса.

Егер мен OpenAI-үйлесімді шлюз арқылы жұмыс істесем, валидация керек емес пе?

Жоқ, бұл тек қосылу жолындағы айырманы азайтады. Бір endpoint орнату модельдердің мінез-құлқын бірдей қылмайды, сондықтан қосымша бәрібір схеманы, аргументтерді және қате кодтарын тексеруі керек.

arguments ішіндегі жарамсыз JSON-мен қалай жұмыс істеу керек?

Алдымен шикі жауапты сақтап, парсинг қатесін нақты көрсетіңіз. Содан кейін модельге шақыруды қайталап көруге бола ма, әлде JSON түсініксіз не backend үшін қауіпті болса, жауапты бірден қабылдамай тастаған дұрыс па — соны шешіңіз.

Қай кезде retry жасауға болады, қай кезде болмайды?

Қайталау көбіне таймауттарда, 429-да және уақытша 5xx кезінде көмектеседі. Ал провайдер схеманы қабылдамаса немесе модель аргументтерді жүйелі түрде шатастырса, retry тек уақыт пен ақшаны құртады; мұнда схеманы, prompt-ты немесе валидация қабатын өзгерту керек.

Prod-қа шығар алдында tool calling-ті қалай тексерген дұрыс?

Бірдей prompt-тарды бірдей құралдармен өзіңіз қосатын барлық провайдерлерде іске қосып шығыңыз. Міндетті түрде қалыпты шақыруды, бос аргументтерді, артық өрісті, қате типті және контекст өскен ұзақ диалогты тексеріңіз.

Ортақ қабық құрып, маңызды айырмашылықтарды қалай жасырып алмауға болады?

Екі қабатты ұстаңыз. Қолданбаның ішінде tool_name, arguments, call_id және өз қате кодыңыз сияқты ортақ форматты сақтаңыз, ал қатарында provider-specific өрістер мен шикі жауапты қалдырыңыз, сонда ақауды талдағанда маңызды детальдар жоғалмайды.