从 Jev 迁移 · API 迁移清单
从 Jev 切换过来的实用清单
把现有的 TypeSafe Jev 集成迁移到 Decision Models 的 Jev 兼容 API:检查配置、测试请求,并有计划地切换流量。
Jev 是 TypeSafe AI 的产品;Decision Models 与 TypeSafe AI 没有关联。
切换流量之前
盘点现有集成
保存当前配置和有代表性的测试用例。检查问题类型、选项、图像、答案解析和重试逻辑。保留原提供商的配置,以便有计划地回滚。
设置 base URL 和路径
文本请求使用 https://api.decisionmodels.io 作为 base URL,以及 POST /v1/systemone。如果你的客户端自己会拼接路径,请去掉已有的 /v1 后缀。请检查实际发出的路径。
创建单独的 API 密钥
在控制台中创建 Decision Models 的密钥,并通过 Authorization: Bearer 发送。TypeSafe 的密钥、余额和账户无法转移。请把密钥保存在环境变量中。
替换模型 ID
把 TypeSafe 的模型 ID 替换为 Decision Models 中可用的 ID,例如 s1-fast。请查看 GET /v1/models,不要沿用 TypeSafe 的别名。
明确指定处理区域
例如设置 S1-Region: eu。取值为 eu 或 global,并受密钥权限限制;不带该请求头时使用密钥的默认值。EU 请求始终留在 EU 境内。在 EU 以外进行 Peer-to-Peer 处理,需要该密钥已同意全球处理。请查阅处理方式与合同条款。
拆分问题以符合模型限制
s1-pro 每个请求最多接受 3 个文本问题;s1-fast 接受 1 个,s1-vision 接受 1 个。多出的问题请自行拆分。服务不会悄悄拆分或丢弃它们;超出的问题会返回 400 request_limit_exceeded。另请查看下面的 token 和选项限制。
检查问题类型和图像
保持 state,以及以问题名称为键的 questions 对象不变。请使用下面的 criteria 结构。对于图像,通过 POST /v1/multimodal 使用 s1-vision,并在 images 数组中放入恰好一张图像。支持 PNG、JPEG 和 WebP 的 data URL,或公开的 HTTPS URL,解码后不超过 4 MiB、2,000,000 像素。下面的文本示例不测试图像请求。
读取答案和用量记录
按问题名称读取 answers 下的结果。记录 usage.input_tokens、usage.output_tokens、usage.decisions 以及返回的 model_version。token 数由模型给出,图像请求也包含图像部分。金额请以控制台中的用量回执为准;不要自行把字符数换算成计费 token。
测试错误、重试和回滚
测试无效密钥、余额不足、模型限制、速率限制和超时。请使用下面的错误码。用你自己的用例评估结果,通过验收检查后再切换流量。本地的接口约定测试并不能说明模型质量或生产环境的可用性。
问题类型与当前的输入限制
noul:是/否问题;答案中的 noul 是为真的概率。choice:criteria 是一个对象,至少包含两个稳定的选项 ID。读取 choice、confidence 和 probabilities。score:criteria 是一个有序数组,至少包含两个等级。score 是以零为起点的等级索引的概率加权平均值,可以是小数。
| 模型 | 每个问题的输入 token 数 | 问题数 | 选项数 |
|---|
s1-fast | 8,000 | 1 | 16 |
|---|
s1-pro | 8,192 | 3 | 64 |
|---|
s1-vision | 8,000 | 1 | 26 |
|---|
每个问题都包含它的 state、criteria 和提示词模板;s1-vision 还会计入图像部分。请查看完整的输入限制。
迁移时会有哪些变化
核查日期:2026年10月27日。带日期的 Jev 替代方案对比和迁移说明界定了兼容范围:密钥、模型 ID、处理层级、计费、限制、元数据和错误均各自独立。更换模型需要你自行评估输出。我们不声称做到逐字节兼容。
我们的 score 评分标准至少需要两个等级;TypeSafe 公布的 schema 也接受单个等级。超出的问题属于不可重试的错误。
使用 Idempotency-Key 时,正在处理中的请求会返回 202 in_progress。结算完成之后,或结算状态尚不确定时,会返回 409 idempotency_replay_unavailable,附带回执,不会再次扣费,但不提供已存储的答案。如果确认失败、没有答案且未扣费,则允许用相同的密钥和请求体重试。在同一个键下使用不同的请求体,会返回 409 idempotency_conflict。只有在确实要发起一次新的推理时,才使用新的键。
经过测试的文本示例
下面的每个文件都原样针对一个独立的本地 HTTP 模拟服务运行过,该模拟服务实现了我们公布的接口约定。检查内容包括方法、路径、Bearer 认证、S1-Region、JSON 请求体,以及读取带有 usage 和 model_version 的模拟答案。没有发出任何生产环境的推理请求。
请把 DECISIONMODELS_API_KEY 设置为你的密钥。可选的 DECISIONMODELS_BASE_URL 可以指向你本地的模拟服务;否则使用公开的 API base。Python 示例需要 Python 3.10 以及所示的包版本。fetch 示例是兼容 JavaScript 的 TypeScript,使用 Node.js 20.19.4 运行。
LiteLLM 会去掉 typesafe/ 提供商前缀;模拟服务收到的是 s1-fast。只测试了 Ollama 的 Python 客户端,没有测试它的命令行。带类型的 SDK 可能会丢弃 model_version 等额外元数据;直接的 HTTP 示例会保留它们。
curl 7.81.0
于 2026年10月27日 针对我们公布的接口约定测试,使用 curl 7.81.0
curl.sh
curl --fail-with-body --silent --show-error --max-time 15 \
"${DECISIONMODELS_BASE_URL:-https://api.decisionmodels.io}/v1/systemone" \
-H "Authorization: Bearer $DECISIONMODELS_API_KEY" \
-H 'Content-Type: application/json' \
-H 'S1-Region: eu' \
--data '{"model":"s1-fast","state":"Mia owns a red bicycle.","questions":{"color":{"type":"choice","instructions":"Which color is the bicycle?","criteria":{"red":null,"blue":null}}}}'
Python requests 2.32.5
于 2026年10月27日 针对我们公布的接口约定测试,使用 Python requests 2.32.5
requests.py
import os
import requests
base = os.environ.get("DECISIONMODELS_BASE_URL", "https://api.decisionmodels.io")
response = requests.post(
base + "/v1/systemone",
headers={
"Authorization": "Bearer " + os.environ["DECISIONMODELS_API_KEY"],
"S1-Region": "eu",
},
json={
"model": "s1-fast",
"state": "Mia owns a red bicycle.",
"questions": {"color": {
"type": "choice",
"instructions": "Which color is the bicycle?",
"criteria": {"red": None, "blue": None},
}},
},
timeout=15,
)
response.raise_for_status()
print(response.json())
Node.js fetch 20.19.4
于 2026年10月27日 针对我们公布的接口约定测试,使用 Node.js fetch 20.19.4
fetch.ts
// JavaScript-compatible TypeScript; native fetch in Node.js.
const base = process.env.DECISIONMODELS_BASE_URL ?? "https://api.decisionmodels.io";
const response = await fetch(`${base}/v1/systemone`, {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.DECISIONMODELS_API_KEY}`,
"Content-Type": "application/json",
"S1-Region": "eu",
},
body: JSON.stringify({
model: "s1-fast",
state: "Mia owns a red bicycle.",
questions: { color: {
type: "choice",
instructions: "Which color is the bicycle?",
criteria: { red: null, blue: null },
} },
}),
signal: AbortSignal.timeout(15000),
});
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
console.log(await response.json());
LiteLLM 1.106.4
于 2026年10月27日 针对我们公布的接口约定测试,使用 LiteLLM 1.106.4
litellm.py
import os
import litellm
response = litellm.systemone(
model="typesafe/s1-fast",
api_base=os.environ.get("DECISIONMODELS_BASE_URL", "https://api.decisionmodels.io"),
api_key=os.environ["DECISIONMODELS_API_KEY"],
extra_headers={"S1-Region": "eu"},
state="Mia owns a red bicycle.",
questions={"color": {
"type": "choice",
"instructions": "Which color is the bicycle?",
"criteria": {"red": None, "blue": None},
}},
timeout=15,
)
print(response.model_dump())
Ollama Python 0.6.3
于 2026年10月27日 针对我们公布的接口约定测试,使用 Ollama Python 0.6.3
ollama.py
import os
from ollama import Client
client = Client(
host=os.environ.get("DECISIONMODELS_BASE_URL", "https://api.decisionmodels.io"),
headers={
"Authorization": "Bearer " + os.environ["DECISIONMODELS_API_KEY"],
"S1-Region": "eu",
},
timeout=15,
)
response = client.systemone(
model="s1-fast",
state="Mia owns a red bicycle.",
questions={"color": {
"type": "choice",
"instructions": "Which color is the bicycle?",
"criteria": {"red": None, "blue": None},
}},
)
print(response.model_dump())
客户端文档:LiteLLM System One · Ollama Python 0.6.3。测试仅覆盖所列版本和所示的文本示例。
切换之前先处理好错误
请明确处理这些错误码;完整规则见错误与重试。
400 invalid_request、request_limit_exceeded:请修正 schema 或模型限制;不要原样重试。401 invalid_api_key、402 insufficient_credit、403 tier_not_allowed、404 unknown_model:请修正密钥、余额、层级权限或所选模型。413 payload_too_large、422 unsupported_modality:请缩小输入大小,或选择受支持的模态。429 rate_limit_exceeded:必须遵守 Retry-After。503 model_unavailable、capacity_limit、504 inference_timeout:重试之前,请先查看文档中说明的等待时间和结算状态。EU 请求绝不会故障转移到 EU 以外。