JavaRush/Курсы/ChatGPT Apps/Как GPT решает вызвать инструмент: модель tool-call и рол...

Как GPT решает вызвать инструмент: модель tool-call и роль описаний

Открыта

1. Зачем вообще разбираться в tool-call

Если упростить, обычное веб‑приложение живёт по схеме «пользователь нажал кнопку — мы вызвали функцию». В мире ChatGPT Apps картина другая: пользователь что-то сказал, модель подумала, и, если посчитала нужным, сформировала структурированный вызов инструмента (tool-call).

То есть вы не пишете:

onClick={() => callSuggestGiftsApi(formData)}

а вместо этого:

  1. Описываете инструмент suggest_gifts (имя, описание, схему аргументов).
  2. Объясняете модели в system-prompt’е, чем этот инструмент полезен.
  3. Отдаёте управление модели: она сама решает, когда и как его вызвать.

Отсюда важно очень рано понять две вещи:

  1. GPT не видит ваш backend-код. Она видит только «шапку» инструмента: имя, описание и схему параметров.
  2. То, насколько «умно» модель будет использовать ваш App, почти напрямую зависит от того, как вы эти описания написали. Хорошие описания — это ваш «промпт для инструмента».

Сегодняшняя лекция как раз про этот «мозг» между пользователем и вашим сервером.

2. Ментальная модель tool-call: что вообще происходит

Начнём с картины целиком. Типичный сценарий для GiftGenius:

  1. Пользователь: «Подбери подарок другу 30 лет, бюджет 100 долларов, он любит видеоигры».
  2. GPT читает это сообщение и смотрит, какие есть инструменты. В нашем App, например, есть suggest_gifts.
  3. GPT решает: «Чтобы ответить хорошо, мне нужно вызвать этот инструмент».
  4. Вместо обычного текстового ответа она генерирует структуру: имя инструмента + JSON аргументы.
  5. Клиент ChatGPT видит: «Ага, это tool-call», отправляет его на ваш MCP/сервер.
  6. Ваш сервер выполняет бизнес-логику и возвращает structured output.
  7. GPT получает результат, читает его, и уже на основе ответа инструмента формирует понятный ответ пользователю и/или обновляет виджет.

С точки зрения OpenAI API, это тот же самый механизм LLM-function-calling: в ответе модели вместо обычного текста появляется объект с name инструмента и arguments, а finish_reason помечается как tool_calls. Модель не запускает код сама — она только предлагает, какой инструмент вызвать, а реальный вызов делает клиент (ChatGPT/Apps SDK).

Выглядит это примерно так (упрощённая последовательность):

sequenceDiagram
    participant U as Пользователь
    participant G as GPT (модель)
    participant C as ChatGPT клиент
    participant S as Ваш MCP/Backend

    U->>G: "Подбери подарок другу..."
    G->>C: tool-call: { name: "suggest_gifts", args: {...} }
    C->>S: HTTP /mcp tools/call (suggest_gifts, args)
    S-->>C: Результат (JSON со списком подарков)
    C-->>G: tool result
    G-->>U: Ответ + обновлённый виджет

Главный вывод: вы не пишете if (userAskedAboutGifts) callSuggestGifts(). Вы создаёте инструмент и его описание, а решение принимает модель.

3. Что видит модель: System Prompt + список инструментов

Чтобы понять, как GPT решает, что делать, нужно ясно представлять, какой набор информации у неё есть в момент выбора.

Упрощённо модель видит:

  • system‑prompt вашего App (мы ещё подробно разберём в модуле 5);
  • историю диалога: сообщения пользователя, свои же ответы, результаты прошлых tool-calls;
  • список доступных инструментов (tools) с их именами, описаниями и схемами параметров;
  • дополнительные аннотации инструментов (readOnly/destructive и т.п.).

Она не видит:

  • реализацию функций;
  • SQL‑запросы;
  • структуру ваших таблиц;
  • содержимое private репозитория с сервисом.

