Руководство
Как использовать grok-4.7 через HiAPI API: curl, Python и один рабочий запрос
Практическое руководство от первого запроса до проверки ответа
Что нужно подготовить перед первым запросом
Прежде чем отправлять что-либо в 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 совпадает с выводом вашего приложения, интеграция завершена.
Похожие статьи
Все статьи →-
Руководство
Как вызвать hailuo-2.3-fast/image-to-video через HiAPI API: практика с curl и Python
Первый рабочий запрос к быстрому и недорогому уровню генерации видео по изображению — от ID модели до загрузки MP4
-
Руководство
Как вызывать hailuo-2.3/text-to-video через API HiAPI: curl, Python и рабочие примеры запросов
-
Руководство
Использование Kandinsky 6.0 Pro для преобразования текста в видео на HiAPI: руководство по curl и Python
Практическая демонстрация с упором на запросы: построение вызова от промпта до видеоклипа, отправка запроса, опрос статуса завершения и скачивание результата