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

# Jev 决策

> TypeSafe Jev 的 Choice、Score、Noul 原生参数、结构化输入、响应与计费说明。

Jev 是 TypeSafe 的结构化决策模型。输入业务状态 `state` 和具名问题 `questions`，同步获得分类、评分或真假概率，而不是生成聊天文本。

`POST https://api.mixroute.ai/v1/systemone`

使用 MixRoute API Key，以 `Authorization: Bearer $MIXROUTE_API_KEY` 认证，`Content-Type: application/json`。请求体保留 TypeSafe 原生的 `model`、`state`、`questions` 层级，不使用 `metadata`、聊天 `messages` 或异步任务轮询。

## 支持模型

| 模型                                            | 调用 ID                       |
| --------------------------------------------- | --------------------------- |
| [Jev 1.13](/cn/model-api/typesafe/jev-1.13.0) | `jev-1.13.0` / `jev-latest` |

`jev-1.13.0` 是固定版本 ID，`jev-latest` 是最新稳定版别名，当前都调用 Jev 1.13，属于同一个模型，不是两个独立型号。以后 latest 可能随新版本发布更新；需要固定行为时使用版本 ID，并读取响应的 model 确认实际版本。

仅使用账户 [模型列表](/cn/api-reference/endpoint/list-models) 中返回的完整型号。

## 选择问题类型

| 类型       | 适用情况                  | 主要返回字段                                           |
| -------- | --------------------- | ------------------------------------------------ |
| `choice` | 从给定候选项中选择一项，如工单分类。    | `choice`, `probabilities`, `confidence`          |
| `score`  | 沿有序、可描述的等级评分，如问题严重程度。 | `score`, `legend`, `probabilities`, `confidence` |
| `noul`   | 判断单个命题为真的概率，如是否请求退款。  | `noul`                                           |

## 顶层参数

| 字段          | 类型                      | 要求 | 说明                                                                  |
| ----------- | ----------------------- | -- | ------------------------------------------------------------------- |
| `model`     | string                  | 必填 | jev-1.13.0 或 jev-latest。使用固定版本可避免别名更新影响集成。                          |
| `state`     | string / object / array | 必填 | 所有问题共同评估的内容。可直接传文本、业务记录或对话数组；顶层不能是 null、数字或布尔值。JSON 内部可保留数字和布尔业务属性。 |
| `questions` | object                  | 必填 | 非空问题映射，不是数组。每个键是自定义 question\_id，每个值是一个问题对象。                        |

问题 ID 只用于请求与答案的对应，不参与模型推理；不要把真正的问题只写在 ID 中。多个问题针对相同 state 独立评估，可以混合三种类型，但不能依赖同一次请求中其他问题的答案。需要前后依赖时，在应用层分两次调用。

## 问题参数

以下字段位于 `questions[question_id]` 内。建议为每个问题显式填写 `instructions`，一次只描述一个明确的判断目标。

### Choice 分类

| 字段                 | 类型                             | 要求   | 说明                                               |
| ------------------ | ------------------------------ | ---- | ------------------------------------------------ |
| `type`             | string                         | 必填   | 固定为 choice。                                      |
| `instructions`     | string / object / array        | 建议提供 | 说明模型应如何选择，复杂业务规则可使用对象或数组组织。                      |
| `criteria`         | object                         | 必填   | 选项名到描述的映射，1-255 个选项，不使用 options 数组。选项名与描述都会参与判断。 |
| `criteria[option]` | string / object / array / null | 按选项  | 该选项的描述；名称本身已足够清楚时可用 null。                        |

返回 `choice` 为概率最高的选项；`probabilities` 包含所有选项，概率和约为 1。可增加 other 或 insufficient\_information 选项处理信息不足的输入。

### Score 评分

| 字段             | 类型                      | 要求   | 说明                                                     |
| -------------- | ----------------------- | ---- | ------------------------------------------------------ |
| `type`         | string                  | 必填   | 固定为 score。                                             |
| `instructions` | string / object / array | 建议提供 | 描述待评价的一个维度，例如严重程度。                                     |
| `criteria`     | array                   | 必填   | 有序等级描述，不能空，最多 10 个；建议至少两个。每项可以是字符串、对象或数组，不使用只有数字的评分标签。 |

等级索引从 0 开始：三个等级对应 0、1、2。`score` 是等级索引的概率加权位置，范围为 0 到等级数减 1，可以是小数，并非固定的 0-1 分数。`legend` 把字符串形式的索引映射回原始描述，`probabilities` 使用相同索引。使用返回的 score，不要直接截断为整数；需要离散等级时由应用选择映射规则。

### Noul 真假判断