Чуть позже мы подробно поговорим про MCP. Пока достаточно знать, что на уровне MCP инструменты объявляются как дескрипторы: у каждого есть name, description и inputSchema (JSON Schema). При handshake ChatGPT запрашивает у MCP-сервера список инструментов и начинает воспринимать их как доступные «действия».

Пример такого дескриптора для GiftGenius (упрощённый JSON):

{
  "name": "suggest_gifts",
  "description": "Подбирает идеи подарков по возрасту, интересам и бюджету",
  "inputSchema": {
    "type": "object",
    "properties": {
      "age": { "type": "integer" },
      "budget": { "type": "number" }
    },
    "required": ["age", "budget"]
  }
}

Модель «читает» здесь только текст и структуру: что такое age, что такое budget, что делает инструмент в целом. Следующая лекция будет как раз про то, как грамотно описывать inputSchema. Сейчас — про то, как из этого описания рождается решение «а давай-ка я вызову suggest_gifts».

4. Как выглядит tool-call глазами API

ChatGPT вызывает инструменты (tools) вашего MCP-сервера примерно так же, как OpenAI Agent вызывает функции на вашем бекенде. В ChatGPT Apps SDK всё чуть более обёрнуто, но базовая механика одинаковая.

Вообразим, что мы на нашем бэкенде делаем обычный запрос к OpenAI API, и при этом передаём инструмент suggest_gifts, который модель может вызвать в своём ответе:

const response = await openai.responses.create({
  model: 'gpt-5-mini',
  messages: [
    {
      role: 'user',
      content: 'Нужен подарок другу 30 лет, бюджет 100 долларов'
    }
  ],
  tools: [ // вот тут мы передает список функций, которые LLM может "вызвать"
    {
      name: 'suggest_gifts',
      description: 'Подбирает подарки по возрасту, бюджету и интересам',
      parameters: {
        type: 'object',
        properties: {
          age: { type: 'integer' },
          budget: { type: 'number' }
        },
        required: ['age', 'budget']
      }
    }
  ]
});

Если модель решит вызвать инструмент, вы получите в ответ не текст, а сообщение ассистента с чем-то вроде:

{
  "role": "assistant",
  "tool_calls": [
    {
      "id": "call_1",
      "name": "suggest_gifts",
      "arguments": "{\"age\":30,\"budget\":100}"
    }
  ],
  "content": []
}

Таким способом LLM говорит вашему бэкенду, что ему нужно вызвать функцию suggest_gifts(30,100).

Здесь важны три вещи:

  1. Имя инструмента (name) — модель реально подставляет сюда ту строку, которую вы указали в описании tools, когда отправляли первый запрос.
  2. Аргументы (arguments) — JSON‑строка, собранная на основе parameters/inputSchema.
  3. Отсутствие обычного текстового ответа (пока что) — вместо него вы получаете структуру для вызова инструмента.

При работе ChatGPT приложения всё то же самое: модель возвращает «хочу вызвать suggest_gifts с такими параметрами», а клиент (ChatGPT) делает HTTP‑запрос на ваш MCP/сервер: tools/call с названием инструмента и аргументами.

5. Как именно модель решает: tool или текст

Теперь самое интересное: когда GPT вообще вспоминает про ваши инструменты?

Механика упрощённо такая:

  1. Модель видит очередное сообщение пользователя и текущий контекст.
  2. Внутри у неё есть «слой», который генерирует следующее сообщение ассистента, но вместо того чтобы всегда выдавать обычный текст, модель может выбрать один из вариантов завершения:
    • обычный текстовый ответ (finish_reason: "stop");
    • один или несколько tool-call’ов (finish_reason: "tool_calls");
    • иногда другие варианты (например, «нужно ещё сообщение пользователя»).
  3. На этот выбор влияет:
    • насколько пользовательский запрос похож на задачи, описанные в ваших инструментах;
    • насколько ваше описание инструмента явно говорит «используй меня именно в таком случае»;
    • данные из app system prompt, которые в Apps SDK задаются в конфигурации.

