> ## 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/typesafe/v1/systemone`

使用 MixRoute API Key，以 `Authorization: Bearer $MIXROUTE_API_KEY` 認證，`Content-Type: application/json`。請求體保留 TypeSafe 原生的 `model`、`state`、`questions` 層級，不使用 `metadata`、聊天 `messages` 或非同步任務輪詢。

## 支援模型

| 模型                                                 | 呼叫 ID                       |
| -------------------------------------------------- | --------------------------- |
| [Jev 1.13](/zh-hant/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 確認實際版本。

僅使用賬戶 [模型列表](/zh-hant/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/typesafe/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/typesafe/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/typesafe/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，再應用賬戶倍率。平臺按內部額度逐筆結算，取整後的賬單可能與直接按美元計算的微小金額略有差異。

額度換算說明見 [認證與額度](/zh-hant/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，避免無上限地重複提交。                    |

網路超時不等於請求沒有執行。重複提交會建立新的評估並可能再次計費，重試策略應由應用明確控制。