| 字段               | 类型                             | 要求   | 说明                             |
| ---------------- | ------------------------------ | ---- | ------------------------------ |
| `type`           | string                         | 必填   | 固定为 noul。                      |
| `instructions`   | string / object / array        | 建议提供 | 一个是非问题或待判断的陈述，高值始终表示更倾向于“是/真”。 |
| `criteria`       | object / null                  | 可选   | 补充真假标准，省略时按 instructions 判断。   |
| `criteria.true`  | string / object / array / null | 可选   | 什么情况算是“是/真”。                   |
| `criteria.false` | string / object / array / null | 可选   | 什么情况算是“否/假”。                   |

返回的 `noul` 是 0-1 的概率，不是布尔值：接近 1 倾向于真，接近 0 倾向于假，接近 0.5 表示不确定。Noul 没有单独的 confidence 字段，也不是用于衡量程度的评分；程度问题使用 Score。

## 输入与上下文限制

| 项目     | 限制                                                 |
| ------ | -------------------------------------------------- |
| 输入模态   | 仅文本。支持文本字符串或包含文本及业务字段的 JSON 对象/数组；图像、音频、视频须先转换为文本。 |
| 请求总上下文 | state 与全部问题合计最多 64k tokens。                        |
| 单问题上下文 | state 与最长的一个问题合计最多 32k tokens；必须同时满足总上下文限制。        |
| Choice | 每个问题最多 255 个选项；criteria 不能为空对象。                    |
| Score  | 每个问题最多 10 个等级；criteria 不能为空数组，建议至少两个有明确区分的等级。      |

文字内容、instructions 和 criteria 都占用上下文预算。多问题请求中的 state 共用，但各个问题仍增加总输入量。不要把厂商的公开速率上限当作 MixRoute 账户的可用配额，实际限额以账户配置为准。

## 请求示例

设置服务端环境变量 `MIXROUTE_API_KEY`。下面在一次请求中混合三种问题。

```bash theme={null}
curl --request POST "https://api.mixroute.ai/v1/systemone" \
  --header "Authorization: Bearer $MIXROUTE_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "model": "jev-latest",
  "state": "I was charged twice for order 123. Please refund the duplicate charge today.",
  "questions": {
    "department": {
      "type": "choice",
      "instructions": "Which team should handle this request?",
      "criteria": {
        "billing": "Duplicate charges, payments and refunds",
        "technical": "Broken software and integration issues",
        "shipping": "Shipment delivery and tracking"
      }
    },
    "urgency": {
      "type": "score",
      "instructions": "How time-sensitive is the request?",
      "criteria": [
        "No deadline; routine request",
        "Needs attention within a week",
        "Explicitly requires action today"
      ]
    },
    "duplicate_charge": {
      "type": "noul",
      "instructions": "The customer was charged twice for the same order.",
      "criteria": {
        "true": "Explicit duplicate payment for the same order",
        "false": "No duplicate payment is mentioned"
      }
    }
  }
}'
```

## 响应示例

```json theme={null}
{
  "model": "jev-1.13.0",
  "answers": {
    "department": {
      "type": "choice",
      "choice": "billing",
      "confidence": 1,
      "probabilities": {
        "technical": 0,
        "billing": 1,
        "shipping": 0
      }
    },
    "urgency": {
      "type": "score",
      "score": 2,
      "confidence": 1,
      "legend": {
        "0": "No deadline; routine request",
        "1": "Needs attention within a week",
        "2": "Explicitly requires action today"
      },
      "probabilities": {
        "0": 0,
        "1": 0,
        "2": 1
      }
    },
    "duplicate_charge": {
      "type": "noul",
      "noul": 0.9
    }
  },
  "usage": {
    "input_tokens": 447,
    "output_tokens": 70
  }
}
```

示例概率和 token 用量仅用于展示响应格式；不同输入或调用可能返回不同值。

| 字段                          | 类型      | 要求             | 说明                                            |
| --------------------------- | ------- | -------------- | --------------------------------------------- |
| `model`                     | string  | 返回             | 实际处理请求的版本号，可能不同于请求中的别名。                       |
| `answers`                   | object  | 返回             | 以原始 question\_id 为键的答案映射；每项 type 与对应问题一致。     |
| `answers[id].type`          | string  | 返回             | choice、score 或 noul，与请求中的对应问题类型相同。            |
| `answers[id].choice`        | string  | Choice         | 选中的选项名称，来自请求的 criteria 键。                     |
| `answers[id].probabilities` | object  | Choice / Score | 选项名或等级索引到概率的映射；各值在 0-1 之间，合计约为 1。             |
| `answers[id].score`         | number  | Score          | 等级索引的概率加权位置，可为小数，范围由 criteria 的等级数决定。         |
| `answers[id].legend`        | object  | Score          | 字符串形式的等级索引到原始 criteria 描述的映射；描述保留字符串、对象或数组结构。 |
| `answers[id].noul`          | number  | Noul           | 命题为真的概率，范围 0-1，不是布尔值。                         |
| `answers[id].confidence`    | number  | Choice / Score | 0-1，从概率分布概括确定程度。不是结果必然正确的保证，也不应等同于最高选项概率。     |
| `usage.input_tokens`        | integer | 返回             | 用于本次评估的计费输入 token 数。                          |
| `usage.output_tokens`       | integer | 返回             | 答案的输出 token 数；当前输出免费。                         |

