首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
CodexBar 模型定价元数据管道:models.dev 缓存、查询规则与自定义定价覆盖层
📅 2026/9/13 17:33:08
✍️ 爱科研究院
👁 阅读 3,247
CodexBar 模型定价元数据管道models.dev 缓存、查询规则与自定义定价覆盖层【免费下载链接】CodexBarShow usage stats for OpenAI Codex and Claude Code, without having to login.项目地址: https://gitcode.com/GitHub_Trending/co/CodexBar导读本文深入剖析 CodexBar 的模型定价元数据管道它如何以 models.dev 作为增量定价源配合内置兜底价格表为 OpenAI Codex 与 Claude Code 的本地会话成本估算提供统一、可离线、可覆盖的价格体系。读者将掌握定价缓存的存放位置与刷新机制、provider/model 双维度的精确查询规则、USD per 1M tokens 到 per-token 的单位换算逻辑以及如何通过custom-pricing.json覆盖层精确修改某个模型在本地扫描中的计价并理解价格指纹fingerprint为何能驱动下游缓存失效。整体架构models.dev 增量定价 内置兜底价格CodexBar 的成本计算并不只依赖一份硬编码价格表。文档明确了它的核心设计以 models.dev 作为增量定价来源additive pricing source与内置兜底费率bundled fallback rates并存。models.dev 覆盖不到的模型例如刚刚发布、尚未收录的新模型回落到仓库内置的价格表一旦 models.dev 收录了该模型后续刷新即优先使用在线数据。二者的分工体现在 CostUsagePricing.swift 中内置表codex与claude两个字典以「每 token」为单位预置了一批常见模型的输入、输出、缓存读/写价格而 models.dev 查询则作为更靠前的数据层。在代码层面模型的最终解析由CostUsagePricing.resolvedCodexPricing(model:...)完成其返回结构CodexPricing同时携带阈值 token 数与超阈值价格带thresholdTokens/inputCostPerTokenAboveThreshold等说明价格解析不仅区分输入/输出还支持长上下文切换价格带见 CostUsagePricing.swift。数据源与本地缓存数据源与缓存位置定价元数据来自一个公开接口无需任何 API Key源 APIhttps://models.dev/api.json本地缓存~/Library/Caches/CodexBar/model-pricing/models-dev-v1.jsonTTL24 小时源码中这三个要素均有对应常量。ModelsDevClient默认 URL 即为该接口请求使用 GET、超时 20 秒并在收到非 2xx 状态码或 JSON 解析失败时抛出ModelsDevClient.Error见 ModelsDevPricing.swift。缓存文件的版本号与 TTL 定义在ModelsDevCache中artifactVersion 1、ttlSeconds 24 * 60 * 60缓存文件路径由cacheFileURL拼装为Caches/CodexBar/model-pricing/models-dev-v版本.json见 ModelsDevPricing.swift。缓存内容是一个带版本号和抓取时间戳的归档ModelsDevCacheArtifact结构体还保留了fetchedAt供判断过期。双入口同步 lookup 与异步 refresh管道对外暴露两个互补的入口见 ModelsDevPricing.swiftModelsDevPricingPipeline.lookup(providerID:modelID:)同步读取最近一次有效的缓存归档并返回价格查询结果供扫描器在遍历每一条 usage 记录时零延迟调用不会触发网络请求。ModelsDevPricingPipeline.refreshIfNeeded(now:cacheRoot:client:)异步检查缓存是否过期过期才发起拉取用于后台维护新鲜度。此外还有一个面向「未知模型」的入口refreshForUnknownModelsIfNeeded(providerID:modelIDs:)当某条记录的模型 ID 在现有目录中查不到价格时若距上次抓取已超过 15 分钟冷却期modelsDevCatalogRetryInterval 15 * 60则触发一次刷新并返回pricingAvailable/unavailable表示新价格是否因此可用。ModelsDevRefreshCoordinatoractor 会按缓存路径合并并发请求同一路径上的并发刷新共享同一个 in-flight Task避免 TTL 刷新与未知模型刷新重复下载失败后 15 分钟内也不会重试见 ModelsDevPricing.swift。原子写入与内存 memo 失效文档强调两处实现细节源码均有一一对应原子写入ModelsDevCache.save使用data.write(to: url, options: [.atomic])落盘见 ModelsDevPricing.swift。因此 macOS 与 Linux 上刷新已有缓存时是「先完整写入新文件再替换」不会先删除目标文件中途断电或进程被杀也不会留下半截 JSON。内存 memo 失效解码 ~800KB 目录 JSON 代价很高如果每条 usage 行都重新读取并解码会拖慢扫描。ModelsDevCacheMemo以「文件路径 mtime 文件大小」为键缓存完整的加载结果包括成功与失败两类结果避免损坏缓存反复触发昂贵的解码save成功后主动invalidate(path:)下一次load必然解码新文件见 ModelsDevPricing.swift。刷新时的数据保全策略拉取到的新目录并不会无条件替换旧缓存ModelsDevPricingPipeline.performRefresh有三层保护见 ModelsDevPricing.swift合理性校验isPlausibleRefresh要求新目录中anthropic与openai两个 provider 至少各存在一个有价格isPriceable的模型直接拒绝空响应或残缺响应见 ModelsDevPricing.swift。兜底合并mergingFallbackPricingmodels.dev 目录会随上游变动增删模型。刷新时若发现旧缓存中有价格、而新目录中已消失的模型会以codexbar-fallback:前缀的键合并进新目录保证历史模型价格不因上游删档而「失忆」见 ModelsDevPricing.swift。失败保底refreshStaleCache在刷新生效前先复查一次缓存是否已被其他并发刷新更新刷新失败时返回false旧的 last-valid 缓存依旧可读。测试ModelsDevPricingTests中network failure preserves last valid cache、refresh preserves cache when fetched catalog drops cached provider、refresh accepts model churn and preserves removed pricing as fallback等用例直接验证了上述行为见 ModelsDevPricingTests.swift。查询规则以 provider id model id 双维度精确匹配定价查询始终以provider id 与 model id 组成的二元组为作用域防止两个 provider 下同名 model 或同名显示名互相串价。ModelsDevCatalog.pricing(providerID:modelID:)先把 provider id 归一化去空白、转小写见ModelsDevProvider.normalizeProviderID再在对应 provider 的模型字典内查找查找时会对模型 ID 生成候选序列如去掉openai/前缀、把claude-xxx补成claude-xxxdefault、剥离日期快照后缀-20251001等见ModelsDevModelIDNormalizer.candidates依次精确比对字典键或模型自身normalizedID见 ModelsDevPricing.swift。测试does not fall back across providers专门验证了隔离性openai下查claude-sonnet-4-6与anthropic下查gpt-4o-mini均返回nil见 ModelsDevPricingTests.swift。Codex/OpenAI 侧的路由规则对于本地 Codex 会话扫描codexModelsDevPricingTargets(for:)负责把原始模型 ID 展开成候选(providerID, modelID)列表见 CostUsagePricing.swift裸的 Codex/OpenAI 模型 ID一律挂到 provider idopenai常量codexModelsDevProviderID见 CostUsagePricing.swift并顺带尝试normalizeCodexModel后的规范化写法例如gpt-5.6规范化为gpt-5.6-sol、gpt-reserve映射为 Luna见 CostUsagePricing.swift。带前缀的 provider 限定路由只有当路由前缀落在codexModelsDevProviderIDs白名单deepseek、kimi-coding、kimi-for-coding、openai、opencode、opencode-free、opencode-go见 CostUsagePricing.swift内才保留原路由例如deepseek/deepseek-chat仍按deepseek计kimi-coding会同时尝试kimi-for-codingopencode-free会同时尝试opencode。未知前缀不计价前缀不在白名单内的带路由 ID 返回空列表保持 unpriced绝不误并入 OpenAI 价格。Claude 侧的一手厂商路由Claude 会话日志里的模型 ID 走的是另一套「一手厂商」路由claudeModelsDevPricingTargets/claudeModelsDevLookup见 CostUsagePricing.swift可辨识的裸 Claude 会话模型族按前缀归属一手厂商目录claude-前缀归anthropicgpt-/o1/o3/o4等归openaigemini-/gemma-等归googlek3/k3[1m]归kimi-for-codingkimi-/moonshot-归moonshot含kimi-for-codingminimax-归minimaxdeepseek-归deepseek见 CostUsagePricing.swift。其他裸 ID 要求唯一命中无法辨识归属的裸 Claude-session ID会在全部一手厂商anthropic、openai、google、moonshot、kimi-for-coding、minimax、deepseek见 CostUsagePricing.swift中查找只有当恰好一个厂商命中时才计价跨厂商歧义命中保持 unpriced见 CostUsagePricing.swift。显式路由不回落带显式provider/model前缀的 Claude-session ID 只在该批准的显式路由上计价绝不回落到其他厂商。Kimi 的 k3[1m] 上下文别名Claude 会话中常见的k3[1m]是 Kimi Code 文档化的「1M 上下文」别名。CodexBar 在kimi-for-coding路由下完成精确行查找之后额外把k3[1m]追加解析为kimi-for-coding/k3见 CostUsagePricing.swift。注意细节记录中的模型名k3[1m]保持不变不会被改写只是价格解析落到k3行其他上下文变体与付费 Moonshot 路由不会被推断目录中k3的零费率只是「已知的估计值」并不代表订阅或额外用量免费——这是文档特意强调的语义边界。Vertex AI 上的 Claude 日志当 Claude 会话来自 Google Vertex AI 时对应的 models.dev provider id 为google-vertex-anthropic。测试supports provider scoped model normalization验证了google-vertex-anthropic/claude-sonnet-4-6与anthropic/claude-sonnet-4-6能各自命中正确的价格见 ModelsDevPricingTests.swift。计价单位从「每百万 token」换算到「每 token」models.dev 对外发布的价格单位是USD per 1M tokens而 CodexBar 内部成本数学使用USD per token换算在元数据层完成perToken modelsDevCost / 1_000_000源码中ModelsDevModel.pricing(providerID:providerName:)即执行该换算input / unit、output / unit其中unit 1_000_000.0缓存读cacheRead→cacheReadInputCostPerToken与缓存写cacheWrite→cacheCreationInputCostPerToken同样按此规则换算见 ModelsDevPricing.swift。超 200K 上下文价格带当 models.dev 包含cost.context_over_200k字段时CodexBar 将其解析为「超过 200K token 之后」的价格带并同样按 per-1M 规则换算。换算后的结构中thresholdTokens被置为200_000并填充inputCostPerTokenAboveThreshold、outputCostPerTokenAboveThreshold、cacheReadInputCostPerTokenAboveThreshold、cacheCreationInputCostPerTokenAboveThreshold四个超阈值字段见 ModelsDevPricing.swift。单位换算有测试覆盖converts models dev per million token prices to per token prices断言 3/1M、15/1M、0.3/1M、3.75/1M 等原始值换算后的 per-token 结果并验证thresholdTokens 200_000及超阈值字段见 ModelsDevPricingTests.swift。在成本计算阶段超阈值价格带会被真正使用codexCostUSD依据thresholdTokens判断整次请求是否进入长上下文计费claudeCostUSD则以input cacheRead cacheCreationTotal是否超过阈值来切换价格带见 CostUsagePricing.swift。值得注意的是 Codex 侧还有一个codexPriorityInputTokenLimit 272_000的优先级输入上限见 CostUsagePricing.swift与 models.dev 的 200K 阈值是两套独立机制。自定义定价覆盖层custom-pricing.json文件位置与平台差异精确匹配的「标价覆盖」存放在平台 Application Support 目录macOS: ~/Library/Application Support/CodexBar/custom-pricing.json Linux: ${XDG_DATA_HOME:-~/.local/share}/CodexBar/custom-pricing.jsonLinux CLI 走的是FileManager的 Application Support 目录即 XDG data home而不是~/.config。只把文件放到 XDG config 下会被忽略。源码中CostUsageCustomPricing.defaultFileURL正是通过AppGroupSupport.localFallbackDirectory定位该目录并拼接固定文件名custom-pricing.json见 CostUsageCustomPricing.swift。解析顺序与作用范围文件内的值一律是USD per 1M tokens。对原生 Codex 会话扫描解析顺序为overlay覆盖层 models.dev builtin内置表。测试codex cost prefers overlay over bundled list prices与aggregate fallback consults the overlay before bundled rates直接验证了覆盖层优先于内置表见 CostUsageCustomPricingTests.swift。改文件即失效文件内容以 SHA-256 生成fingerprint见 CostUsageCustomPricing.swift该指纹被拼入CostUsagePricingKey.codex(...)的定价键见 CostUsagePricingKey.swift。因此任何一次编辑保存都会使 Codex 定价指纹失效下一次原生 Codex 扫描会重新加载费率。测试overlay fingerprint invalidates the Codex pricing key验证了这一点见 CostUsageCustomPricingTests.swift。作用范围限制重要覆盖层目前只作用于原生 Codex/OpenAI 兼容会话的计价。Claude 的本地扫描器、Cursor 以及生产环境的 OpenCodex 快照加载都不读取该文件OpenCodex 侧始终持有空覆盖层。因此写入anthropic/claude-…这样的键不会改变任何 Claude 标价。键的规范与完整 JSON 示例键大小写不敏感统一 trim 小写归一化见CostUsageCustomPricing.normalizeKey。键可以是裸模型 IDgpt-5.4也可以是provider/modelopenai/gpt-5.4。只有精确归一化后的键能匹配不存在前缀或家族通配。同一模型两种写法并存时裸键优先provider 限定行被忽略。除非你就是想让裸键覆盖生效否则不要同时定义两行。{ gpt-5.4: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 }, openai/gpt-5.4-mini: { input: 0, output: 0 } }查询时先查裸键、再查provider/model复合键的顺序在rates(providerID:model:)中实现见 CostUsageCustomPricing.swift。字段规则0表示该 token 类别免费不是未知。测试overlay exact match uses per-million rates and treats zero as free验证了输入 0 费率参与求和时按 0 计算见 CostUsageCustomPricingTests.swift。缺字段保持未知CodexBar 不会用 models.dev 或内置表去填补缺失字段。因此一个只写了input的局部覆盖行整体是「未定价」而不是「覆盖层与目录混合价」。测试missing overlay fields stay unknown instead of falling through与matching partial overlay stays unknown instead of using bundled list prices双双验证见 CostUsageCustomPricingTests.swift。负数与非有限数被忽略rate(_:)只接受有限且 0的数字0是合法免费值见 CostUsageCustomPricing.swift。缓存字段接受替代拼写cache_read、cache_write、cacheCreation、cache_creation见 CostUsageCustomPricing.swift。测试隔离测试进程通过XCTestConfigurationFilePath、.xctest后缀等环境/进程特征识别永远不读开发者 Application Support 目录中的真实覆盖文件load直接返回空覆盖层测试只使用 fixtures 或空覆盖层见 CostUsageCustomPricing.swift。测试保障行为可验证定价管道的行为在仓库中有系统性测试覆盖是排查问题时的第一手参照ModelsDevPricingTests.swift覆盖 models.dev 子集解析、按 provider/model 查询、跨 provider 不回落、per-1M 到 per-token 换算、过期缓存仍可读、网络失败保底、部分目录不覆盖、未知模型刷新与冷却、TTL 与未知模型刷新合并单次下载等。CostUsageCustomPricingTests.swift覆盖零费率、缺字段保持未知、覆盖层优先于内置表、指纹失效定价键、聚合路径同样优先覆盖层等。这两份测试文件完整刻画了本文所述每一条规则的预期行为无论是自行接入该管道还是排查「为什么这个模型没有价格」都可以从中找到对应断言。结语三层价格体系的协作方式至此可以完整概括 CodexBar 的定价元数据体系custom-pricing 覆盖层用户精确覆盖→ models.dev 目录在线增量、24h TTL 缓存、失败保底、合并兜底→ 内置价格表离线最后防线。三层之间通过 provider id model id 精确作用域隔离通过 SHA-256 指纹串联缓存失效通过单元测试锁定每一条规则。理解这套管道后无论是调试「某模型价格不更新」、排查「为什么某条记录未定价」还是为自己的私有模型添加本地标价都能快速定位到对应的源码位置与测试用例。【免费下载链接】CodexBarShow usage stats for OpenAI Codex and Claude Code, without having to login.项目地址: https://gitcode.com/GitHub_Trending/co/CodexBar创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/9/13 17:33:08
CAN自定义协议设计的五大核心维度与工程实践
2026/9/13 17:33:08
notebooklm-py 工件生成结果的密封类型设计:GenerationStatus 角色分区、迁移路径与推迟决策(ADR-0020 深度解析)
2026/9/13 17:33:08
Renovate 的 GitLab CI/CD 管理器:从 gitlab-ci.yml 提取 Docker 依赖与 registryAliases 配置指南
2026/9/13 17:58:09
Easy-Vibe 开源课程深度解析:从“说出想法“到“发布产品“的 AI 编程实战指南
2026/9/13 17:58:09
VictoriaMetrics 开源仓库导读:单机与集群架构、多协议摄入与构建发布的源码级剖析
2026/9/13 17:58:09
Teable 开发模式修改后端代码不生效、3000 端口被占用怎么排查?
2026/9/13 17:58:09
amis Page 页面组件完全指南:顶级容器、数据初始化与事件动作实战
2026/9/13 17:58:09
深入解析 lo.CountValues:用 Go 泛型统计切片元素频次的完整指南
2026/9/13 17:53:09
OpenClaw 会话转录卫生(Transcript Hygiene):Provider 重放前的内存级清理、配对修复与签名处理机制全解
2026/9/13 0:01:25
拯救者Y7000黑屏故障排查与维修实战指南
2026/9/13 0:01:25
AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验
2026/9/13 0:01:25
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化
2026/9/13 0:01:25
拯救者Y7000黑屏故障排查与维修实战指南
2026/9/13 0:01:25
AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验
2026/9/13 0:01:25
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化