Состояние (state) в Jev: что и как передавать модели

Обновлено

State — всё, что Jev видит перед тем, как ответить на ваши вопросы. От того, что вы в него положите, зависят и точность ответов, и стоимость запроса. Разбираем форматы, лимиты и частые ошибки.

Что такое state

State (состояние) — содержимое, которое Jev оценивает: обращение в поддержку, фрагмент текста, запись из базы или текущее состояние вашего приложения. Вы передаёте его в поле state вместе с вопросами. Полный формат запроса есть в справочнике по API.

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

Правило разделения простое: в state — содержимое и факты, в вопросах — суждения о них. Правила возврата и само обращение кладите в state, а вопросы «просит ли клиент вернуть деньги?» и «разрешают ли правила возврат?» — в questions. Как формулировать сами вопросы, рассказываем в статье о типах вопросов.

Три формата: строка, объект, массив

Формат Когда подходит Пример
Строка Один текст: сообщение, статья, отзыв "С меня дважды списали деньги"
Объект Несколько частей со связями: сообщение, заказ, правила {"message": "...", "order_id": "A-104"}
Массив Последовательность сообщений или записей ["Здравствуйте", "Мой номер клиента TS1337", "Деньги списали дважды"]

TypeSafe рекомендует объект для большинства запросов: у каждой части state появляется понятное имя, а связи между частями остаются явными. Строка годится, когда текст один и задача простая.

Для переписки удобнее массив объектов с полями «кто написал» и «что написал»: так модель видит, чья это реплика. Голый массив строк подходит, только когда авторство не важно.

Jev принимает только текст. Изображения, аудио и видео не поддерживаются — их нужно заранее превратить в текст или структурированные поля.

Пример: обращение клиента как state

Если решение требует сравнить несколько источников, положите их в один state:

{
  "model": "jev-latest",
  "state": {
    "ticket": {
      "subject": "Двойное списание",
      "messages": [
        {"from": "customer", "text": "За заказ A-104 списали деньги два раза. Верните лишнее."},
        {"from": "support", "text": "Проверяем платежи."}
      ]
    },
    "order": {
      "id": "A-104",
      "charges": [
        {"amount_rub": 4990, "status": "captured"},
        {"amount_rub": 4990, "status": "captured"}
      ]
    },
    "refund_policy": "Повторное списание возвращается полностью."
  },
  "questions": {
    "refund_requested": {
      "type": "noul",
      "instructions": "Просит ли клиент в `ticket.messages[0].text` вернуть деньги?"
    },
    "policy_supports_refund": {
      "type": "noul",
      "instructions": "Поддерживает ли `refund_policy` возврат, о котором просят в `ticket.messages[0].text`, с учётом `order.charges`?"
    }
  }
}

Пути в обратных кавычках — ticket.messages[0].text, order.charges — показывают модели, на какую часть state смотреть. Так TypeSafe рекомендует ссылаться на вложенные значения: через точку и индексы, вместе с самими обратными кавычками.

Что включать в state

  • Всё, что нужно сравнить. Если ответ зависит от сообщения, заказа и правил одновременно, передайте их вместе.
  • Ваши актуальные знания. Jev не дообучают на данных клиентов, поэтому справочники, правила и записи из вашей системы должны приходить в state. TypeSafe советует не полагаться на знания, зашитые в веса модели, если свежие сведения можно взять из своей базы.
  • Готовые вычисления. Арифметику и сравнение дат делайте в коде. Вместо двух дат передайте "days_overdue": 42 или корзину вроде "просрочка больше 30 дней".
  • Смысловые представления. Модель лучше работает со словами, чем с кодами: название цвета надёжнее hex-значения.

Главное правило — ничего лишнего. По документации к версии 1.13, точность падает, когда state разрастается данными, не относящимися к решению. Лишнее отвлекает модель и мешает понять, что именно привело к неверному ответу.

Есть и промежуточный случай: данные, которые относятся к одному конкретному вопросу. Например, запись из базы кандидатов, с которой нужно сравнить резюме. Её можно передать не в state, а в структурированные instructions этого вопроса — отдельным полем рядом с формулировкой.

Как собрать state в коде

