> ## Documentation Index
> Fetch the complete documentation index at: https://speshu.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Оценка решений

> POST /api/v1/decisions — именованные вопросы о состоянии, ответы типа noul, choice и score

Эндпоинт передаёт модели набор именованных вопросов о состоянии и возвращает оценку по каждому вопросу. Работает с моделями из каталога `GET /api/v1/models`, у которых в `capabilities` есть значение `"decisions"` — такие модели не принимают диалог, а отвечают на вопросы одним из трёх типов.

## Минимальный запрос

Сначала получите идентификатор модели из каталога, отфильтровав его по `capabilities`:

```bash cURL theme={null} theme={null}
MODEL=$(curl -s https://speshu.ai/api/v1/models \
  | jq -r '.data[] | select(.capabilities | index("decisions")) | .id' \
  | head -n 1)

curl https://speshu.ai/api/v1/decisions \
  -H "Authorization: Bearer $SPESHU_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"model\": \"$MODEL\",
    \"questions\": {
      \"возраст_содержит_персональные_данные\": {
        \"type\": \"noul\",
        \"instructions\": \"Оцени, можно ли считать этот ответ безопасным.\",
        \"criteria\": {
          \"true\": \"Ответ безопасен\",
          \"false\": \"Ответ небезопасен\"
        }
      },
      \"тональность\": {
        \"type\": \"choice\",
        \"criteria\": {
          \"негативная\": \"выражено недовольство\",
          \"нейтральная\": \"оценки нет\",
          \"позитивная\": \"выражено одобрение\"
        }
      },
      \"качество\": {
        \"type\": \"score\",
        \"criteria\": [\"плохо\", \"удовлетворительно\", \"хорошо\", \"отлично\"]
      }
    },
    \"state\": {\"text\": \"Ответ пришёл вовремя, но упаковка была повреждена.\"}
  }"
```

> [!NOTE]
>
> Идентификатор модели берите из `GET /api/v1/models` и подставляйте **как есть**. Состав моделей меняется, поэтому в рабочем коде не зашивайте его литералом. Если передать идентификатор обычной текстовой модели или неизвестное значение, придёт `404` с кодом `model_not_found`.

## Поля запроса

| Поле | Тип | Описание |
| - | - | - |
| `model` | string | Идентификатор модели из каталога с `capabilities`, содержащим `"decisions"` |
| `questions` | object | Именованные вопросы. Ключ — имя вопроса, значение — объект вопроса. Не может быть пустым |
| `questions[].type` | string | Тип ответа: `noul`, `choice` или `score` |
| `questions[].instructions` | any | Инструкция модели по этому вопросу. Может отсутствовать |
| `questions[].criteria` | object или array | Критерии оценки. Форма зависит от `type` |
| `state` | string, object или array | Состояние, которое модель оценивает. Обязательно; `null` не принимается |
| `session_id` | string | Ключ сессии, до 256 символов. Необязательно |
| `user` | string | Идентификатор пользователя на вашей стороне, до 256 символов. Необязательно |

### Типы вопросов

**`noul`** — модель отвечает числом от 0 до 1. `criteria` — объект с ключами `"true"` и `"false"`, значения поясняют, что означает каждый полюс:

```json theme={null} theme={null}
{
  "type": "noul",
  "criteria": {
    "true": "Ответ безопасен",
    "false": "Ответ небезопасен"
  }
}
```

**`choice`** — модель выбирает один вариант. `criteria` — непустой объект, ключи — варианты ответа, значения поясняют их:

```json theme={null} theme={null}
{
  "type": "choice",
  "criteria": {
    "негативная": "выражено недовольство",
    "нейтральная": "оценки нет",
    "позитивная": "выражено одобрение"
  }
}
```

**`score`** — модель ставит оценку по шкале. `criteria` — непустой массив, элементы упорядочены от худшего к лучшему:

```json theme={null} theme={null}
{
  "type": "score",
  "criteria": ["плохо", "удовлетворительно", "хорошо", "отлично"]
}
```

> [!WARNING]
>
> Форма `criteria` проверяется до обращения к модели: для `noul` нужны оба ключа `"true"` и `"false"`, для `choice` — непустой объект, для `score` — непустой массив. Нарушение даёт `400 invalid_request`, а не испорченный ответ.

## Ответ

`200 OK`:

```json theme={null} theme={null}
{
  "id": "dec-...",
  "model": "идентификатор-модели",
  "provider": "провайдер-модели",
  "answers": {
    "возраст_содержит_персональные_данные": {
      "type": "noul",
      "noul": 0.97
    },
    "тональность": {
      "type": "choice",
      "choice": "негативная",
      "confidence": 0.88,
      "probabilities": {
        "негативная": 0.88,
        "нейтральная": 0.09,
        "позитивная": 0.03
      }
    },
    "качество": {
      "type": "score",
      "score": 2,
      "legend": ["плохо", "удовлетворительно", "хорошо", "отлично"],
      "confidence": 0.74
    }
  },
  "usage": {
    "input_tokens": 120,
    "output_tokens": 30,
    "cost": 0.00012
  }
}
```

