jevbooks

完成第一个 Jev 判断

最后拿到一个可以检查的结果:保存的响应会说明实际模型、问题答案和用量。接着明确,答案不确定或请求失败时,程序该怎么办。

jevbooks 独立于 TypeSafe。模型别名与错误处理于 2026 年 11 月 2 日核对官方文档。下方响应保存自 9 月 25 日的 Jev 1.13;本轮改写的脚本仅做离线检查,没有新的 API 推理。

还不清楚 Jev 是什么?先看「Jev 是什么?」→

准备账号与终端

  1. 在官方控制台 console.typesafe.ai 登录,到 console.typesafe.ai/keys 创建 key。不需要第三方注册工具。
  2. macOS/Linux 使用 Bash 和 curl;Windows 可使用 WSL 等 Bash 环境。离线校验器另需 Node.js 22 以上,不需要 npm 安装包。
  3. 脚本会隐藏输入地读取 key,不要把它写进源码或请求正文。文件保存在 jev-first-decision/;再次运行会覆盖,要保留的结果请先复制。

1. 发送并保存一个请求

在一个空工作目录中,把下面保存为 quickstart-request.sh,运行 bash quickstart-request.sh。未设置 TYPESAFE_API_KEY 时会提示输入 key。这会发送一次计费的 API 请求。

下载 quickstart-request.sh

#!/usr/bin/env bash
# Save as quickstart-request.sh; run: bash quickstart-request.sh
set -euo pipefail
mkdir -p jev-first-decision
cd jev-first-decision
if [[ -z "${TYPESAFE_API_KEY:-}" ]]; then
  read -r -s -p "TypeSafe API key: " TYPESAFE_API_KEY
  printf '\n'
  export TYPESAFE_API_KEY
fi
: "${TYPESAFE_API_KEY:?API key is required}"
cat > request.json <<'JSON'
{
  "model": "jev-latest",
  "state": "I was charged twice. Please fix this today.",
  "questions": {
    "urgency": {
      "type": "noul",
      "instructions": "Does this message express urgency?"
    }
  }
}
JSON
rm -f response.json response.status
if ! status=$(curl --silent --show-error --max-time 30 \
  https://api.typesafe.ai/v1/systemone \
  -H "Authorization: Bearer $TYPESAFE_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @request.json --output response.json --write-out '%{http_code}'); then
  printf 'Unfinished: network error or timeout. Do not use a partial response.\n' >&2
  exit 1
fi
printf '%s\n' "$status" > response.status
case "$status" in
  2??) printf 'HTTP %s. Now check jev-first-decision/response.json.\n' "$status" ;;
  *) printf 'Unfinished: HTTP %s. Inspect response.json before retrying.\n' "$status" >&2; exit 1 ;;
esac

问题只问消息是否表达了紧急诉求,不判断实际严重程度,也不授权退款。11 月 2 日核对时,jev-latest 与 jev-preview 均指向 jev-1.14.0。对照运行时使用固定版本,并记录响应实际返回的 model。

官方模型与别名

2026 年 9 月 25 日保存的响应;当时别名指向 Jev 1.13:

{
  "model": "jev-1.13.0",
  "answers": { "urgency": { "type": "noul", "noul": 0.95 } },
  "usage": { "input_tokens": 282, "output_tokens": 21 }
}

这份 JSON 保留了教程源码中保存的响应,没有提供独立的原始 HTTP 日志。新请求可能返回不同数值或版本;0.95 是历史观察,不是程序应当断言的固定结果。

下载 2026-09-25 保存的响应

2. 检查响应,再决定队列

将校验器下载到同一个工作目录,请求成功后运行以下命令。它只读本地文件,不调用 API。

下载 quickstart-check.mjs

node quickstart-check.mjs jev-first-decision/response.json "$(cat jev-first-decision/response.status)"
  • HTTP 状态必须是 2xx。超时、错误状态或不完整响应,都表示任务未完成。
  • answers.urgency.type 必须是 noul,noul 必须为 0 到 1 的有限数值;缺项或类型错误时停止。
  • 要求非空 model,以及非负整数 usage.input_tokens / usage.output_tokens。和输入一起保存,便于比较各次运行。

校验器打印模型、紧急程度、用量和一个教学用队列:≥0.8 进入优先人工处理,≤0.2 进入普通队列,中间值保留未判并交人工。阈值仅作示意,尚未校准。通过响应检查不代表判断正确。

没有 key 也能练习:把保存的响应放在校验器旁,运行 node quickstart-check.mjs quickstart-response-2026-09-25.json。应输出模型 jev-1.13.0、紧急程度 0.95 和 priority-human-review。这只检查历史文件,不验证当前 HTTP 调用。