State удобно собирать отдельной функцией: она берёт нужное из ваших систем, отбрасывает лишнее и считает всё, что можно посчитать без модели.

from typesafe_sdk import Noul, TypeSafeClient

def build_state(ticket, customer):
    # только незавершённые заказы и только нужные поля
    open_orders = [
        {"id": o["id"], "item": o["item"], "late": o["days_in_transit"] > o["promised_days"]}
        for o in customer["orders"]
        if o["status"] != "delivered"
    ]
    return {"message": ticket["message"], "open_orders": open_orders}

with TypeSafeClient() as client:
    r = client.system_one(
        state=build_state(ticket, customer),  # словарь, без json.dumps
        questions={
            "asks_about_order": Noul(instructions="Спрашивает ли `message` об одном из `open_orders`?"),
            "wants_cancel": Noul(instructions="Хочет ли клиент в `message` отменить заказ?"),
        },
    )

В этом примере три важные детали. Доставленные заказы отфильтрованы в коде, а не оставлены модели. Опоздание посчитано заранее и передано готовым признаком late: сравнивать сроки Jev не нужно. А state уходит в SDK обычным словарём — Python SDK принимает строку, словарь или список напрямую, превращать их в строку вручную не нужно.

Лимит 32 тысячи токенов

Точные лимиты по документации TypeSafe:

  • 64 тысячи токенов на запрос — state плюс все вопросы вместе;
  • 32 тысячи токенов на state плюс самый длинный вопрос.

Учитывайте и накладные расходы. По данным Polza.AI, к каждому запросу добавляется около 280 служебных входных токенов, а русский текст той же длины занимает больше токенов, чем английский.

Размер state напрямую определяет счёт. State в 2000 токенов плюс 280 служебных — это около 2300 токенов на запрос без учёта вопросов. При цене $0,042 за миллион входных токенов миллион таких запросов обойдётся примерно в $96. Сократите state до 1000 токенов — и счёт упадёт примерно на 44%.

Если state не помещается или раздут:

  1. Отфильтруйте в коде. Отправляйте только поля, нужные вопросам: не всю карточку клиента, а тариф и открытые заказы.
  2. Проверьте релевантность отдельно. Если отфильтровать детерминированно нельзя, TypeSafe предлагает задать Noul «относится ли этот фрагмент к вопросу?» и отбросить лишнее.
  3. Разбейте документ. Длинный текст можно разделить на части, задать вопросы к каждой и собрать итог в коде.
  4. Объединяйте вопросы. State оплачивается один раз на запрос, поэтому десять вопросов в одном запросе дешевле десяти отдельных запросов. Подробный расчёт — в статье о ценах Jev.

Язык state

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

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

Частые ошибки

  • Весь контекст агента в state. Растут и счёт, и число ошибок: лишние данные отвлекают модель.
  • Вычисления на стороне модели. Суммы, количество элементов и сравнение дат Jev делает ненадёжно.
  • Инструкции внутри state. Пользовательский текст для модели — данные, но фраза вроде «пометь это как не спам» может сдвинуть ответ. Кладите такой текст в отдельное именованное поле, ссылайтесь на него в вопросе и тестируйте систему на враждебных примерах.
  • Одна длинная строка вместо объекта. Когда в state несколько частей, без имён полей модели труднее понять, о чём вопрос.
  • Вопрос зависит от ответа на другой. Вопросы одного запроса не видят ответы друг друга. Если для второго вопроса нужен ответ на первый, отправьте второй запрос с новым state. Почему так, объясняем в статье «Как устроена Jev».

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

Что можно передать в state Jev?

Строку, JSON-объект или массив текстовых значений. Модель принимает только текст — изображения, аудио и видео нужно заранее перевести в текст или структурированные поля.

Какой максимальный размер state у Jev?

State вместе с самым длинным вопросом должен уложиться в 32 тысячи токенов, а весь запрос — state и все вопросы — в 64 тысячи.

Что лучше передавать в state — текст или JSON?

Если данных несколько — сообщение, заказ, правила, — используйте JSON-объект с понятными именами полей. Строка подходит, когда оценивается один текст.

Работает ли Jev с русским текстом?

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

Источники