两行代码,接入所有大模型

一个接口打通 DeepSeek、通义千问、豆包、智谱、Kimi 等六家厂商。

对你的用户

不用注册多家大模型、不用一家家充值——一个账号、一个钱包用遍所有模型,用多少付多少,没有月费、没有最低消费。

对你

不用写注册登录页、不用管 API Key、不用逐家对接、不用垫付 token 成本——用户自己付自己的。

⬇ 下载 Java SDK (JAR) 创建应用拿 app_id(免实名)

先选一种接入模式

分岔点只有一个:这些 AI 调用,谁付钱?

模式 A · 用户各自付费 推荐 · 你零垫资

面向 C 端、有很多最终用户:每个用户用自己的 Tokin 钱包付自己的量,你一分钱不垫、也不用管 Key。桌面应用、网页服务、App 都适用。

不用注册:标识自己起一个 dev_你的应用名 写进代码即可跑通全流程(开发联调、或长期只做中转,都可以一直这么用)

② 接 OAuth 授权(托管登录页,用户点一次授权,之后自动续期永久免登录)

③ 用拿到的 access_token 调 /v1 —— 用量自动归属你的 app_id

要不要注册,看你需不需要这些:独占标识、用量统计归属、上架商店。需要就到控制台注册,把 dev_xxx 换成签发的 app_xxx,其余代码不动。

dev_ 标识不保证唯一:任何人都能用同一个字符串,用量统计会与之混在一起。要独占标识与干净的统计,请注册取得 app_(该号段只由平台签发,无法被他人占用)。切换到 app_ 后,此前记在 dev_ 名下的历史用量不会自动合并——在意统计连续性就一开始直接注册。

⑤ 上架应用商店 / 查看应用用量统计 —— 这两项需注册并完成实名认证(面向公众分发的合规要求)

模式 B · 你自己付费 最快 · 零门槛

内部工具、自研服务、原型验证:用你自己账号的余额跑,不必实名、不必注册应用、不必上架。

① 注册 Tokin 账号并充值(建议给项目单开一个账号当"公户",账目清爽、便于交接)

② 控制台 → API Keys → 新建子 Key,设额度上限 / 模型白名单 / 预算告警

③ 代码里用该子 Key 调 /v1(Key 只放服务端)

④ 想分开看用量:请求加 X-App-Id: 你起的标签,无需注册即可分组统计

日后要转成"用户各自付费",只需补认证 + 换授权那段代码,模型调用部分不动。

模式 A:你的用户会经历什么

01
打开你的应用
首次用到 AI 功能
02
浏览器自动弹出
在 Tokin 注册/登录并授权
03
凭证自动绑定
回到应用,立刻能用
04
之后永久免登录
自动续期,用多少付多少

注册登录页由 Tokin 托管(含短信验证码 + 滑动验证)。你的应用一行代码都不用写。

Java

零依赖 · JDK 17+
1. 拿到 SDK(三选一)
⬇ tokin-sdk-0.2.0.jar

丢进项目 libs/,加进 classpath 即可(零第三方依赖)。Maven 中央仓库即将上线。

# 装进本地 Maven 仓库后即可引用:
mvn install:install-file \
  -Dfile=tokin-sdk-0.2.0.jar \
  -DgroupId=ai.tokin -DartifactId=tokin-sdk \
  -Dversion=0.2.0 -Dpackaging=jar
2. 两行接入
import ai.tokin.TokinClient;

TokinClient tokin = new TokinClient("app_abax_jz");
String reply = tokin.chat("tokin-balanced", "帮我记一笔:午餐 35 元");

// 没绑定?自动弹浏览器让用户注册授权
// 绑定后自动续期,永久免登录
其它能力
tokin.chatStream(model, msgs,
  delta -> print(delta));         // 流式:打字机效果,强烈推荐
tokin.balance();                  // 余额(元)
tokin.topupUrl();                 // 充值页,放个按钮打开它
tokin.auth().switchAccount();     // 换用户
tokin.auth().setApiKey("sk-tokin-…"); // 手动绑定(备用)