Если говорить по‑человечески, модель «примеряет» ваш инструмент к текущему запросу. Если описание: «Подбирает подарки по возрасту и интересам», а пользователь просит «анализ бюджета государства», модель даже не попытается его вызвать. Если описание слишком размытое — «делает крутые штуки» — модель не поймёт, по каким запросам его вообще стоит использовать.

Интересный нюанс: модель не обязана вызывать инструмент, даже если вы его описали. GPT может решить: «Ну тут и так всё понятно, отвечу сам, без tool‑call». Поэтому дальше в курсе мы будем активно тренироваться писать такие описания инструментов, которые делают использование инструмента для модели максимально очевидным и выгодным.

6. Имя инструмента: почему tool1 — плохая идея

Название инструмента — это по сути идентификатор, который модель будет использовать в своих вызовах. Казалось бы, это чисто техническое поле, но на практике имя очень влияет на поведение модели.

Если вы назовёте инструмент tool1, модель ничего из этого не поймёт. Для неё это просто набор символов. Если же вы назовёте его suggest_gifts, search_products или fetch_user_orders, само имя уже даёт сильный сигнал, о чём этот инструмент.

Подумайте о том, как вы сами читаете незнакомый код. Видя функцию calculateCartTotal, вы примерно представляете, чего от неё ждать. Модели нужен такой же «семантический якорь».

Для GiftGenius логичные имена инструментов могут быть:

suggest_gifts
search_products
get_product_details
create_order

Хорошо, если имя:

  • короткое, но содержательное;
  • в едином стиле (snake_case, латиница, глагол_существительное);
  • отражает одно конкретное действие.

Плохая идея — смешивать разные действия в одном инструменте, вроде do_all_gift_stuff. Модель труднее понять, когда именно его использовать, и в следующих лекциях мы увидим, как это ломает схему аргументов и осложняет отладку.

7. Описание инструмента: ваш промпт для модели

Если имя — это заголовок, то description — это мини‑документация, но не для человека‑разработчика, а именно для GPT. Разработчик прочитает код; модель — нет. Она опирается на текст описания при выборе, когда вызывать инструмент и какие аргументы туда подставлять.

Важно писать описание в стиле «инструкции по применению»:

  • когда использовать инструмент;
  • какие у него ограничения;
  • чего он делать не должен.

Возьмём наш suggest_gifts. Вот три варианта описаний.

Слишком широкое:

"Подбирает подарки."

Модель не поймёт, по какому поводу, для кого, с какими параметрами. Этот инструмент может «конкурировать» в голове модели с её общими знаниями о подарках, и она нередко решит просто ответить текстом.

Слишком узкое:

"Подбирает подарки только для младших братьев на день рождения."

Здесь мы фактически запретили использовать инструмент почти всегда. Любой другой сценарий — мама, коллега, годовщина — уже «не подходит», и модель будет избегать вызова.

Оптимальное:

"Используй этот инструмент, когда нужно подобрать подарки человеку по возрасту, типу отношений (друг, партнёр, коллега и т.п.), бюджету и интересам.
Не вызывай его для вопросов, не связанных с подарками (например, политика или погода)."

Здесь чётко описано, что инструмент делает, какие параметры для этого есть и когда его вызывать, а также добавлено отрицательное условие — для каких запросов его лучше не трогать.

Модель «любит» такие чёткие рамки. Чем яснее вы обозначите, при каких пользовательских формулировках (интентах) инструмент уместен, тем предсказуемее будет поведение App.

Мини‑упражнение

Можете прямо сейчас, не отходя от монитора, взять свой будущий App (может быть, не про подарки) и придумать для одного из его инструментов три описания: очень широкое, очень узкое и сбалансированное. А затем протестируйте, как GPT ведёт себя с разными версиями.

8. Схема аргументов: как она помогает решению

Подробно про JSON Schema мы будем говорить в следующей лекции, но для понимания tool-call’ов важно хотя бы верхнеуровневое ощущение.

Когда модель решает вызвать инструмент, ей нужно:

  1. Понять, какие аргументы этот инструмент вообще ожидает.
  2. Извлечь эти значения из текста пользователя (или из контекста).
  3. Сформировать JSON с этими аргументами.

