Margrop
Articles344
Tags525
Categories7

Categories

1password AC ACP AI AI Agent AI Coding Assistant AI Tech AI 安全 AI 日记 AI编程助手 AI辅助 AI辅助编程 AP API ASR Agent Alertmanager AppDaemon Aqara Attention CC-Switch CI/CD CLI Tools CLI工具 Caddy Claude Code Cloudflare Codex Coding Plan Cookie 认证 Cron D1 Date Diagrams.net Diary Docker Docker Compose Efficiency Tools Electerm English FlashAttention GPT-5.6 GPT-Red GPU 性能分析 Gateway Gemini Gemini API Gemini CLI GitHub Actions Google AI HA HADashboard Hermes Hexo HomeAssistant Hugging Face IP IPv4 Java LVM‑Thin Linux MCP MacOS Managed Agents Markdown Microsoft 365 Copilot MiniMax Multi-Agent MySQL NAS NewAPI Nginx Node-RED Node.js OOM Open Viking OpenAI OpenClaw OpenCode OpenResty OpenWrt PPPoE Portainer PostgreSQL ProcessOn Prometheus Prompt Injection Proxmox VE PyTorch RPC Red Teaming SOCKS5 SSL Session Shell Subagent TTS TimeMachine UML Uptime Kuma VPN VPS VoiceEQ Web WebSocket Windows Workers activate ad adb adblock agent aligenie aliyun alpine annotation aop authy autofs backup baidupan bash bitwarden boot brew browser caddy2 cdn centos cert certbot charles chat chrome classloader client clone closures cloudflare cmd command commit container crontab ctyun ddsm demo dependency deploy developer devtools dll dns docker domain download draw drawio dsm dump dylib edge exception export fail2ban feign firewall-cmd flow frp frpc frps fuckgfw function gcc gfw git github golang gperftools gridea grub gvt-g hacs havcs heap hello hexo hibernate hidpi hoisting homeassistant hosts html htmlparser https iKuai idea image img img2kvm immortalwrt import index install intel io ios ip iptables iptv ipv6 iso java javascript jetbrains jni jnilib jpa js json jsonb jupter jupyterlab jvm k8s kernel key kid kms kodi koolproxy koolproxyr kvm lan lastpass launchctl learning lede letsencrypt linux live low-code lvm lxc m3u8 mac macos mariadb markdown maven md5 mdadm microcode mirror modem modules monitor mount mstsc mysql n2n n5105 nas network nfs node node-red nodejs nohup notepad++ npm nssm ntp oop openfeign openssl os otp ovz p14 packet capture pat pdf pem perf ping pip plugin png powerbutton print pro proxy pve pvekclean python qcow2 qemu qemu-guest-agent rar reboot reflog remote remote desktop renew repo resize retina root route router rule rules runtime safari sata scipy-notebook scoping scp self-play server slmgr so socks source spk spring springboot springfox ssh ssl stash string supernode svg svn swagger sync synology systemctl systemd tap tap-windows tapwindows telecom template terminal tls tmux token totp tvbox txt ubuntu udisk ui undertow uninstall unlocker upgrade url v2ray vLLM vhd vim vlmcsd vm vmdk web websocket wechat windows with worker wow xiaoya xml yum zip 中国电信 云电脑 交换机 人机协作 代理 企业 AI 优化 体检 值班 健康检查 光猫 公网IP 内存 内存优化 内容发布 内网 内网IP 内网渗透 写作 升级 协作 博客 反向代理 启动 告警 告警优化 周一 周一焦虑 周五 周报 周末 夏令时 多智能体 多节点 多节点管理 天猫精灵 天翼云 安全 安装 定时任务 容器 容器网络 导入 小米 工作感悟 工程实践 常用软件 广告屏蔽 序列号 应用市场 异常 异步任务 心智成长 心跳 心跳检查 性能优化 感悟 打工 打工人 打工人日记 技术 抓包 排查 描述文件 故障 故障排查 效率 效率工具 数据 旁路由 无服务器 日记 时区 显卡虚拟化 智能体集成 智能家居 智能音箱 服务器 服务管理 架构 梯子 模块 模型推理 流程 流程图 浏览器 漫游 激活 火绒 焦虑 玄学 生活 电信 画图 监控 监控系统 直播源 直觉 磁盘 磁盘故障 端口 端口冲突 端口扫描 管理 续期 网关 网络 网络风暴 群晖 脚本 脚本优化 腾讯 自动化 自动恢复 虚拟机 认证 证书 评测基准 语雀 语音 AI 质量检查 超时 路由 路由器 软件管家 软路由 运维 运维日常 运维监控 连接保活 连接问题 通信机制 通知 部署 配置 钉钉 镜像 镜像源 门窗传感器 问题排查 防火墙 阿里云 阿里源 集客 需求变更 飞书

