From e5902a4fd490451c05ec1537e310e8f79c9a4c0c Mon Sep 17 00:00:00 2001 From: yumoqing Date: Tue, 8 Sep 2026 13:58:50 +0800 Subject: [PATCH] =?UTF-8?q?feat(platform):=20apply=5Fllm=5Fconfig=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E4=BA=A7=E5=93=81=E6=98=A0=E5=B0=84(2026-09-08?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E9=9C=80=E6=B1=82:=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E6=97=B6=E5=A6=82=E6=9C=89=E4=BA=A7=E5=93=81?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E8=87=AA=E5=8A=A8=E6=98=A0=E5=B0=84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根治记账failed"模型未映射到产品"不靠人工事后补: - _sync_model_products:apply落库后调env.import_categories_and_products (resource_module=pipeline_llm)增量导入所有active模型为产品(幂等:已映射按 resource_ref_id+org_id跳过,顺带自愈其他漏映射模型) - 父类别复用已有pipeline_llm根类别"大模型消费"(防类别树分裂) - 产品模块未装→跳过不阻断(模型注册已成功,映射是下游增值步骤);失败如实记 product_mapping.note - check_model_accounting hint与工作流prompt同步:未映射→重跑apply触发自动映射 --- pipeline_platform/platform_ability.py | 68 ++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/pipeline_platform/platform_ability.py b/pipeline_platform/platform_ability.py index d806140..f47cf35 100644 --- a/pipeline_platform/platform_ability.py +++ b/pipeline_platform/platform_ability.py @@ -735,6 +735,61 @@ async def _write_model_skill(sor, vmid, m, spec, profile_ids): logger.info("模型配套技能已写入: %s", path) +# pipeline_llm 产品类别根名(首次自动建;已存在则复用,防类别树分裂) +_LLM_PRODUCT_ROOT_NAME = "大模型消费" +_LLM_ROOT_CAT_ID = "7S4za5hOEJqBGXb2f-NmK" # 现有根类别 id(实测),新建时兜底用它 + + +async def _sync_model_products(sor, org_id="0"): + """模型上线后自动产品映射(2026-09-08 用户需求:添加模型时如有产品模块自动映射)。 + + 根治记账 failed「模型未映射到产品」:apply 落库模型后,调产品模块的 + import_categories_and_products(resource_module='pipeline_llm') 增量导入 + 所有 active 模型为产品(幂等:已映射的按 resource_ref_id+org_id 跳过, + 顺带自愈其他漏映射模型)。 + + 产品模块未装(env 无 import_categories_and_products)→ 返回跳过说明, + 不阻断 apply(模型注册本身已成功,产品映射是下游增值步骤)。 + 返回 (ok, note)。 + """ + from ahserver.serverenv import ServerEnv + env = ServerEnv() + import_fn = getattr(env, "import_categories_and_products", None) + if not callable(import_fn): + return True, "产品模块(product_management)未加载,跳过自动产品映射(模型已注册成功,可后续在产品管理手动导入产线模型)" + + # 定父类别:复用已有 pipeline_llm 根类别(防类别树分裂);没有则新建根 + parent_cat = _LLM_ROOT_CAT_ID + try: + recs = await sor.sqlExe( + "SELECT id FROM product_category WHERE resource_module='pipeline_llm' " + "AND parent_id IS NULL AND org_id=${o}$ LIMIT 1", {"o": org_id}) + await sor.sqlExe("COMMIT", {}) + if recs: + parent_cat = getattr(recs[0], "id", "") or _LLM_ROOT_CAT_ID + else: + # 查名字兜底(parent_id 可能存 '0' 而非 NULL) + recs2 = await sor.sqlExe( + "SELECT id FROM product_category WHERE name=${n}$ AND org_id=${o}$ LIMIT 1", + {"n": _LLM_PRODUCT_ROOT_NAME, "o": org_id}) + await sor.sqlExe("COMMIT", {}) + if recs2: + parent_cat = getattr(recs2[0], "id", "") or _LLM_ROOT_CAT_ID + except Exception as e: + logger.warning("_sync_model_products 父类别解析失败(用默认根): %s", e) + + try: + result = await import_fn( + resource_module="pipeline_llm", org_id=org_id, + parent_category_id=parent_cat, user_id="system") + except Exception as e: + return False, "自动产品映射调用失败(模型已注册,请手动在产品管理导入产线模型):%s" % repr(e)[:150] + if not result or not result.get("success"): + err = (result or {}).get("error", "导入无返回") if isinstance(result, dict) else "导入无返回" + return False, "自动产品映射未成功(模型已注册,请手动导入):%s" % str(err)[:150] + return True, "自动产品映射完成:%s" % str((result or {}).get("message", ""))[:150] + + async def _h_apply_llm_config(sor, params, ctx): """按提取的规格写库:供应商(复用/新建)+ 适配模板 + 模型。 @@ -1123,6 +1178,10 @@ async def _h_apply_llm_config(sor, params, ctx): except Exception as e: skill_notes.append("%s: 配套技能生成失败(%s)——完备性判断将按能力语义降级" % (vmid, str(e)[:80])) + # 6. 自动产品映射(2026-09-08 用户需求:添加模型时如有产品模块自动做产品映射)。 + # 根治记账 failed「模型未映射到产品」——不靠人工事后补。产品模块未装则 + # 跳过不阻断(模型注册已成功);映射幂等(已映射跳过+自愈其他漏映射模型)。 + prod_ok, prod_note = await _sync_model_products(sor, org_id="0") return json.dumps({ "vendor": vendor_action, "profiles": profile_ids, "models_created": created, "models_updated": updated, "models_skipped": skipped, @@ -1131,6 +1190,7 @@ async def _h_apply_llm_config(sor, params, ctx): "template_notes": tpl_notes, "account_notes": account_notes, "skill_notes": skill_notes, + "product_mapping": {"ok": prod_ok, "note": prod_note}, "runtime_note": rt_note, "media_audit": audit_note, }, ensure_ascii=False) @@ -2385,7 +2445,9 @@ async def _h_check_model_accounting(sor, params, ctx): item["verdict"] = "记账失败" item["reason"] = (row.get("note") or "")[:200] item["hint"] = ("常见处置:模型未挂ppid→apply_model_pricing;" - "模型未映射产品→产品管理导入产线模型;" + "模型未映射产品→apply_llm_config 已自动映射(2026-09-08)," + "仍报未映射说明自动映射失败(看 apply 返回 product_mapping.note," + "多为产品模块未加载),重跑一次 apply 或告知用户;" "定价无匹配档位→核对usages维度值与定价YAML是否一致") elif st == "created": # 2026-09-06 用户定夺:只有 status='SUCCEEDED' 的行才写 accounting_status, @@ -2711,7 +2773,9 @@ PLATFORM_PROMPT = """ - failed → 按 reason/hint 处置;需要核实库内数据(产品映射/定价挂接/流水明细) 一律用 `db_query` 只读查询,**禁止用 run_command 手搓连库脚本**(沙箱 /tmp 不跨 命令持久、平台目录只读、输出双截断——手搓必陷多轮试错)。 - 未映射产品→告知用户在产品管理导入产线模型(人工步骤,如实转告即止,不要自行深挖) + 产品映射由 apply_llm_config 自动完成(2026-09-08 起)——若仍报「未映射到产品」, + 回看 apply 返回的 product_mapping.note(多为产品模块未加载),重跑一次 + apply_llm_config(幂等)触发自动映射,仍失败才如实告知用户。 9. 汇报:配置/定价/测试/记账四段结果 + 出处 URL + 遗留事项(如模板需人工核对项)。 用户发现问题后按其说明修改,再重新走对应环节(全链幂等,重跑安全)。