Как вызвать Jev на AiHubMix: руководство по структурированной классификации

AIHubMix5 мин чтения
Как вызвать Jev на AiHubMix: руководство по структурированной классификации

Коротко: jev-1.13 не генерирует текст. Вы отправляете POST-запрос с фрагментом текста и набором именованных вопросов на https://aihubmix.com/v1/systemone, а в ответ получаете типизированные ответы, индексированные по именам ваших вопросов: категорию, оценку или вероятность. Разбирать ничего не нужно. Ниже приведены рабочий запрос, полный формат ответа и одна ошибка в проектировании, которая незаметно снижает точность.

Для чего нужен Jev

Используйте его, когда нужно суждение, а не абзац текста: маршрутизация обращения в поддержку, оценка серьёзности, определение срочности, фильтрация контента. На странице модели это сказано прямо: «Без генерации текста, нечего разбирать».

Если нужны объяснения, резюме или любой свободный вывод, используйте обычную чат-модель. Jev такие результаты не формирует.

Перед началом

  • [ ] Установлен Python 3 (достаточно стандартной библиотеки)
  • [ ] Есть аккаунт AiHubMix и API-ключ
  • [ ] Ключ экспортирован как AIHUBMIX_API_KEY, и его никогда не прописывают прямо в коде

Пакеты OpenAI SDK, LangChain или requests не нужны.

Шаг 1. Изучите эндпоинт

POST https://aihubmix.com/v1/systemone
Authorization: Bearer YOUR_KEY
Content-Type: application/json

Это специфичный для модели маршрут, а не /v1/chat/completions. Клиенты, совместимые с OpenAI, его вызвать не могут. Используйте обычный HTTP.

Шаг 2. Выберите типы вопросов

Всего три типа, и их можно свободно комбинировать в одном запросе:

ТипДля чего использоватьЧто вы передаёте
choiceВыбор одной категорииcriteria в виде словаря: метка → определение
scoreОценка по упорядоченной шкалеcriteria в виде списка, от самого низкого значения к самому высокому
noulОтвет «да/нет»ничего, кроме instructions

Шаг 3. Соберите запрос

state — это текст, который нужно оценить. Ключи в questions — это имена, которые вы придумываете сами; в ответе используются те же имена.

payload = {
    "model": "jev-1.13",
    "state": "Hi, I have been trying to connect my Stripe account for 3 days "
             "and it keeps failing. I am losing sales. Please help ASAP.",
    "questions": {
        "department": {
            "type": "choice",
            "instructions": "Which team should handle this",
            "criteria": {
                "billing":   "Payment or subscription issues",
                "technical": "Bugs or integration problems",
                "sales":     "Pricing or account questions",
            },
        },
        "frustration": {
            "type": "score",
            "instructions": "How frustrated the customer appears",
            "criteria": [
                "Calm, just stating facts",
                "Frustrated but civil",
                "Very angry, strong language",
            ],
        },
        "is_urgent": {
            "type": "noul",
            "instructions": "The message conveys urgency or time-sensitivity",
        },
    },
}

Шаг 4. Отправьте запрос со стандартной библиотекой

import json, os, urllib.error, urllib.request

def ask(payload):
    req = urllib.request.Request(
        "https://aihubmix.com/v1/systemone",
        data=json.dumps(payload).encode(),
        headers={"Authorization": "Bearer " + os.environ["AIHUBMIX_API_KEY"],
                 "Content-Type": "application/json"},
        method="POST",
    )
    try:
        with urllib.request.urlopen(req, timeout=60) as r:
            return json.loads(r.read())
    except urllib.error.HTTPError as e:
        raise SystemExit(f"HTTP {e.code}: {e.read().decode(errors='replace')[:500]}")

Формируйте запрос внутри функции. Если собирать и отправлять его на уровне модуля, то при импорте файла вызов запустится снова и потратит токены.

Шаг 5. Читайте ответы

Каждый ответ хранит значение под ключом, соответствующим его type, поэтому одна функция доступа подходит для всех трёх типов:

data = ask(payload)
for name, ans in data["answers"].items():
    kind = ans["type"]
    print(name, kind, ans[kind], ans.get("confidence"))
print("usage:", data.get("usage"))

Проверенный вывод:

department   choice  billing   0.51
frustration  score   1         1
is_urgent    noul    1         None
usage: {'input_tokens': 424, 'output_tokens': 73}

