Files
submmit/modelhub_submmit_api/failure_taxonomy.py

106 lines
4.4 KiB
Python

from __future__ import annotations
import re
from dataclasses import asdict, dataclass
from typing import Iterable
@dataclass(frozen=True)
class FailureClassification:
category: str
scope: str
action: str
deterministic: bool
needs_llm: bool
reason: str
def to_dict(self) -> dict[str, object]:
return asdict(self)
DETERMINISTIC_POLICIES: dict[str, FailureClassification] = {
"PREFLIGHT_OOM": FailureClassification(
"memory_capacity", "model_gpu", "reject_if_estimated_load_exceeds_memory", True, False, "structured_oom",
),
"MODEL_FILE_NOT_FOUND": FailureClassification(
"repository_structure", "model", "require_framework_specific_root_files", True, False, "structured_missing_files",
),
"CONTEXT_LENGTH_ERROR": FailureClassification(
"context_length", "configuration", "clamp_requested_context_to_model_limit", True, False, "structured_context_limit",
),
"DEVICE_OOM": FailureClassification(
"runtime_memory", "model_gpu", "lower_memory_risk_or_reject_combination", True, False, "structured_device_oom",
),
"STORAGE_ERROR": FailureClassification(
"platform_storage", "platform", "retry_later_without_blaming_model", True, False, "structured_storage_error",
),
"NO_LOG_PROGRESS": FailureClassification(
"platform_stall", "gpu_framework", "open_short_gpu_framework_circuit", True, False, "structured_no_progress",
),
}
SEMANTIC_POLICIES: dict[str, FailureClassification] = {
"MODEL_NOT_SUPPORTED": FailureClassification(
"architecture_compatibility", "model_gpu_framework", "consult_profile_history_then_llm", False, True, "framework_version_dependent",
),
"MODEL_LOAD_FAILED": FailureClassification(
"model_load", "model_gpu_framework", "inspect_root_exception_then_llm_if_unknown", False, True, "broad_load_error",
),
"TOKENIZER_FAILED": FailureClassification(
"tokenizer_compatibility", "model_framework", "check_tokenizer_files_then_llm", False, True, "broad_tokenizer_error",
),
"MISSING_OPERATOR": FailureClassification(
"backend_operator", "gpu_framework", "prefer_other_proven_framework_or_gpu", False, True, "backend_version_dependent",
),
"ATTENTION_NOT_SUPPORTED": FailureClassification(
"attention_backend", "gpu_framework", "prefer_other_proven_framework_or_gpu", False, True, "backend_version_dependent",
),
}
PLATFORM_PATTERNS = (
(re.compile(r"welcome\.sh: No such file|data: command not found", re.I), "broken_platform_launch_script"),
(re.compile(r"id_rsa.*No such file", re.I), "missing_platform_credential"),
(re.compile(r"找不到空闲卡|no idle (?:gpu|card)", re.I), "no_idle_device"),
(re.compile(r"storage|download.*timed? out|connection reset", re.I), "platform_io_transient"),
)
DETERMINISTIC_LOG_PATTERNS = (
(re.compile(r"PREFLIGHT_OOM|out of memory", re.I), "PREFLIGHT_OOM"),
(re.compile(r"max_model_len.*greater than.*max_position_embeddings", re.I), "CONTEXT_LENGTH_ERROR"),
(re.compile(r"config\.json.*(?:not found|no config)|Invalid repository ID or local directory", re.I), "MODEL_FILE_NOT_FOUND"),
)
def classify_failure_report(report_code: str | None, log_lines: Iterable[str] = ()) -> FailureClassification:
code = str(report_code or "").strip().upper()
text = "\n".join(str(line) for line in log_lines)
# Infrastructure signatures override broad report codes such as
# EXECUTE_EMPTY_RESULT so they do not poison model compatibility feedback.
for pattern, reason in PLATFORM_PATTERNS:
if pattern.search(text):
return FailureClassification(
"platform_infrastructure",
"gpu_framework",
"open_short_gpu_framework_circuit_and_retry_other_models",
True,
False,
reason,
)
if code in DETERMINISTIC_POLICIES:
return DETERMINISTIC_POLICIES[code]
for pattern, inferred_code in DETERMINISTIC_LOG_PATTERNS:
if pattern.search(text):
return DETERMINISTIC_POLICIES[inferred_code]
if code in SEMANTIC_POLICIES:
return SEMANTIC_POLICIES[code]
return FailureClassification(
"ambiguous_runtime",
"unknown",
"send_compact_profile_and_root_exception_to_llm",
False,
True,
code.lower() if code else "missing_structured_error_code",
)