在应用层设置概率/置信度阈值，并为不确定的输入保留人工处理或补充信息的路径。高 confidence 不保证结论正确；尤其要用自身业务数据验证非英语任务。

## 结构化输入

state、instructions 和描述性 criteria 可以使用原生 JSON 结构。以下示例同时展示对象指令、数组指令及结构化等级描述。

```json theme={null}
{
  "model": "jev-1.13.0",
  "state": {
    "incident": {
      "feature": "export",
      "symptom": "CSV export always fails",
      "workaround": "Download JSON instead"
    },
    "customer_request": "Please fix this when convenient; no immediate deadline."
  },
  "questions": {
    "route": {
      "type": "choice",
      "instructions": {
        "question": "Which team owns the incident?",
        "field": "incident"
      },
      "criteria": {
        "engineering": {
          "covers": [
            "software errors",
            "broken export"
          ],
          "excludes": "billing"
        },
        "billing": [
          "payments",
          "refunds"
        ]
      }
    },
    "impact": {
      "type": "score",
      "instructions": [
        "Assess the functionality impact of incident only.",
        "Use the documented workaround when judging."
      ],
      "criteria": [
        {
          "description": "Cosmetic only",
          "examples": [
            "misaligned label"
          ]
        },
        [
          "A feature fails but a workaround is available"
        ],
        {
          "description": "Completely blocked and no workaround"
        }
      ]
    },
    "has_workaround": {
      "type": "noul",
      "instructions": {
        "question": "Does incident describe a usable workaround?"
      },
      "criteria": {
        "true": {
          "description": "A concrete alternative is provided"
        },
        "false": [
          "No alternative",
          "Explicitly no workaround"
        ]
      }
    }
  }
}
```

### 对话数组

对话记录直接作为 state 数组传入；这里的 role/text 是业务字段，不是 Chat Completions 的消息协议。

```json theme={null}
{
  "model": "jev-1.13.0",
  "state": [
    {
      "role": "customer",
      "text": "Please check order 123. It was charged twice."
    },
    {
      "role": "agent",
      "text": "The duplicate charge has now been refunded."
    }
  ],
  "questions": {
    "refund_done": {
      "type": "noul",
      "instructions": "The agent says the duplicate charge has been refunded."
    },
    "shipment_lost": {
      "type": "noul",
      "instructions": "The conversation says a shipment was lost."
    }
  }
}
```

## Python

需要 Python 3 和 requests。示例直接读取同步答案，不进行任务轮询或自动重复提交。

```python theme={null}
import json
import os
import requests

def evaluate_jev(payload):
    response = requests.post(
        "https://api.mixroute.ai/v1/systemone",
        headers={"Authorization": "Bearer " + os.environ["MIXROUTE_API_KEY"]},
        json=payload,
        timeout=60,
        allow_redirects=False,
    )
    request_id = response.headers.get("x-oneapi-request-id", "")
    try:
        result = response.json()
    except ValueError as exc:
        raise RuntimeError(
            f"HTTP {response.status_code}; request_id={request_id}; invalid JSON"
        ) from exc
    if not 200 <= response.status_code < 300:
        detail = result.get("detail", result) if isinstance(result, dict) else result
        raise RuntimeError(
            f"HTTP {response.status_code}; request_id={request_id}; detail={detail}"
        )
    if not isinstance(result, dict) or not isinstance(result.get("answers"), dict):
        raise RuntimeError("Invalid Jev response; request_id=" + request_id)
    if set(result["answers"]) != set(payload["questions"]):
        raise RuntimeError("Response question IDs do not match the request")
    return result

if __name__ == "__main__":
    payload = json.loads(r'''
{
  "model": "jev-latest",
  "state": "I was charged twice for order 123. Please refund the duplicate charge today.",
  "questions": {
    "department": {
      "type": "choice",
      "instructions": "Which team should handle this request?",
      "criteria": {
        "billing": "Duplicate charges, payments and refunds",
        "technical": "Broken software and integration issues",
        "shipping": "Shipment delivery and tracking"
      }
    },
    "urgency": {
      "type": "score",
      "instructions": "How time-sensitive is the request?",
      "criteria": [
        "No deadline; routine request",
        "Needs attention within a week",
        "Explicitly requires action today"
      ]
    },
    "duplicate_charge": {
      "type": "noul",
      "instructions": "The customer was charged twice for the same order.",
      "criteria": {
        "true": "Explicit duplicate payment for the same order",
        "false": "No duplicate payment is mentioned"
      }
    }
  }
}
''')
    result = evaluate_jev(payload)
    print(result["model"])
    print(result["answers"]["department"]["choice"])
    print(result["answers"]["urgency"]["score"])
    print(result["answers"]["duplicate_charge"]["noul"])
    print(result["usage"])
```