Шаг 6. Разберите полный ответ

Цикл вывода скрывает полезные поля. Вот необработанный JSON для ответа типа score:

{
  "type": "score",
  "score": 1,
  "legend": {"0": "Calm, just stating facts", "1": "Frustrated but civil", "2": "Very angry, strong language"},
  "probabilities": {"0": 0, "1": 1, "2": 0},
  "confidence": 1
}
  • legend сопоставляет индекс с вашими формулировками. Целое число самодостаточно, поэтому в коде не нужна таблица соответствий.
  • probabilities даёт полное распределение, которое помогает обнаружить почти равные варианты.
  • noul не содержит поля confidence. Его сигналом служит вероятность.

На верхнем уровне также возвращаются usage, id, provider (TypeSafe) и фактическая версия бэкенда typesafe/jev-1.13-20260917.

Ошибка, которая снижает точность

В запросе выше department вернул billing с уверенностью 0.51. При повторе того же запроса та же метка пришла с уверенностью 0.38. Ответ оказался стабильным, а заявленная уверенность — нет.

Причина кроется в критериях, а не в модели. billing означает «Проблемы с платежами или подпиской», а technical — «Ошибки или проблемы интеграции». Интеграция Stripe, которая постоянно даёт сбои, действительно подходит под обе категории. Модель отразила неоднозначность, заложенную в саму схему.

Два правила перед запуском в продакшн:

  1. Формулируйте критерии choice так, чтобы они взаимно исключали друг друга. Если человек колебался бы между двумя метками, колебаться будет и модель.
  2. Задайте порог уверенности и отправляйте результаты с низкой уверенностью в очередь на проверку человеком, а не принимайте их как окончательные решения. Модель, которая признаёт неуверенность, полезнее той, которая её скрывает.

Чек-лист перед запуском

  • [ ] Ключ загружен из переменных окружения или из файла с правами 600, который игнорирует VCS
  • [ ] Критерии choice проверены на пересечения
  • [ ] Определён порог уверенности, и ниже него предусмотрен резервный путь
  • [ ] Ответы noul обрабатываются отдельно, поскольку у них нет confidence
  • [ ] Неиспользуемые вопросы удалены (3 вопроса стоили 424 входных токена, 2 вопроса — 355)
  • [ ] Ответы с кодом, отличным от 2xx, записываются в лог вместе с исходным телом

Частые вопросы

Можно ли использовать OpenAI SDK? Нет. /v1/systemone не является маршрутом, совместимым с OpenAI.

Может ли jev вернуть предложение или резюме? Нет. Он отвечает только на типизированные вопросы, которые вы определили.

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

Есть ли псевдоним версии? На странице модели указан псевдоним jev-latest наряду с jev-1.13. Если важна воспроизводимость, закрепите явно указанную версию.

Сколько это стоит? На странице модели опубликованы цены: $0.0462 / M за входные токены и $0 / M за выходные токены. Это данные вендора, поэтому перед планированием бюджета уточните актуальные цены.

Каков размер контекстного окна? Страница модели противоречива: в заголовке указано 64K, а в таблице провайдера 32K. Проверьте на собственном самом длинном входе, прежде чем опираться на любое из этих значений.

Границы этого руководства

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

Начните работу на AiHubMix

jev-1.13 доступна через AiHubMix, а на странице модели есть всё, на что ссылается это руководство: эндпоинт /v1/systemone, три типа вопросов с форматами criteria, полные поля ответа и опубликованная цена: $0.0462 / M за входные токены и $0 / M за выходные токены. Псевдоним jev-latest указывает на самый новый релиз, поэтому он остаётся актуальным по мере выхода версий.

Начать здесь: https://aihubmix.com/model/jev-latest

Дальнейшие шаги:

  1. Создайте аккаунт AiHubMix и получите API-ключ
  2. Скопируйте запрос из шага 3 и функцию ask() из шага 4
  3. Замените state реальной записью из вашей очереди
  4. Сравните результат с тем, как вы классифицируете эту запись сейчас

Если это руководство оказалось полезным, подпишитесь, чтобы получать новые материалы о моделях со структурированным выводом и конвейерах классификации.

Один шлюз ко многим провайдерам ИИ. Создан для продакшена.

Перейти на AIHubMix