3. 试三个输入

只改所选脚本的 state,每次结果单独保存。记录实际答案和分支;下表是人工阅读目标,没有预填模型概率。

输入检查什么
I was charged twice. Please fix this today.有明确的时间要求。题目识别的是文字表达出的紧急程度吗?
Where can I download last month’s invoice?普通账单咨询。仅仅提到钱,会不会就进了优先队列?
Send it.缺少上下文:发送什么、什么时候要?再自信的数值也补不出这些事实。

第三例也在检查你的程序:应补充上下文,或保留人工复核。模型可能自信地答错;单靠概率中间区不是完整的未知策略。

请求未完成时怎么办

示例会停止,并保存收到的完整 HTTP 错误正文;不会自动重试。

情况下一步
401检查 key 是否存在、Authorization 请求头是否正确。不要把 key 放进问题报告。
400 / 422阅读保存的错误正文;修复 JSON、上下文长度或服务端指出的字段,再重试。
429 / 529采用有次数上限的指数退避;有 Retry-After 时遵循它,不要立即循环重试。
超时、其他非 2xx、无效 JSON 或答案缺项保持任务未完成。先检查保存结果与相关服务状态,再决定重试;不要把缺失概率替换成零。

官方错误处理说明

10 月 22 日本站本机测试收到 HTTP 451,没有产出新推理。这是当时的环境记录,不能代表其他账号或地区会收到什么。

4. 换成你自己的任务

增加题目前,先填四格。客服队列可以这样写:

材料
客户消息,以及理解它确实需要的上下文。
判断题
消息是否表达了紧急诉求?实际严重程度和能否退款另列问题。
允许的结果
优先人工处理、普通队列、未判并人工复核。
未知时怎么办
补问缺失上下文;API 失败或答案无效时,保持任务未完成。

带着这四格去 Ask →

想用 JavaScript 或 Python?

下面两种写法发送同一个请求,并检查响应。运行前在终端设置 TYPESAFE_API_KEY;以下命令隐藏读取,不把 key 值写进 shell 历史。每次运行会替换 jev-first-decision/ 下的文件。

# Bash
read -r -s -p "TypeSafe API key: " TYPESAFE_API_KEY
printf '\n'
export TYPESAFE_API_KEY

Python 3.10 以上,只用标准库,不需要 pip 安装。保存为 quickstart-request.py,运行 python3 quickstart-request.py。

下载完整文件 · Python

查看完整 Python 文件
# Python 3.10+; standard library only, no pip install.
# Save as quickstart-request.py; run: python3 quickstart-request.py
import json
import math
import os
import sys
from pathlib import Path
from urllib.error import HTTPError
from urllib.request import Request, urlopen


def inspect_response(data):
    answer = data.get("answers", {}).get("urgency", {})
    value = answer.get("noul")
    if (answer.get("type") != "noul" or type(value) not in (int, float)
            or not math.isfinite(value) or not 0 <= value <= 1):
        raise ValueError("urgency must be a noul number in [0, 1]")
    if not isinstance(data.get("model"), str) or not data["model"].strip():
        raise ValueError("missing model version")
    usage = data.get("usage", {})
    if any(type(usage.get(k)) is not int or usage[k] < 0
           for k in ("input_tokens", "output_tokens")):
        raise ValueError("invalid token usage")
    # Teaching thresholds only; validate on labelled examples before use.
    queue = ("priority-human-review" if value >= 0.8 else "normal-queue"
             if value <= 0.2 else "undecided-human-review")
    return dict(model=data["model"], urgency=value, usage=usage, queue=queue)


def main():
    key = os.environ.get("TYPESAFE_API_KEY")
    if not key:
        raise ValueError("Set TYPESAFE_API_KEY first")
    folder = Path("jev-first-decision")
    folder.mkdir(exist_ok=True)
    request = {
        "model": "jev-latest",
        "state": "I was charged twice. Please fix this today.",
        "questions": {"urgency": {
            "type": "noul", "instructions": "Does this message express urgency?"
        }},
    }
    payload = json.dumps(request)
    (folder / "request.json").write_text(payload, encoding="utf-8")
    for name in ("response.json", "response.status"):
        (folder / name).unlink(missing_ok=True)
    req = Request("https://api.typesafe.ai/v1/systemone", payload.encode(), {
        "Authorization": f"Bearer {key}", "Content-Type": "application/json"
    })
    try:
        with urlopen(req, timeout=30) as response:
            status, body = response.status, response.read()
    except HTTPError as error:
        status, body = error.code, error.read()
    (folder / "response.json").write_bytes(body)
    (folder / "response.status").write_text(str(status), encoding="utf-8")
    if not 200 <= status < 300:
        raise ValueError(f"HTTP {status}; inspect response.json before retrying")
    print(json.dumps(inspect_response(json.loads(body)), indent=2))


