ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

国内大模型API定价模型开源:统一建模与成本计算

国内大模型API定价模型开源:统一建模与成本计算 1. 这个开源目录到底解决了什么问题国内大模型 API 的价格说实话是我见过最混乱的定价体系之一。同一个模型不同渠道价格能差出好几倍同一个平台输入和输出分开计价缓存命中与否又是另一个价有的按 token 计费有的按字符有的干脆按调用次数。你要是手上同时跑着三四个模型的业务月底对账的时候大概率会怀疑人生。我做这个开源目录的起因特别朴素当时在给一个内部工具做模型选型需要横向对比 DeepSeek、通义、智谱、Kimi、豆包这几家的 API 成本。结果我花了整整一个下午开了十几个浏览器标签页把各家的定价文档翻了个遍还发现有些页面的价格已经过期了官方公告里改了但文档没同步。更离谱的是DeepSeek 有个错峰折扣机制夜间时段价格直接砍半甚至更多这个规则藏在文档的一个角落里用文字描述没有任何现成的计算工具。所以我就想干脆自己做一个结构化的目录把所有国内主流大模型 API 的定价信息统一建模做成可查询、可对比、可计算的形式。这就是这个开源项目的由来。它不是一个简单的价格表格而是一套定价模型——把每家厂商的计费规则抽象成统一的字段包括输入单价、输出单价、缓存命中单价、缓存写入单价、阶梯定价、时段折扣、免费额度等等。你输入一段文本的 token 量它就能算出在不同厂商、不同时段下的实际成本。这个目录适合谁用如果你是个人开发者想找个便宜的 API 跑自己的小项目它能帮你快速找到性价比最高的选项。如果你是团队的技术负责人需要做成本预算和模型选型它能给你提供结构化的对比数据。如果你只是好奇国内大模型 API 到底什么价位它也能让你一目了然。代码完全开源数据可以自己更新不依赖任何第三方服务。2. 定价模型的抽象设计思路2.1 为什么不能只做一个价格表格最开始我确实只想做一个 Markdown 表格把各家的价格列出来就完事了。但真正动手之后发现表格根本表达不了这些定价规则的复杂度。举几个例子你就明白了。DeepSeek 的定价是分时段的。它的标准时段和优惠时段价格不同优惠时段的折扣力度相当大。这意味着同一个 API 调用凌晨两点和下午两点的成本可能差一倍以上。如果你只做一个静态表格写一个输入 1 元/百万 token那这个数字在优惠时段就是错的。再比如缓存机制。DeepSeek 和部分厂商支持上下文缓存缓存命中的 token 价格远低于未命中的。但缓存有写入成本而且缓存有有效期。这就意味着一个高频调用的场景和一个低频调用的场景实际成本结构完全不同。表格里写一个单价根本反映不了这种差异。还有阶梯定价。有些厂商的定价是按用量分档的月调用量越大单价越低。这种规则用表格表达也很别扭因为你得列好几行读者还得自己去判断自己落在哪一档。所以我的结论是必须把定价规则抽象成数据模型而不是静态文本。只有这样才能做到可计算、可对比、可更新。2.2 统一字段的设计我把每家厂商的定价规则抽象成了这样一组核心字段字段名含义是否必填provider厂商名称是model模型名称是input_price输入单价元/百万 token是output_price输出单价元/百万 token是cache_hit_price缓存命中单价否cache_write_price缓存写入单价否currency货币单位是tier_rules阶梯定价规则否time_rules时段折扣规则否free_quota免费额度否context_window上下文窗口大小否notes备注否这套字段的设计逻辑是能结构化的绝不写成文字不能结构化的才放进 notes。比如 DeepSeek 的时段折扣我用 time_rules 字段存一个数组每个元素包含起始时间、结束时间和折扣系数。这样计算的时候直接遍历数组就行不需要人去读文字描述。阶梯定价用 tier_rules 存每个元素包含用量下限、用量上限和对应单价。免费额度用 free_quota 存包含额度类型token 数还是调用次数、额度大小和有效期。这里有个设计上的取舍我没有把是否支持流式输出是否支持函数调用这类功能特性放进定价模型。原因是这些特性影响的是能不能用而不是花多少钱。把它们混在一起会让模型变得臃肿。功能特性我单独维护了一个 capabilities 字段和定价解耦。2.3 为什么选择 YAML 而不是数据库数据存储格式我选了 YAML而不是 SQLite 或者 JSON。原因有几个。第一YAML 对人友好。这个项目的核心价值在于数据本身我希望任何人都能直接打开文件、修改数据、提交 PR。YAML 的可读性比 JSON 好很多不需要处理引号和转义。第二YAML 支持注释。定价规则经常有特殊情况需要说明比如此价格仅适用于新用户首月之类的。JSON 不支持注释只能塞进字段里很别扭。第三YAML 的解析库在各语言里都很成熟。Python 有 PyYAMLJavaScript 有 js-yamlGo 有 gopkg.in/yaml.v3。不管你想用什么语言来消费这份数据都不会有障碍。第四不需要数据库的查询能力。这个数据集规模很小几十个模型、几百条记录全量加载到内存里做计算完全没问题。引入数据库反而增加了部署复杂度。数据结构大概长这样- provider: DeepSeek model: deepseek-chat input_price: 2.0 output_price: 8.0 cache_hit_price: 0.5 cache_write_price: 2.0 currency: CNY context_window: 65536 time_rules: - start: 00:30 end: 08:30 discount: 0.5 label: 夜间优惠 notes: 价格单位为元/百万token夜间时段输入输出均五折这种结构一眼就能看懂改起来也方便。你新增一个模型复制一段改改就行不需要理解任何 schema。3. 核心计算逻辑与实操要点3.1 单次调用成本的计算计算单次调用成本看起来简单其实有几个坑。最基础的公式是cost (input_tokens / 1_000_000) * input_price (output_tokens / 1_000_000) * output_price但实际场景里input_tokens 往往包含缓存命中的部分和未命中的部分。如果模型支持缓存那么cost (cache_hit_tokens / 1_000_000) * cache_hit_price (cache_miss_tokens / 1_000_000) * input_price (output_tokens / 1_000_000) * output_price这里有个容易忽略的点缓存写入本身是有成本的。当你第一次发送一段长文本时这段文本会被写入缓存写入价格通常等于或略高于普通输入价格。只有后续命中缓存时才享受低价。所以如果你的场景是同一段长文本只发一次那缓存对你没有任何成本优势反而可能更贵。我在计算器里做了一个开关让你可以选择是否启用缓存以及缓存命中率。如果你不确定自己的缓存命中率可以先用 0% 和 100% 各算一遍看看成本区间。3.2 时段折扣的处理DeepSeek 的时段折扣是我见过最实用的定价机制之一。它的逻辑是在指定的时间窗口内API 调用享受折扣价。这个机制对批处理任务特别友好——你完全可以把非实时的任务攒到夜间跑成本直接砍半。但处理时段折扣有几个细节要注意。第一时区问题。官方文档里写的时间通常是北京时间但你的服务器可能跑在 UTC 时区。如果你直接用服务器本地时间来判断是否在优惠时段很可能会算错。我在代码里统一用北京时间UTC8来判断避免这个问题。第二跨天的时间窗口。比如优惠时段是 00:30 到 08:30这个好处理。但如果某个厂商的优惠时段是 23:00 到次日 07:00那就跨天了判断逻辑要特殊处理。我的做法是把时间窗口统一转换成从当天 00:00 开始的分钟数区间跨天的窗口拆成两段。第三折扣的叠加。有些厂商的折扣是乘性的有些是加性的。比如夜间五折和新用户九折能不能叠加大部分情况下不能但规则不明确的时候我倾向于按最保守的方式计算即不叠加并在 notes 里注明。计算时段折扣的代码逻辑大概是这样from datetime import datetime, time import pytz def get_discount(provider_rule, check_timeNone): tz pytz.timezone(Asia/Shanghai) now check_time or datetime.now(tz) current_minutes now.hour * 60 now.minute for rule in provider_rule.get(time_rules, []): start_h, start_m map(int, rule[start].split(:)) end_h, end_m map(int, rule[end].split(:)) start_min start_h * 60 start_m end_min end_h * 60 end_m if start_min end_min: if start_min current_minutes end_min: return rule[discount] else: # 跨天窗口 if current_minutes start_min or current_minutes end_min: return rule[discount] return 1.0这段代码的关键在于跨天窗口的处理。如果 start_min 大于 end_min说明窗口跨天了判断条件就变成当前时间大于起始时间 或 小于结束时间。3.3 阶梯定价的累进计算阶梯定价比时段折扣更复杂因为它是累进的。假设某厂商的定价规则是月用量 0 到 100 万 token输入 2 元/百万月用量 100 万到 500 万 token输入 1.5 元/百万月用量 500 万以上输入 1 元/百万如果你这个月用了 300 万 token那前 100 万按 2 元算后 200 万按 1.5 元算总成本是 2 3 5 元。而不是简单地把 300 万乘以 1.5。这种累进计算在代码里需要遍历所有档位逐段累加def calc_tiered_cost(tokens, tiers): total 0 remaining tokens for tier in sorted(tiers, keylambda x: x[min]): if remaining 0: break tier_min tier[min] tier_max tier.get(max, float(inf)) tier_size tier_max - tier_min used min(remaining, tier_size) total (used / 1_000_000) * tier[price] remaining - used return total实操心得很多厂商的阶梯定价是按自然月累计用量来算的而不是按单次调用。这意味着你的成本会随着月用量增加而边际递减。如果你在做成本预估一定要把整个月的预期用量代入计算而不是只算单次调用。3.4 免费额度的抵扣逻辑免费额度的处理也有讲究。大部分厂商的免费额度是一次性赠送比如新用户送 500 万 token用完就没了。但也有厂商是每月重置比如每月送 100 万 token。在计算器里我把免费额度分成两类一次性额度只在首次使用时抵扣抵扣完就归零周期性额度每个周期通常是月重置可以持续抵扣抵扣的顺序也有讲究。通常免费额度会优先抵扣输入 token然后再抵扣输出 token。但也有厂商是反过来的。这个细节在文档里往往写得不清楚我一般按先抵扣输入来处理并在 notes 里注明。还有一个容易忽略的点免费额度通常不适用于所有模型。有些厂商的免费额度只能用于特定模型比如只能用于小参数量的模型不能用于旗舰模型。这个限制我在数据结构里用applicable_models字段来标记。4. 实操过程与核心环节实现4.1 数据采集与校验数据采集是整个项目里最耗时的环节。我的流程是这样的第一步打开每家厂商的官方定价页面把价格信息复制下来。这一步没什么技术含量但要注意页面的更新时间。有些厂商的定价页面会标注最后更新于 XXXX 年 XX 月如果这个日期太久远我会去翻官方公告确认是否有变动。第二步把采集到的数据填入 YAML 文件。这一步要特别注意单位统一。有的厂商写元/千 token有的写元/百万 token有的写分/千 token。我统一换算成元/百万 token因为这是最常用的单位。第三步写一个校验脚本检查数据的完整性和合理性。校验规则包括所有必填字段不能为空价格必须为正数缓存命中价格不能高于普通输入价格否则缓存就没意义了时段折扣系数必须在 0 到 1 之间阶梯定价的档位必须连续不能有缺口def validate_entry(entry): errors [] required [provider, model, input_price, output_price, currency] for field in required: if field not in entry or entry[field] is None: errors.append(f缺少必填字段: {field}) if entry.get(input_price, 0) 0: errors.append(输入价格必须为正数) if entry.get(output_price, 0) 0: errors.append(输出价格必须为正数) cache_hit entry.get(cache_hit_price) if cache_hit is not None and cache_hit entry[input_price]: errors.append(缓存命中价格不应高于普通输入价格) for rule in entry.get(time_rules, []): if not (0 rule.get(discount, 1) 1): errors.append(f折扣系数异常: {rule.get(discount)}) return errors第四步人工复核。校验脚本只能查格式错误查不了逻辑错误。比如某个厂商的价格我抄错了脚本是发现不了的。所以我会定期大概每月一次重新核对一遍所有数据确保没有过期或错误的信息。4.2 计算器的实现计算器的核心逻辑不复杂就是把前面说的几个计算模块串起来。我把它做成了一个命令行工具输入参数输出成本对比。使用方式大概是这样python calc.py --input-tokens 10000 --output-tokens 2000 --models deepseek-chat,qwen-max,glm-4输出结果是一个表格列出每个模型在当前参数下的成本模型 输入成本 输出成本 总成本 备注 deepseek-chat 0.0200 0.0160 0.0360 夜间五折 qwen-max 0.0400 0.0240 0.0640 - glm-4 0.0300 0.0300 0.0600 -如果你想算整个月的成本可以加上--monthly参数并指定月调用次数python calc.py --input-tokens 10000 --output-tokens 2000 --calls-per-month 5000 --models deepseek-chat这时候计算器会自动应用阶梯定价和免费额度给出月度总成本。实操心得在对比不同模型时不要只看单价要看完成同一个任务的总成本。有些模型单价便宜但输出质量差你需要多次重试才能得到满意结果实际成本反而更高。我在计算器里加了一个--retry-factor参数让你可以模拟重试带来的额外成本。4.3 数据更新流程定价数据是会变的。厂商调价、新增模型、修改折扣规则这些都会让数据过期。所以我设计了一套更新流程让任何人都能参与维护。流程是这样的发现价格变动后Fork 项目仓库修改对应的 YAML 文件运行校验脚本确保数据格式正确提交 PR在描述里附上官方定价页面的链接和截图我或者维护者审核后合并为了降低参与门槛我写了一个update_helper.py脚本它会引导你一步步填写数据python update_helper.py --provider DeepSeek --model deepseek-chat脚本会依次问你输入价格、输出价格、缓存价格等信息然后自动生成 YAML 片段你只需要复制粘贴到文件里就行。4.4 自动化监控手动更新毕竟有延迟。为了更快地发现价格变动我加了一个简单的监控脚本定期抓取各厂商的定价页面对比内容是否有变化。如果有变化就发一个提醒。这个脚本的实现思路是把定价页面的正文内容提取出来算一个哈希值存到本地。下次抓取时对比哈希值如果不一样说明页面有更新需要人工确认。import hashlib import requests from bs4 import BeautifulSoup def get_page_hash(url): resp requests.get(url, timeout30) soup BeautifulSoup(resp.text, html.parser) # 只提取正文内容去掉导航栏、页脚等噪音 content soup.find(main) or soup.find(article) or soup.body text content.get_text(stripTrue) return hashlib.sha256(text.encode()).hexdigest()这个方案不完美因为页面上的动态内容比如访问计数、时间戳会导致哈希值频繁变化。我的做法是加一个白名单把已知的动态元素排除掉。但即便如此还是会有误报。所以这个监控只作为提醒不作为自动更新的依据。5. 常见问题与排查技巧实录5.1 价格对不上怎么办这是最常见的问题。你按目录里的价格算出来一个数实际账单却是另一个数。原因通常有这几个原因一单位理解错误。有些厂商的定价页面写的是元/千 token但你在计算时当成了元/百万 token。这个错误会导致成本差 1000 倍。我的建议是在录入数据时把原始页面的单位也记下来放在 notes 里方便日后核对。原因二缓存命中率估计不准。如果你在计算时假设了 50% 的缓存命中率但实际只有 20%那算出来的成本就会偏低。缓存命中率取决于你的业务场景很难准确预估。我的做法是先用 0% 和 100% 各算一遍看看成本区间有多大。如果区间很宽说明缓存对你的成本影响很大需要重点关注。原因三阶梯定价的累计周期不同。有些厂商按自然月累计有些按滚动 30 天累计。这个差异会导致你在月初和月末的成本不同。如果你在跨月的时候做预算要特别注意这一点。原因四免费额度已经用完。如果你在计算时没有扣除已使用的免费额度算出来的成本会偏低。这个错误在新用户身上特别常见。排查方法很简单拿一个已知的实际账单反推单价看看和目录里的数据是否一致。如果不一致就逐项检查上面的几个原因。5.2 时段折扣没生效如果你发现夜间调用的成本没有按预期打折检查这几个点服务器时间是否正确用date命令确认一下时区是否设置正确如果你的服务器是 UTC 时区北京时间凌晨 2 点对应的是 UTC 前一天 18 点折扣规则是否适用于你使用的模型有些厂商的折扣只适用于特定模型是否在折扣时段内有些厂商的折扣时段是 00:30 到 08:30如果你在 00:15 调用是不享受折扣的注意时段折扣通常以请求发起时间为准而不是请求完成时间。如果你在折扣时段结束前 1 分钟发起了一个耗时 3 分钟的请求这个请求是否享受折扣取决于厂商的具体规则。大部分厂商按发起时间算但也有例外。5.3 数据更新后计算器报错如果你修改了 YAML 文件后计算器报错大概率是格式问题。YAML 对缩进非常敏感多一个空格少一个空格都可能导致解析失败。常见的格式错误包括用了 Tab 而不是空格缩进冒号后面没有空格字符串里包含了特殊字符但没有加引号列表项的缩进不一致排查方法是运行校验脚本python validate.py --file data/deepseek.yaml脚本会告诉你具体哪一行有问题。如果脚本也报错可以用在线 YAML 校验工具检查一下。5.4 常见问题速查表问题现象可能原因排查方法成本算出来差 1000 倍单位搞错了检查原始页面的单位标注夜间成本没打折时区或时间窗口问题确认服务器时区和折扣时段缓存没省钱缓存命中率太低或写入成本太高计算缓存写入和命中的总成本阶梯定价算错累计周期理解错误确认是按自然月还是滚动周期免费额度没抵扣额度不适用于该模型检查 applicable_models 字段YAML 解析失败缩进或格式问题运行校验脚本定位错误行5.5 几个容易踩的坑坑一把输入价格和输出价格搞反。大部分模型的输出价格比输入价格贵因为生成 token 比处理 token 更耗算力。但有些模型是反过来的或者两者相同。录入数据时一定要看清楚。坑二忽略了最小计费单位。有些厂商按 1000 token 为最小计费单位不足 1000 的部分按 1000 算。这意味着如果你每次只发 100 token实际成本是按 1000 token 算的比你预期的高 10 倍。坑三没考虑并发限制。有些低价套餐有并发限制比如最多同时 5 个请求。如果你的业务需要高并发就得升级到更贵的套餐。这个成本在单价里是看不出来的。坑四忽略了网络传输成本。如果你用的是云服务器API 调用产生的网络流量也是要花钱的。虽然这部分成本通常很小但在大规模调用时也不能忽略。坑五把限时优惠当成了永久价格。有些厂商会做限时促销价格比平时低很多。如果你按促销价做预算促销结束后成本会大幅上升。我在目录里用is_promotional字段标记这类价格提醒用户注意。6. 这个目录后续还能怎么扩展目前这个目录覆盖了国内主流的十几家厂商、几十个模型。但大模型这个领域变化太快了几乎每个月都有新模型发布、旧模型调价。所以这个项目本质上是一个持续维护的工程而不是一次性的作品。我接下来想做的几个方向第一增加更多维度的对比。除了价格还想加入延迟、吞吐量、上下文窗口、功能特性等维度的对比。这样用户在选型时能有一个更全面的视角。第二做一个 Web 界面。命令行工具对开发者友好但对非技术用户不太友好。我想做一个简单的网页版计算器让用户可以在浏览器里直接对比成本。第三接入实时汇率。有些厂商的定价是美元计价的换算成人民币会随汇率波动。如果能接入实时汇率计算会更准确。第四增加成本优化建议。比如根据你的使用场景推荐最合适的模型和调用策略。这个功能需要一些业务逻辑但我觉得很有价值。如果你对这个项目感兴趣欢迎来提 PR 或者 Issue。数据更新、功能建议、bug 反馈都欢迎。我一个人维护毕竟精力有限多一些人参与这个目录才能保持准确和及时。最后分享一个我在做这个项目过程中最大的体会大模型 API 的成本优化本质上是一个理解计费规则的游戏。同样的调用量懂规则的人可能比不懂的人少花一半的钱。缓存、时段折扣、阶梯定价、免费额度这些机制用好了成本能降很多。希望这个目录能帮你把这些规则搞清楚少花冤枉钱。
返回列表