HiAPI
Блог

Руководство

Как использовать grok-4.7 через HiAPI API: curl, Python и один рабочий запрос

Практическое руководство от первого запроса до проверки ответа

Nov 3, 2026
HiAPI 博客教程封面图:多层半透明玻璃平面在浅色背景上折射出克制的冷蓝色带。

Что нужно подготовить перед первым запросом

Прежде чем отправлять что-либо в API, убедитесь, что готовы четыре вещи. Пропуск любого из них — самая частая причина неудачи при первом вызове, и причина неудачи зачастую вовсе не связана с самой моделью.

Учётная запись HiAPI

Вам нужна действующая учётная запись HiAPI.ai. Войдите в панель управления, чтобы управлять проектами, ключами и расходом. Все действия в этом руководстве выполняются через один и тот же унифицированный интерфейс API, поэтому ключ, созданный здесь, будет работать со всеми моделями, которые предоставляет платформа.

API-ключ

Создайте API-ключ в панели управления и храните его в безопасном месте — при тестировании можно использовать переменную окружения оболочки, а для всего, что пойдёт в производство, — менеджер секретов. Никогда не коммитьте ключ в репозиторий кода и не вставляйте его в клиентское приложение.

Для локального тестирования достаточно экспортировать его один раз за сеанс оболочки:

export HIAPI_API_KEY="your-api-key-here"

Базовый URL

Базовый URL — это корневой адрес HiAPI API. Все запросы в этом руководстве выполняются относительно него. Сверьтесь с панелью управления, чтобы узнать точный базовый URL для вашей учётной записи, и сохраните его в переменную, чтобы скрипты и код приложения ссылались на одно и то же значение:

export HIAPI_BASE_URL="https://api.hiapi.ai"

Идентификатор модели

В этом руководстве используется идентификатор модели grok-4.7. Он передаётся в теле запроса как обычная строка. Если идентификатор неверен, вы обычно получите явную ошибку в ответе, а не тихий откат к другой модели, поэтому опечатку легко обнаружить.

Когда эти четыре элемента — учётная запись, ключ, базовый URL, идентификатор модели — готовы, у вас есть всё необходимое для формирования запроса. Способ с curl не требует установки никакого SDK, а способ с Python нужен только HTTP-клиент, который у вас, скорее всего, уже есть.

Быстрая проверка окружения

Убедитесь, что ключ и базовый URL видны в оболочке, которую вы будете использовать:

[ -n "$HIAPI_API_KEY" ] && echo "key set"
[ -n "$HIAPI_BASE_URL" ] && echo "base url set"

Если обе строки напечатались, можно переходить к следующему разделу.

Форма запроса к grok-4.7 на HiAPI

Все запросы в этом руководстве имеют одинаковые четыре элемента: эндпоинт, заголовок авторизации, поле model и массив messages. Понимание каждого из них по отдельности значительно упростит последующее понимание потоковой передачи и вызова инструментов, поскольку эти функции меняют лишь часть этой формы.

Эндпоинт

Вызов — это POST-запрос к эндпоинту чат-дополнений по базовому URL. В этом руководстве мы обозначаем его так:

POST {HIAPI_BASE_URL}/v1/chat/completions

Если в вашей панели управления указан другой путь, используйте путь из панели управления; в любом случае тело запроса одинаково.

Заголовок авторизации

Авторизация выполняется через bearer-токен в заголовке Authorization:

Authorization: Bearer $HIAPI_API_KEY

Поскольку это заголовок, а не query-параметр, ключ никогда не попадает в URL, журналы доступа или историю браузера.

Тип содержимого

Тело запроса — это JSON, поэтому отправляйте Content-Type: application/json. curl и любой HTTP-клиент Python устанавливают его за вас, но указать его явно стоит, чтобы набор заголовков не вызывал двусмысленности.

Тело запроса: model и messages

Тело запроса — это JSON-объект, содержащий как минимум два поля:

  • model — строка идентификатора модели, здесь grok-4.7.
  • messages — упорядоченный массив объектов сообщений. Каждый объект имеет role и content. Обычно используемые роли: system для инструкций, задающих рамки диалога, user для самого запроса, assistant для предоставления предыдущих реплик модели при продолжении диалога.

Минимальное тело запроса выглядит так:

