Руководство
Как вызывать kimi-k3.1-pro через API HiAPI: curl, Python и готовые к запуску запросы
Практическое руководство по интеграции: эндпоинт, параметры запроса, потоковая передача, вызовы инструментов и устранение ошибок
На этой странице
Зачем вызывать kimi-k3.1-pro через агрегирующий API
Каждая интеграция модели несёт одинаковые скрытые издержки: в первый день это интересно, во второй месяц — это поддержка. Когда вы подключаете kimi-k3.1-pro напрямую к приложению, вы вместе с ним наследуете схему аутентификации провайдера, семантику ошибок, модель квот и темп релизов. Для прототипа на одной модели это нормально. Но как только вам понадобится вторая модель, второе окружение или путь деградации на случай проблем с каким-то эндпоинтом, это превращается в трение.
Агрегирующий API сводит эти различия к одному контракту. HiAPI предоставляет kimi-k3.1-pro в виде запроса, совместимого с OpenAI, а значит, клиентский код, который вы напишете здесь, не является одноразовым. Замените идентификатор модели — и та же структура запроса будет работать с другими моделями платформы: те же заголовки, тот же массив сообщений, та же обёртка потоковой передачи.
Конкретно для kimi-k3.1-pro это имеет три практических следствия:
- Единая поверхность учётных данных. Вы управляете одним API-ключом и одним базовым URL, а не растущим набором аккаунтов провайдеров.
- Предсказуемая нагрузка. Схемы запросов и ответов стабильны между моделями, поэтому ваш слой разбора, повторов и логирования пишется один раз.
- Низкая стоимость миграции. Если позже какая-то нагрузка лучше подойдёт другой модели, изменение будет одной строкой в запросе, а не переписыванием транспортного слоя.
Остальная часть руководства — это сама интеграция: анатомия запроса, готовые к копированию вызовы curl, эквивалентный клиент на Python, затем две функции, которые обычно вызывают больше всего проблем в продакшене, — потоковая передача и вызовы инструментов, — и в конце список для устранения ошибок.
Что нужно подготовить перед началом
- API-ключ HiAPI, хранящийся там, где ваш проект хранит секреты.
- Базовый URL API вашего аккаунта из консоли HiAPI. Во всех примерах ниже используется
https://api.hiapi.ai/v1как заполнитель базового адреса; перед запуском в продакшене уточните реальный хост в консоли. - Строка идентификатора модели kimi-k3.1-pro — скопируйте её дословно из списка моделей в консоли, так как идентификатор чувствителен к регистру.
curlдля первого теста, а также Python 3.9+ с библиотекойrequestsдля примера клиента.
Форма запроса: эндпоинт, заголовки и параметры модели
Каждый вызов диалога следует одной и той же анатомии. Разберитесь в каждой части один раз — и дальше вам не придётся отлаживать каждое поле по отдельности.
Эндпоинт
Диалоговые дополнения находятся по одному пути под базовым URL:
POST {BASE_URL}/chat/completions
Это единственный эндпоинт, необходимый для всех примеров в руководстве. Потоковая передача и вызовы инструментов — не отдельные эндпоинты, а опции одного и того же тела запроса.
Заголовки
Реально важны только два заголовка:
Authorization: Bearer $HIAPI_API_KEY
Content-Type: application/json
Ключ передаётся в заголовке Authorization с префиксом Bearer. Не помещайте его в URL, параметры запроса или тело — все три способа приведут к его утечке в логи и отчёты об ошибках. Явно задавайте Content-Type; некоторые HTTP-клиенты не определяют его автоматически.
Поля тела запроса, которые действительно важны
Минимальное тело запроса содержит четыре значимых поля:
model— идентификатор kimi-k3.1-pro. Обязателен. Это поле чаще всего пишут неправильно при первой попытке, потому что оно должно совпадать точно.messages— упорядоченный массив объектов, каждый из которых содержитrole(system,userилиassistant) иcontent. Обязателен и не пуст. Порядок — это ваша история диалога; модель видит именно этот массив, и ничего больше.stream— булево значение, по умолчаниюfalse. Приtrueответ приходит в виде событий, отправленных сервером, а не единого JSON-тела. Ниже есть отдельный раздел.temperature— необязательный контроль сэмплирования. Меньшие значения дают более детерминированный вывод; большие — больше разнообразия. Выберите значение один раз для каждого случая использования и не трогайте его, не настраивайте при каждом запросе.
Необязательные поля, которые можно добавить по мере взросления интеграции:
max_tokens— верхний предел длины генерации. Полезен как ограничитель затрат и задержки. Обратите внимание: он ограничивает вывод, а не ввод.tools— массив определений инструментов, подробно описан ниже.tool_choice— управляет тем, вызывает ли модель ваши инструменты и как именно.stop— одна или несколько последовательностей, останавливающих генерацию.
Ответ, который следует ожидать
Нестриминговый ответ возвращает JSON-объект, массив choices которого содержит как минимум один элемент. В этом элементе вы найдёте объект message с role и content, а также finish_reason, который сообщает, почему генерация остановилась. Всегда разветвляйте логику по finish_reason, а не предполагайте, что содержимое полное — усечённый ответ всё равно имеет содержимое, просто это не полный ответ.
Пишите парсер для этой структуры, а не для строкового представления ответа. Так он переживёт любые смены моделей на платформе.
Рабочий запрос curl
Начните отсюда. Если он возвращает корректный ответ, значит ваш ключ, базовый URL и идентификатор модели верны, и любые дальнейшие проблемы находятся в коде, а не в учётных данных.
curl -sS "$HIAPI_BASE_URL/chat/completions" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "kimi-k3.1-pro",
"messages": [
{"role": "system", "content": "Ты — лаконичный технический ассистент."},
{"role": "user", "content": "Объясни в двух предложениях, что такое идемпотентный ключ."}
],
"temperature": 0.3,
"max_tokens": 256
}'
Пояснение к полям
-sSзаставляет curl молчать о прогрессе, но всё равно показывать ошибки. Без второйSнеудачный запрос может завершиться молча, потратив впустую целый раунд отладки.- Переменные окружения не дают ключу попасть в историю shell или остаться в буфере прокрутки терминала. Экспортируйте
HIAPI_BASE_URLиHIAPI_API_KEYв конфигурационном файле shell или загруженном.env. - Тело запроса в одинарных кавычках — правильно для POSIX shell, пока в полезной нагрузке нет одинарных кавычек. Как только они понадобятся, переместите тело в файл и передавайте через
-d @body.json— это позволяет избежать целого класса ошибок с кавычками, которые выглядят как ошибки формата JSON. - Сообщение
systemнеобязательно, но его стоит включить. Это самое простое место для фиксации тона и формата вывода. max_tokensв этом примере намеренно консервативен. Он ограничивает одновременно задержку и стоимость дымового теста.
Интерпретация результата
Успешный вызов возвращает HTTP 200 и JSON-тело. Перед продолжением убедитесь в трёх вещах:
choices— непустой массив.choices[0].message.contentсодержит реальный ответ.choices[0].finish_reason— значение нормального завершения, а не усечения по длине.
Если тело ответа — объект ошибки, переходите к разделу устранения неполадок — сообщение об ошибке обычно указывает конкретное проблемное поле.
Совет по воспроизводимости
Сохраните этот вызов curl как shell-скрипт в репозитории. Одна команда для дымового теста живого API — самый быстрый способ отличить «моя интеграция сломалась» от «мой аккаунт или ключ изменились». Запускайте её каждый раз, когда что-то кажется неправильным.
Тот же запрос на Python
Версия на Python должна выглядеть скучно — это и есть цель. Все интересные решения (идентификатор модели, базовый URL, таймауты) должны находиться в конфигурации, а не разбрасываться по местам вызова.
import os
import requests
BASE_URL = os.environ["HIAPI_BASE_URL"].rstrip("/")
API_KEY = os.environ["HIAPI_API_KEY"]
MODEL = os.environ.get("HIAPI_MODEL", "kimi-k3.1-pro")
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
def chat(messages, temperature=0.3, max_tokens=512, timeout=60):
payload = {
"model": MODEL,
"messages": messages,
"temperature": temperature,
"max_tokens": max_tokens,
}
resp = requests.post(
f"{BASE_URL}/chat/completions",
headers=HEADERS,
json=payload,
timeout=timeout,
)
resp.raise_for_status()
data = resp.json()
choice = data["choices"][0]
return choice["message"]["content"], choice.get("finish_reason")
if __name__ == "__main__":
text, reason = chat([
{"role": "system", "content": "Ты — лаконичный технический ассистент."},
{"role": "user", "content": "Объясни в двух предложениях, что такое идемпотентный ключ."},
])
print(reason)
print(text)
Почему именно так
json=, а неdata=— библиотекаrequestsсериализует словарь за вас и устанавливает тип содержимого. Ручная сериализация легко вносит ошибки экранирования.- Всегда
timeout=60— отсутствие таймаута — самая частая причина зависания рабочего процесса до его убийства менеджером. Каждый сетевой вызов в сервисе должен иметь таймаут. raise_for_status()перед разбором — это превращает сбой HTTP-уровня в исключение в точке вызова, а не позволяет некорректному телу ответа уйти вниз по потоку.MODELиз окружения — при смене модели меняется только идентификатор модели. Хранение его в конфигурации означает, что переключение — это переменная развёртывания, а не изменение кода.- Возврат
finish_reason— вызывающей стороне почти всегда нужно знать, был ли ответ усечён.
Сохранение переносимости между моделями
Сигнатура chat(messages, ...) намеренно не раскрывает ничего специфичного для модели. Если позже вы направите более дешёвую нагрузку на другую модель, либо передайте явный параметр переопределения модели, либо создайте второй клиентский объект с другим MODEL. Транспорт, заголовки, стратегия повторов и обработка ошибок остаются неизменными.
Замечание о повторах
Не выполняйте слепые повторы внутри chat(). Повторяйте на том уровне, который знает, безопасно ли повторять операцию — неудачное дополнение обычно безопасно, а запрос, уже изменивший состояние ниже по потоку, — нет. Повторяйте только при кратковременных транспортных сбоях и ответах об ограничении скорости, и только с ограниченной экспоненциальной задержкой.
Потоковые ответы без поломки клиента
Потоковая передача — это разница между мгновенным ощущением чат-интерфейса и десятью секундами пустоты. Она же вносит больше всего ошибок интеграции, потому что ответ больше не является единым JSON-документом.
Как включить
Добавьте "stream": true в тело запроса. Остальная часть запроса не меняется.
with requests.post(
f"{BASE_URL}/chat/completions",
headers=HEADERS,
json={"model": MODEL, "messages": messages, "stream": True},
stream=True,
timeout=120,
) as resp:
resp.raise_for_status()
for line in resp.iter_lines(decode_unicode=True):
if not line or not line.startswith("data:"):
continue
chunk = line[len("data:"):].strip()
if chunk == "[DONE]":
break
# разобрать chunk как JSON и прочитать choices[0].delta.content
Что фактически приходит
Тело ответа — серия событий, отправленных сервером. Каждое событие — строка data:, несущая небольшой JSON-объект. В choices[0] находится объект delta, а не объект message — delta обычно содержит фрагмент content, а может и не содержать ничего. Поток заканчивается строкой-маркером data: [DONE].
Четыре правила покрывают почти все ошибки:
- Накапливайте, не заменяйте. Каждая delta — это фрагмент. Добавляйте
delta.contentв буфер; полный ответ — это конкатенация всех фрагментов по порядку. - Пропускайте пустые delta. Первое и последнее события часто не несут содержимого. Защищайтесь от добавления
None. - Считайте
[DONE]терминатором, а не данными. Останавливайте чтение там; всё после него не относится к ответу. - Читайте
finish_reasonиз последнего события, которое его несёт. В потоковом режиме состояние завершения появляется в более поздних delta, а не в поле верхнего уровня.
Подводные камни, которые стоит назвать
- Забыли установить
stream=Trueв клиентском вызове. Вы получите весь поток как один буферизованный объект, что противоречит цели и выглядит как очень медленный нестриминговый запрос. - Таймаут задан как для нестримингового режима. Потоковая передача длинной генерации длится дольше короткого запроса. Дайте потоковому пути более щедрый таймаут чтения и рассмотрите таймер простоя, прерывающий запрос, если в течение выбранного интервала не пришло ни одного байта.
- Построчный разбор без проверки префикса. Не каждая строка является данными. Пустые строки разделяют события; игнорируйте их.
- Предположение, что у delta есть ключ
content. Потоковая передача вызовов инструментов кладёт в delta другие ключи. Всегда читайте защитно. - Забыли о клиентском потребителе. Сервер пишет поток в буфер и выводит его только в конце — технически это потоковая передача, практически — нет. Убедитесь, что нижележащий потребитель отображает фрагменты по мере их поступления.
Когда не нужна потоковая передача
Пакетные задачи, фоновое суммирование и всё, чей вывод потребляется программой, а не показывается человеку, обычно проще без потоковой передачи. Нестриминговый ответ разбирается один раз, легче логируется и проще проверяется по схеме. Используйте потоковую передачу там, где задержка видна пользователю; не делайте её режимом по умолчанию.
Добавление вызовов инструментов в поток
Вызовы инструментов позволяют модели просить ваш код выполнить действие, а не выдумывать ответ. Протокол — это двухраундовый диалог: вы объявляете инструменты, модель может ответить запросом на вызов, вы выполняете его, затем отправляете результат обратно.
Объявление инструментов
Добавьте массив tools в запрос. Каждый элемент оборачивает описание функции:
{
"model": "kimi-k3.1-pro",
"messages": [{"role": "user", "content": "Какая погода в Лиссабоне?"}],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Возвращает текущую погоду в указанном городе.",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "Название города"}
},
"required": ["city"]
}
}
}
],
"tool_choice": "auto"
}
description у функции и у каждого её параметра — не украшение, а единственное руководство для модели о том, когда и как вызывать инструмент. Пишите его так, как написали бы инструкцию новому коллеге.
Цикл ответа
- Отправьте запрос.
- Если
choices[0].finish_reasonуказывает на вызов инструмента, прочитайтеchoices[0].message.tool_calls. Каждый элемент имеетid, имя функцииnameиarguments— JSON-кодированную строку, а не объект. Разберите её. - Выполните функцию в своём коде. Проверьте аргументы перед любыми действиями с ними; модель может сгенерировать правдоподобную, но некорректную нагрузку с отсутствующими полями или неверными типами.
- Добавьте сообщение ассистента — включая его
tool_calls— в ваш массивmessages. - Добавьте новое сообщение с ролью
tool, с совпадающимtool_call_id, а результат — какcontent. - Отправьте запрос снова. Теперь модель формирует окончательный ответ, используя вывод инструмента.
Шаг 4 — тот, который все пропускают, и именно он ломается. Если вы отправите только результат инструмента без раунда вызова инструмента ассистента, в диалоге будет висячая ссылка, и у модели не будет записи о том, что она что-то запрашивала.
Обработка нескольких вызовов
Ответ может содержать несколько вызовов инструментов в одном раунде. Выполните каждый по отдельности и верните одно сообщение tool для каждого вызова, каждое со своим tool_call_id. Не объединяйте их.
Управление вызовами
tool_choice — ваш рычаг политики: auto позволяет модели решать, требование конкретного инструмента заставляет вызвать его, отключение инструментов говорит ей отвечать напрямую. Держите бюджет — если инструмент постоянно падает, а модель постоянно повторяет, цикл инструментов может работать долго. Ограничьте число итераций в своём цикле и при достижении предела верните понятное сообщение, а не позволяйте запросу тянуться бесконечно.
Считайте вывод инструмента недоверенным
Модель читает результаты инструментов как текст. Держите их маленькими, структурированными и не содержащими инструкций, а параметры проверяйте на своей стороне. Инструмент, возвращающий неограниченный текст, — это и проблема затрат, и риск корректности.
Устранение частых ошибок
Большинство сбоев интеграции попадают в пять категорий. Прежде чем менять промпт, пройдитесь по этому списку.
1. Аутентификация и авторизация
- Симптом: HTTP-статус в диапазоне 401/403.
- Проверка: ключ существует, при вставке нет пробелов до и после, и он снабжён именно префиксом
Bearer. - Проверка: базовый URL совпадает с указанным в консоли HiAPI — устаревший или неверно вставленный хост даёт запутанные ошибки аутентификации.
- Исправление: заново экспортируйте переменные окружения, затем повторите дымовой тест curl, прежде чем трогать код.
2. Некорректная нагрузка
- Симптом: ошибка валидации запроса с указанием поля или неразбираемое тело ответа.
- Проверка: тело запроса — валидный JSON. При ручной сборке проверьте его быстрым
json.tool; при сборке кодом убедитесь, что словарь случайно не вложен лишним уровнем. - Проверка:
messagesне пуст, и каждый элемент имеетroleиcontent. - Проверка: значения
roleиз поддерживаемого набора. Такая опечатка, какrole: "human", в некоторых клиентах является молчаливой ошибкой, а не очевидной. - Проверка: элементы
toolsимеютtype: "function"и вложенный объектfunction. Сглаженное определение — самая частая ошибка вызова инструментов.
3. Идентификатор модели
- Симптом: ошибка вида «не найдено» или сообщение о том, что модель недоступна для вашего аккаунта.
- Проверка: идентификатор скопирован из консоли дословно. Регистр и разделители важны.
- Проверка: модель включена для вашего ключа. Даже при валидном идентификаторе модель, которую ваш аккаунт не может вызывать, всё равно даст сбой.
4. Контекст и ограничения длины
- Симптом: ошибка о превышении максимального контекста запросом или ответ, завершающийся
finish_reason, связанным с длиной. - Проверка: сумма вашего системного промпта, истории сообщений и любых определений инструментов. Схемы инструментов учитываются в бюджете и легко забываются.
- Исправление: обрежьте историю, суммируйте ранние раунды или разделите задачу. Для усечения вывода, если нагрузка действительно требует большего, увеличьте
max_tokens; иначе держите его ограниченным.
5. Ограничения скорости и таймауты
- Симптом: статус ограничения скорости под нагрузкой или таймаут чтения на клиенте.
- Проверка: не выполняются ли повторы без какой-либо задержки. Плотный цикл повторов превращает кратковременное ограничение в постоянное.
- Исправление: следуйте сигналам ограничения скорости из ответа, используйте ограниченную экспоненциальную задержку с джиттером и контролируйте параллелизм на каждый ключ. Для таймаутов сначала проверьте значение клиентского таймаута — клиентское ограничение короче времени генерации модели даёт именно этот симптом.
Общая дисциплина отладки
При каждом сбое логируйте четыре вещи: HTTP-статус, тело ответа, идентификатор модели и был ли установлен stream. Эти четыре элемента объясняют подавляющее большинство инцидентов. И держите дымовой тест curl актуальным — когда он проходит, а ваше приложение падает, вы знаете, что проблема в коде, а не в учётных данных.
Чтение сообщений об ошибках
Агрегирующий слой обычно явно указывает, какое поле вызвало отказ. Подавите импульс переписать промпт. Прочитайте сообщение, исправьте указанное поле, повторите один раз. Если та же ошибка сохраняется, прежде чем углубляться, проверьте запрос по дымовому тесту.
Перед запуском в продакшен: чек-лист
Разрыв между «работает в моём терминале» и «работает в продакшене» в основном состоит из чек-листа, который никто не записал. Вот один, который стоит скопировать.
Конфигурация и секреты
- API-ключ хранится в менеджере секретов, никогда в системе контроля версий и никогда в URL или строках логов. Убедитесь, что ваш HTTP-клиент не может печатать заголовок
Authorizationна уровне отладки. - Базовый URL и идентификатор модели — это конфигурация, а не константы, разбросанные по кодовой базе. Сверьте базовый URL с консолью.
- Планово ротируйте ключи и ротируйте их после ухода любого члена команды. Ваш клиентский код должен подхватывать ротированный ключ без изменений.
Гигиена запросов
- У каждого исходящего вызова есть явный таймаут, у потокового пути — более щедрый таймаут плюс правило прерывания по простою.
- На каждом пути вызова задан
max_tokens. Неограниченная генерация — это неограниченные счета. - Настройки сэмплирования зафиксированы для каждого случая использования и задокументированы, чтобы результаты были воспроизводимы при необходимости отладки.
Обработка ответов
- Ваш парсер разветвляется по
finish_reasonи рассматривает усечение как отдельный результат, а не как полный ответ. - Потоковое накопление протестировано и на коротких, и на длинных ответах, включая ответы, завершающиеся досрочно.
- Аргументы вызовов инструментов проверяются перед использованием, а раунд вызова инструмента ассистента всегда возвращается в массив сообщений.
- Цикл инструментов имеет верхний предел итераций и понятное сообщение о сбое.
Поведение при сбое
- Повторы ограничены, используют ограниченную экспоненциальную задержку с джиттером и применяются только к безопасно повторяемым операциям.
- Ответы об ограничении скорости соблюдаются, а не забиваются запросами.
- Сбои логируют статус, тело ответа, идентификатор модели и флаг stream — именно эти четыре поля действительно решают инциденты.
- Дымовой тест curl запускается в CI или по расписанию, чтобы вы узнавали об изменениях учётных данных или модели из дашборда, а не от клиентов.
Затраты и ёмкость
- Вы понимаете, как тарифицируется использование — платформа взимает плату за обработанные токены, поэтому длинные промпты и длинные генерации имеют значение. Актуальные тарифы смотрите на панели цен в консоли.
- Вы знаете, какая нагрузка потребляет больше всего и нужна ли ей полная модель или более лёгкая.
- У вас есть путь деградации: если вызов неоднократно падает, приложение заметно деградирует, а не зависает молча.
Последний вопрос
Спросите себя: сможет ли человек, не написавший эту интеграцию, наблюдать за ней. Если разработчик в вашей команде может прочитать дымовой тест, поля логов ошибок и конфигурацию и понять, как диагностировать сбой, вы закончили. Если нет, чек-лист не завершён.
С работающим вызовом curl, переиспользуемым клиентом на Python и этим чек-листом kimi-k3.1-pro действительно интегрирована, а не просто подключена.
Похожие статьи
Все статьи →-
Руководство
ElevenLabs Music API на HiAPI: генерация музыки с помощью curl, Python и рецептов промптов
Практическое руководство по вызову elevenlabs/music-v2.5 через HiAPI с готовыми к копированию рецептами промптов для стиля, настроения и длительности
-
Руководство
Как использовать gpt-image-2.5-sunburst/image-to-image через HiAPI API: curl и Python
Готовые к запуску запросы для разработчиков, процесс загрузки референсных изображений и устранение ошибок
-
Руководство
Как использовать gemini-omni-1.2-flash через HiAPI API: curl и Python