Для этого в описании инструмента есть схема параметров (inputSchema), которая рассказывает модели:

  • какие поля есть (age, budget, relationship_type, interests и т.д.);
  • какие поля обязательные (required);
  • какие бывают типы (integer, number, string, массивы и пр.);
  • иногда — какие значения допустимы (enum) и пояснения к полям (description).

Простейший TypeScript‑интерфейс для параметров suggest_gifts может выглядеть так:

interface SuggestGiftsParams {
  age: number;
  relationship_type: 'friend' | 'partner' | 'colleague';
  budget: number;
  interests?: string[];
}

На уровне модели это превращается в JSON Schema, а модель уже по имени и описанию каждого поля догадывается, что:

  • age брать из фраз «30 лет», «для подростка» и т.п.;
  • budget из «бюджет 100 долларов», «до 50 евро»;
  • relationship_type из «друг», «коллега»;
  • interests — из «любит видеоигры».

Если вы дадите схему без описаний и с абстрактными именами полей (a, b, c), модель будет гораздо чаще ошибаться при заполнении аргументов. Мы ещё вернёмся к этому в модуле про локализацию и UX‑подсказки. Ключевая мысль здесь проста: схема — это не только проверка на бэкенде, это в первую очередь подсказка модели, что куда класть.

Мы поговорили про то, как схема помогает модели правильно собрать аргументы. Но помимо «что и как вызывать» важно ещё и «можно ли это вызывать прямо сейчас и насколько это безопасно». Здесь в игру вступают пермишены и мета‑информация об инструментах.

9. Пермишены и контекст: не каждый инструмент доступен всегда

Помимо имени, описания и схемы аргументов у инструментов есть ещё одно важное измерение — безопасность и доступ. Инструменты в реальном App сильно различаются по уровню «опасности». Одно дело — поиск подарков в публичном каталоге, другое — списание денег с карты пользователя.

Apps SDK и MCP позволяют отразить это в описании инструментов и аннотациях — например, помечать их как read-only или destructive.

Идея такая:

  • Инструменты, которые только читают публичные данные (search_products, get_weather), можно вызывать без лишних подтверждений.
  • Инструменты, которые что-то изменяют (create_order, cancel_order, charge_user), помечаются как «деструктивные». ChatGPT UI может просить у пользователя дополнительное подтверждение («Вы уверены, что хотите оформить заказ?»), а сама модель будет реже предлагать их без явного запроса.

В будущих модулях, когда будем настраивать MCP, вы увидите, как эти аннотации (_meta, destructiveHint, readOnlyHint) выглядят в реальных JSON‑дескрипторах, как они влияют на UX и на то, как ChatGPT формирует «Are you sure?» диалоги перед вызовом. Сейчас достаточно понимать:

  • GPT учитывает не только текст описания, но и метаинформацию про безопасность.
  • Инструмент, требующий аутентификации, не будет использоваться до тех пор, пока пользователь не залогинен (или пока App не получил нужный токен).

Это ещё один фактор, влияющий на решение «запускать tool или нет»: даже если по смыслу инструмент подходит, он может быть недоступен по пермишенам, и модель тогда выберет другой путь.

10. Откуда инструменты вообще берутся в ChatGPT

С архитектурной точки зрения инструмент может попасть к модели двумя основными путями.

Во‑первых, из конфигурации вашего ChatGPT App. Когда вы регистрируете App, вы указываете, какие MCP‑сервера (и их инструменты) к нему привязаны, или какие встроенные tools есть в самом приложении. При старте сессии ChatGPT получает эту конфигурацию и понимает, какие инструменты вообще доступны.

Во‑вторых, непосредственно из MCP. MCP (Model Context Protocol) определяет стандартный способ, как клиент (в нашем случае ChatGPT/Apps SDK) узнаёт, что умеет ваш сервер: он делает запрос tools/list, получает JSON с описаниями инструментов и хранит их как capabilities. Подробную механику мы разберём в отдельном модуле про MCP, сейчас важно только понять общую идею.

