AI资讯

我的 Codex 额度被偷偷砍了三分之一(附自查脚本)

作者:AI产品普洱0 次浏览 来源:AI产品普洱
我的 Codex 额度被偷偷砍了三分之一(附自查脚本)

最近蹬 Codex 干活,没蹬几下就跑掉了 5% 的周限额。 我严重怀疑自己被官方限额了。 可打开用量页面,它只肯告诉我一件事,还剩百分之多少。 至于 100% 到底是多少,从头到尾没写过。 分母不给

最近蹬 Codex 干活,没蹬几下就跑掉了 5% 的周限额

我严重怀疑自己被官方限额了。

可打开用量页面,它只肯告诉我一件事,还剩百分之多少。

至于100% 到底是多少,从头到尾没写过。

分母不给,我连自己有没有被砍都验证不了。

昨天我把它算出来了。

我这个号一周的额度上限是41666 Credits,折合 1666 美元。

听着不少,但大家之前普遍在 2200 到 2500 这个区间。

我被砍掉了三分之一,页面上一个字都没提。

下面这段代码你可以直接拿走。

粘进浏览器控制台,十几秒就能算出自己号的天花板,顺便看看有没有被动过手脚。

先说为什么官方页面看不出来。

用量页面在,chatgptcom/codex/cloud/settings/analytics

文章配图

Codex 用量页面显示每周限额还剩 92%

我这里显示每周使用限额还剩 92%,重置时间 8 月 31 日 9 点。

绿条拉得满满的,看着很健康。

问题出在这个百分比是相对值

上限从 2500 掉到 1666,页面还是只给你一个百分比。

分母缩了,绿条照样从满格开始走,你看不出来。

这就是它偷偷的地方,它给了你一个看不出问题的数

那就把分母算出来。

我写了个脚本干这件事,直接读你自己账号的数据,跑完出一张账本。

下面是操作,四步,跟着点就行

第一步,打开上面那个用量页面。

第二步,在页面空白处右键,点菜单最下面的检查

文章配图

右键菜单最下面那行检查

红框那行就是,在整个菜单的最下面。

第三步,在弹出来的面板里切到控制台

文章配图

DevTools 顶部的控制台标签

文章配图

控制台最下面那行输入区

左边这张是控制台标签的位置,右边这张是最下面那行输入区,光标点进去。

第四步,把下面整段代码复制进去,回车。

如果这时候弹出提醒不让粘贴,就先手动敲一句allow pasting回车,再粘一次。

Chrome 怕你被人骗着往控制台粘恶意代码,第一次会拦一下,敲完这句就放行了。

代码在这,全选复制。