if __name__ == "__main__":
    try:
        main()
    except Exception as error:
        print(f"Unfinished: {error}", file=sys.stderr)
        sys.exit(1)

Node.js 22 以上,不需要 npm 安装。保存为 quickstart-request.mjs,并把 quickstart-check.mjs 放在旁边,运行 node quickstart-request.mjs。

下载完整文件 · JavaScript

下载 quickstart-check.mjs

查看完整 JavaScript 文件
// Node.js 22+; no npm install. Keep quickstart-check.mjs beside this file.
// Run: node quickstart-request.mjs (TYPESAFE_API_KEY must be set).
import { mkdirSync, writeFileSync, rmSync } from "node:fs";
import { inspectResponse } from "./quickstart-check.mjs";

const request = {
  model: "jev-latest",
  state: "I was charged twice. Please fix this today.",
  questions: {
    urgency: { type: "noul", instructions: "Does this message express urgency?" },
  },
};
try {
  if (!process.env.TYPESAFE_API_KEY) throw new Error("Set TYPESAFE_API_KEY first.");
  mkdirSync("jev-first-decision", { recursive: true });
  writeFileSync("jev-first-decision/request.json", JSON.stringify(request, null, 2));
  for (const file of ["response.json", "response.status"]) {
    rmSync(`jev-first-decision/${file}`, { force: true });
  }
  const response = await fetch("https://api.typesafe.ai/v1/systemone", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.TYPESAFE_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(request),
    signal: AbortSignal.timeout(30_000),
  });
  const body = await response.text();
  writeFileSync("jev-first-decision/response.json", body);
  writeFileSync("jev-first-decision/response.status", String(response.status));
  if (!response.ok) throw new Error(`HTTP ${response.status}; inspect response.json.`);
  console.log(inspectResponse(JSON.parse(body), response.status));
} catch (error) {
  console.error(error.message.startsWith("Unfinished:") ? error.message : `Unfinished: ${error.message}`);
  process.exitCode = 1;
}

这里使用直接 HTTP 调用,不是 SDK 示例。官方 Python / JavaScript SDK 的安装与默认重试行为,请查看 TypeSafe 的 SDK 文档。

官方 SDK 文档

价格与模型限制

模型表于 2026 年 11 月 2 日核对官方文档;实验图片细节最后核对于 10 月 22 日。

TypeSafe 官方接口
输入价格每百万 token $0.042;输出 token 免费
默认上下文state 加全部题目 ≤64k token;state 加任意单题 ≤32k
实验长上下文加 TypeSafe-Danger-Zone-Long-Context: true 后两项均为 262k;更慢且准确率更低
模型名11 月 2 日,jev-latest 和 jev-preview 均指向 jev-1.14.0;可固定 jev-1.13.0 或 jev-1.14.0。核对时没有单独的 preview 版本。
图片实验性 assets 需要 TypeSafe-Danger-Zone-Images: true;box 需要 1.14。本教程只发送文本。
限流按组织配置,见 console.typesafe.ai/rate-limits

按公布的输入价,1,000 token 花 $0.000042。保存的 282 输入 token 响应约花 $0.000012。当前账号优惠以控制台为准。

其他通道

  • 2026 年 9 月的 OpenRouter 测量使用 typesafe/jev-1.13 和 /api/alpha/decisions,不能证明当前已支持 1.14 或实验图片功能。本教程使用上面的官方直连。

选下一个任务

常见问题

Jev 怎么注册?

在 console.typesafe.ai 登录,再到 console.typesafe.ai/keys 创建 API key。jevbooks 独立于 TypeSafe,不能代开账号。

Jev 免费吗?

2026 年 11 月 2 日核对的官方模型价为输入每百万 token $0.042,输出免费。账号额度或优惠请查看控制台。

一定要装 SDK 吗?

不用。这些示例只使用 curl、Node.js 内置 fetch 或 Python 标准库。TypeSafe 也提供官方 Python 与 JavaScript SDK。

模型名填什么?

2026 年 11 月 2 日官方文档中,jev-latest 和 jev-preview 都指向 jev-1.14.0。对照版本时可固定 jev-1.13.0 或 jev-1.14.0,并记录响应的 model;固定版本不保证重复调用答案完全相同。

响应有效就代表判断正确吗?

不代表。HTTP 成功和类型检查只能确认请求送达与返回格式。判断质量、阈值与回退策略需要用标注样本评估。

下一步

带着任务去 Ask逛图鉴官方文档去拿 API key