Схематично:

flowchart LR
  A[ChatGPT Client] -->|handshake| B[MCP Server]
  B -->|tools/list| A
  A -->|передаёт список| G[GPT Model]

После этого список инструментов становится частью контекста для модели. Если вы измените схему или описание инструмента на сервере и перезапустите App, новый дескриптор попадёт в ChatGPT при следующем handshake’е, и модель начнёт по‑новому принимать решения о вызове.

И важная практическая мысль: когда вы правите только backend (реализацию инструмента), модель об этом не знает. Но когда вы меняете name/description/schema, вы реально меняете «мозг» App. Иногда полезнее поправить одну строчку в description, чем писать 200 строк кода с эвристиками.

11. Применяем к GiftGenius: делаем инструмент, который модель захочет вызывать

Давайте теперь аккуратно свяжем всё с нашим учебным приложением GiftGenius. Представим, что у нас уже есть MCP‑сервер или backend‑слой, в котором мы регистрируем инструменты. Давайте зарегистрируем инструмент suggest_gifts с помощью server.registerTool(...).

Примитивный набросок на TypeScript (пока без реальной логики):

// pseudo-mcp-server/tools/suggestGifts.ts
server.registerTool(
  'suggest_gifts', //имя инструмента
  {
    title: 'Подбор подарков',
    description:
      'Используй этот инструмент, чтобы подобрать идеи подарков по возрасту, ' +
      'типу отношений и бюджету. Не вызывай для вопросов, не связанных с подарками.',
    inputSchema: { //описание параметров инструмента
      type: 'object',
      properties: {
        age: { type: 'integer', description: 'Возраст получателя в годах' },
        relationship_type: {
          type: 'string',
          description: 'Тип отношений: friend, partner, colleague'
        },
        budget: {
          type: 'number',
          description: 'Максимальный бюджет на подарок в валюте пользователя'
        }
      },
      required: ['age', 'budget']
    }
  },
  async ({ age, relationship_type, budget }) => { //код функции/инструмента
    // Реальная логика будет позже
    return { suggestions: [] };
  }
);

Обратите внимание на детали, которые мы продумали уже на этом этапе, хотя логика пока «заглушка»:

  • Имя: suggest_gifts, а не tool1.
  • Описание: в явном виде объясняет, когда вызывать инструмент и когда не вызывать.
  • Описания полей: помогают модели правильно маппить пользовательский текст на аргументы.

В результате, когда пользователь напишет «Подбери подарок коллеге за 50 долларов», модель увидит, что:

  • есть инструмент с именем suggest_gifts и описанием про подбор подарков;
  • у него есть поля age, relationship_type, budget;
  • budget — это «максимальный бюджет на подарок», relationship_type — «тип отношений: friend, partner, colleague».

Даже если пользователи будут выражаться неточно («до полтинника», «для напарника по проекту»), у модели будет достаточно контекста, чтобы попытаться грамотно собрать JSON аргументов.

Когда наш инструмент заработает по‑настоящему (в модуле про backend и MCP), вы уже будете отлично ориентироваться в теме: GPT будет его вызывать предсказуемо, просто потому что мы хорошо спроектировали интерфейс и описание.

12. Небольшая практика для вас

Чтобы тема не осталась чисто теоретической, рекомендую сделать небольшой эксперимент прямо после лекции.

Сначала возьмите один из своих сценариев GiftGenius или придумайте новый App. Выпишите на бумаге или в редакторе одну функцию, которую вы явно хотите дать модели — что-то вроде search_products, find_hotels, calculate_shipping.

Потом придумайте для этого же инструмента три пары «имя + описание»:

  1. Очень абстрактное имя и описание.
  2. Слишком конкретное (почти special-case).
  3. Хорошо сбалансированное имя + описание, где чётко сказано, когда вызывать инструмент и чего он не должен делать.

