Мощный блог

Язык, на котором говорят LLM: разбираем контракт OpenAI API

4 августа 2026 · LLM
Язык, на котором говорят LLM: разбираем контракт OpenAI API

API-вызовы (OpenAI-совместимый формат): запрос и ответ

При работе с LLM часто требуется знать верхнеуровневый формат «запрос-ответ», который обеспечивает полноценную коммуникацию между клиентом и LLM.

Единого официального стандарта нет: каждый вендор может использовать свои соглашения. Но для ~80% кейсов можно придерживаться OpenAI-совместимого формата.

Его используют локальные серверы и провайдеры:

  • Ollama;
  • vLLM;
  • llama.cpp server;
  • DeepSeek;
  • Groq;
  • Mistral AI;
  • Anthropic через прокси/шлюз.

Важно: совместимость обычно частичная. Базовые GET /v1/models и POST /v1/chat/completions встречаются часто, а assistants, files, threads, vector stores — не везде.


Базовые правила

  • Обычно используется HTTP + JSON.
  • Основной рабочий метод — POST.
  • Справочная информация — GET.
  • Удаление объектов — DELETE.
  • Путь обычно начинается с /v1, например:
https://api.openai.com/v1

или локально:

http://localhost:11434/v1
  • В ответах часто встречается поле object. Оно показывает тип объекта: list, model, chat.completion, chat.completion.chunk и т.д.
  • Chat Completions API обычно stateless: сервер не хранит диалог автоматически. Историю нужно передавать в messages при каждом запросе.
  • Если требуется авторизация:
Authorization: Bearer <API_KEY>
Content-Type: application/json

GET-запросы

GET используется для получения справочной информации.

Список всех моделей

GET /v1/models

Пример ответа:

{
  "object": "list",
  "data": [
    {
      "id": "qwen2.5:14b",
      "object": "model",
      "created": 1785339494,
      "owned_by": "library"
    },
    {
      "id": "hodza/cotype-nano-1.5-unofficial:latest",
      "object": "model",
      "created": 1772537295,
      "owned_by": "hodza"
    }
  ]
}

Информация по конкретной модели

GET /v1/models/qwen2.5:14b

Пример ответа:

{
  "id": "qwen2.5:14b",
  "object": "model",
  "created": 1785339494,
  "owned_by": "library"
}

Обратите внимание на ключ object. Это особенность формата: он указывает тип возвращаемого объекта.

Расширенные GET-endpoint'ы

Эти endpoint'ы относятся к расширенным возможностям, например Assistants API, и поддерживаются не всеми серверами:

GET /v1/assistants
GET /v1/threads/{thread_id}/messages
GET /v1/vector_stores

Например:

  • GET /v1/assistants — список созданных ИИ-агентов.
  • GET /v1/threads/{thread_id}/messages — история сообщений из сохранённого потока.
  • GET /v1/vector_stores — список векторных хранилищ для RAG.

DELETE-запросы

Так как API работает с объектами, некоторые из них можно удалить, если сервер это поддерживает.

Важно: удаление обычно необратимо.

Удаление модели

Если сервер поддерживает удаление моделей:

DELETE /v1/models/qwen2.5:14b

Пример ответа:

{
  "id": "qwen2.5:14b",
  "object": "model",
  "deleted": true
}

В OpenAI удаление моделей обычно доступно только для отдельных owned/fine-tuned моделей. В локальных серверах поддержка зависит от реализации.

Удаление файлов

Файлы удаляются отдельно:

DELETE /v1/files/{file_id}

Пример:

DELETE /v1/files/file-abc123

Пример ответа:

{
  "id": "file-abc123",
  "object": "file",
  "deleted": true
}

Не путайте файлы и модели: модель не удаляется через /v1/files/....

Удаление расширенных объектов

Если сервер поддерживает Assistants/Threads/Vector Stores:

DELETE /v1/assistants/{assistant_id}
DELETE /v1/threads/{thread_id}
DELETE /v1/vector_stores/{vector_store_id}

Назначение:

  • удаление созданного ИИ-агента;
  • удаление сохранённого потока сообщений;
  • удаление векторного хранилища с документами.

Это важно в том числе для конфиденциальности пользователей.


POST-запросы

Основной рабочий метод — POST.

Главный endpoint для чата:

POST /v1/chat/completions

Основные поля запроса

Поле Тип Назначение
model string имя модели
messages array диалог/контекст
temperature float случайность генерации
stream boolean потоковый режим ответа
tools array доступные инструменты
tool_choice string/object режим использования инструментов
max_tokens integer лимит токенов ответа

Минимальный запрос:

{
  "model": "qwen2.5:14b",
  "messages": [
    {
      "role": "user",
      "content": "Привет"
    }
  ]
}

Поле stream

"stream": true

Если stream: true, сервер будет отправлять ответ частями, по мере генерации, а не одним целым сообщением.

Если stream: false или поле не указано, обычно возвращается один полный JSON-ответ.


Поле tools

tools — список инструментов, которые модель может предложить вызвать.

