# QAZBot API — инструкция для разработчиков Базовый адрес: **https://llm.kazakh.asia/v1**. Swagger: **https://llm.kazakh.asia/docs**. Эта инструкция: **https://llm.kazakh.asia/guide**. Проверка готовности: **https://llm.kazakh.asia/ready** → `{"ready":true}`. Домен подключён по HTTPS; сертификат продлевается автоматически. Это текстовый API QAZBot. Распознавание речи и озвучивание остаются отдельными сервисами: `https://stt.kazakh.asia` и `https://tts.kazakh.asia`. Для LLM, STT и TTS используются разные ключи. Сам API аватара не изменён. ## 1. Авторизация Получите у администратора **ключ LLM API для вашей организации/интеграции**. Для QAZ Bot он выдан отдельно. Передавайте его в каждом запросе: ```http Authorization: Bearer ``` Ключ имеет вид `llm_qazbot_...`. Это ключ нашего шлюза, а не временный корпоративный `access_token`. Клиенту не нужны `client_id`, `client_secret` и запросы в OAuth: шлюз получает и обновляет корпоративный токен самостоятельно. Выданный ключ действует до отзыва или замены администратором. Храните ключ на доверенном сервере интеграции. Не вшивайте его в публичный JavaScript или приложение, доступное посторонним пользователям. Для примеров ниже задайте переменные на вашей стороне: ```bash export BASE='https://llm.kazakh.asia/v1' export QAZBOT_API_KEY='<полученный ключ LLM>' ``` Без действующего ключа защищённые методы возвращают401. Swagger и `/ready` доступны без ключа. В Swagger нажмите **Authorize**, вставьте только ключ без слова Bearer, затем выполняйте запросы. ## 2. Полный список методов | Метод | Путь после базового адреса /v1 | Назначение | |---|---|---| | POST | `/chats/` | Создать новый диалог | | GET | `/chats/?offset=0&limit=20` | Получить свои диалоги | | GET | `/chats/{chat_id}/dialog` | Получить вопросы и ответы диалога | | POST | `/qazbot/chats/{chat_id}/messages` | Отправить вопрос, ответ ожидать в истории | | POST | `/qazbot/chats/{chat_id}/messages/stream` | Отправить вопрос и получить ответ через SSE | | GET | `/usage` | Посмотреть число запросов и коды ответов своего клиента | Используйте слеш в конце `/chats/`, как в примерах. `chat_id` — UUID, полученный при создании чата. Сессия разговора — это чат; это не браузерная cookie-сессия и не WebRTC-соединение. ## 3. Создание и продолжение сессии ```bash curl --fail-with-body "$BASE/chats/" \ -H "Authorization: Bearer $QAZBOT_API_KEY" \ -H 'Content-Type: application/json' \ --data '{"name":"Диалог с QAZBot"}' ``` Ожидается201 и JSON с `id`. Сохраните это значение: ```bash export CHAT_ID='' ``` Каждый следующий вопрос данного разговора отправляйте с тем же `chat_id`. Чтобы начать с чистой историей, создайте **новый чат**. При перезапуске клиента не создавайте чат заново, если хотите продолжить: сохраните его UUID у себя. Привязка чата к клиенту переживает перезапуск шлюза. Для разных пользователей создавайте разные чаты. Один ключ организации позволяет видеть все чаты этой организации: если у вас несколько конечных пользователей, их права дополнительно проверяет ваш доверенный сервер. ## 4. Формат вопроса ```json { "text": "Какой статус проекта ГПЗ в Жанаозене?", "language": "ru", "gender": "male", "preferred_address": "Арман" } ``` - `text`: обязательный чистый вопрос,1–8000символов после удаления пробелов по краям. Не добавляйте к нему системные инструкции о языке/роде. - `language`: обязательное значение `ru`, `kk` или `en`; задаётся в каждом вопросе, даже при продолжении того же чата. - `gender`: `male` или `female`, по умолчанию `male`. В русском — «нашёл/нашла», «готов/готова». Это род речи робота; пол упомянутых людей он не меняет. - `preferred_address`: необязательное обращение/имя,1–80символов. Можно не передавать или передать null. Это не поле для дополнительных инструкций. Примеры других языков: ```json {"text":"Сәлем! Өзің туралы айтып бер.","language":"kk","gender":"male"} ``` ```json {"text":"Hello! Tell me about yourself.","language":"en","gender":"male"} ``` Дополнительные поля, включая `system_prompt`, `tools`, `skydata_enabled`, отклоняются с422. Для методов сообщений шлюз использует только профиль QAZBot. Маршруты обычного SKAI и Avatar через этот домен не опубликованы. ## 5. Вариант A: ответ по SSE Для одного вопроса выбирайте **либо SSE, либо обычный POST** из следующего раздела. Отправка в оба метода создаст два сообщения. ```bash curl --no-buffer --fail-with-body \ "$BASE/qazbot/chats/$CHAT_ID/messages/stream" \ -H "Authorization: Bearer $QAZBOT_API_KEY" \ -H 'Content-Type: application/json' \ -H 'Accept: text/event-stream' \ --data '{"text":"Привет! Кто ты?","language":"ru","gender":"male"}' ``` Тип ответа: `text/event-stream`. Пример: ```text data: {"type":"start","chat_id":"...","user_message_id":"...","response_id":"..."} data: {"type":"delta","content":"Привет! Я QAZBot.","is_final":false} data: {"type":"done","response_id":"..."} data: [DONE] ``` Объединяйте **`delta.content`** в порядке получения. Для отображения и озвучки используется этот текст. Текущий бэкенд сначала формирует и проверяет ответ, затем выдаёт его частями: это не прямой поток токенов модели. События отделяются пустой строкой. Строки, начинающиеся с `:`, — служебные keep-alive-комментарии; игнорируйте их. Не считайте границы TCP-пакетов границами SSE-событий. Поток может передавать JSON частями внутри сетевых пакетов. При `type:error` покажите ошибку и проверьте историю. `[DONE]` после ошибки не означает успешный ответ. Успех — завершение `done` и `[DONE]` без `error`. Если соединение оборвалось без завершения, **не повторяйте POST автоматически**: вопрос уже мог сохраниться и обрабатываться. Сначала получите историю чата. Возобновления SSE и идемпотентного ключа у upstream API нет. ## 6. Вариант B: отправка и ожидание через историю ```bash curl --fail-with-body "$BASE/qazbot/chats/$CHAT_ID/messages" \ -H "Authorization: Bearer $QAZBOT_API_KEY" \ -H 'Content-Type: application/json' \ --data '{"text":"Какие сведения о компании доступны?","language":"ru","gender":"male"}' ``` 201 означает, что **вопрос сохранён**, а не что ответ готов. Сохраните `id` отправленного сообщения из JSON. Далее опрашивайте историю, например раз в секунду: ```bash curl --fail-with-body "$BASE/chats/$CHAT_ID/dialog" \ -H "Authorization: Bearer $QAZBOT_API_KEY" ``` Ответ — массив сообщений. Поля: `id`, `text`, `role` (`user`/`agent`), `created_at`. Найдите своё сообщение по сохранённому `id`, затем новый ответ `agent` после него. Не принимайте предыдущий ответ за ответ на новый вопрос. Даже после окончания SSE сохранение истории может слегка отставать: повторите только GET. Не пересылайте тот же вопрос из-за этой задержки. В одном чате задавайте вопросы последовательно: дождитесь ответа на предыдущий. Для независимых параллельных диалогов создавайте разные чаты. ## 7. Список сессий и доступ к истории ```bash curl --fail-with-body "$BASE/chats/?offset=0&limit=20" \ -H "Authorization: Bearer $QAZBOT_API_KEY" ``` Формат списка: ```json { "data": [{"id":"UUID","name":"Диалог с QAZBot","created_at":"2026-10-19T00:00:00+00:00"}], "meta": {"offset":0,"limit":20,"total":1} } ``` Параметры: `offset>=0`, `limit` от1до100. Список содержит только чаты, созданные через этот шлюз с вашим идентификатором клиента. Старые чаты SKAI, аватара и чаты других клиентов сюда не попадают. Чужой/неизвестный UUID возвращает404, даже если такой чат существует в корпоративной системе. История хранится в корпоративном QAZBot, локально — только каталог и владелец чатов. Замена ключа того же клиента не удаляет его историю. ## 8. Ошибки и ограничения | Код | Значение и действие | |---|---| | 401 | Ключ шлюза неверный или отозван; запросите актуальный ключ | | 404 | Чат неизвестен этому клиенту либо URL не поддерживается | | 409 | В этом чате ещё выполняется другой HTTP-запрос сообщения | | 413 | Тело запроса превышает64КиБ | | 422 | Неверные поля, язык, род, UUID или длина текста | | 429 | Занятость; учитывайте `Retry-After`, не запускайте частые повторы | | 502 | Ошибка/разрыв связи с QAZBot; перед повтором POST проверьте историю | | 503 | Временно недоступна серверная авторизация QAZBot | | 504 | Истёк таймаут ожидания; сначала проверьте историю | В шлюзе до двух одновременно открытых запросов сообщений на клиента и16на весь шлюз. Это предел открытых запросов, не гарантия скорости корпоративной модели. Фоновая генерация после201 может ещё продолжаться: клиент ждёт её по истории. Максимум открытого SSE-потока —300секунд после подключения к upstream. Обрыв клиента закрывает его upstream-соединение и освобождает занятые ресурсы шлюза; это не обещание удаления уже сохранённого вопроса. В ответе есть `X-Request-ID`. При обращении в поддержку передайте его, время, URL метода и код ошибки; сам ключ присылать не нужно. ## 9. Статистика ```bash curl --fail-with-body "$BASE/usage" \ -H "Authorization: Bearer $QAZBOT_API_KEY" ``` `requests` — число авторизованных HTTP-запросов клиента, включая создание, список, историю и сообщения; запросы статистики не считаются. `http_statuses` показывает HTTP-коды. Это не счётчик только LLM-генераций и не счёт за токены. Число токенов и тариф upstream не передаёт: `tokens:null`, `monetary_cost:null`. Ошибка внутри уже открытого SSE может сопровождаться HTTP200 — проверяйте SSE-события. Локальный журнал содержит метаданные запросов, без текста диалогов, API-ключей и корпоративных access_token. ## 10. Готовый Python-клиент В комплекте исходников есть `examples/client.py`: создание чата, список, история, обычный POST и обработка SSE с проверкой ошибок и завершения. ```bash python3 -m pip install httpx==0.28.1 export QAZBOT_API_KEY='<ваш ключ>' python3 examples/client.py ``` Использование в своём коде: ```python import os from examples.client import QAZBotClient client = QAZBotClient(os.environ['QAZBOT_API_KEY']) try: chat_id = client.create_chat('Робот: пользователь 123')['id'] # Сохраните chat_id в своей базе для продолжения этого разговора. answer = ''.join(client.stream(chat_id, 'Привет! Кто ты?', language='ru', gender='male')) print(answer) print(client.chats()) print(client.history(chat_id)) # При задержке сохранения повторите GET позже. finally: client.close() ``` Новая сессия — новый `create_chat`. Продолжение — тот же `chat_id`. Для речи: STT → `text` QAZBot → ответ QAZBot → TTS.