Дальше — по желанию — вы можете, используя обычный OpenAI SDK, сделать простой запрос с этими вариантами и посмотреть, как меняется поведение модели: вызывается ли инструмент, как она заполняет аргументы. В ресёрче по этой теме как раз приводится упражнение такого типа для suggest_gifts.

13. Типичные ошибки при проектировании tool-call и описаний

Ошибка №1: Называть инструменты tool1, handler, doStuff.
Такой нейминг абсолютно бесполезен для модели. GPT не угадывает «намерения разработчика» по названию файла; ей нужно семантически понятное имя. Если вы дадите набор tool1, tool2, tool3 без описаний, инструмент практически не будет вызываться: модель попросту не поймёт, что именно каждый делает, и либо проигнорирует их, либо выберет случайно.

Ошибка №2: Относиться к description как к комментариям для людей.
Многие пишут в описании что-то формальное вроде «Функция для подбора подарков», считая, что подробности всё равно известны из кода. Но код модель не видит, она видит только текст описания и схему аргументов. Нечёткое описание превращается в источник галлюцинаций: GPT либо попытается ответить сама, даже когда нужно было вызвать инструмент, либо вызовет инструмент в странных ситуациях.

Ошибка №3: Делать описание слишком широким или слишком узким.
Если вы пишете «Делает крутые вещи», модель не понимает границ применения. Если пишете «Подбирает подарок только для младшего брата на 18‑летие», вы фактически запрещаете использовать инструмент почти всегда. Оптимальное описание задаёт чёткую область задач (подбор подарков по ряду параметров), список ключевых параметров (возраст, отношения, бюджет, интересы) и оговаривает, для каких классов вопросов инструмент использовать не надо.

Ошибка №4: Игнорировать схему аргументов как часть «промпта».
Некоторые разработчики воспринимают JSON Schema только как способ валидации на сервере. На деле модель активно анализирует имена полей, их типы и описания, чтобы понять, какие данные нужно вытащить из пользовательского текста. Если вы назовёте поле x без описания и сделаете его опциональным, GPT начнёт заполнять его хаотично или не заполнять вовсе. Корректная схема с ясными именами и краткими описаниями сильно снижает количество невалидных tool-call’ов.

Ошибка №5: Ожидать, что модель «обязана» вызвать инструмент.
Разработчики иногда удивляются: «Почему GPT не вызвала мой инструмент, ведь он есть?». Ответ почти всегда один: из описания или system‑prompt’а не следует, что инструмент нужен именно для такого вопроса, или текст запроса попал в зону, где модель считает, что ей проще ответить самой.

Ошибка №6: Смешивать несколько разнотипных действий в одном инструменте.
Иногда хочется сделать универсальный manage_orders, который и ищет заказы, и создаёт новые, и отменяет старые. Для человека это ещё можно объяснить, а для модели получается туманный инструмент без чётких границ. GPT хуже понимает, когда именно его вызывать, и сложнее заполняет аргументы — ведь внутри становится куча опциональных полей. Лучше разделять такие действия на несколько узких инструментов (get_order, create_order, cancel_order) с ясными описаниями и схемами.

Ошибка №7: Не учитывать пермишены и безопасность в tool‑дизайне.
Если вы описываете инструмент, который может делать разрушительные действия (списание средств, удаление данных), но не помечаете его как destructive и не ограничиваете область использования в описании, вы создаёте риск. ChatGPT UI не будет спрашивать лишнее подтверждение, а модель может решиться вызвать инструмент даже в «пограничных» сценариях. Правильные аннотации и аккуратное описание («используй только после явного согласия пользователя») помогают снизить такие риски уже на уровне tool‑call’а.

1
Задача
ChatGPT Apps,  4 уровень0 лекция
Недоступна
Два интента — tool или текст (роль description)
Два интента — tool или текст (роль description)
1
Задача
ChatGPT Apps,  4 уровень0 лекция
Недоступна
Compare без “MUST call tool” (добиваемся вызова описанием)
Compare без “MUST call tool” (добиваемся вызова описанием)
Комментарии
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
У этой страницы еще нет ни одного комментария