上架 & 版本自动更新

提交新版本不会影响线上:新包进审核队列期间,商店照常展示当前版本、用户下载与 /latest 自动更新拿到的仍是当前版本;审核通过才整体顶替,驳回则只丢弃新包、线上不受影响。

平台托管分发
1. 把安装包传上来供下载

控制台 →「上传应用」,选安装包(exe/apk)、填版本号(如 1.3.0)+ 更新说明。平台自动做安全检查,通过即上架应用商店供下载;下载地址固定不变:

https://tokincloud.com/store/download/<appId>

发新版就是「传个更新版本号的新包」——下载地址不变,老用户下次查更新即可拿到。

2. App 启动查更新(平台给"最新版",你负责装)

机制:平台当"更新源",你的 App 启动时查一下、有新版就下载安装(只有 App 自己能装自己)。

// Java:SDK 一行查更新
var u = TokinClient.checkUpdate(
  "https://api.tokincloud.com", "app_abax_jz", "1.2.0");
if (u != null && u.hasUpdate()) {
  // 下载 u.downloadUrl(),SHA-256 校验 u.hash(),再拉起安装
  Desktop.getDesktop().browse(URI.create(u.downloadUrl()));
}

任意语言:直接 GET /store/apps/<appId>/latest → 返回 {version, downloadUrl, releaseNotes, hash},版本不同就下载安装。

3. 用户反馈(平台统一通道,免登录)

接法 A · 零界面工作(推荐):「反馈」按钮直接打开平台托管反馈页,界面我们出(建议/投诉单选、留言、联系方式、截图):

// Java:一行打开托管反馈页
Desktop.getDesktop().browse(URI.create(
  tokin.feedbackUrl("1.3.0")));
// 或任意语言直接拼 URL:
https://tokincloud.com/feedback.html?app_id=...&version=...

接法 B · 应用内自绘:自己画表单,一个 POST 发平台:

POST https://api.tokincloud.com/feedback
{ "appId": "...", "version": "1.3.0",
  "kind": "suggestion",        // suggestion=建议 | complaint=投诉
  "message": "...",            // 必填 ≤2000字
  "contact": "微信/手机/邮箱",  // 选填
  "imageBase64": "..." }       // 选填 ≤2MB PNG/JPEG/WebP

反馈界面请让用户自选「建议 / 投诉」。建议类你可在控制台开发者中心只读查看(联系方式脱敏);投诉类仅平台可见、由平台跟进。

// Java:SDK 一行
TokinClient.sendFeedback(
  "https://api.tokincloud.com", appId,
  "1.3.0", 留言, 联系方式, 截图路径或null);

⚠️ 红线:截图必须由用户主动粘贴或选择,发送前让用户看到发的是什么——绝不自动抓屏(用户屏幕上可能是敏感数据)。自动附带的只允许版本号等系统信息。
发送失败(断网等)请兜底提示改发邮件,别让用户的话丢了。

其它语言

TypeScript / Node
npm i @tokincloud/sdk
const c = TokinClient.withApiKey(baseUrl, apiKey);
await c.chat({ model, messages });
await c.panel({ messages, judge: true }); // 多 agent
Python
pip install tokincloud
from tokincloud import TokinClient
c = TokinClient.with_api_key(base_url, api_key)
c.chat(model=..., messages=[...])
c.panel(messages=[...], judge=True)
任意语言(OpenAI 兼容)

用你熟悉的 OpenAI SDK,只改 base_url:

client = OpenAI(
  api_key="sk-tokin-…",
  base_url="https://api.tokincloud.com/v1")

移动端 / 其它栈想做「一键连接」?流程是标准 OAuth 2.0 授权码 + PKCE: 桌面用 loopback 回调,iOS/安卓用自定义 scheme 深链 —— 每种语言都有现成 OAuth 库,照标准接即可。细节见下方「OAuth 接入细节」。

进阶能力

函数调用(tools)

