Jev SDK:第一个能跑通的调用
大家搜的 Jev SDK,发布时挂的是 TypeSafe 的名字:根本没有一个叫 jev-sdk 的包,去找它就是多数人丢掉的头半个小时。这一页走另一条路——装对包,打一个真能返回答案的调用,读懂回来的对象,认出挡在第一次成功之前的三个报错。Jev 是决策模型不是聊天模型(Jev AI 是什么),这些库底下的 HTTP 细节在Jev API 那页。
装上 Jev SDK
它以两个官方包发布,都是 MIT 许可的开源,都从 TYPESAFE_API_KEY 读 key,都默认用 jev-latest 这个模型、打向 https://api.typesafe.ai。下面的版本号截至 2026-09-21 是最新的。
Python
pip install typesafe-sdkPython 版的 Jev SDK 是 0.7.0,需要 Python 3.10 或更新——它用的类型写法在 3.9 上过不了语法。import 名是 typesafe_sdk,中间是下划线不是连字符。
JavaScript / TypeScript
npm install @typesafe-ai/sdkJavaScript 版的 Jev SDK 是 0.6.0,要 Node 20 或更新。一个包里同时带 ESM、CommonJS 和 TypeScript 声明,答案的类型从你传进去的问题推出来,所以跑之前编辑器就知道一道 choice 能返回哪几个标签。
第一个完整的 Jev SDK 调用
一张客服工单,三道不同类型的问题,在一个请求里答完。两个版本做的是同一件事:
from typesafe_sdk import Choice, Noul, Score, TypeSafeClient
# key 从 TYPESAFE_API_KEY 读取,绝不要写死在代码里。
with TypeSafeClient() as client:
result = client.system_one(
state="I paid yesterday by card and still have no activation code.",
questions={
"category": Choice(
instructions="Which queue should handle this message",
criteria={
"not_received": "Paid but has not received the product",
"refund": "Asking for a refund",
"presale": "Has not bought yet, asking about price",
},
),
"urgency": Score(
instructions="How time-sensitive is this",
criteria=["Just asking", "Wants it today", "Needs it immediately"],
),
"is_frustrated": Noul(instructions="The customer sounds frustrated"),
},
)
print(result.choices["category"].choice)
print(result.scores["urgency"].score)
print(result.nouls["is_frustrated"].noul)import { choice, noul, score, TypeSafeClient } from "@typesafe-ai/sdk";
// key 从 TYPESAFE_API_KEY 读取,绝不要写死在代码里。
const client = new TypeSafeClient();
const { answers } = await client.systemOne({
state: "I paid yesterday by card and still have no activation code.",
questions: {
category: choice("Which queue should handle this message", {
not_received: "Paid but has not received the product",
refund: "Asking for a refund",
presale: "Has not bought yet, asking about price",
}),
urgency: score("How time-sensitive is this", [
"Just asking",
"Wants it today",
"Needs it immediately",
]),
is_frustrated: noul("The customer sounds frustrated"),
},
});
console.log(answers.category.choice, answers.urgency.score);三件事值得留意。常见情况下客户端一个参数都不用传——key、基础地址、模型全部来自环境,所以代码里不出现任何秘密。问题的名字(category、urgency、is_frustrated)是你起的,它们会变成答案回来时的键,所以挑你自己的代码愿意读的名字。三道问题走的是同一个请求:Jev 只按输入 token 计费,对着一张工单问三件事,花的是一张工单的钱,不是三张。
想先看到返回再决定装不装,本站的演练场在浏览器里跑同一个请求体,并导出成 Python、TypeScript 或 curl。
读懂返回
Jev SDK 交还一个结果对象,里面带着模型名、token 用量,以及每道问题一个答案对象。每个答案都有类型,所以没有 JSON 要解析,也没有 schema 要校验——但三种类型交还的东西不一样,多出来的字段才是有用的部分。
choice —— 选中的那个,和全部概率
你会拿到 choice,是你定义的标签之一;confidence;还有 probabilities,每个标签一个数。只看标签去路由,等于把有意思的那一半扔了:当排在前两位的标签停在 0.41 和 0.39,这张工单要的是人,而概率是唯一能让这件事显形的地方。
score —— 那个数,和它的对照表
分数按你列判据的顺序从零开始编号,而且是期望值,可以落在两级之间:三级标尺上的 1.6 意味着这条输入大半已经靠到最高那一级。你还会拿到一个 legend,把每一级映回你写的那句话,于是你能记下一个人能读的标签,又不用把评分标准维护两份。
noul —— 一个概率
一道是非题回来的是 noul 底下一个 0 到 1 的数。不是布尔值:阈值由你定,给工单自动关闭定的线可以跟给打标记定的不一样。Python 这边有 result.choices、result.scores、result.nouls 三个便利映射按类型分好组;JavaScript 这边全部挂在 answers 上,类型是推出来的。
你大概率会撞上的三个报错
这三个在我们跑通第一个 Jev SDK 调用的路上真花了时间,按通常发生的顺序排。
1. 顺手抓了个聊天客户端
绕开 Jev SDK,把一个 OpenAI 兼容的库指向这个模型,服务端会拿 is a decisions model and cannot be used with the chat/completions endpoint 把调用拒掉。key 和请求体都没错,错的是路由。为什么会这样,端点那一页讲了。用官方包能整个避开,它只会调那条正确的路径。
2. 那个从来没被加载的 .env
写成 TYPESAFE_API_KEY = "your-key-here"——等号两边有空格,值上带引号——再跑 set -a; . ./.env,shell 根本不会设这个变量:等号两边一旦有空格,那行就不是赋值而是一条命令。于是 SDK 报一个 key 缺失的错,而你的文件里明明白白写着 key,这是最难读的一类 bug。更迷糊的是,有些框架能正确加载同一个文件(Next.js 就解析得好好的),同一份文件在一个终端能用,在另一个不能。写成 TYPESAFE_API_KEY=your-key-here 不留空格,怪库之前先用 echo $TYPESAFE_API_KEY 看一眼。
3. 服务端不收的请求体
state 发得太多,或者一次塞太多问题,服务端会拒。这一个会伪装成网络不稳,因为人们默认大请求体是超时了,但它是拒绝不是网络故障:SDK 抛的是带状态码的 API 错误,而不是连接错误或超时错误,原样重试每次都会以同样的方式失败。加重试之前先读状态码。把长文档切成小节、把长问题列表拆成两次调用,就是解法。
这三条底下是同一条规矩:key 属于服务端。不要打进浏览器产物,不要提交,所有 Jev SDK 示例一律走环境变量,这样被复制走的代码不会带着活着的凭据。
常见问题
有官方的 Jev SDK 吗?
有,由 TypeSafe 用自己的名字而不是模型的名字发布:PyPI 上的 typesafe-sdk 和 npm 上的 @typesafe-ai/sdk,都是 MIT 许可。以 Jev 命名的包不存在,所以那样搜什么也搜不到。
需要哪个 Python 版本?
Python 3.10 或更新。在 3.9 上装是能装上,但 import 会卡在语法上。
能在浏览器里调 Jev 吗?
不该这么做。跑在页面里的东西会把 key 发给每一个访客,JavaScript 版的 Jev SDK 默认就拒绝浏览器环境,理由正是这个——覆盖它的那个选项叫 dangerouslyAllowBrowser,作者的态度都写在名字里了。把调用放到你自己的接口后面。
报错怎么处理?
两个 Jev SDK 包抛的都是有类型的错误,而不是返回状态码:鉴权、请求有误、限流、服务端错误、超时、连接失败各有各的类。接住限流和连接这两类,值得重试;鉴权和请求有误就让它响亮地失败,重试只是浪费时间。带退避的重试本来就内置,默认开着。
Jev SDK 支持异步吗?
Python 这边支持——有一个跟同步客户端方法面一致的异步客户端。JavaScript 客户端全程基于 Promise,本来就是异步的。