CC Switch
在 CC Switch 中配置 Fast AI,并显示当前 API Key 可见权益的多套餐用量。
适合人群
多客户端用户
你同时用 Claude Code、Codex、OpenCode 等多个工具,想统一管理配置。
查询接口
/v1/usage
适合显示当前 API Key 可见范围内的权益、剩余额度和多套餐信息。
官方文档
特点与使用场景
特点
跨平台桌面工具,适合集中管理多个 AI CLI 的 provider、skills、MCP、用量脚本和切换逻辑。
适用场景
你不想频繁手改各家客户端配置文件,或者需要给团队提供统一、可视化的供应商切换入口。
第 1 步:安装 CC Switch
1
macOS
官方 Releases 页面提供 Homebrew 安装方式。
Homebrew
brew tap farion1231/ccswitch
brew install --cask cc-switch2
Windows / Linux
到 Releases 页面下载对应的 MSI、便携版、
.deb 或 .rpm 安装包。3
验证安装
启动 CC Switch,确认主界面能正常打开并进入 Provider 管理。
第 2 步:先把 Fast AI 供应商配置好
先在 CC Switch 中创建或编辑 Fast AI 供应商,把基础请求配置补齐。
为什么 Base URL 要写到 /v1
下面的脚本会直接拼接
{{baseUrl}}/usage。所以 Base URL 请写成 https://api.fastai.run/v1,不要额外再带结尾 /,否则可能变成双斜杠。1
填写 Base URL 和 API Key
Base URL 直接填写 Fast AI 的 OpenAI 兼容入口,API Key 使用你在控制台创建的 Key。
供应商配置
Base URL: https://api.fastai.run/v1
API Key: sk-fastai.run-...2
保存供应商
先保存一次供应商配置,再进入“配置用量查询”。这样脚本测试和正式查询都能拿到同一套 Base URL / API Key。
第 3 步:配置用量查询脚本
在“配置用量查询”中选择“通用模板”,然后粘贴下面这份脚本。
这份脚本会显示什么
它会优先读取
/v1/usage 返回的 all_entitlements,把每个权益都转成 CC Switch 的套餐项;当前绑定、限制类型、到期时间和失效状态也会一起显示。如果没有 all_entitlements,它会回退到顶层兼容字段。CC Switch 用量脚本
({
request: {
url: "{{baseUrl}}/usage",
method: "GET",
headers: {
"Authorization": "Bearer {{apiKey}}",
"User-Agent": "cc-switch/1.0"
}
},
extractor: function (response) {
function num(value) {
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
}
function pickLimit(entitlement) {
if (!entitlement || entitlement.type === "pay_as_you_go") return null;
const limitedBy = Array.isArray(entitlement.effective_remaining?.limited_by)
? entitlement.effective_remaining.limited_by
: [];
const first = limitedBy[0];
if (first === "token_quota") return entitlement.token_quota || null;
if (first === "rolling_5h") return entitlement.rolling_5h || null;
if (first === "rolling_7d") return entitlement.rolling_7d || null;
if (first === "rolling_4w") return entitlement.rolling_4w || null;
const fallbacks = [
entitlement.token_quota,
entitlement.rolling_5h,
entitlement.rolling_7d,
entitlement.rolling_4w
];
for (const item of fallbacks) {
if (item && item.unlimited !== true && typeof item.remaining === "number") {
return item;
}
}
return null;
}
function limitLabel(name) {
if (name === "balance") return "余额";
if (name === "token_quota") return "总额度";
if (name === "rolling_5h") return "5小时窗口";
if (name === "rolling_7d") return "7天窗口";
if (name === "rolling_4w") return "4周窗口";
if (name === "expired") return "已过期";
if (name === "inactive") return "未激活";
return name || "";
}
function buildExtra(entitlement) {
const parts = [];
const limitedBy = Array.isArray(entitlement.effective_remaining?.limited_by)
? entitlement.effective_remaining.limited_by
: [];
if (entitlement.bound_to_current_key) parts.push("当前绑定");
if (entitlement.status) parts.push("状态: " + entitlement.status);
if (limitedBy.length > 0) parts.push("限制: " + limitedBy.map(limitLabel).join(", "));
if (entitlement.expires_at) parts.push("到期: " + entitlement.expires_at);
return parts.join(" | ") || undefined;
}
const entitlements = Array.isArray(response?.all_entitlements)
? response.all_entitlements
: [];
if (entitlements.length > 0) {
return entitlements.map(function (entitlement, index) {
const effective = entitlement.effective_remaining || {};
const limit = pickLimit(entitlement);
const result = {
planName: entitlement.plan_name || ("权益 " + (index + 1)),
isValid: entitlement.is_active !== false,
invalidMessage: entitlement.is_active === false
? (entitlement.is_expired ? "权益已过期" : (entitlement.status || "权益不可用"))
: undefined,
remaining:
num(effective.value) ??
num(limit?.remaining) ??
num(entitlement.balance?.remaining_usd) ??
0,
unit: String(
effective.unit ||
limit?.unit ||
entitlement.quota_unit ||
response?.unit ||
response?.quota?.unit ||
"USD"
).toUpperCase(),
extra: buildExtra(entitlement)
};
if (limit && limit.unlimited !== true) {
result.used = num(limit.used);
result.total = num(limit.limit);
} else if (entitlement.type === "pay_as_you_go") {
const used = num(entitlement.api_usage?.actual_cost);
if (used !== undefined) result.used = used;
}
return result;
});
}
return {
isValid: response?.is_active ?? response?.isValid ?? true,
invalidMessage: response?.invalidMessage || response?.invalid_message,
remaining: response?.remaining ?? response?.quota?.remaining ?? response?.balance ?? 0,
used: response?.used ?? response?.quota?.used,
total: response?.total ?? response?.quota?.limit,
unit: String(response?.unit ?? response?.quota?.unit ?? "USD").toUpperCase(),
planName: response?.planName ?? response?.plan_name ?? "当前 Key",
extra: response?.extra
};
}
})第 4 步:测试并确认展示效果
脚本保存后,点击“测试脚本”或等待自动查询,就可以在供应商卡片中看到套餐列表。
- 只有一个权益时,卡片会显示单条数据。
- 返回多个权益时,CC Switch 会把它们展开成多套餐列表。
- 如果返回中包含未激活或已过期权益,脚本会保留它们,并在卡片上标记不可用原因。
常见问题
Unknown balance provider
说明模板类型选错了。请切换到“通用模板”,不要使用旧的 balance 模板。
relative URL without a base
说明脚本测试时没有拿到可用的 Base URL。先确认供应商 Base URL 已填写为完整地址,并先保存供应商配置。
只显示一个套餐
先确认脚本返回的是数组,其次确认 `/v1/usage` 的 `all_entitlements` 中已经包含多个权益。
按量付费没有出现
先确认 `/v1/usage` 的 `all_entitlements` 里是否真的返回了按量付费权益;这版脚本不会再额外过滤它,但上游没返回时也不会凭空显示。
请求地址多了双斜杠
检查供应商 Base URL 末尾是否多写了 `/`。这版脚本是直接拼接 `{{baseUrl}}/usage`,建议固定填写成 `https://api.fastai.run/v1`。