tools / tool_choice 全量透传上游,响应 tool_calls 原样返回,流式同理。在售文本模型(DeepSeek / 通义 / 智谱 / Kimi / 豆包 / MiniMax)基本都支持。

{ "model": "deepseek-chat",
  "messages": [...],
  "tools": [{ "type":"function",
    "function": { "name":"add_expense", ... } }],
  "tool_choice": "auto" }

tool 消耗计入正常 usage 计费,无额外费用。

视觉(识图 / OCR)

messages 放 OpenAI 标准 image_url,http(s) 地址或 data:image/…;base64, 均可。推荐:qwen3-vl-flash(便宜) / qwen3-vl-plus / qwen-vl-max / glm-5v-turbo

{ "role": "user", "content": [
  { "type":"text", "text":"识别这张发票" },
  { "type":"image_url", "image_url":
    { "url":"data:image/png;base64,..." } } ] }

图片 token 计入输入价计费。注意:图片别太小(几像素会被上游拒);base64 带完整前缀。

OAuth 接入细节

· 授权页:tokincloud.com/authorize.html?app_id=…&redirect_uri=…&code_challenge=…&state=…(PKCE S256

· 换码/刷新:POST api.tokincloud.com/oauth/token(grant_type = authorization_code / refresh_token)

· 回调地址:loopback 免登记;自定义回调用主 Key 自助登记(精确匹配,至多 5 条):
PUT /v1/apps/<app_id>/redirects {"uris":["https://…/oauth/callback"]}

· 有效期:access 900 秒;refresh 无固定过期、每次刷新即轮换(重放触发吊销);用户可在控制台随时吊销。

· scope:无细分——凭证代表「该用户在你的 app 下」的数据面权限,计费落用户钱包、用量归属你的 app_id。

· 裸 REST 接入(不用 SDK):启动时发一次 POST /attest {"appId":"…"}(免鉴权,点亮后台"运行时握手")。

· X-App-Id 什么时候要加:用 OAuth access_token 调用时不需要(凭证里已含 app_id,加了会被忽略);只有用主 Key / 子 Key 直调且想区分应用时才加。

· 授权页可带 &phone=1xxxxxxxxxx 预填手机号(减少用户输入;验证码/密码仍只在我方页面输入,应用永远碰不到凭证)。

联网搜索(带真实来源)

让模型查实时信息,并拿到搜索引擎返回的真实链接——可入库、可点开核验,适合尽调 / 教学笔记 / 任何要留痕的场景。无需额外 Key,按 token 计费(搜索结果算输入)。

用法:加两个字段
POST /v1/chat/completions
{ "model": "qwen-plus",
  "messages": [{"role":"user","content":"今天上海天气?"}],
  "enable_search": true,
  "search_options": { "forced_search": true }  # 可选,默认已强制联网
}

# 响应在标准结构上多一个 search_info:
{ "choices":[…], "usage":{…},
  "search_info": { "search_results": [
    { "title": "…", "url": "https://…" }, … ] } }

响应头 X-Tokin-Web-Search: native 表示本次真的联网了。

三个必须知道的限制

· 仅通义千问系模型支持(qwen-plus / qwen-max / qwen3.7-max 等)。其它厂商会返回 X-Tokin-Web-Search: unsupported,我们不假装成功。

· 正文里的链接不可信,只信 search_info。正文的 [1] 角标与 URL 是模型自己写的、可能是编的;search_info.search_results 才是搜索引擎返回的真实标题与 URL。要留痕就存这个。

· 流式暂不带来源stream: true 时走的是兼容模式,能搜但没有 search_info。要来源请用非流式。

成本量级(实测)

搜索结果作为输入 token 计费:天气类问题约 2000 输入 token(≈¥0.002),人物/新闻类约 5000(≈¥0.004)。比独立搜索接口便宜。

防幻觉建议:在 prompt 里明确「只依据检索结果作答,未覆盖的写『未检索到』,绝不编造链接/日期/数字」。

音频转写(带时间戳)

OpenAI 兼容的 /v1/audio/transcriptions。返回句级 + 字级时间戳,可直接做字幕、或建立「第几分几秒讲了什么」的时间轴索引。按音频秒数计费,输出不计费。

上传即转写
curl https://api.tokincloud.com/v1/audio/transcriptions   -H "Authorization: Bearer sk-tokin-…"   -F file=@lecture.mp3   -F response_format=verbose_json   -F prompt="吉布斯抽样,卡尔曼滤波"   # 领域词表,显著降错字

# → { text, duration, segments:[
#      { start: 0.48, end: 3.43, text: "…",
#        speaker: 0, words:[{word,start,end}] } ] }

response_formatjson(默认) / verbose_json(带时间戳) / text / srt / vtt。后两个直接就是字幕文件。

长音频走异步
# 长录音:流式上传 + 异步(参数走 query)
curl -X POST "…/v1/audio/transcriptions?async=true&response_format=srt"   -H "Content-Type: audio/mpeg" --data-binary @lecture.mp3
# → 202 { task_id, poll: "/v1/audio/transcriptions/{id}" }

GET /v1/audio/transcriptions/{task_id}?response_format=srt
# → 202 处理中 / 200 结果

· 同步模式等待超过 90 秒会自动转异步并返回 task_id,不会白等一场。

· 结果可在 24 小时内重复取回(换 response_format 再取一次也行)——取结果时网络断了不必重转,同一任务只计费一次

· 长录音请走流式上传multipart 会把整个文件读进服务端内存,因此限 25MB;把音频直接作为请求体Content-Type: audio/*,参数放 query)则边收边写盘,可到 200MB。

· 一节课 90 分钟约 90MB → 用流式上传或 file_url;超限返回 413 upstream_rejected

· diarization=true 开说话人分离,段里带 speaker

· 已有公网音频地址可用 file_url 替代上传,省一次中转。

计费

按音频时长计费,转出多少字都不加钱。响应头 X-Tokin-Audio-Seconds / X-Tokin-Billing 回显本次秒数与金额。90 分钟的课约 ¥0.44。

实时语音转写(边说边出字幕)

WebSocket 双向流:麦克风音频往上送,识别结果边说边回。约 1 秒出首字,中间稿持续刷新,句末给带时间戳的终稿。适合课堂字幕、会议纪要、直播实时字幕。

连接与协议
// 凭证走 query:浏览器无法给 WS 设 Authorization 头
const ws = new WebSocket(
  "wss://api.tokincloud.com/v1/realtime/transcriptions"
  + "?token=sk-tokin-…&sample_rate=16000&format=pcm");

ws.onmessage = (e) => {
  const m = JSON.parse(e.data);
  // session.started → transcript(多次) → billing
  if (m.type === "transcript")
    render(m.text, m.is_final, m.begin_time, m.end_time);
};
// 上行:二进制帧 = 音频块;说完发 {"type":"finish"}
ws.send(pcmChunk);
ws.send(JSON.stringify({ type: "finish" }));

音频建议 16kHz 单声道 PCM,每 100ms 一块(3200 字节)。也支持 opus/mp3/aac 等,用 format 指定。

下行消息
{"type":"session.started", model, sample_rate}
{"type":"transcript", text, is_final,
 begin_time, end_time}      // 毫秒
{"type":"billing", seconds, amount,
 final}                     // 每结算一次一条
{"type":"error", message, code}

· is_final=false 是中间稿(会被后续覆盖),true 才是定稿——入库只存终稿

· 单账号同时最多 5 路;单会话最长 2 小时,超时服务端主动断。

· 每满 60 秒音频结算一次并推一条 billing 消息(seconds 是累计值,不是增量),不是断开才算——余额花光会被中断,不会欠账。

· 会话结束时若还有不满 60 秒的零头,补结一次并推 final:true 的 billing——以这条为最终账单。一节 90 分钟的课共 90 条左右。

· 课上到一半余额用尽会当场断开并给 insufficient_quota;因为是「先扣款再发现」,最多透支一个计费周期(约 ¥0.015),不会持续欠账。长课建议课前确认余额。

· 断线(网络抖动/客户端崩溃)已转写部分照常计费,重连请重新建立会话。

计费

按音频秒数,¥0.00024/秒 × 加价倍率 → 一节 90 分钟的课约 ¥1.3。比课后文件转写(约 ¥0.44)贵,换来的是实时。

增值接口(按次计费)

模型之外的能力,同一个 Key、同一个钱包:调用成功按次扣费(价格见 GET /v1/services),支持代付、X-Usage-Tag 分组、子 Key 预算——口径与模型调用完全一致。上游失败不收费。

联网搜索
POST /v1/search
{ "query": "2026 世界杯 举办地", "count": 10,
  "freshness": "noLimit" }   # 可选 oneDay/oneWeek/oneMonth/oneYear

# → { results:[{title,url,snippet,publishedTime?,siteName?}],
#     billing:{service:"web-search",amount} }

给模型喂实时信息的标配:搜索 → 把 results 拼进 prompt → 再调 /v1/chat/completions。query ≤200 字符,count 1–20;snippet 已是长摘要,可直接入 prompt。

企业数据(10 类:工商 / 风险 / 知产 / 裁判文书 / 标讯…)
# 简易:按关键词查企业(自动走「实体识别」)
POST /v1/company
{ "keyword": "阿里巴巴" }

# 进阶:先看工具目录,再精确调任一工具
GET  /v1/company/tools?server=risk   # 目录免费
POST /v1/company
{ "server":"risk", "tool":"工具名", "arguments":{…} }

# → { result:…, billing:{service:"company-search",amount} }

数据源为企查查智能体数据平台,共 185 个原子工具。服务可选:company / risk / ipr / operation / history / executive / regulation / case / tender / document。「客户尽调 / 合同相对方核验 / 供应商体检」直接搭。

按工具计价:不同工具单价不同(约 ¥0.1~¥2 / 次),GET /v1/company/tools 的每个工具都带 price 字段,调用前即可知价;实际扣费以响应里的 billing.amount 为准。查无结果不收费。

端点速查(两个域名别搞混)

授权页在主域,API 在 api 子域——这是最常见的接错点。

用途端点鉴权
授权页(浏览器打开)https://tokincloud.com/authorize.html用户登录
换码 / 刷新令牌POST https://api.tokincloud.com/oauth/token无(PKCE)
模型推理POST https://api.tokincloud.com/v1/chat/completionsBearer access_token 或 sk-tokin-*
多 agent 面板POST https://api.tokincloud.com/v1/panel同上
实时转写(WebSocket)wss://api.tokincloud.com/v1/realtime/transcriptions?token=…token 走 query
音频转写POST https://api.tokincloud.com/v1/audio/transcriptions同上(按秒计费)
联网搜索 / 企业查询POST https://api.tokincloud.com/v1/search · /v1/company同上(按次计费)
余额 / 用量GET https://api.tokincloud.com/v1/balance · /v1/usage同上
启动握手(可选)POST https://api.tokincloud.com/attest
回调地址登记PUT https://api.tokincloud.com/v1/apps/<app_id>/redirects开发者本人的 sk-tokin-*

Web 服务端接入(多用户)

桌面应用用 SDK 的 connect()(拉起浏览器 + loopback 收码)。Web 后端要为 N 个用户分别保管凭证——Python 有官方封装,其它语言按下方协议自己实现(就三步)。

Python:官方封装,三行接完
推荐
pip install tokincloud

from tokincloud import TokinWebAuth, SqliteTokenStore

auth = TokinWebAuth(
    base_url="https://api.tokincloud.com",
    app_id="app_xxxxxxxxxxxxxxxx",               # 线上域名回调须用平台签发的 app_
    redirect_uri="https://你的域名/oauth/callback",
    store=SqliteTokenStore("tokens.db"),          # 换成你自己的库:实现 save/load/delete 三个方法
)

url = auth.start(user_id="本站用户ID")             # ① 302 跳过去(PKCE + state 内部生成)
uid = auth.callback(code=code, state=state)        # ② 回调换凭证并落库,从 state 还原本站用户
auth.client_for(uid).chat(model=..., messages=...) # ③ 之后随时用,过期自动续、轮换自动回存

可跑示例:FastAPI · Django。本地调试用 http://127.0.0.1:8000/oauth/callbackdev_ 前缀即可,免注册;多进程部署(gunicorn -w 4)把 pending 换成 Redis 实现,示例文件末尾有现成的。

其它语言 / 想自己实现:下面是完整协议。
① 发起授权(每个用户一次)
# 服务端生成并暂存(按 state 索引本站用户)
verifier  = base64url(random(32))
challenge = base64url(sha256(verifier))
state     = random()
store[state] = { user_id, verifier }   # 5~10 分钟过期

# 302 跳转用户浏览器到:
https://tokincloud.com/authorize.html
  ?app_id=dev_yourapp
  &redirect_uri=https://你的域名/oauth/callback
  &code_challenge={challenge}&state={state}

非 loopback 回调需先登记:PUT /v1/apps/<app_id>/redirects(用开发者本人的 sk-tokin-* 主 Key,不是终端用户的)。

② 回调换码 + 按用户持久化
# GET /oauth/callback?code=..&state=..
{ user_id, verifier } = store.pop(state)   # state 不匹配即拒绝

POST https://api.tokincloud.com/oauth/token
{ "grant_type":"authorization_code",
  "code": code, "code_verifier": verifier }
# → { access_token, refresh_token, expires_in, token_type }

db.save(user_id, refresh_token, access_token,
        expires_at = now + expires_in)
③ 调用前自动续期
if now >= expires_at - 60:
    POST /oauth/token
    { "grant_type":"refresh_token",
      "refresh_token": db.get(user_id) }
    # refresh_token 每次刷新都会轮换 → 必须回写覆盖
凭证刷新语义(自研接入方的对照检查清单)

刷新是自研最容易出错的部分。官方 SDK(TokinWebAuth / TokenManager)已内置下面全部行为;自己实现请逐条对照:

· 并发单飞:同一用户多个线程/请求同时发现过期时,只应发出一次刷新(拿锁后先复查凭证是否已被别人换新)。否则并发刷新互相作废对方的 refresh_token。

· 轮换必回存:每次刷新返回新的 refresh_token,必须覆盖保存后再放行业务请求。先用后存的窗口里进程崩溃 = 该用户凭证永久失效。

· 30 秒宽限期:多副本用同一个旧值重复刷新,30 秒内会回放同一结果(不误判盗用);超过 30 秒的重放按泄露处理、整条授权吊销。宽限期是兜底,不是许可——仍应以单飞为目标。

· 失败要分类,不能一律清凭证重授权:401 invalid_grant = 授权确实失效 → 清凭证、引导重新授权;503 temporarily_unavailable = 瞬时故障 → 重试,别清凭证403 access_revoked(业务调用时)= 用户主动吊销 → 清凭证。

· 401 兜底重试一次:业务请求撞上刚好过期的 access → 强制刷新后重放一次即可,不要循环。

令牌字段 & 错误处理

/oauth/token 请求 / 响应
// 请求(二选一)
{ "grant_type":"authorization_code",
  "code":"...", "code_verifier":"..." }
{ "grant_type":"refresh_token",
  "refresh_token":"..." }

// 响应 200
{ "access_token":  "...",   // Bearer 用它调 /v1
  "refresh_token": "...",   // 每次刷新都轮换,务必覆盖保存
  "expires_in":    900,     // 秒(access 有效期)
  "token_type":    "Bearer" }

// 失败 401
{ "error":"invalid_grant", "message":"..." }

refresh_token 无固定过期。支持轮换宽限期:多副本服务并发刷新时,30 秒内用同一个旧值重复刷新会回放上次结果(返回同一个新 refresh_token),不会误判为盗用;超过 30 秒的重放仍按泄露处理、吊销整条授权,所以务必以最新值覆盖保存。

/v1/models 响应结构
{ "object":"list", "data":[
  { "id":"tokin-balanced", "object":"model-mode",
    "description":"速度效果均衡(默认)" },
  { "id":"deepseek-v4-flash", "object":"model",
    "owned_by":"deepseek" } ] }

object 区分:model-mode=语义模式,model=具体模型。只列当前已上架可调用的,可直接用于选择器与可用性校验。

常用响应字段
// GET /v1/balance
{ "balance": 12.3456 }        // 单位:元(人民币),可为小数

// GET /v1/usage
{ "count": 42, "totalSpent": 1.234,
  "records": [ { "ts":…, "provider":"deepseek",
    "model":"deepseek-chat", "promptTokens":…,
    "completionTokens":…, "spent":0.0021 } ] }
错误码与应对

401 invalid_token — access 过期/无效 → 用 refresh_token 刷新后重试一次

403 access_revoked — 用户已吊销授权 → 刷新无用,引导用户重新授权

402 insufficient_quota — 用户余额不足 → 提示去充值

429 rate_limit_exceeded — 超过 RPM(默认 60/分钟)→ 退避重试

429 app_quota_exceeded — 单应用窗口花费上限 → 退避 / 联系我们调额

400 model_not_found — 模型名错或未开放 → 对照 /v1/models

400 upstream_rejected — 上游拒绝了请求本身(如输入超长)→ 不会故障转移,按 message 修请求

502 upstream_error — 上游全失败(已自动故障转移过)→ 可稍后重试

503 temporarily_unavailable — 刷新令牌时的瞬时冲突 → 退避重试即可,勿清除凭证

所有端点(含 /oauth/token)错误体统一为 {"error":{"message","type","code"}},只写一套解析即可;OAuth 端点额外在顶层保留 code 字段兼容旧客户端。

流式输出(SSE)

标准 OpenAI SSE 协议,裸 REST 即可用。强烈建议开启——首字通常几百毫秒返回,体感比等全文快得多。

请求 & 帧格式
POST /v1/chat/completions
{ "model":"deepseek-v4-flash",
  "messages":[…], "stream": true }

# 响应 Content-Type: text/event-stream
data: {"choices":[{"delta":{"content":"你"}}]}
data: {"choices":[{"delta":{"content":"好"}}]}
data: {"choices":[…],"usage":{…}}   # 见右
data: [DONE]

按行读,取 data: 后的 JSON;遇 [DONE] 结束。非 JSON 帧(心跳等)忽略即可。

usage 在哪 & 中途出错怎么表达

· usage 在最后一个数据帧([DONE] 之前那帧)。我们已自动向上游注入 stream_options.include_usage,你不必自己传。计费以该帧为准。

· 中途出错:HTTP 已 200,无法再改状态码,因此以一个错误帧表达,随后关闭流:
data: {"error":{"message":"…","type":"upstream_error"}}
所以每帧都要检查有没有 error 字段

· 已扣费的部分以收到的 usage 帧为准;未产生 usage 帧则不计费。

运行期约束(限流 / 超长 / 超时)

限流的计量主体

· rate_limit_exceeded每「用户 × 应用」60 次/分钟(滑动窗口)。不是按 app 汇总——一个班几十人同时用互不挤占。

· app_quota_exceeded:同样按「用户 × 应用」计,默认 ¥10/窗口,防单用户异常烧钱。

· 两者都返回 429 + Retry-After(秒),响应体也带 error.retryAfter,照它退避即可。

量确实不够用时联系我们按 app 调高,不必自建排队层。

超长输入

· 我们绝不静默截断——请求原样透传给上游,不做任何裁剪。

· 超出模型上下文时,上游会拒绝,我们原样回传原因
400 {"error":{"code":"upstream_rejected","message":"…"}}

· 这类「请求本身的问题」不会触发故障转移(换厂商也一样失败),会立即返回,不浪费时间。

长文(如整节课转写)建议选长上下文模型,或自行分段后合并。

超时建议

· 非流式:建议客户端超时 120 秒(长文本+推理模型可能跑到 1 分钟以上)。

· 流式:建议按「首字超时 30 秒 + 帧间超时 60 秒」,别用总时长卡。

· 我们侧不主动截断长生成;上游各家自身有其超时策略。

用量分组 & 可追溯

自定义用量标签 X-Usage-Tag

按班级 / 课程 / 项目分组对账。平台不解释标签含义,只做聚合(≤64 字符)。多维标签的约定:一个字符串装多层、用 . 分隔,报表用 prefix 过滤任一层。

POST /v1/chat/completions
X-Usage-Tag: course_abc.feature_note   # 第一层=班级,第二层=功能

# 查询聚合(含调用次数与 token 数——判断"变多"还是"变贵")
GET /v1/usage/by-tag?days=30
# → { tags:[{tag,calls,tokensIn,tokensOut,spent,lastUsedAt}] }

# 前缀过滤:course_abc. 开头 = 这个班的全部功能
GET /v1/usage/by-tag?days=30&prefix=course_abc.
# 按天分桶(做周报/月报客户端按天汇总即可)
GET /v1/usage/by-tag?days=30&bucket=day
# → { tags:[{tag,day:"2026-08-13",calls,…}] }(标签×天,Asia/Shanghai)

# 机构视角(看自己代付的成员,按标签分),同样支持 prefix/bucket
GET /v1/sponsor/usage/by-tag?days=30
# → { tags:[{tag,calls,members,tokensIn,tokensOut,spent}] }

标签会不会被别人"污染"?不会——以上报表都按「你的账号 / 你代付的成员」聚合,从不按 app 汇总;即使有人用了与你相同的 dev_ 标识和标签,也进不了你的报表(app 维度的平台统计才会混,这是尽早注册 app_ 的又一理由)。

这次实际用了哪个模型

用语义模式(tokin-balanced 等)时,响应头会明示真实模型,便于留痕与复现:

X-Tokin-Served-Model: deepseek-v4-flash  # 实际模型
X-Tokin-Served-By:    deepseek           # 实际厂商
X-Tokin-Mode:         tokin-balanced     # 你传的模式(仅模式调用时)
X-Tokin-Failover:     true               # 发生了故障转移(仅转移时)

直接指定具体模型时,返回体 model 字段即为实际模型。流式同样带这些响应头(胜出候选在首帧确定后才开流),流式与非流式可共用一套"读响应头"代码。

授权流程细节

用户拒绝授权时
# 带 redirect_uri 时 → 原样回跳并带上:
{redirect_uri}?error=access_denied&state={state}

# 无 redirect_uri(桌面手动复制场景)
# → 停在我们页面显示"已取消授权",不回跳

回调里请同时处理 codeerror 两种参数;state 一律原样带回。

loopback 回调的边界

· 主机名 127.0.0.1 / localhost / ::1 等价,均免登记。

· 端口任意(遵循 RFC 8252,桌面应用可用随机端口)。

· loopback 允许 http;其它主机必须登记,登记后按完整字符串精确匹配(含路径与端口)。

授权范围(用户看到什么)

授权页向用户明示:该应用仅可代其发起模型调用并从钱包扣费拿不到账户密码或主密钥不能提现、不能改账户、不能读取其它数据;凭证可随时在控制台一键吊销。

面向学校 / 家长解释时可直接引用这段。

模型与智能模式

可填具体模型名,也可填语义模式——由平台按你的意图自动选最优模型并故障转移:

tokin-fast
最快响应
tokin-balanced
速度质量平衡
tokin-quality
最强效果
tokin-cheapest
最省成本
tokin-reasoning
深度推理
模型会自适应吗?需要你做什么?

会自适应,而你什么都不用做——只要把 model 填成语义模式(如 tokin-balanced): 平台按意图自动选当前最优模型,某家故障时自动切换下一家。 新模型上线、厂商降价、接口变更,都由我们在服务端跟进,你的应用零改动自动受益。 想锁死某个模型?把 model 填具体名(如 deepseek-chat),我们就不替你选。

具体模型名与实时价格见 定价页,或调用 GET /v1/models