name: qjudge-ai-model-registry description: 新增 / 更新 / 下架 AI 模型(ai-service + backend + frontend 全域)的操作 skill。涵蓋 canonical id、provider string、pricing、token 限制、預設值、migration、tests 與前端 fallback / 預設的一次性落點。
QJudge AI Model Registry Owner
Quick start
- 決定操作類型:ADD / UPDATE(pricing、context、display)/ REMOVE。
- 對照
references/touch-points.md全部 touch point 逐一檢查。 - 依
references/cost-math.md驗算 credits / USD。 - 驗證:pricing contract test、ai-service 端對端 smoke、前端 tsc、migration 套用。
責任邊界(Owner Scope)
- ✅ Canonical model id(
openai-nano/deepseek-v4等)。 - ✅
ai-service/services/model_factory.py所有 lookup table(_MODEL_MAP、PRICING、MODEL_MAX_INPUT_TOKENS、MODEL_SUMMARY_TRIM_TOKENS、MODEL_INFO)。 - ✅
backend/apps/ai/credits.py::DEFAULT_MODEL_PRICING(與 ai-servicePRICING有 CI contract test 把關)。 - ✅ Backend
serializers.StartRunSerializerchoices、ModelListView.MODELS、models.py預設、對應 Django migration。 - ✅ Frontend
FALLBACK_MODELS、grading 預設、stories、ModelSelect label。 - ✅ 更動預設模型時的 deepagent_runner 介面
model_id=預設。 - ❌ 不負責 credits 換算公式(
usage_to_credits)本身;只負責 pricing 餵料。 - ❌ 不負責 provider SDK 整合細節(
ChatOpenAI/ChatDeepSeek初始化選項只動該 model 專用欄位)。 - ❌ 不負責 UI 視覺(交
qjudge-ui-carbon-owner);只動MODEL_INFO.display_name/description。
核心規則
- Canonical id 是前後端與 SDK 邊界的唯一識別;provider model string 只出現在
_MODEL_MAP一個地方,其他檔案一律用 canonical id。 ai-service::PRICING與backend::DEFAULT_MODEL_PRICING永遠一致,由backend/apps/ai/tests/test_pricing_alignment.pyAST 比對。兩邊要同一次 commit 改完。- Pricing 單位:cents per 1M tokens(亦即 USD/1M × 100)。cache-hit input 目前未在 PRICING 表中追蹤(僅以 cache-miss 結算)。
- 變更
backend/apps/ai/models.py的default=字串 必須跟一支 Django migration。 - 新模型顯示名稱:以 canonical id 為底(例:
deepseek-v4、gpt-5-nano);後端MODEL_INFO/ModelListView.MODELS與前端FALLBACK_MODELS三份 metadata 欄位一字不差(model_id/display_name/description/is_default)。 - Frontend
ModelSelect.normalizeModelLabel會 trim 並 fallback 到gpt-5-nano,不會修改 display_name。要在 label 直接顯示 thinking / variant(例:deepseek-v4 (thinking))是預期做法。 - DeepSeek V4 thinking mode 與多輪對話的接法:thinking ON 時 API 要求每輪 assistant 訊息都把上一輪的
reasoning_content回傳,LangChain 的AIMessage序列化預設會丟掉。解法已內建在model_factory.py::ReasoningPreservingChatDeepSeek:覆寫_get_request_payload在送出前從additional_kwargs["reasoning_content"]讀回並填入對應的 assistant message dict。新增需 thinking 的 DeepSeek 模型(例如deepseek-v4-pro)時必須使用該子類別;純聊天模型用原生ChatDeepSeek並以extra_body={"thinking": {"type": "disabled"}}關閉即可。
操作流程
ADD 新模型
按 references/touch-points.md 的「ADD」欄逐項補齊,最後跑 references/verify.sh 的四個驗證。
UPDATE 既有模型
只有 pricing / context / display 變動時:
ai-service::PRICING+backend::DEFAULT_MODEL_PRICING同步更新。- 若 context 改變:
MODEL_MAX_INPUT_TOKENS、必要時MODEL_SUMMARY_TRIM_TOKENS。 MODEL_INFO/ModelListView.MODELS/FALLBACK_MODELS三份 metadata 同步。- Pricing 變動必跑
apps/ai/tests/test_pricing_alignment.py與apps/ai/tests/test_credits.py;credits 預期值可能需要重算。 - 不需要 migration(field default 字串沒變)。
REMOVE / 下架模型
- 先決定 「誰要取代它」 作為預設 fallback:
- 原本是 system default(
_DEFAULT_MODEL_ID、models.py::default=、deepagent_runner3 個介面的model_id=預設)—改指向取代者並寫 migration。 - 原本是 grading 預設(
AI_GRADING_DEFAULT_MODEL_ID)—改指向合理的推理模型。 - 歷史 session 若 DB 中有
model_id="<舊>"row,讀回時會 fallback 到_DEFAULT_MODEL_ID(ModelFactory.resolve_model_string含 warning log),不會壞;若要優雅 alias,在_MODEL_MAP加一行"<舊>": "<新 provider string>"當相容層。
- 原本是 system default(
- 從所有 touch point 移除 entry(見
references/touch-points.md的「REMOVE」欄)。 - 相關 tests 裡硬編的
model_id="<舊>"要換成 仍存在的模型 id,並重算 credits 期望值。 - 跑
references/verify.sh。
驗證清單(照序)
backend pytest apps/ai/tests/test_credits.py test_model_contract.py test_pricing_alignment.py— pricing 契約與 credits 數學。ai-service pytest tests/test_model_factory.py(isolated run,避免 stub 污染)— 每個 canonical id 的創建 kwargs。ai-service pytest tests/test_api.py—/api/models端點回傳順序與欄位。frontend tsc --noEmit— 前端 types。- 真實 API smoke(ADD 或 provider 變動時必跑):
bash .codex/skills/qjudge-env-compose-owner/scripts/qjudge-dc.sh dev exec -T ai-service \ python -c " import asyncio from services.model_factory import ModelFactory m = ModelFactory.create_model('<new-canonical-id>') asyncio.run(m.ainvoke('Reply only: OK')) " - 若動過
backend/apps/ai/models.py::default=:bash .codex/skills/qjudge-env-compose-owner/scripts/qjudge-dc.sh dev exec -T backend \ python manage.py makemigrations ai --name="<desc>" && \ python manage.py migrate ai
參考
references/touch-points.md— 每個檔案、每個 symbol 的欄位對照表(ADD/UPDATE/REMOVE 三欄)。references/cost-math.md— credits 計算公式、典型輪次對照、常見 pricing table。