SDK 快速开始
使用项目 SDK 或 TypeSafe 官方客户端,并从响应头读取平台元数据。
创建 API 密钥
在 System One 主站使用现有账户流程登录,验证邮箱后打开 API 密钥,为新密钥设置名称。完整密钥只在创建时展示一次,请及时复制;列表仅显示前缀,之后无法取回完整密钥。将密钥保存在服务端。
已验证邮箱的账户默认可获得一次 100 积分的欢迎赠送,运营者可以调整或关闭。实际余额以控制台为准;新增密钥不会再次获得赠送。
安装已发布的 SDK
本示例使用 Node.js 22 或更新版本。SDK 本身支持 Node.js 20 及更新版本,以及提供标准 Web API 的运行环境。
第一个示例使用项目客户端 @system-one-ai/sdk@0.3.0。下文的官方客户端示例使用 @typesafe-ai/sdk@0.6.0;两个客户端的构造参数、问题类型和结果结构不同。
npm install @system-one-ai/sdk@0.3.0创建已加入版本控制忽略列表的本地 .env 文件。SYSTEM_ONE_API_KEY 是你的平台密钥,不是运营者使用的上游密钥。
SYSTEM_ONE_API_KEY=replace-with-your-platform-key
SYSTEM_ONE_BASE_URL=https://your-deployment.example.com/v1将域名替换为 主应用的部署地址,文档站不提供推理接口。本地主应用地址为 http://localhost:7001/v1。
发送第一个决策请求
保存为 decision.mjs。在 TypeScript 应用中,相同的工厂函数也会保留选项的字面量类型。
import { SystemOne, choice, score, booleanQuestion } from '@system-one-ai/sdk';
const apiKey = process.env.SYSTEM_ONE_API_KEY;
const baseURL = process.env.SYSTEM_ONE_BASE_URL;
if (!apiKey || !baseURL) throw new Error('请设置 SYSTEM_ONE_API_KEY 和 SYSTEM_ONE_BASE_URL。');
const client = new SystemOne({
apiKey,
baseURL,
model: 'jev-latest',
timeoutMs: 30_000,
maxRetries: 0,
});
// 将此值与业务操作一起保存,以便恢复未收到的响应。
const idempotencyKey = crypto.randomUUID();
const result = await client.evaluate({
state: { message: '同一笔订单被扣款两次。' },
questions: {
team: choice('选择负责审核这条请求的团队。', {
billing: '付款、发票与退款',
support: '技术故障排查',
review: '需要更多上下文',
}),
urgency: score('根据以下有序标准评估紧急程度。', [
'可以等待常规审核',
'需要及时回复',
'需要立即由人工处理',
]),
duplicate: booleanQuestion('消息是否反映了重复扣款?'),
},
}, {
headers: { 'Idempotency-Key': idempotencyKey },
});
console.log({
team: result.answers.team.choice,
distribution: result.answers.team.probabilities,
urgency: result.answers.urgency.score,
duplicateProbability: result.answers.duplicate.probability,
inputTokens: result.usage.inputTokens,
});node --env-file=.env decision.mjs这条命令会发起真实计费请求,不存在固定的预期答案或延迟。上游必须已配置,账户积分也必须足够。
理解响应
team.choice 是已定义的选项名称之一。对于这份三档标准,urgency.score 可以是 0 到 2 之间的小数。duplicate.probability 是 0 到 1 的数值,不是 JavaScript 布尔值。TypeSafe 原生 Choice 必须提供 probabilities 与 confidence,Score 还必须提供 legend。缺失用量和 token 计数保持未知。SDK 0.3.0 可能为转换后的结果补充 rounding/warnings 默认值,因此其结果不是精确原生正文。
在原生协议中,booleanQuestion() 转换为 type: "noul",对应响应字段为 noul。SDK 将其映射为公开的 boolean 答案与 probability。连接本平台无需自定义适配器,即使运营者在上游使用 OpenRouter 也是如此。
可在客户端或请求中指定模型别名或固定版本 ID,显式模型原样发送给 TypeSafe。只有客户端尚未填入自己的默认模型时,省略模型才会使用网关默认值。jev-latest 是示例别名,不是唯一允许值。带平台密钥请求 GET /v1/models 可读取真实上游 { models } 正文;有效版本 ID 不一定出现在列表中。
官方 TypeSafe 客户端与响应头
官方 SDK 支持必填但可为 null 的 state、可省略或为 null 的 instructions、以及可为 null 的 Noul criteria;SDK 0.3.0 会在发送前拒绝其中部分形式。原生 HTTP 与 Playground 会保留这些值,由上游决定接受或拒绝。以下示例使用 nullable 输入,不将其替换为空字符串。
npm install @typesafe-ai/sdk@0.6.0保存为 official-decision.mjs,使用相同服务端环境。官方客户端的 base URL 是 不带 /v1 的 API 根地址,因为它会自行追加 /v1/systemone。
import { TypeSafeClient } from '@typesafe-ai/sdk';
const apiKey = process.env.SYSTEM_ONE_API_KEY;
const baseURL = process.env.SYSTEM_ONE_BASE_URL;
if (!apiKey || !baseURL) throw new Error('请设置 SYSTEM_ONE_API_KEY 和 SYSTEM_ONE_BASE_URL。');
const client = new TypeSafeClient({
apiKey,
baseURL: baseURL.replace(/\/v1\/?$/, ''),
defaultModel: 'jev-latest',
timeout: 30_000,
retry: { maxRetries: 0 },
logLevel: 'off',
});
const operationKey = crypto.randomUUID(); // 与业务操作一起保存此键
const { data, response, requestId: typeSafeRequestId } = await client.systemOne({
model: 'jev-latest',
state: null,
questions: { ready: { type: 'noul', criteria: null } },
}, { headers: { 'Idempotency-Key': operationKey } }).withResponse();
const reportedCredits = response.headers.get('X-System-One-Credits');
const credits = reportedCredits !== null && /^\d+$/.test(reportedCredits)
&& Number.isSafeInteger(Number(reportedCredits)) ? Number(reportedCredits) : undefined;
console.log({
platformRequestId: response.headers.get('X-Request-Id'),
upstreamRequestId: response.headers.get('X-Upstream-Request-Id'),
typeSafeRequestId,
credits,
replayed: response.headers.get('X-Idempotency-Replayed') === 'true',
mode: response.headers.get('X-System-One-Response-Mode'),
model: data.model,
inputTokens: data.usage?.input_tokens,
});node --env-file=.env official-decision.mjs显式运行此命令会发起另一次真实计费评估,不是离线样例,也不表示所有上游都会接受 null State。withResponse().requestId 来自 X-TypeSafe-Request-Id,平台记账使用 X-Request-Id。扣费头缺失时保持未知,尤其是退款对账未完成时。正文中的 billing 或 request_id 属于上游,不能覆盖响应头。成功重放通过扣费头表示零,不添加正文字段。
需要精确响应文本时,在同一次调用上选用 .asResponse() 而不是 .withResponse(),再自行调用 response.text();两者遇到非 2xx 都会拒绝。官方 models.list() 返回解包后的数组,而原始 HTTP 保持 { models }。不要把运营者上游密钥放入客户端,也不要启用浏览器密钥暴露选项。
TypeSafe 原生模式保留有效成功文本、状态与扩展,不补默认 usage、warnings 或 rounding。openrouter-adapted 明确表示协议转换,legacy-cache 表示有限制的旧缓存。除安全替换与校验例外外,有效上游错误保留 4xx/5xx 与 JSON;稳定分类和来源读取响应头,不读取任意上游文字。
恢复中断请求
SDK 0.3.0 不会自动生成幂等键。两个示例都关闭重试并显式保存键。网络超时后,使用 相同的实际请求模型、状态、问题、扩展与幂等键 恢复,不因未收到响应就生成新键。精确高精度数字也必须保持一致;JavaScript Number 会在序列化前舍入的值,应使用原始 HTTP 或编辑器文本发送。
请求尚在处理时返回 409 request_in_progress,按 Retry-After 等待。已记录失败的请求再次使用原键会返回 409 idempotency_failed,积分已经返还;此时才使用新键发起新的尝试。详见幂等与重试。