{
  "model": "grok-4.7",
  "messages": [
    { "role": "system", "content": "You are a concise technical assistant." },
    { "role": "user", "content": "Explain what an idempotent HTTP method is in two sentences." }
  ]
}

Это весь контракт базового вызова. Всё остальное — потоковая передача, определения инструментов — это дополнительные поля того же объекта, и именно поэтому предыдущие разделы важны: как только эта форма верна, всё остальное — лишь дополнения.

Как выглядит ответ

Ответ — это JSON-объект. Часть, которая вам почти всегда нужна, находится в choices — это массив; каждый элемент содержит message с role и content. Кроме того, есть метаданные, например модель, обработавшая запрос, и блок usage, описывающий количество токенов. Прочитайте choices[0].message.content — и вы получите текст ответа. Остальные поля полезны для ведения журналов и отслеживания затрат, но для начала они не нужны.

Рабочий запрос через curl

Когда ключ экспортирован, а форма запроса понятна, вызов curl получается кратким. Это та версия, которую стоит копировать, когда нужно изолировать проблему от кода приложения.

curl -sS "$HIAPI_BASE_URL/v1/chat/completions" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "grok-4.7",
    "messages": [
      { "role": "system", "content": "You are a concise technical assistant." },
      { "role": "user", "content": "In one sentence, what is a bearer token?" }
    ]
  }'

Что делает каждый флаг

  • -sS подавляет вывод, но по-прежнему печатает ошибки. Без него неудачный запрос может выглядеть как пустой ответ.
  • URL состоит из переменной базового URL и пути чат-дополнений, поэтому вам никогда не придётся жёстко прописывать хост в скрипте.
  • -H "Authorization: ..." отправляет bearer-токен. Переменная раскрывается оболочкой — вот почему её важно было экспортировать ранее.
  • -H "Content-Type: application/json" сообщает серверу, что тело запроса — JSON.
  • -d '...' — это тело запроса. Одинарные кавычки вокруг JSON не дают оболочке интерпретировать фигурные скобки и кавычки внутри.

Если вы предпочитаете хранить тело запроса в файле, запишите его в body.json и замените аргумент -d на -d @body.json. По мере роста массива messages это обычно удобнее.

Чтение исходного JSON

Ответ приходит в стандартный вывод в виде JSON-объекта. Если хотите проверить его глазами, пропустите через форматировщик:

curl -sS "$HIAPI_BASE_URL/v1/chat/completions" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d @body.json | python -m json.tool

Вы должны увидеть массив choices, первый элемент которого содержит объект message со строкой content — эта строка и есть ответ модели. Рядом с ним обычно есть идентификатор ответа, повторённое имя модели и объект usage со счётчиками токенов промпта и дополнения. Запишите успешный ответ сейчас: когда будете проверять клиент Python, именно с ним вы будете сравнивать.

Типичные ошибки на этом этапе

401 почти всегда означает, что bearer-токен отсутствует, имеет неверный формат или не был фактически экспортирован в текущей оболочке. 400 с сообщением о теле запроса обычно означает некорректный JSON — частые виновники — лишние запятые или «умные» кавычки, вставленные из документации. Сначала исправьте эти две вещи, прежде чем смотреть на что-либо ещё.

Тот же запрос на Python

Версия на Python делает то же самое с тем же телом запроса. Смысл переноса в том, чтобы перейти от теста в оболочке к коду, который можно вставить в приложение, где тело запроса — это структура данных, а не строка в кавычках.

Использование стандартной библиотеки

Если вы не хотите добавлять зависимости, достаточно urllib:

import json
import os
import urllib.request

api_key = os.environ["HIAPI_API_KEY"]
base_url = os.environ["HIAPI_BASE_URL"]

payload = {
    "model": "grok-4.7",
    "messages": [
        {"role": "system", "content": "You are a concise technical assistant."},
        {"role": "user", "content": "In one sentence, what is a bearer token?"},
    ],
}

request = urllib.request.Request(
    f"{base_url}/v1/chat/completions",
    data=json.dumps(payload).encode("utf-8"),
    headers={
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    },
    method="POST",
)

with urllib.request.urlopen(request) as response:
    body = json.loads(response.read().decode("utf-8"))

print(body["choices"][0]["message"]["content"])

Использование requests

