Быстрый старт API
Эта страница проводит разработчика от нуля до первого ответа из Нейронета. Вы обращаетесь к шлюзу AETRON, шлюз выбирает майнера, выполняет ваш запрос и возвращает результат. Проверка этого результата происходит потом, поэтому вердикт забирается вторым вызовом по идентификатору запроса. Всё описанное ниже взято из HTTP-поверхности шлюза в том виде, как она реализована сегодня.
Что нужно до старта
Нужны три вещи:
- Хост шлюза. В тестнете managed-шлюз публично доступен по адресу
https://gateway-testnet.aetron.ai, и примеры ниже используют его. В мейннете managed-шлюз пока не опубликован, поэтому хост берётся у того, кто держит шлюз вашего Нейронета, либо это ваш собственный адрес, если шлюз поднимаете вы. Подставьте его вместо хоста в примерах. Все публичные адреса перечислены в статье Сети и эндпоинты. - Идентификатор Нейронета. Целое число. Оно появляется в каждом пути слоя данных как
/n/{id}/. - Идентификатор задачи. Целое число, указывающее, какую задачу внутри Нейронета вы вызываете. Нейронет может держать несколько задач (скажем, языковую модель и модель изображений), у каждой своя модель и свои настройки проверки. См. Конфигурацию задачи.
Перед всем остальным проверьте, что шлюз вообще доступен:
curl https://gateway-testnet.aetron.ai/healthz
# ok
Аутентификация
Аутентифицироваться можно двумя способами, и дают они разное.
Ключ API. Интеграции конечных пользователей шлют ключ в заголовке x-api-key. Ключи выпускает control plane, и по префиксу видно, к какому окружению ключ относится: ak_live_ для боевых и ak_test_ для тестовых. Ключ привязан к одному Нейронету, поэтому вызов с ним другого идентификатора отклоняется. Шлюз проверяет ключ в control plane и ненадолго кэширует ответ. Если control plane недоступен, ключ отклоняется, а не пропускается.
-H "x-api-key: ak_live_YOUR_KEY"
Подпись холодным ключом владельца. Владелец Нейронета аутентифицируется, подписывая челлендж холодным ключом, которому Нейронет принадлежит, тремя заголовками: x-aetron-account (адрес ss58), x-aetron-signature (sr25519 в hex) и x-aetron-timestamp (unix-секунды). Подписывается константа AETRON-owner-auth:v1, за которой идут идентификатор Нейронета и метка времени, оба little-endian. Подпись принимается только в пределах 300 секунд от текущего времени, что закрывает повтор. Браузерные кошельки оборачивают полезную нагрузку в <Bytes>...</Bytes> перед подписью, и шлюз принимает обе формы, обёрнутую и сырую.
Ключи API дают путь инференса. Для запуска обучения нужна подпись владельца.
Отправить запрос на инференс
curl -X POST https://gateway-testnet.aetron.ai/n/7/v1/1/infer \
-H "x-api-key: ak_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": "Explain gradient clipping in two sentences.",
"params": {}
}'
В теле два поля. input - строка, а как она трактуется (обычный текст или base64), решает схема самого Нейронета. params - произвольный JSON-объект, который пробрасывается майнеру, и его можно опустить.
Успешный вызов возвращает HTTP 200:
{
"id": "9f2c...c41a",
"output": "Gradient clipping caps the norm of the gradient ...",
"verification": {
"status": "pending",
"receipt": "vrc_9f2cbe4471a0d3e2"
}
}
id - идентификатор запроса, шестнадцатеричная строка на 64 символа. Сохраните его: это ручка для запроса вердикта. receipt - короткая ссылка, собранная из того же идентификатора.
Если задача выдаёт двоичный результат (например, картинку), output будет пустой строкой, а появятся два дополнительных поля: output_b64 с сырыми байтами в base64 и content_type с определённым типом вроде image/png. На текстовом пути этих полей нет вовсе, поэтому клиент, читающий только output, продолжает работать.
Под капотом шлюз выбирает майнера, и если тот не ответил, повторяет то же задание на другом, до трёх попыток, прежде чем сдаться. У задания стоит дедлайн в 30 секунд.
Забрать вердикт проверки
Ответ модели приходит в ответе на infer, а вот вердикт по нему нет. Проверка идёт постфактум: пересчитывается только отобранная доля запросов, а кворуму нужно время, чтобы отчитаться. Поэтому вердикт забирается отдельным вызовом по идентификатору запроса.
curl https://gateway-testnet.aetron.ai/n/7/v1/requests/9f2c...c41a
{
"id": "9f2c...c41a",
"verification": {
"status": "pending",
"votes": 3,
"quorum": 20
}
}
Возможны четыре статуса:
pending: запрос попал в выборку, проверяющие ещё голосуют.votesиquorumпоказывают прогресс.verified: кворум сошёлся на честном вердикте.flagged: кворум сошёлся на мошенничестве.not_sampled: запрос не попал в выборку на пересчёт, так что докладывать по нему нечего. Большинство запросов заканчивают здесь, и это задумано: пересчитывать всё означало бы удвоить стоимость сети.
not_sampled - не отказ. Именно выборка делает проверку дешёвой, а как частичная выборка всё равно делает систематический обман невыгодным, объяснено в разделе Proof of Intelligence.
Запустить обучение
Обучение асинхронно от начала до конца. Вызов ставит задание и сразу возвращает HTTP 202, а дальше вы опрашиваете второй эндпоинт по идентификатору обучения. Этот путь требует подписи холодным ключом владельца, ключ API не подойдёт.
curl -X POST https://gateway-testnet.aetron.ai/n/7/v1/training \
-H "x-aetron-account: 5Dt..." \
-H "x-aetron-signature: 0x..." \
-H "x-aetron-timestamp: 1750000000" \
-H "Content-Type: application/json" \
-d '{
"task_id": 2,
"dataset_hash": "3ab1...9f0d",
"n_steps": 1000,
"method": "lora"
}'
dataset_hash - 64 шестнадцатеричных символа. method по умолчанию lora и принимает full, lora, sft, dpo, orpo и qlora. Поля lr, seed и round_nonce необязательны.
{
"training_id": "5b70...ee13",
"miner": "5Dt...",
"checkpoint_root": "0f44...a2c8",
"n_steps": 1000,
"status": "dispatched"
}
Дальше опрашиваем:
curl https://gateway-testnet.aetron.ai/n/7/v1/training/5b70...ee13
Статус идёт от dispatched к committed, как только обязательство майнера видно в цепи, а затем через челлендж к финальному вердикту. checkpoint_root появляется в ответе только после того, как обязательство оказалось в цепи, потому что до этого момента майнеру просто нечем отвечать залогом. Что именно доказывается, разобрано в статье Proof of Training.
Ошибки
В любом ответе с ошибкой есть поле error со стабильным строковым кодом.
| HTTP | Код | Что означает |
|---|---|---|
| 401 | unauthorized | Учётные данные отсутствуют, битые или просрочены. |
| 402 | tenant_suspended | Тариф арендатора не оплачен. |
| 403 | not_owner | Вызывающий не владеет этим Нейронетом. |
| 409 | neuronet_frozen | Нейронет неактивен. |
| 422 | pulse_floor_unmet | Нейронет ниже требуемого порога активности. |
| 429 | rate_limited | Всплеск сверх лимита на аккаунт. |
| 429 | capacity_exceeded | Мощность в цепи на эпоху исчерпана. Добавляет capacity, used и reset_epoch. |
| 429 | quota_exceeded | Дневной бюджет ключа израсходован. Добавляет limit, used и reset_at. |
| 502 | miner_error | Майнер ответил ошибкой. Причина в detail. |
| 503 | no_miner_available | Задачу никто не обслуживает. |
| 504 | miner_timeout | Ни один майнер не ответил вовремя. |
| 503 | overloaded | Шлюз сбрасывает нагрузку. |
overloaded и rate_limited приходят с заголовком Retry-After, поэтому повтор после указанной задержки - правильная реакция. У quota_exceeded Retry-After намеренно нет, потому что бюджет вернётся в момент reset_at, и повторять раньше бессмысленно.