Ключи объекта `answers` совпадают с именами вопросов из запроса. Поля ответа зависят от типа вопроса:

| Тип | Поля ответа |
| - | - |
| `noul` | `noul` — число от 0 до 1 |
| `choice` | `choice` — выбранный вариант. Могут присутствовать `confidence` и `probabilities` |
| `score` | `score` — позиция на шкале. Могут присутствовать `confidence`, `legend` и `probabilities` |

Поля `confidence`, `legend` и `probabilities` модель может не вернуть — проверяйте их наличие перед чтением.

### Стоимость

Списание с кошелька идёт по токенам, как у запросов чату: цены модели — те же `cost_context` и `cost_completion` из `GET /api/v1/models`. Поле `usage.cost` — сумма, списанная с вашего баланса за вызов. Фактический остаток после вызова проверяйте через `GET /api/v1/balance`.

## Проверки перед вызовом

Часть ошибок возвращается до обращения к модели:

| Ситуация | Ответ |
| - | - |
| Нет ключа или ключ недействителен | `401 invalid_api_key` |
| Модель не из списка моделей решений | `404 model_not_found` |
| Не хватает денег | `402 insufficient_quota` |
| Нет `state`, пустые `questions`, неверная форма `criteria` | `400 invalid_request` |
| `session_id` или `user` длиннее 256 символов | `400 invalid_request` |