Если requests уже есть в вашем окружении, вызов получается короче:

import os
import requests

response = requests.post(
    f"{os.environ['HIAPI_BASE_URL']}/v1/chat/completions",
    headers={"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"},
    json={
        "model": "grok-4.7",
        "messages": [
            {"role": "system", "content": "You are a concise technical assistant."},
            {"role": "user", "content": "In one sentence, what is a bearer token?"},
        ],
    },
    timeout=60,
)
response.raise_for_status()
print(response.json()["choices"][0]["message"]["content"])

Почему эта версия безопаснее для приложения

Обратите внимание на три осознанных решения. Ключ и базовый URL берутся из переменных окружения, а не из литералов в исходном коде. Тело запроса — это словарь Python, поэтому неправильно расположенная кавычка немедленно вызовет SyntaxError, а не загадочный отказ на стороне сервера. И в вызове задан таймаут: без таймаута зависшее соединение может на неопределённый срок подвесить рабочий процесс.

Запустите версию на Python с тем же промптом, который использовали в curl. Формулировка ответа может немного отличаться от запуска к запуску — модель не детерминирована, — но структура ответа должна быть точно такой же: массив choices, message с content и блок usage. Если структура совпадает, ваш клиент подключён правильно, а все остальные разделы — необязательные улучшения.

Включение потоковой передачи

Потоковая передача меняет способ поступления токенов, а не то, что вы запрашиваете. Вместо ожидания полного ответа вы получаете его постепенно — именно поэтому интерфейсы чата кажутся отзывчивыми.

Изменения в запросе

Добавьте одно поле в уже имеющееся тело запроса:

{
  "model": "grok-4.7",
  "stream": true,
  "messages": [
    { "role": "user", "content": "Count from one to five, one number per line." }
  ]
}

Эндпоинт, заголовки и остальная часть messages не меняются. В этом и весь смысл предварительного изучения базовой формы: потоковая передача — это дополнительный флаг, а не второй API.

Что возвращается

При включённом stream ответ больше не является единым JSON-объектом. Это последовательность событий, отправляемых сервером (SSE). Каждое событие несёт строку data:, полезная нагрузка которой — JSON-фрагмент той же формы, что и обычный ответ, только в choices[0] находится объект delta, а не полный message. Ранние фрагменты могут содержать только роль; средние фрагменты несут части содержимого; поток заканчивается строкой-маркером data: [DONE].

Ваша задача как клиента — объединять строки delta.content по порядку и остановиться на маркере. Любой фрагмент без content следует считать пустой операцией, а не ошибкой.

Обработка чанков в Python

import json
import os
import requests

with requests.post(
    f"{os.environ['HIAPI_BASE_URL']}/v1/chat/completions",
    headers={"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"},
    json={
        "model": "grok-4.7",
        "stream": True,
        "messages": [{"role": "user", "content": "Count from one to five."}],
    },
    stream=True,
    timeout=60,
) as response:
    response.raise_for_status()
    for line in response.iter_lines():
        if not line:
            continue
        line = line.decode("utf-8")
        if not line.startswith("data: "):
            continue
        data = line[len("data: "):]
        if data == "[DONE]":
            break
        delta = json.loads(data)["choices"][0].get("delta", {})
        text = delta.get("content")
        if text:
            print(text, end="", flush=True)

Две детали определяют, будет ли потоковая передача работать или выглядеть зависшей. Передайте HTTP-клиенту stream=True, чтобы он не буферизовал всё тело ответа, и итерируйте построчно, а не читайте ответ сразу целиком. flush=True в print влияет только на то, что вы видите на экране; без него вывод может выглядеть как внезапный всплеск в конце, даже если чанки обрабатывались по мере поступления.

Проверяйте потоковую передачу отдельно

Не проверяйте потоковую передачу и вызов инструментов в одном и том же тесте. Сначала убедитесь, что объединённый текст даёт разумный ответ на простой промпт, затем добавляйте функции по одной. Если поток завершается без маркера, это сигнал проверять соединение, а не модель.

Вариант с вызовом инструментов

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

Куда добавляется опция

Определения инструментов — это массив tools в теле запроса. Каждый элемент описывает вызываемый объект: имя, описание того, когда его использовать, и описание JSON schema его параметров. Описание важнее, чем кажется — это единственное руководство для модели при определении, когда инструмент применим.