Пример:

{
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "bash",
        "description": "Execute a shell command and return the output.",
        "parameters": {
          "type": "object",
          "properties": {
            "command": {
              "type": "string",
              "description": "The bash command to execute."
            }
          },
          "required": [
            "command"
          ]
        }
      }
    }
  ]
}

Здесь передаются:

  • имя функции;
  • описание;
  • входные параметры.

Поле tool_choice

tool_choice задаёт режим работы с инструментами.

Примеры:

"tool_choice": "auto"

Модель сама решает, что делать. Если для ответа нужны инструменты — генерирует вызов. Если нет — отвечает текстом.

"tool_choice": "none"

Модель игнорирует инструменты и обязана ответить обычным текстом.

"tool_choice": "required"

Модель обязана вызвать хотя бы один инструмент из списка tools. Конкретную функцию она выбирает сама на основе контекста.


Поле max_tokens

"max_tokens": 4096

Это максимальное количество токенов, которое мы ожидаем от модели в ответе.

Важно:

  • max_tokens ограничивает ответ модели;
  • prompt-токены обычно считаются отдельно;
  • суммарный объём prompt + completion должен укладываться в контекстное окно модели;
  • в некоторых API вместо или вместе с max_tokens может использоваться max_completion_tokens.

Поле messages

messages — основной блок запроса. Это массив сообщений, который формирует контекст для модели.

Пример:

{
  "messages": [
    {
      "role": "system",
      "content": "You are a coding agent. Your job is to help the user with programming tasks.\n\nYou have access to ONE tool: `bash` — which executes shell commands and returns stdout/stderr.\n\nWorkflow:\n1. Plan what needs to be done.\n2. Use `bash` to read files, run commands, write code, etc.\n3. After gathering enough information or completing the task, give your final answer in natural language.\n4. To finish, reply with a regular message (no tool call).\n\nBe concise. Explain what you're doing before each command."
    },
    {
      "role": "user",
      "content": "Посчитай общее количество файлов в директории code-rag"
    },
    {
      "role": "assistant",
      "content": "Для подсчета общего количества файлов в директории `code-rag`, я выполню команду `find` с флагом `-type f`, чтобы найти только файлы, и посчитаю их количество.",
      "tool_calls": [
        {
          "id": "call_a5w0a9jy",
          "index": 0,
          "type": "function",
          "function": {
            "name": "bash",
            "arguments": "{\"command\":\"find code-rag -type f | wc -l\"}"
          }
        }
      ]
    },
    {
      "role": "tool",
      "tool_call_id": "call_a5w0a9jy",
      "content": "Exit code: 0\n442\n"
    }
  ]
}

Роли сообщений

Роль Назначение
system инструкции для модели
user сообщение пользователя
assistant ответ модели
tool результат выполнения инструмента

Как работает вызов инструмента

В примере модель предложила вызвать инструмент bash:

"tool_calls": [
  {
    "id": "call_a5w0a9jy",
    "index": 0,
    "type": "function",
    "function": {
      "name": "bash",
      "arguments": "{\"command\":\"find code-rag -type f | wc -l\"}"
    }
  }
]

Здесь:

  • id — уникальный идентификатор вызова;
  • index — порядковый номер вызова внутри ответа;
  • function.name — имя функции;
  • function.arguments — аргументы в виде JSON-строки.

Поле id, например call_a5w0a9jy, нужно, чтобы связать вызов инструмента с его результатом.

Ключ index можно считать счётчиком или порядковым номером вызова внутри конкретного ответа.

Если модель за раз хочет узнать погоду и курс доллара, она может вернуть массив из двух элементов:

  • у первой функции, например погоды, index будет 0;
  • у второй функции, например курса валюты, index будет 1.

Важно: модель не выполняет функцию сама. Она только возвращает предложение вызвать функцию. Выполняет функцию ваш клиент, агент или runtime. Затем результат нужно отправить обратно в messages с ролью tool.

Для корректной работы tool calling функция bash должна быть доступна на стороне клиента и должна быть описана в tools с соответствующими входными параметрами.

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


Ответ модели

Структура ответа содержит похожие логические блоки и требует понимания нюансов работы LLM.

Основные поля ответа

Поле Назначение
id уникальный идентификатор ответа
object тип ответа
created Unix Timestamp
model имя модели
system_fingerprint идентификатор конфигурации/окружения
choices список вариантов ответа
usage информация о токенах

Пример:

"object": "chat.completion"

Это означает ответ в режиме чата.

created

Содержит временную метку в формате Unix Timestamp, также известную как POSIX time.

system_fingerprint

Уникальный идентификатор, который показывает, какая конфигурация сервера и инференса использовалась при генерации ответа.

Нужен, чтобы понимать, не изменились ли:

  • серверное оборудование;
  • конфигурация;
  • параметры инференса;
  • окружение модели.

Поле может отсутствовать или быть null в некоторых реализациях.


Поле choices

choices — список вариантов ответа.

