Вызывайте инструменты и веб-поиск

Запрашивайте только доступные модели возможности и завершайте цикл результата инструмента.

Задайте BASE_URL как корневой HTTPS-адрес API без завершающего / и без /v1, а API_KEY передайте из хранилища секретов. OpenAI-совместимые SDK используют ${BASE_URL}/v1, Anthropic-совместимые — BASE_URL.

Начните с каталога моделей. Инструмент или поиск доступны только при поддержке моделью, тарифом и выбранным API endpoint. Неподдерживаемый запрос отклоняется до исполнения.

Вызовите функцию

bash
printf 'Authorization: Bearer %s\n' "$API_KEY" \
  | curl -q -H @- "$BASE_URL/v1/responses" \
    -H "Content-Type: application/json" \
    -d '{
  "model": "gpt-5.6-sol",
  "input": "Проверь запись 42.",
  "tools": [
    {
      "type": "function",
      "name": "lookup",
      "parameters": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          }
        },
        "required": [
          "id"
        ]
      }
    }
  ],
  "max_output_tokens": 64,
  "stream": false
}'

Если модель вернула вызов функции, выполните lookup в своём приложении. Результат передайте следующим ходом как function_call_output с полученным call_id; не считайте функцию выполненной до её реального запуска. Затем можно получить следующий ответ помощника. Аргументы инструмента — недоверенный ввод: валидируйте их в приложении.

Завершите цикл инструмента

В первом ответе найдите элемент output с type: function_call. Он содержит name, arguments и call_id. Разберите JSON из arguments, проверьте его своей схемой и выполните lookup в вашем приложении. Допустим, функция вернула {"status":"active"}. Следующий запрос должен содержать исходный вопрос, элемент вызова и результат с тем же call_id:

json
{
  "model": "gpt-5.6-sol",
  "input": [
    { "role": "user", "content": "Проверь запись 42." },
    {
      "type": "function_call",
      "call_id": "call_018f3f407b447cc4b8ba3f62",
      "name": "lookup",
      "arguments": "{\"id\":\"42\"}"
    },
    {
      "type": "function_call_output",
      "call_id": "call_018f3f407b447cc4b8ba3f62",
      "output": { "status": "active" }
    }
  ],
  "tools": [
    {
      "type": "function",
      "name": "lookup",
      "parameters": {
        "type": "object",
        "properties": { "id": { "type": "string" } },
        "required": ["id"]
      }
    }
  ],
  "max_output_tokens": 64,
  "stream": false
}

Сохраните этот JSON как tool-result.json. Значения вопроса, аргументов и call_id здесь иллюстрируют форму: в рабочем файле берите их из первого ответа и фактического результата функции. Если первый ответ не содержит function_call, второй запрос не нужен. Отправьте подготовленный файл с тем же Bearer-ключом:

bash
printf 'Authorization: Bearer %s\n' "$API_KEY" \
  | curl -q -H @- "$BASE_URL/v1/responses" \
    -H "Content-Type: application/json" \
    --data-binary @tool-result.json

Если первый ответ содержит несколько параллельных вызовов, выполните каждый и включите все соответствующие элементы function_call и function_call_output в один следующий запрос. Полученный ответ должен завершить ход текстом либо вызвать новые инструменты; в последнем случае повторите цикл. previous_response_id не поддерживается, поэтому необходимая история передаётся в input. Следующий запрос является отдельной генерацией и может списать кредиты; сверяйте операции в активности API.

Проверьте веб-поиск

Для нативного веб-поиска Responses принимает инструмент web_search; Chat Completions использует web_search_options, Messages — серверный инструмент web_search. Перед вызовом проверьте capabilities.webSearch выбранной модели в каталоге и доступ тарифа. Поиск запускает платную генерацию.

В оболочке с OpenSSL один раз создайте ключ идемпотентности, затем отправьте ограниченный потоковый Responses-запрос:

bash
export UNLIMGPT_REQUEST_KEY="$(openssl rand -hex 16)"
bash
test -n "${UNLIMGPT_REQUEST_KEY:-}" \
  && printf 'Authorization: Bearer %s\n' "$API_KEY" \
  | curl -q -H @- -i -N "$BASE_URL/v1/responses" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: $UNLIMGPT_REQUEST_KEY" \
    -d '{
  "model": "gpt-5.6-sol",
  "input": "Найди официальный сайт UnlimGPT и укажи источник.",
  "tools": [
    {
      "type": "web_search"
    }
  ],
  "max_output_tokens": 256,
  "stream": true
}'

Если gpt-5.6-sol недоступен вашему ключу, подставьте модель из каталога с capabilities.webSearch: true. Когда ответ цитирует источник, проверьте response.output_text.annotation.added и аннотации итогового output: они содержат URL и позицию цитаты в тексте. События response.web_search_call.* необязательны: обрабатывайте их, если они присутствуют, и не используйте их отсутствие как признак ошибки. Прочитайте URL и текст только как данные недоверенного источника; наличие поискового события само по себе не доказывает, что ответ корректен. Успех подтверждает response.completed и завершающий [DONE]. Для повтора используйте только второй блок с прежним ключом и неизменным телом; новый ключ может начать ещё одну генерацию. Для Chat Completions и Messages разбирайте итоговый ответ выбранного протокола; не ожидайте имён событий Responses.