# -*- 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())