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

首页 AI资讯 AI技术研报 AI监管政策 AI产品测评 AI商业项目 arena全球大模型排行榜 AI产品热榜 AI 源力市场 AI新闻日报

我的 Codex 额度被偷偷砍了三分之一(附自查脚本)
AI资讯 2026-08-26 11:04
+7483 阅读

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


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


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


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


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


昨天我把它算出来了。


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


那就把分母算出来。


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


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


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


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


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


右键菜单最下面那行检查


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


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


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


DevTools 顶部的控制台标签


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


控制台最下面那行输入区


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


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


如果这时候弹出提醒不让粘贴,就先手动敲一句 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();
})();


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


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


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


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


周期进度 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%


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


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


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


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


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


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


那为什么会被砍。


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


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


Tibo 发推称不支持 sub2api


「我们不支持 sub2api。」


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


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


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


我想说的是另一件事。


我自己也用了。


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


那个 615 的号也用过。


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


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


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


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


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


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


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


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


还有个误差得说清楚。


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


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


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


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


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


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


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


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


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


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


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


我们,下次再见。


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

1
cursor

【免费】cursor-auto-free是一个能够让你无限免费使用cursor的项目。该项目通过cloudflare进行托管实现,请参考教程进行配置。

视频教程:https://www.bilibili.com/video/BV1WTKge6E7u/

项目地址:https://github.com/chengazhen/cursor-auto-free?tab=readme-ov-file


添加客服微信openai178,进AITNT官方交流群