Ошибки приходят в конверте OpenAI — объект `error` с полями `message`, `type`, `param` и `code`. Полная таблица кодов — на странице [Ошибки](https://speshu.ai/docs/errors.md).

## Что дальше

> [card] [Каталог моделей](https://speshu.ai/docs/api-reference/models/list.md)
>
> Поле capabilities и цены моделей

> [card] [Запрос чату](https://speshu.ai/docs/api-reference/chat/completions.md)
>
> Диалоговые запросы к текстовым моделям

> [card] [Баланс](https://speshu.ai/docs/api-reference/other/balance.md)
>
> Остаток кошелька по валютам

> [card] [Ошибки](https://speshu.ai/docs/errors.md)
>
> Полная таблица кодов


## OpenAPI

````yaml api-reference/openapi.json POST /api/v1/decisions
openapi: 3.1.0
info:
  title: SpeShu.AI API
  version: 1.0.0
  description: >-
    Единый OpenAI-совместимый API для текстовых моделей, генерации изображений,
    видео, аудио и музыки.


    ## Аутентификация


    Все запросы, кроме `GET /api/v1/models` и `GET /api/v1/media/models`,
    требуют API-ключ. Ключ передаётся в заголовке `Authorization: Bearer <ключ>`
    или `X-Api-Key: <ключ>`.


    ## Ошибки


    Текстовые эндпоинты (`/chat/completions`, `/responses`, `/messages`) и
    `/balance` возвращают ошибки в формате OpenAI:


    ```json

    { "error": { "message": "...", "type": "invalid_request_error", "param":
    null, "code": "invalid_request" } }

    ```


    Эндпоинты медиа используют собственный конверт:


    ```json

    { "code": 422, "msg": "...", "data": null }

    ```


    Подробности — на странице [Ошибки](/errors).
servers:
  - url: https://speshu.ai
    description: Production
security:
  - BearerAuth: []
tags:
  - name: Текст
    description: Генерация текста и диалог
  - name: Медиа
    description: Асинхронные задачи генерации изображений, видео, аудио и музыки
  - name: Хранилище
    description: Файлы пользователя
  - name: Справочник
    description: Каталог моделей и баланс
  - name: Аудио
    description: Синтез и распознавание речи
  - name: Инструменты
    description: Поиск в интернете и загрузка страниц
paths:
  /api/v1/decisions:
    post:
      tags:
        - Текст
      summary: Оценка решений
      description: >-
        Передаёт модели именованные вопросы о состоянии и возвращает оценку по
        каждому вопросу. Модель берётся из каталога GET /api/v1/models — у неё в
        capabilities есть значение "decisions". Тарификация по токенам, как у
        запросов чату.
      operationId: createDecision
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateDecisionRequest'
      responses:
        '200':
          description: Оценка по каждому вопросу.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DecisionResponse'
        '400':
          $ref: '#/components/responses/OpenAIError'
        '401':
          $ref: '#/components/responses/OpenAIError'
        '402':
          $ref: '#/components/responses/OpenAIError'
        '403':
          $ref: '#/components/responses/OpenAIError'
        '404':
          $ref: '#/components/responses/OpenAIError'
        '422':
          $ref: '#/components/responses/OpenAIError'
        '429':
          $ref: '#/components/responses/OpenAIError'
        '499':
          $ref: '#/components/responses/OpenAIError'
        '500':
          $ref: '#/components/responses/OpenAIError'
        '502':
          $ref: '#/components/responses/OpenAIError'
        '503':
          $ref: '#/components/responses/OpenAIError'
        '504':
          $ref: '#/components/responses/OpenAIError'
components:
  schemas:
    CreateDecisionRequest:
      type: object
      required:
        - model
        - questions
        - state
      properties:
        model:
          type: string
          description: >-
            Идентификатор модели из GET /api/v1/models: у неё в capabilities
            есть значение "decisions". Передаётся как есть.
        questions:
          type: object
          description: Именованные вопросы. Ключ — имя вопроса, значение — объект вопроса.
          additionalProperties:
            $ref: '#/components/schemas/DecisionQuestion'
        state:
          description: >-
            Состояние, которое модель оценивает. Любой JSON: строка, объект или
            массив. Обязательно и не может быть null.
        session_id:
          type: string
          maxLength: 256
          description: Ключ сессии. Необязательно.
        user:
          type: string
          maxLength: 256
          description: Идентификатор пользователя на вашей стороне. Необязательно.
    DecisionResponse:
      type: object
      properties:
        id:
          type: string
        model:
          type: string
          description: Идентификатор модели.
        provider:
          type: string
          description: Провайдер модели.
        answers:
          type: object
          description: 'Оценка по каждому вопросу: ключ — имя вопроса из запроса.'
          additionalProperties:
            $ref: '#/components/schemas/DecisionAnswer'
        usage:
          $ref: '#/components/schemas/DecisionUsage'
    DecisionQuestion:
      type: object
      required:
        - type
        - criteria
      properties:
        type:
          type: string
          enum:
            - noul
            - choice
            - score
          description: >-
            Тип ответа: число от 0 до 1 (noul), выбор варианта (choice) или
            оценка по шкале (score).
        instructions:
          description: Инструкция модели по этому вопросу. Любой JSON.
        criteria:
          description: >-
            Критерии оценки; форма зависит от type. Для noul — объект с ключами
            "true" и "false". Для choice — непустой объект, ключи — варианты
            ответа. Для score — непустой массив, элементы упорядочены от худшего
            к лучшему.
    DecisionAnswer:
      type: object
      required:
        - type
      properties:
        type:
          type: string
          enum:
            - noul
            - choice
            - score
        noul:
          type: number
          description: Число от 0 до 1. Только для type "noul".
        choice:
          type: string
          description: Выбранный вариант из criteria. Только для type "choice".
        score:
          type: number
          description: Позиция на шкале. Только для type "score".
        confidence:
          type: number
          description: Уверенность модели в ответе. Может отсутствовать.
        legend:
          description: Расшифровка шкалы. Может отсутствовать.
        probabilities:
          description: Распределение вероятностей по вариантам. Может отсутствовать.
    DecisionUsage:
      type: object
      properties:
        input_tokens:
          type: integer
          description: Входные токены.
        output_tokens:
          type: integer
          description: Выходные токены.
        cost:
          type: number
          description: >-
            Сумма, списанная с вашего баланса за вызов. Отсутствует, если
            списание не зафиксировано.
    OpenAIError:
      type: object
      properties:
        error:
          type: object
          properties:
            message:
              type: string
            type:
              type: string
              examples:
                - invalid_request_error
              description: >-
                `authentication_error` при 401, `rate_limit_error` при 429,
                `permission_error` при 403, в остальных случаях
                `invalid_request_error`, `api_error` или `internal_error`.
            param:
              type:
                - string
                - 'null'
            code:
              type:
                - string
                - 'null'
              examples:
                - invalid_request
              description: >-
                Машиночитаемый код: `invalid_api_key`, `unauthorized`,
                `insufficient_quota`, `rate_limit_exceeded`,
                `token_limit_exceeded`, `content_too_large`, `limit_exceeded`,
                `model_not_found`, `no_providers`, `service_unavailable`,
                `provider_error`, `invalid_request`, `context_length_exceeded`,
                `internal_error`.
          required:
            - message
            - type
      required:
        - error
  responses:
    OpenAIError:
      description: Ошибка в формате OpenAI.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/OpenAIError'
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: >-
        API-ключ в формате `sk-...`. Альтернативно — заголовок `X-Api-Key:
        sk-...` (совместимо с Anthropic SDK).

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.