{
  "model": "grok-4.7",
  "messages": [
    { "role": "user", "content": "What is the weather in Lisbon right now?" }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Return the current weather for a named city.",
        "parameters": {
          "type": "object",
          "properties": {
            "city": { "type": "string", "description": "City name, e.g. Lisbon" }
          },
          "required": ["city"]
        }
      }
    }
  ]
}

Форма, которую следует запомнить, — это type плюс function, где вложены name, description и parameters. Если у вас уже есть определения JSON schema, блок parameters — именно то место, куда их помещать.

Как отвечает модель

Когда модель решает, что нужен инструмент, сообщение assistant в choices[0] не является обычным текстом. Его content обычно пуст, а вместо него присутствует массив tool_calls. Каждый элемент имеет идентификатор, имя функции, совпадающее с одним из ваших определений, и строку arguments, содержащую JSON. Разбирайте эту строку arguments — это строка, а не объект, и её трактовка как объекта — частый источник ошибок.

Затем ваш код выполняет эту функцию и отправляет последующий запрос: исходный диалог, сообщение assistant с tool_calls и новое сообщение с ролью tool, содержащее идентификатор вызова и результат. Модель использует этот результат для генерации окончательного ответа. tool_call_id должен совпадать с идентификатором в сообщении assistant; без него последующий запрос неоднозначен.

Практические меры защиты

  • Проверяйте разобранные параметры по той же schema, которую отправили. Модель руководствуется schema, но не ограничена ею.
  • Считайте возвращённое имя функции недоверенным вводом и маршрутизируйте только к явному списку разрешённых функций.
  • Не включайте stream и инструменты одновременно при первом тестировании. Сначала убедитесь в сквозном непоточном вызове инструмента, затем, если ваш вариант использования требует обоих, комбинируйте.

Проверка ответа перед запуском в production

Вызов, работающий в терминале, не эквивалентен проверенной интеграции. Пройдите весь этот список, а затем сохраните скрипт как smoke-тест.

Подтвердите транспортный уровень

Прежде чем что-либо разбирать, проверьте, что HTTP-статус равен 200. Клиент, который разбирает ответ раньше времени, получит сбивающий с толку KeyError, когда реальная проблема — 401. Явно проверяйте статус и при неудаче логируйте вместе с телом ответа — сервер обычно сообщает, что пошло не так.

Подтвердите структуру ответа

Проверяйте, а не предполагайте. В успешном непоточном вызове проверьте три вещи: choices существует и не пуст, choices[0].message.content — непустая строка, и модель, повторённая в ответе, совпадает с той, что вы отправили. Последняя проверка ловит удивительное количество ошибок конфигурации — когда модель по умолчанию перекрывает запрошенную.

Намеренно отработайте пути ошибок

Не ждите сбоя, чтобы узнать поведение вашего кода. Выполните три быстрых негативных теста:

  • Вызовите без заголовка авторизации и убедитесь, что ваш код выдаёт явную ошибку авторизации, а не бесконечно повторяет попытки.
  • Отправьте тело запроса без поля model и убедитесь, что получаете ошибку клиента, а не зависание.
  • Отправьте намеренно очень длинный промпт и убедитесь, что ваш таймаут и обработка усечения ведут себя как ожидалось.

Каждый из них должен давать конкретный, залогированный сбой — а не общее «что-то пошло не так».

Проверяйте улучшения по отдельности

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

Сделайте проверки воспроизводимыми

Поместите всю последовательность в один файл, завершайте с ненулевым кодом при любом сбое проверки и запускайте его против вашей staging-конфигурации перед каждым развёртыванием. Это должно занимать всего несколько секунд и покрывать базовый вызов, один потоковый вызов и, если вы используете инструменты, один цикл вызова инструмента. Когда он проходит, вы можете быть уверены, что сбои в production связаны с отправляемыми вами запросами, а не с базовой инфраструктурой.

После прохождения проверок выполните вызов curl ещё раз. Если исходный JSON совпадает с выводом вашего приложения, интеграция завершена.

Похожие статьи

Все статьи →

Начните работать с постоянными артефактами ИИ

Получите API-ключ и вызывайте модели изображений, видео и аудио через один API на основе tasks.

Читать документацию API