jevbooks 独立于 TypeSafe。模型别名与错误处理于 2026 年 11 月 2 日核对官方文档。下方响应保存自 9 月 25 日的 Jev 1.13;本轮改写的脚本仅做离线检查,没有新的 API 推理。
准备账号与终端
- 在官方控制台
console.typesafe.ai登录,到console.typesafe.ai/keys创建 key。不需要第三方注册工具。 - macOS/Linux 使用 Bash 和 curl;Windows 可使用 WSL 等 Bash 环境。离线校验器另需 Node.js 22 以上,不需要 npm 安装包。
- 脚本会隐藏输入地读取 key,不要把它写进源码或请求正文。文件保存在
jev-first-decision/;再次运行会覆盖,要保留的结果请先复制。
1. 发送并保存一个请求
在一个空工作目录中,把下面保存为 quickstart-request.sh,运行 bash quickstart-request.sh。未设置 TYPESAFE_API_KEY 时会提示输入 key。这会发送一次计费的 API 请求。
#!/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 是历史观察,不是程序应当断言的固定结果。
2. 检查响应,再决定队列
将校验器下载到同一个工作目录,请求成功后运行以下命令。它只读本地文件,不调用 API。
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 失败或答案无效时,保持任务未完成。
想用 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 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 文件
// 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 文档。
价格与模型限制
模型表于 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 成功和类型检查只能确认请求送达与返回格式。判断质量、阈值与回退策略需要用标注样本评估。