Некоторые LLM могут генерировать несколько вариантов ответа, если запросить это параметром n.

Чаще всего для экономии токенов и повышения производительности используется один вариант ответа:

choices[0]

Пример:

"choices": [
  {
    "index": 0,
    "message": {
      "role": "assistant",
      "content": "Для подсчета общего количества файлов в директории `code-rag`, я выполню команду `find` с флагом `-type f`, чтобы найти только файлы, и посчитаю их количество.\n\n",
      "tool_calls": [
        {
          "id": "call_a5w0a9jy",
          "index": 0,
          "type": "function",
          "function": {
            "name": "bash",
            "arguments": "{\"command\":\"find code-rag -type f | wc -l\"}"
          }
        }
      ]
    },
    "finish_reason": "tool_calls"
  }
]

Если вариант ответа один, index обычно равен 0, так как нумерация начинается с нуля.

Поле message похоже на элемент messages из запроса, но в ответе рядом с ним также находится finish_reason.


Поле finish_reason

finish_reason показывает, почему модель остановила генерацию.

Основные значения:

stop

Успешное завершение.

Модель закончила мысль, ответила на вопрос или встретила специальный токен конца текста, например <|endoftext|>.

tool_calls

Модель поняла, что для продолжения нужны внешние данные или действие.

Она остановилась и сформировала JSON в массиве tool_calls.

length

Превышен лимит токенов.

Ответ был принудительно оборван, потому что был достигнут лимит:

  • max_tokens;
  • max_completion_tokens;
  • общий лимит контекста или серверные ограничения.

content_filter

Сработал фильтр контента.

Генерация была заблокирована системой безопасности провайдера, например из-за политик по токсичному контенту, оружию, персональным данным и т.п.

Значение может зависеть от провайдера.

null

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

Он означает, что модель ещё генерирует ответ. В последнем чанке статус изменится, например на stop или tool_calls.


Поле usage

usage показывает расход токенов.

Пример:

"usage": {
  "prompt_tokens": 272,
  "completion_tokens": 82,
  "total_tokens": 354
}

Где:

  • prompt_tokens — объём данных, отправленных на сервер;
  • completion_tokens — объём данных, сгенерированных моделью;
  • total_tokens — сумма двух предыдущих.

Это нужно для мониторинга лимитов, стоимости и производительности.


Streaming

Если в запросе передано:

"stream": true

сервер переключает заголовок ответа в:

Content-Type: text/event-stream

Вместо одного большого JSON сервер отправляет данные порциями, чанками, по мере генерации.

Пример:

data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1677652288,"model":"gpt-4o","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}

data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1677652288,"model":"gpt-4o","choices":[{"index":0,"delta":{"content":"TCP"},"finish_reason":null}]}

data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1677652288,"model":"gpt-4o","choices":[{"index":0,"delta":{"content":" — надежный"},"finish_reason":null}]}

data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1677652288,"model":"gpt-4o","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: [DONE]

В стриминге обычно используется тип:

"object": "chat.completion.chunk"

Вместо полного message может приходить delta, например:

"delta": {
  "content": "TCP"
}

Клиент должен накапливать эти части и собирать финальный ответ.


Ошибки и надёжность

При реальной интеграции обязательно обрабатывайте ошибки.

Пример ошибки:

{
  "error": {
    "message": "Invalid value for 'messages'",
    "type": "invalid_request_error",
    "param": "messages",
    "code": null
  }
}

Типовые HTTP-коды:

Код Значение
400 некорректный запрос
401 отсутствует или неверный API-ключ
403 нет доступа
404 модель или объект не найдены
429 rate limit
500 ошибка сервера
503 сервис временно недоступен

Практические рекомендации:

  • устанавливайте timeout;
  • используйте retry для 429 и 5xx;
  • применяйте exponential backoff;
  • обрабатывайте обрыв стриминга;
  • не выполняйте инструменты без проверки;
  • проверяйте finish_reason;
  • логируйте usage для контроля лимитов.

Краткий итог

  • Единого официального стандарта API для LLM нет, но часто используют OpenAI-совместимый формат.
  • Данные обычно передаются в JSON; при стриминге используется SSE.
  • Основной рабочий endpoint:
POST /v1/chat/completions
  • LLM ожидает ключ messages с полями role и content.
  • Роли: system, user, assistant, tool.
  • Инструменты описываются в tools.
  • Модель не выполняет инструменты сама: она только возвращает tool_calls, а выполняет их клиент.
  • Ответ содержит choices, message, finish_reason и usage.
  • finish_reason показывает причину завершения генерации.
  • При stream: true ответ приходит частями в виде чанков.
  • Расширенные объекты — files, assistants, threads, vector stores — поддерживаются не везде и должны рассматриваться отдельно.
0,0
0 оценок
5★
0
4★
0
3★
0
2★
0
1★
0

Оставить отзыв

Нажмите на звезду для оценки от 1 до 5
Необязательно. Используется только для связи
0/2000

Комментарии

Все С ответами Проверенные Только 4-5★