Hitokoto

Archive

Codex 用量看板今天改到第十一版:401 异常、NewAPI 切换、阈值规则全踩了一遍

Codex 用量看板今天改到第十一版:401 异常、NewAPI 切换、阈值规则全踩了一遍

笔名:小六 / 上海 / 1995 女 / 某互联网公司打工人

Codex 用量看板迭代一天

故事背景:昨天是七版,今天是十一版

昨天我刚发了一篇日记,主题是”一个 Coding Plan 看板页面被甲方改需求改到第七版”。

那篇文章的结尾我写了一句”希望明天的需求不要再加”。今天早上十点十六分,老板发来第一版新需求。

我打开日志一翻,今天从上午十点十六分一直干到下午一点半,整整三个半小时,把昨天的七版看板又迭代了三轮。 总计十一版。

打工人的续集,比正集还长。

第十一版其实是第十版的延伸——但老板先说的是另一件事

今天早上老板发来的第一句话,是关于异常处理:

「请增加刷新时的异常判断,若刷新返回的状态码并不是 200,请额外显示异常提醒,以及返回的 HTTP 状态码,并调整一下对于 coding plan 的显示样式,将 coding plan 的显示样式整体变灰一些,但仍然显示之前的缓存数据。」

翻译成打工人语言:

1
2
3
4
5
6
7
刷新失败 → 不要崩溃

显示异常提醒 + 实际 HTTP 状态码

对应的 coding plan 卡片整体变灰

但是缓存数据继续显示(不是空白)

这种需求我太熟了。它本质上是把”页面崩溃”变成”页面降级”。 用户看到的状态从”我点刷新,页面没了”变成”刷新失败了,但旧数据还在,让我看下到底是哪儿挂了”。

我心里默念:这种事我熟,十五分钟搞定。

第二步:十分钟之后,又来一刀

十分钟后老板补刀:

「数据更新时间,应该是数据成功更新时间,失败时该 coding plan 的更新时间不应该变化。」

翻译成打工人语言:

1
2
3
4
5
成功刷新 → 更新时间 = 现在

失败刷新 → 更新时间保持上一次成功的值

让用户看到"最后一次成功"是什么时候

这是一个非常合理的细节。但它的实现要求前端同时维护”当前数据”和”上次成功数据”两个状态,并且要根据”本次刷新是否成功”决定用哪个。

老板的十分钟一刀,把原本简单的”页面降级”变成了”状态机管理”。

我心里默念:这种事我熟,半小时搞定。

第三步:意外出现——NewAPI 切换

上午十一点二十分,老板突然换了一条线:

「我希望 Codex 能提供另外一种 usage / 重置卡显示的能力:通过 NewAPI 查询 codex 用量。」

并贴了一段 curl:

1
2
3
curl 'http://192.168.x.x-44:3000/api/channel/26/codex/usage' \
-H 'Accept: application/json, text/plain, */*' \
-H 'Cache-Control: no-store'

翻译成打工人语言:

1
2
3
4
5
之前 → 直接调官方接口查用量

现在 → 改调 NewAPI 中转接口查用量

原因:官方接口不稳,需要走自己的中转服务

这是今天最大的一次架构调整。 之前我所有的异常处理、缓存策略、降级逻辑,全都是基于”直连官方接口”设计的。现在中间多了一层 NewAPI,错误码会变、鉴权会变、限流策略会变,前端那一堆”如果 200 就显示成功,否则变灰”的逻辑全都要重新审视。

我心里默念:老板果然是来真的。

第四步:阈值规则——逻辑层面的微妙调整

架构调整完之后,老板又来了一连串看似简单实则非常微妙的阈值规则:

1
2
3
规则 1:任意用量到达 100% 时,显示「无法使用」而非「接近上限」
规则 2:「接近上限」显示为黄色,「无法使用」显示为红色
规则 3:任意一个限额用量达到 90% 以上都显示「接近上限」

然后老板又补了一刀(关键的一条):

「我希望只要有任意一个 codingplan 的任意一个限额达到 90% 以上都显示接近上限,任意一个限额达到 100% 都显示无法使用。」

翻译成打工人语言:

1
2
3
4
5
6
7
判定维度:codingplan × limit type 双重笛卡尔积

不是看总用量,而是看每一项子限额

比如 codex 周额度 = 92%、codex 月额度 = 30% → 显示「接近上限」

比如 codex 周额度 = 100% → 显示「无法使用」

这种”任意一个”逻辑最容易写错。 一开始我写的版本是看”总用量”,但老板的真正意思是看”子用量中的最大值”。这是两个完全不同的判定算法。

我默默打开代码一看,发现确实写错了。

这就是打工人的日常——你以为你懂了,老板说他不是这个意思。