(() => { const ID = "puer-ledger", RATE = 40 / 1000, PAGE = "/codex/cloud/settings/analytics";   ["-panel", "-btn", "-css"].forEach((s) => document.getElementById(ID + s)?.remove()); if (!location.pathname.startsWith(PAGE)) returnalert("请先打开这个页面再运行:\nhttps://chatgpt.com" + PAGE);  const n = (v) => (Number.isFinite(+v) ? +v : 0); const tk_ = (t = {}) => n(t.text_total_tokens) || n(t.cached_text_input_tokens) + n(t.uncached_text_input_tokens) + n(t.text_output_tokens); const fmtN = (v) => v >= 1e6 ? (v / 1e6).toFixed(2) + "M" : v >= 1e3 ? (v / 1e3).toFixed(2) + "K" : v; const dur = (s) => s >= 86400 ? (s / 86400).toFixed(1) + " 天" : s >= 3600 ? (s / 3600).toFixed(1) + " 小时" : Math.round(s / 60) + " 分钟"; const sum = (l) => ({     c: l.reduce((s, d) => s + (d.totals?.credits || 0), 0),     t: l.reduce((s, d) => s + tk_(d.totals), 0),     r: l.reduce((s, d) => s + (d.totals?.turns || 0), 0),   });  const css = document.createElement("style");   css.id = ID + "-css";   css.textContent = `#${ID}-panel{position:fixed;top:5%;left:50%;transform:translateX(-50%);width:min(760px,92vw);max-height:88vh;overflow:auto;background:#fff;color:#333;border:1px solid #e5e5e5;border-radius:14px;box-shadow:0 12px 60px rgba(0,0,0,.35);z-index:2147483646;padding:24px;font:14px/1.7 -apple-system,system-ui,sans-serif} #${ID}-panel h3{margin:0 0 15px;font-size:18px} #${ID}-panel .g{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:16px} #${ID}-panel .g>div{background:#f9f9f9;border:1px solid #eee;border-radius:8px;padding:12px;font-size:12px;color:#666} #${ID}-panel .g>div:nth-child(3){background:#eefaf5;border-color:#d1f2e1} #${ID}-panel .g b{display:block;margin-top:4px;font-size:15px;color:#10a37f} #${ID}-panel .w{background:#fff8e6;border:1px solid #ffe1a3;color:#8a5a00;border-radius:8px;padding:10px 12px;font-size:12px;margin:12px 0} #${ID}-panel table{width:100%;border-collapse:collapse;font-size:12px;margin-bottom:15px} #${ID}-panel th,#${ID}-panel td{padding:8px;border-bottom:1px solid #f0f0f0;text-align:left} #${ID}-panel th{background:#f5f5f5;color:#666} #${ID}-panel tfoot td{font-weight:700;background:#fafafa} #${ID}-btn{position:fixed;bottom:28px;right:28px;z-index:2147483647;padding:16px 28px;border:0;border-radius:999px;background:#10a37f;color:#fff;font-size:17px;font-weight:700;cursor:pointer;box-shadow:0 8px 28px rgba(16,163,127,.45)}`; document.head.appendChild(css);  const panel = document.createElement("div");   panel.id = ID + "-panel";   panel.style.display = "none"; document.body.appendChild(panel);  constget = async (url, token) => { const r = awaitfetch(url, { headers: { Authorization: `Bearer ${token}` } }); if (!r.ok) thrownewError(`接口 ${r.status}`); return r.json();   };  // 没有油猴环境,token 只能自己从页面里捞 const readToken = () => { const jwt = /[\w-]{30,}\.[\w-]{30,}\.[\w-]{30,}/; returndocument.getElementById("client-bootstrap")?.textContent?.match(jwt)?.[0] ||       [...document.scripts].map((s) => s.textContent?.match(jwt)?.[0]).find(Boolean);   };  const sheet = (list) => { const s = sum(list); const row = (d) => `<tr><td>${d.date}</td><td>${(d.totals?.credits || 0).toFixed(3)}</td><td>${fmtN(tk_(d.totals))}</td><td>$ ${((d.totals?.credits || 0) * RATE).toFixed(2)}</td><td>${d.totals?.turns || 0}</td></tr>`; return`<table><thead><tr><th>日期</th><th>Credits</th><th>Tokens</th><th>折算金额</th><th>轮数</th></tr></thead> <tbody>${[...list].reverse().map(row).join("")}</tbody> <tfoot><tr><td>合计</td><td>${s.c.toFixed(3)}</td><td>${fmtN(s.t)}</td><td>$ ${(s.c * RATE).toFixed(2)}</td><td>${s.r}</td></tr></tfoot></table>`;   };  const run = async () => {     btn.disabled = true; btn.textContent = "⏳ 算账中…"; try { const token = readToken(); if (!token) thrownewError("没拿到登录令牌,请刷新页面后重试");  const rl = (awaitget("/backend-api/wham/usage", token))?.rate_limit || {}; // 口径经常是坑:secondary 拿不到会退回 primary(短窗口),得让人看见用的是哪个 const key = rl.secondary_window ? "secondary_window" : "primary_window"; const w = rl[key] || {}; console.log("[额度账本] rate_limit 原始数据", rl);  const DAY = 86400000; const qs = `start_date=${new Date(Date.now() - 30 * DAY).toISOString().slice(0, 10)}&end_date=${new Date(Date.now() + DAY).toISOString().slice(0, 10)}&group_by=day`; const list = (awaitget(`/backend-api/wham/analytics/daily-workspace-usage-counts?${qs}`, token)).data || [];  // 优先用接口给的 reset_at 反推周期起点,拿不到就退回最后一个有数据的日子 const winSec = w.limit_window_seconds || 0; const cs = w.reset_at ? newDate((w.reset_at - winSec) * 1000) : null; const split = cs ? cs.toISOString().slice(0, 10)         : list.filter((d) => tk_(d.totals) > 0).map((d) => d.date).sort().pop(); const cur = list.filter((d) => !split || d.date >= split); const his = list.filter((d) => split && d.date < split);  const c = sum(cur), ratio = (w.used_percent || 0) / 100; let cap = "—", money = "—", why = ""; if (ratio > 0 && c.c > 0) {         cap = (c.c / ratio).toFixed(1) + " Credits";         money = "$ " + (c.c / ratio * RATE).toFixed(2); // 周期不是从 00:00 开始的,起始日那天混着上一周期的量,分子会偏大 if (cs && (cs.getHours() || cs.getMinutes()))           why = `${cs.toLocaleDateString("zh-CN")} 的日用量里含有 ${cs.toLocaleTimeString("zh-CN", { hour: "2-digit", minute: "2-digit" })} 之前、属于上一周期的消耗,日粒度切不开,反推分子会略偏大。`;       } elseif (ratio > 0) {         cap = "待统计";         why = `本周期刚重置不久,已用 ${w.used_percent || 0}% 是实时数据,但每日用量接口还没聚合出这段时间的量,分子为 0 所以反推不出来。等几小时后再点一次按钮即可。`;       } else {         why = "拿不到已用比例,反推不出上限。";       } if (winSec && winSec <= 86400)         why = `注意:拿到的是 ${dur(winSec)} 短窗口(${key}),这个比例说的不是周额度,反推出来的也不是周上限。` + why;        panel.innerHTML = `<h3>Codex 额度账本 · v3.2.0<span id="${ID}-x" style="float:right;cursor:pointer;color:#999">×</span></h3> <div class="g"><div>周期进度<b>${w.used_percent || 0}%</b></div> <div>本周期已用<b>${c.c.toFixed(1)} Credits</b></div> <div>额度上限(反推)<b>${cap}</b></div> <div>周期折算金额<b>${money}</b></div></div> <div style="font-size:12px;color:#666">口径 <b>${key}</b> · 窗口 <b>${winSec ? dur(winSec) : "未知"}</b><br> 本周期 <b>${cs ? cs.toLocaleString("zh-CN") : "未知"}</b> ~ <b>${w.reset_at ? new Date(w.reset_at * 1000).toLocaleString("zh-CN") : "未知"}</b> · 剩余 <b>${w.reset_after_seconds ? dur(w.reset_after_seconds) : "未知"}</b></div> ${why ? `<div class="w">${why}</div>` : ""} <p><b>当前周期明细</b>(自 ${cur[0]?.date || split || "未知"} 起)</p>${sheet(cur)} ${his.length ? `<p><b>已结算区间</b>(${his[0].date} ~ ${his[his.length - 1].date})</p>${sheet(his)}` : ""}`;       panel.style.display = "block"; document.getElementById(ID + "-x").onclick = () => (panel.style.display = "none"); console.table(cur.map((d) => ({ 日期: d.date, Credits: +(d.totals?.credits || 0).toFixed(3), 轮数: d.totals?.turns || 0 })));     } catch (e) { console.error("[额度账本]", e); alert("算账失败:" + e.message);     } finally {       btn.disabled = false; btn.textContent = "💰 查额度账本";     }   };  const btn = document.createElement("button");   btn.id = ID + "-btn";   btn.textContent = "💰 查额度账本";   btn.onclick = run; document.body.appendChild(btn); run(); })();

回车之后账本直接弹出来,右下角还会留一个绿色按钮,随时点它重新查。

文章配图

脚本跑出来的额度账本面板

顶上四个数字,从左往右看。

周期进度 7%,就是官方那个剩余百分比反过来说

本周期已用 2916.6 Credits。

额度上限反推出来 41666.3 Credits,这个数官方页面从来不显示。

周期折算金额 1666.65 美元,按1000 Credits 折 40 美元算的。

再往下是明细表。

我这个周期从 8 月 24 日 9 点开始,8 月 31 日 9 点重置,每天用了多少一行一行列着

最下面还有一段已结算区间,7 月 25 日到 8 月 23 日。

那一个月我跑了 219832 Credits,7449M tokens,5472 轮对话。

这些量折算下来是 8793.28 美元

现在到最关键的地方,你算出来这个数,到底正不正常

给你三个台阶做参照。

没碰过那些玩法的号,普遍在 2200 到 2500

我这个号 1666,砍掉三分之一。

还有一个更狠的,Pro 套餐,7 天窗口才过了 12 小时就跑到 100%

文章配图

另一个 Pro 号跑满 7 天窗口只折算 615 美元

它的天花板只有 615.4 美元,不到我的四成。

这张图是第三方面板的口径,跟我脚本按 Credits 折算的算法不完全是一把尺子。

所以别抠小数点,看量级就够了。

2400、1666、615,三个台阶摆在这。

那为什么会被砍。

8 月 23 日,OpenAI 负责 Codex 的 Tibo在 X 上发了一句话。

文章配图

Tibo 发推称不支持 sub2api

「我们不支持 sub2api。」

sub2api 是市面上流传的一种玩法,把订阅额度转出去当接口用

官方这句话把态度摆得很明白了。

具体它怎么装怎么配我不写,那不是这篇的重点,也不是我推荐的方向。

我想说的是另一件事。

我自己也用了。

我这个号 1666 的上限,大概率就是这么来的

那个 615 的号也用过。

数字我摆在这了,你自己判断。

顺带说一句,这个上限不是一成不变的

IP 老是变、几个人共用一个号、设备时区跟账号对不上,这些都可能让它波动。

所以你跑出来的数偏低,未必只有一个原因。

最后说几句这个脚本的实话,免得你跑出来觉得它坏了。

刚重置那几个小时,它反推不出来。

因为已用百分比是实时的,每日用量接口还没聚合出这段数据,分子是 0,除不动。

这时候面板会弹一条黄色提示告诉你原因,等几小时再点一次按钮就行

还有个误差得说清楚。

我这个周期是早上 9 点开始的,不是零点。

所以 8 月 24 日那一整天的用量里,混着 9 点之前属于上一周期的消耗。

日粒度切不开,反推出来的分子会略微偏大

另外如果接口只给到短窗口,反推的就不是周上限,面板同样会提示你。

这些我都写进提示条里了,跑出来看到黄条别慌。

建议你现在就跑一遍,把那个上限数字存下来

下个周期再跑一次,两个数一对,有没有被动过手脚,一眼就知道。

额度被砍了你是看不见的,因为百分比的分母跟着一起缩了。

平台愿意给你看什么,你就只能看到什么,除非你自己动手把数算出来

我是AI产品普洱,专注分享好用的AI工具和技巧。

你的号跑出来是多少?留言报个数,咱们凑一批样本,比谁猜都准。

我们,下次再见。

文章来自于微信公众号 “AI产品普洱”,作者 “AI产品普洱”

相关主题

读完之后

加入 AINRK 交流群

了解加入交流群的方式,与更多 AI 从业者交流。

查看交流群说明(在新窗口打开)