chore(scripts): 存档MiniMax定价落库(M3分档五折/M2.7/M2.7-highspeed,不配缓存写入因子-无usage证据)与4模型下线脚本(上游下架,disabled+产品下架,幂等)
This commit is contained in:
parent
bfaa8c70c8
commit
9cb6b5abdf
170
scripts/apply_pricing_minimax_20260907.py
Normal file
170
scripts/apply_pricing_minimax_20260907.py
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""MiniMax 定价落库(2026-09-07 用户提供价目表)。
|
||||||
|
|
||||||
|
覆盖:M3(≤512k/>512k 分档,永久五折价)、M2.7、M2.7-highspeed。
|
||||||
|
不配:M2/M2.1/M2.1-highspeed/M2.5/M2.5-highspeed(价目表没有,铁律不编造);
|
||||||
|
「缓存写入2.625」因子(无运行时usage证据,历史流水为空,配了永远命中不了)。
|
||||||
|
所有 YAML 已过引擎试算(tmp_mm.py,8组用例含分档边界全过)。
|
||||||
|
幂等:方案按名复用;timing 每 ppid 单条有效行(同内容跳过/同日原地/历史拉链)。
|
||||||
|
用法:py3/bin/python tmp_mm_apply.py [--dry]
|
||||||
|
"""
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
sys.path.insert(0, '/d/pipeline/pipeline-app')
|
||||||
|
|
||||||
|
import yaml # noqa: E402
|
||||||
|
from sqlor.dbpools import DBPools # noqa: E402
|
||||||
|
from appPublic.uniqueID import getID # noqa: E402
|
||||||
|
from appPublic.jsonConfig import getConfig # noqa: E402
|
||||||
|
|
||||||
|
DRY = '--dry' in sys.argv
|
||||||
|
DOC_QUOTE = '用户提供的MiniMax按量计费价目表(2026-09-07粘贴正文)'
|
||||||
|
|
||||||
|
TOKEN_FIELDS = {
|
||||||
|
'price_factors': {'type': 'string', 'role': 'factor', 'label': '计价因子'},
|
||||||
|
'unit_prices': {'type': 'float', 'role': 'factor', 'label': '单位定价'},
|
||||||
|
'unit': {'type': 'string', 'role': 'factor', 'label': '计价单位'},
|
||||||
|
'uncache_tokens': {'type': 'int', 'role': 'factor', 'label': '非缓存输入Token',
|
||||||
|
'derived': 'prompt_tokens - prompt_tokens_details.cached_tokens'},
|
||||||
|
'cached_tokens': {'type': 'int', 'role': 'factor', 'label': '缓存Token',
|
||||||
|
'derived': 'prompt_tokens_details.cached_tokens'},
|
||||||
|
'completion_tokens': {'type': 'float', 'role': 'factor', 'label': '输出tokens'},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def token_yaml(u, c, ca):
|
||||||
|
return yaml.dump({'unit_values': {'百万': 1000000}, 'fields': TOKEN_FIELDS,
|
||||||
|
'pricings': [
|
||||||
|
{'price_factors': 'uncache_tokens', 'unit_prices': u, 'unit': '百万'},
|
||||||
|
{'price_factors': 'completion_tokens', 'unit_prices': c, 'unit': '百万'},
|
||||||
|
{'price_factors': 'cached_tokens', 'unit_prices': ca, 'unit': '百万'}]},
|
||||||
|
allow_unicode=True, sort_keys=False)
|
||||||
|
|
||||||
|
|
||||||
|
def tiered_token_yaml(tiers):
|
||||||
|
fields = dict(TOKEN_FIELDS)
|
||||||
|
fields['prompt_tokens'] = {'type': 'int', 'role': 'filter', 'label': 'prompt_tokens',
|
||||||
|
'value_mode': 'between'}
|
||||||
|
pricings = []
|
||||||
|
for fi, factor in enumerate(('uncache_tokens', 'completion_tokens', 'cached_tokens')):
|
||||||
|
filters = []
|
||||||
|
for lo, hi, u, c, ca in tiers:
|
||||||
|
op = ('0 =~= %d' % hi) if lo == 0 else ('%d ~= %d' % (lo, hi))
|
||||||
|
filters.append({'prompt_tokens': op, 'value_mode': 'between',
|
||||||
|
'unit_prices': (u, c, ca)[fi]})
|
||||||
|
pricings.append({'price_factors': factor, 'unit_prices': tiers[-1][2 + fi],
|
||||||
|
'unit': '百万', 'filters': filters})
|
||||||
|
return yaml.dump({'unit_values': {'百万': 1000000}, 'fields': fields, 'pricings': pricings},
|
||||||
|
allow_unicode=True, sort_keys=False)
|
||||||
|
|
||||||
|
|
||||||
|
PLANS = [
|
||||||
|
('MiniMax-M3 定价', tiered_token_yaml([
|
||||||
|
(0, 512000, 2.10, 8.40, 0.42),
|
||||||
|
(512000, 1000000, 4.20, 16.80, 0.84)]),
|
||||||
|
'MiniMax-M3 ≤512k输入tokens永久五折 输入2.10/输出8.40/缓存读取0.42; '
|
||||||
|
'>512k永久五折 4.20/16.80/0.84 元/百万tokens', ['MiniMax-M3']),
|
||||||
|
('MiniMax-M2.7 定价', token_yaml(2.1, 8.4, 0.42),
|
||||||
|
'MiniMax-M2.7 输入2.1/输出8.4/缓存读取0.42 元/百万tokens', ['MiniMax-M2.7']),
|
||||||
|
('MiniMax-M2.7-highspeed 定价', token_yaml(4.2, 16.8, 0.42),
|
||||||
|
'MiniMax-M2.7-highspeed 输入4.2/输出16.8/缓存读取0.42 元/百万tokens',
|
||||||
|
['MiniMax-M2.7-highspeed']),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
cfg = getConfig()
|
||||||
|
DBPools(cfg.databases)
|
||||||
|
db = DBPools()
|
||||||
|
log = []
|
||||||
|
now = time.strftime('%Y-%m-%d')
|
||||||
|
async with db.sqlorContext('pipeline') as sor:
|
||||||
|
for pname, yml, quote, model_names in PLANS:
|
||||||
|
desc = '定价出处:%s | 文档原文:%s' % (DOC_QUOTE, quote)
|
||||||
|
recs = await sor.sqlExe(
|
||||||
|
"SELECT id FROM pricing_program WHERE name=${n}$ LIMIT 1", {"n": pname})
|
||||||
|
await sor.sqlExe("COMMIT", {})
|
||||||
|
if recs:
|
||||||
|
ppid = recs[0].id
|
||||||
|
action = '复用方案'
|
||||||
|
recs2 = await sor.sqlExe(
|
||||||
|
"SELECT id, pricing_data, enabled_date FROM pricing_program_timing "
|
||||||
|
"WHERE ppid=${p}$ AND expired_date='9999-12-31' "
|
||||||
|
"ORDER BY enabled_date DESC LIMIT 1", {"p": ppid})
|
||||||
|
await sor.sqlExe("COMMIT", {})
|
||||||
|
cur = recs2[0] if recs2 else None
|
||||||
|
same = False
|
||||||
|
if cur is not None:
|
||||||
|
try:
|
||||||
|
same = (yaml.safe_load(cur.pricing_data or '{}') == yaml.safe_load(yml))
|
||||||
|
except Exception:
|
||||||
|
same = (cur.pricing_data or '') == yml
|
||||||
|
if same:
|
||||||
|
action = '复用方案+内容无变化(幂等跳过)'
|
||||||
|
elif cur is not None and str(cur.enabled_date)[:10] == now:
|
||||||
|
if not DRY:
|
||||||
|
await sor.sqlExe(
|
||||||
|
"UPDATE pricing_program_timing SET pricing_data=${y}$ WHERE id=${i}$",
|
||||||
|
{"y": yml, "i": cur.id})
|
||||||
|
await sor.sqlExe("COMMIT", {})
|
||||||
|
action = '复用方案+原地更新(同日)'
|
||||||
|
elif cur is not None:
|
||||||
|
if not DRY:
|
||||||
|
await sor.sqlExe(
|
||||||
|
"UPDATE pricing_program_timing SET expired_date=${d}$ "
|
||||||
|
"WHERE ppid=${p}$ AND expired_date='9999-12-31'",
|
||||||
|
{"d": now, "p": ppid})
|
||||||
|
await sor.C('pricing_program_timing', {
|
||||||
|
'id': getID(), 'ppid': ppid, 'name': pname, 'pricing_data': yml,
|
||||||
|
'enabled_date': now, 'expired_date': '9999-12-31'})
|
||||||
|
await sor.sqlExe("COMMIT", {})
|
||||||
|
action = '复用方案+拉链更新'
|
||||||
|
else:
|
||||||
|
if not DRY:
|
||||||
|
await sor.C('pricing_program_timing', {
|
||||||
|
'id': getID(), 'ppid': ppid, 'name': pname, 'pricing_data': yml,
|
||||||
|
'enabled_date': now, 'expired_date': '9999-12-31'})
|
||||||
|
await sor.sqlExe("COMMIT", {})
|
||||||
|
action = '复用方案+新建时序'
|
||||||
|
if not DRY:
|
||||||
|
await sor.sqlExe(
|
||||||
|
"UPDATE pricing_program SET description=${d}$ WHERE id=${i}$",
|
||||||
|
{"d": desc[:1000], "i": ppid})
|
||||||
|
await sor.sqlExe("COMMIT", {})
|
||||||
|
else:
|
||||||
|
ppid = getID()
|
||||||
|
if not DRY:
|
||||||
|
await sor.C('pricing_program', {
|
||||||
|
'id': ppid, 'name': pname, 'ownerid': '0', 'providerid': '',
|
||||||
|
'pricing_belong': '', 'description': desc[:1000], 'currency': 'CNY'})
|
||||||
|
await sor.C('pricing_program_timing', {
|
||||||
|
'id': getID(), 'ppid': ppid, 'name': pname, 'pricing_data': yml,
|
||||||
|
'enabled_date': now, 'expired_date': '9999-12-31'})
|
||||||
|
await sor.sqlExe("COMMIT", {})
|
||||||
|
action = '新建方案+时序'
|
||||||
|
for mn in model_names:
|
||||||
|
recs3 = await sor.sqlExe(
|
||||||
|
"SELECT id, COALESCE(ppid,'') AS ppid FROM llm_model "
|
||||||
|
"WHERE name=${n}$ AND status='active'", {"n": mn})
|
||||||
|
await sor.sqlExe("COMMIT", {})
|
||||||
|
if not recs3:
|
||||||
|
log.append(' ⚠ 模型 %s 未找到(active)——跳过挂载' % mn)
|
||||||
|
continue
|
||||||
|
mid = recs3[0].id
|
||||||
|
old_ppid = recs3[0].ppid or ''
|
||||||
|
if old_ppid == ppid:
|
||||||
|
log.append(' %s ppid 已正确' % mn)
|
||||||
|
continue
|
||||||
|
if not DRY:
|
||||||
|
await sor.sqlExe(
|
||||||
|
"UPDATE llm_model SET ppid=${p}$, updated_at=NOW() WHERE id=${i}$",
|
||||||
|
{"p": ppid, "i": mid})
|
||||||
|
await sor.sqlExe("COMMIT", {})
|
||||||
|
log.append(' %s: ppid %s→%s [%s]' % (mn, old_ppid or '空', ppid, action))
|
||||||
|
print(json.dumps({'dry': DRY, 'log': log}, ensure_ascii=False, indent=1))
|
||||||
|
|
||||||
|
|
||||||
|
asyncio.run(main())
|
||||||
84
scripts/retire_models_20260907.py
Normal file
84
scripts/retire_models_20260907.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""模型下线(2026-09-07 用户确认:4个模型上游已下架)。
|
||||||
|
|
||||||
|
目标模型:ali-deepseek-v4-flash / qwen3-vl-embedding / qwen3-vl-rerank /
|
||||||
|
tongyi-embedding-vision-flash
|
||||||
|
|
||||||
|
下线动作(两层):
|
||||||
|
1. llm_model.status='disabled'(停用,字典合法值 active/disabled/suspended/exhausted)
|
||||||
|
2. product.status='0'(产品映射同步下架,商城不再展示)
|
||||||
|
|
||||||
|
安全性依据(代码级核对):
|
||||||
|
- 治理链 gateway._model_chain 加载主/备/辅助模型时都带 status='active' 过滤
|
||||||
|
(gateway.py L183/L203)——备链里的停用模型会被自动顺延跳过,不会断链,
|
||||||
|
无需改 6 个组织的 backup_model_ids JSON(引擎天然过滤,改 JSON 反而有风险)
|
||||||
|
- 模型下拉(get_llm_model_options/get_llm_online_check_models/selection.model_options)
|
||||||
|
全部 WHERE status='active'——停用后自动从所有选择器消失
|
||||||
|
- 出账不受影响:停用只拦新调用,历史流水照常出账
|
||||||
|
|
||||||
|
幂等:重复执行结果一致。用法:py3/bin/python tmp_retire_models.py [--dry]
|
||||||
|
"""
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.insert(0, '/d/pipeline/pipeline-app')
|
||||||
|
|
||||||
|
from sqlor.dbpools import DBPools # noqa: E402
|
||||||
|
from appPublic.jsonConfig import getConfig # noqa: E402
|
||||||
|
|
||||||
|
DRY = '--dry' in sys.argv
|
||||||
|
TARGETS = ['ali-deepseek-v4-flash', 'qwen3-vl-embedding', 'qwen3-vl-rerank',
|
||||||
|
'tongyi-embedding-vision-flash']
|
||||||
|
NOTE_SUFFIX = '[下线:上游已下架2026-09-07]'
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
cfg = getConfig()
|
||||||
|
DBPools(cfg.databases)
|
||||||
|
db = DBPools()
|
||||||
|
log = []
|
||||||
|
async with db.sqlorContext('pipeline') as sor:
|
||||||
|
for name in TARGETS:
|
||||||
|
recs = await sor.sqlExe(
|
||||||
|
"SELECT id, status, COALESCE(description,'') AS descr FROM llm_model "
|
||||||
|
"WHERE name=${n}$ LIMIT 1", {"n": name})
|
||||||
|
await sor.sqlExe("COMMIT", {})
|
||||||
|
if not recs:
|
||||||
|
log.append('%s: 未找到(跳过)' % name)
|
||||||
|
continue
|
||||||
|
mid = recs[0].id
|
||||||
|
old_status = recs[0].status
|
||||||
|
if old_status == 'disabled':
|
||||||
|
log.append('%s: 已是 disabled(幂等跳过)' % name)
|
||||||
|
else:
|
||||||
|
descr = recs[0].descr or ''
|
||||||
|
new_descr = (descr + ' ' + NOTE_SUFFIX).strip() \
|
||||||
|
if NOTE_SUFFIX not in descr else descr
|
||||||
|
if not DRY:
|
||||||
|
await sor.sqlExe(
|
||||||
|
"UPDATE llm_model SET status='disabled', description=${d}$, "
|
||||||
|
"updated_at=NOW() WHERE id=${i}$", {"d": new_descr[:1000], "i": mid})
|
||||||
|
await sor.sqlExe("COMMIT", {})
|
||||||
|
log.append('%s: status %s→disabled(描述追加下线标注)' % (name, old_status))
|
||||||
|
# 产品同步下架
|
||||||
|
prec = await sor.sqlExe(
|
||||||
|
"SELECT id, status FROM product WHERE resource_ref_id=${r}$", {"r": mid})
|
||||||
|
await sor.sqlExe("COMMIT", {})
|
||||||
|
if prec:
|
||||||
|
p_old = prec[0].status
|
||||||
|
if p_old == '0':
|
||||||
|
log.append(' 产品: 已下架(幂等跳过)')
|
||||||
|
else:
|
||||||
|
if not DRY:
|
||||||
|
await sor.sqlExe(
|
||||||
|
"UPDATE product SET status='0', updated_at=NOW() WHERE id=${i}$",
|
||||||
|
{"i": prec[0].id})
|
||||||
|
await sor.sqlExe("COMMIT", {})
|
||||||
|
log.append(' 产品: status %s→0(商城下架)' % p_old)
|
||||||
|
else:
|
||||||
|
log.append(' 产品: 无映射行(跳过)')
|
||||||
|
print(json.dumps({'dry': DRY, 'log': log}, ensure_ascii=False, indent=1))
|
||||||
|
|
||||||
|
|
||||||
|
asyncio.run(main())
|
||||||
Loading…
x
Reference in New Issue
Block a user