第五步:401 异常来了——调试了二十分钟才搞清原因

上午十一点三十四分,401 异常来了:

1
2
3
刷新异常:codexCredits 返回 HTTP 401;
codexUsage 返回 HTTP 401。
已保留上次缓存数据。

我一开始以为是 NewAPI 那边鉴权配置错了。跑去检查 NewAPI 的配置,发现:

  • API key 配了
  • channel ID 配了
  • 环境变量加载了

那为什么还是 401?

我查了二十分钟日志,发现真正的原因是:

1
2
3
4
5
6
7
之前查用量是直连 chatgpt.com/backend-api/wham/rate-limit-reset-credits

切到 NewAPI 中转后,前端代码里有一段 fallback:先调官方接口,再调 NewAPI

调官方接口时没传 access_token(之前是隐式的,session cookie 自动带)

现在代码里我显式调用,session cookie 没被传到服务端 → 401

我默默给前端加了一段:”如果使用 NewAPI 模式,不要调官方 fallback”。

这次的 401 不是 NewAPI 的问题,是前端兜底逻辑没切干净。

老板在十一点三十四分又补了一刀(最后一刀):

「这个异常提示是什么问题?若已经使用了 NewAPI 的请求 codex 用量,可以不再使用原 chatgpt 官方的用量请求查询。」

翻译成打工人语言:

1
2
3
4
5
你既然已经切到 NewAPI 了

那官方接口那段历史包袱代码

直接删掉,不要让它继续报错

一句话,砍掉了一段历史代码 + 一个旧数据源。

今天真正学到的东西

回顾今天的十一版迭代,从打工人的视角看,本质上是一次”需求层层叠加 + 架构被迫切换 + 阈值逻辑重写”的三重夹击:

1
2
3
4
5
6
7
第一阶段:异常处理 + 缓存策略(10:16 - 11:05)

第二阶段:架构切换到 NewAPI(11:20)

第三阶段:阈值规则 + 判定逻辑重写(11:27 - 11:32)

第四阶段:401 异常排查 + 历史代码清理(11:34)

每一步都是新东西,但每一步都跟前面的版本有关联。这就是甲方需求最让人崩溃的地方——它不是线性的,是网状的。

我几条想记下来:

第一,”任意一个”是判定逻辑里最容易踩的词。 “任意一个限额达到 90%” vs “总用量达到 90%” 是两种完全不同的算法。第一种要遍历子项取 max,第二种只看一个数。下次接到这种需求,我会立刻反问:”你说的 90% 是看子项最大值还是总用量?”

第二,”刷新失败保留缓存”是一个看似简单但实现很复杂的需求。 它要求前端维护”当前显示数据”和”上次成功数据”两个状态,并且要根据”本次刷新是否成功”决定用哪个。表面上是一行 CSS 变灰,背后是一个状态机。

第三,架构切换一定会带出历史包袱。 今天从”直连官方”切到”走 NewAPI”,原以为只是改一个 URL,结果发现前端代码里有一段”如果 NewAPI 失败就 fallback 调官方”的兜底逻辑。这段逻辑在切换之后变成了噪声,但老板不说你根本不会想到它存在。

第四,401 这种”凭证错误”是最容易让人怀疑人生的错误。 它不像 500 那样告诉你”代码错了”,而是告诉你”你的请求被服务端认为无效”。这种时候最容易在鉴权、token、session、cookie 上反复试错。最佳实践是:先确认鉴权链路,再确认请求格式,最后才怀疑服务端。

写在最后

今天最戏剧性的,不是十一版需求,也不是 401 异常。

戏剧性的是:昨天我刚发了一篇日记吐槽”被改到第七版”,今天又被打脸打到第十一版。

这让我想起一句话:打工人的日记,最后总会变成自己的回旋镖。

但说真的,比起昨天,今天的状态其实还不错。原因有两个:

第一,今天的需求虽然更多,但每一条都说得清楚。”加异常处理”、”切 NewAPI”、”改阈值规则”——每一条都是具体动作,不是”再优化一下”那种灵魂指令。

第二,今天的 401 异常排查虽然花了二十分钟,但最后定位很准——是 fallback 逻辑没切干净,不是 NewAPI 本身的问题。这种”清晰可定位的 bug”,比”看着像 bug 但不知道为什么”舒服太多。

打工人的成长曲线,不是”问题越来越少”,而是”同样的问题定位越来越快”。

希望明天的十二版需求不要再加。也希望下次再写”任意一个”需求时,我能立刻反问一句——“你说的’任意一个’是子项最大值还是总数?”


作者:小六,一个在上海打工、把 Codex 用量看板迭代到第十一版的普通打工人

Author:Margrop
Link:http://blog.margrop.com/post/2026-07-16-codex-usage-dashboard-eleven-fixes/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可