feat(catalog): 统一模型调用身份并梳理生命周期
新增官方调用名、供应商真实名、显示名和兼容别名的独立契约,调整路由、目录聚合、管理端与 OpenAPI。 增加 Gemini、Qwen、DeepSeek、Claude 和 MiniMax 生命周期迁移、别名观测及引用保护,并补充数据库与聚合测试。
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
ALTER TABLE base_model_catalog
|
||||
ADD COLUMN IF NOT EXISTS invocation_name text;
|
||||
|
||||
UPDATE base_model_catalog
|
||||
SET invocation_name = COALESCE(
|
||||
NULLIF(metadata->>'officialModelId', ''),
|
||||
NULLIF(provider_model_name, ''),
|
||||
canonical_model_key
|
||||
)
|
||||
WHERE invocation_name IS NULL OR trim(invocation_name) = '';
|
||||
|
||||
UPDATE base_model_catalog
|
||||
SET display_name = COALESCE(
|
||||
NULLIF(metadata->>'officialDisplayName', ''),
|
||||
NULLIF(default_snapshot->>'displayName', ''),
|
||||
NULLIF(display_name, ''),
|
||||
invocation_name
|
||||
)
|
||||
WHERE catalog_type = 'system';
|
||||
|
||||
ALTER TABLE base_model_catalog
|
||||
ALTER COLUMN invocation_name SET NOT NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_base_model_catalog_invocation_name
|
||||
ON base_model_catalog(invocation_name);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS model_compatibility_aliases (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
base_model_id uuid NOT NULL REFERENCES base_model_catalog(id) ON DELETE CASCADE,
|
||||
alias text NOT NULL,
|
||||
model_type text NOT NULL,
|
||||
active boolean NOT NULL DEFAULT true,
|
||||
expires_at timestamptz,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT model_compatibility_aliases_nonempty CHECK (trim(alias) <> ''),
|
||||
CONSTRAINT model_compatibility_aliases_unique UNIQUE (base_model_id, alias, model_type)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_model_compatibility_aliases_lookup
|
||||
ON model_compatibility_aliases(alias, model_type)
|
||||
WHERE active = true;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS model_alias_usage_metrics (
|
||||
alias text NOT NULL,
|
||||
canonical_model_key text NOT NULL,
|
||||
model_type text NOT NULL,
|
||||
hit_count bigint NOT NULL DEFAULT 0,
|
||||
first_used_at timestamptz NOT NULL DEFAULT now(),
|
||||
last_used_at timestamptz NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (alias, canonical_model_key, model_type)
|
||||
);
|
||||
|
||||
-- Preserve unambiguous historical card/call names for the 14-day compatibility
|
||||
-- window. Ambiguous names are deliberately not inferred: they must be resolved
|
||||
-- to one canonical identity by an administrator before they can be registered.
|
||||
WITH alias_candidates AS (
|
||||
SELECT b.id AS base_model_id,
|
||||
old_name.alias,
|
||||
model_type.value AS model_type,
|
||||
b.invocation_name
|
||||
FROM base_model_catalog b
|
||||
CROSS JOIN LATERAL jsonb_array_elements_text(b.model_type) AS model_type(value)
|
||||
CROSS JOIN LATERAL (
|
||||
SELECT b.display_name AS alias
|
||||
UNION
|
||||
SELECT b.canonical_model_key AS alias
|
||||
) old_name
|
||||
WHERE trim(COALESCE(old_name.alias, '')) <> ''
|
||||
AND old_name.alias <> b.invocation_name
|
||||
), unambiguous AS (
|
||||
SELECT alias, model_type, min(base_model_id::text)::uuid AS base_model_id
|
||||
FROM alias_candidates
|
||||
GROUP BY alias, model_type
|
||||
HAVING count(DISTINCT invocation_name) = 1
|
||||
)
|
||||
INSERT INTO model_compatibility_aliases (base_model_id, alias, model_type, expires_at)
|
||||
SELECT base_model_id, alias, model_type, now() + interval '14 days'
|
||||
FROM unambiguous
|
||||
ON CONFLICT (base_model_id, alias, model_type) DO NOTHING;
|
||||
|
||||
-- Keep the old platform model_name/model_alias values as explicit compatibility
|
||||
-- aliases before canonical invocation names are written to platform_models.
|
||||
WITH platform_alias_candidates AS (
|
||||
SELECT b.id AS base_model_id,
|
||||
old_name.alias,
|
||||
model_type.value AS model_type,
|
||||
b.invocation_name
|
||||
FROM platform_models pm
|
||||
JOIN base_model_catalog b ON b.id = pm.base_model_id
|
||||
CROSS JOIN LATERAL jsonb_array_elements_text(pm.model_type) AS model_type(value)
|
||||
CROSS JOIN LATERAL (
|
||||
SELECT pm.model_name AS alias
|
||||
UNION
|
||||
SELECT pm.model_alias AS alias
|
||||
) old_name
|
||||
WHERE trim(COALESCE(old_name.alias, '')) <> ''
|
||||
AND old_name.alias <> b.invocation_name
|
||||
), unambiguous AS (
|
||||
SELECT alias, model_type, min(base_model_id::text)::uuid AS base_model_id
|
||||
FROM platform_alias_candidates
|
||||
GROUP BY alias, model_type
|
||||
HAVING count(DISTINCT invocation_name) = 1
|
||||
)
|
||||
INSERT INTO model_compatibility_aliases (base_model_id, alias, model_type, expires_at)
|
||||
SELECT base_model_id, alias, model_type, now() + interval '14 days'
|
||||
FROM unambiguous
|
||||
ON CONFLICT (base_model_id, alias, model_type) DO NOTHING;
|
||||
|
||||
WITH ranked_targets AS (
|
||||
SELECT pm.id,
|
||||
b.invocation_name,
|
||||
COALESCE(NULLIF(b.display_name, ''), b.invocation_name) AS display_name,
|
||||
row_number() OVER (
|
||||
PARTITION BY pm.platform_id, b.invocation_name
|
||||
ORDER BY CASE WHEN pm.model_name = b.invocation_name THEN 0 ELSE 1 END,
|
||||
pm.created_at ASC,
|
||||
pm.id ASC
|
||||
) AS identity_rank
|
||||
FROM platform_models pm
|
||||
JOIN base_model_catalog b ON b.id = pm.base_model_id
|
||||
)
|
||||
UPDATE platform_models pm
|
||||
SET model_name = target.invocation_name,
|
||||
model_alias = target.invocation_name,
|
||||
display_name = target.display_name,
|
||||
updated_at = now()
|
||||
FROM ranked_targets target
|
||||
WHERE target.id = pm.id
|
||||
AND target.identity_rank = 1
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM platform_models conflict
|
||||
WHERE conflict.platform_id = pm.platform_id
|
||||
AND conflict.id <> pm.id
|
||||
AND conflict.model_name = target.invocation_name
|
||||
);
|
||||
|
||||
UPDATE base_model_catalog
|
||||
SET default_snapshot = default_snapshot || jsonb_build_object(
|
||||
'invocationName', invocation_name,
|
||||
'modelAlias', invocation_name,
|
||||
'displayName', display_name
|
||||
)
|
||||
WHERE catalog_type = 'system'
|
||||
AND COALESCE(default_snapshot, '{}'::jsonb) <> '{}'::jsonb;
|
||||
|
||||
CREATE OR REPLACE FUNCTION fill_system_base_model_default_snapshot()
|
||||
RETURNS trigger AS $$
|
||||
BEGIN
|
||||
IF NEW.catalog_type = 'system' AND NEW.default_snapshot IS NULL THEN
|
||||
NEW.default_snapshot = jsonb_build_object(
|
||||
'providerKey', NEW.provider_key,
|
||||
'canonicalModelKey', NEW.canonical_model_key,
|
||||
'invocationName', NEW.invocation_name,
|
||||
'providerModelName', NEW.provider_model_name,
|
||||
'modelType', NEW.model_type,
|
||||
'modelAlias', NEW.invocation_name,
|
||||
'displayName', NEW.display_name,
|
||||
'capabilities', NEW.capabilities,
|
||||
'baseBillingConfig', NEW.base_billing_config,
|
||||
'defaultRateLimitPolicy', NEW.default_rate_limit_policy,
|
||||
'pricingRuleSetId', COALESCE(NEW.pricing_rule_set_id::text, ''),
|
||||
'runtimePolicySetId', COALESCE(NEW.runtime_policy_set_id::text, ''),
|
||||
'runtimePolicyOverride', NEW.runtime_policy_override,
|
||||
'metadata', NEW.metadata,
|
||||
'pricingVersion', NEW.pricing_version,
|
||||
'status', NEW.status
|
||||
);
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
Reference in New Issue
Block a user