## JavaScript

Node.js 18+，使用 ES module（.mjs）。API Key 仅保存在服务端，不放入浏览器代码。

```javascript theme={null}
async function evaluateJev(payload) {
  const apiKey = process.env.MIXROUTE_API_KEY;
  if (!apiKey) throw new Error("Set MIXROUTE_API_KEY");
  const response = await fetch("https://api.mixroute.ai/v1/systemone", {
    method: "POST",
    headers: {
      Authorization: "Bearer " + apiKey,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(payload),
    redirect: "error",
    signal: AbortSignal.timeout(60000),
  });
  const requestId = response.headers.get("x-oneapi-request-id") ?? "";
  let result;
  try {
    result = await response.json();
  } catch {
    throw new Error("HTTP " + response.status + "; request_id=" + requestId + "; invalid JSON");
  }
  if (!response.ok) {
    throw new Error("HTTP " + response.status + "; request_id=" + requestId +
      "; detail=" + JSON.stringify(result?.detail ?? result));
  }
  if (!result?.answers || typeof result.answers !== "object" || Array.isArray(result.answers)) {
    throw new Error("Invalid Jev response; request_id=" + requestId);
  }
  const requested = Object.keys(payload.questions).sort();
  const returned = Object.keys(result.answers).sort();
  if (JSON.stringify(requested) !== JSON.stringify(returned)) {
    throw new Error("Response question IDs do not match the request");
  }
  return result;
}

const payload = {
  "model": "jev-latest",
  "state": "I was charged twice for order 123. Please refund the duplicate charge today.",
  "questions": {
    "department": {
      "type": "choice",
      "instructions": "Which team should handle this request?",
      "criteria": {
        "billing": "Duplicate charges, payments and refunds",
        "technical": "Broken software and integration issues",
        "shipping": "Shipment delivery and tracking"
      }
    },
    "urgency": {
      "type": "score",
      "instructions": "How time-sensitive is the request?",
      "criteria": [
        "No deadline; routine request",
        "Needs attention within a week",
        "Explicitly requires action today"
      ]
    },
    "duplicate_charge": {
      "type": "noul",
      "instructions": "The customer was charged twice for the same order.",
      "criteria": {
        "true": "Explicit duplicate payment for the same order",
        "false": "No duplicate payment is mentioned"
      }
    }
  }
};
const result = await evaluateJev(payload);
console.log(result.model);
console.log(result.answers.department.choice);
console.log(result.answers.urgency.score);
console.log(result.answers.duplicate_charge.noul);
console.log(result.usage);
```

## 价格与用量

| 模型                                     | 输入 / 百万 token | 输出 / 百万 token |
| -------------------------------------- | ------------- | ------------- |
| Jev 1.13 (`jev-1.13.0` / `jev-latest`) | \$0.042       | \$0           |

以上为美元基础单价，实际价格以 [模型广场](https://console.mixroute.ai/models)、账户分组倍率及账单为准。输入用量包括 state 和问题定义，更多问题与选项也会增加输入 token。响应的 `usage.output_tokens` 可以大于 0，但输出 token 不收费。

使用 `usage.input_tokens` 估算费用：输入 token 数 × 输入单价 ÷ 1,000,000，再应用账户倍率。平台按内部额度逐笔结算，取整后的账单可能与直接按美元计算的微小金额略有差异。

额度换算说明见 [认证与额度](/cn/api-reference/system-api/authentication-and-quota)。

## 响应处理

先检查 HTTP 状态，再读取 JSON。成功响应直接包含 answers；错误响应通常使用 detail，可能是字符串、对象或字段错误数组。保留响应头 x-oneapi-request-id 便于定位请求，不要记录完整 API Key。

| 状态            | 处理方式                                          |
| ------------- | --------------------------------------------- |
| `200`         | 读取 model、answers 和 usage，按 question\_id 对应结果。 |
| `400` / `422` | 检查 model、字段类型、非空约束、选项/等级数和上下文长度；修改请求后再发送。     |
| `401` / `403` | 检查 MixRoute Key、模型权限及认证请求头。                   |
| `429` / `529` | 限流或上游繁忙；如有 Retry-After 则遵守，并采用有上限的退避重试。       |
| `5xx`         | 检查错误内容并保留请求 ID，避免无上限地重复提交。                    |

网络超时不等于请求没有执行。重复提交会创建新的评估并可能再次计费，重试策略应由应用明确控制。
