feat: strengthen CAD experience distillation and routing

This commit is contained in:
Jerry
2026-07-23 20:03:26 +08:00
parent a2f3ba6a90
commit 2edf8fb4c8
67 changed files with 16045 additions and 83 deletions
+110 -2
View File
@@ -76,6 +76,11 @@ EXPERIENCE_FAMILY_RULES: tuple[tuple[str, tuple[str, ...]], ...] = (
("shaft", ("shaft", "轴类", "传动轴")),
("flange", ("flange", "法兰")),
("bushing", ("bushing", "sleeve", "轴套", "衬套")),
("plate", ("plate", "mounting plate", "安装板", "平板")),
("bracket", ("bracket", "mounting bracket", "支架", "托架")),
("block", ("block", "rectangular body", "方块", "块体")),
("manifold", ("manifold", "valve body", "housing", "歧管", "阀体", "壳体")),
("rotational_part", ("roller", "pulley", "cylindrical body", "滚轮", "带轮")),
)
EXPERIENCE_FEATURE_RULES: tuple[tuple[str, tuple[str, ...]], ...] = (
@@ -90,8 +95,90 @@ EXPERIENCE_FEATURE_RULES: tuple[tuple[str, tuple[str, ...]], ...] = (
("conical_transition", ("cone", "taper", "锥", "斜面过渡")),
("gear_teeth", ("gear", "teeth", "齿轮", "齿")),
("coaxial_cylindrical_stack", ("stepped shaft", "阶梯轴", "同轴", "轴肩")),
(
"repeated_axial_hole_pattern",
(
"mounting holes",
"corner holes",
"four holes",
"multiple holes",
"bolt holes",
"安装孔",
"四个孔",
"多个孔",
),
),
("planar_dominant_body", ("plate", "bracket", "flat body", "板", "支架")),
(
"multi_level_planar_profile",
("pocket", "recess", "stepped plate", "台阶面", "凹槽", "沉台"),
),
(
"rotational_body",
("cylindrical body", "roller", "pulley", "revolved", "圆柱体", "滚轮", "回转体"),
),
(
"stepped_rotational_profile",
("stepped shaft", "multiple diameters", "shoulder", "阶梯轴", "多段直径", "轴肩"),
),
("shaft_like_body", ("shaft", "axle", "rod", "轴", "长杆")),
(
"flange_like_rotational_body",
("flange", "flanged", "法兰", "带法兰"),
),
(
"cylindrical_feature_network",
("bore", "passage", "drilled holes", "孔系", "流道", "钻孔"),
),
(
"multi_axis_passage",
("cross hole", "intersecting passage", "multi-axis", "交叉孔", "多轴孔"),
),
)
# The router vocabulary is request-facing (plate, bracket, flange), while the
# distilled library vocabulary is geometry-facing (patterned_plate,
# plate_or_bracket, flanged_rotational_part). Keep the query semantic by
# expanding a request family into compatible generalized scopes; this never
# uses held-out case geometry or instance parameters.
EXPERIENCE_FAMILY_SCOPE_ALIASES: dict[str, set[str]] = {
"flanged_hub_adapter": {
"flanged_hub_adapter",
"flanged_rotational_part",
"hollow_or_stepped_shaft",
"rotational_part",
},
"connecting_rod": {
"connecting_rod",
"patterned_prismatic_part",
"plate_or_bracket",
},
"gear": {"gear", "rotational_part"},
"shaft": {"shaft", "hollow_or_stepped_shaft", "rotational_part"},
"flange": {"flange", "flanged_rotational_part", "rotational_part"},
"bushing": {"bushing", "hollow_or_stepped_shaft", "rotational_part"},
"plate": {"plate", "patterned_plate", "plate_or_bracket"},
"bracket": {
"bracket",
"plate_or_bracket",
"patterned_plate",
"patterned_prismatic_part",
},
"block": {"block", "prismatic_block", "patterned_prismatic_part"},
"manifold": {
"manifold",
"multi_axis_manifold",
"prismatic_block",
"patterned_prismatic_part",
},
"rotational_part": {
"rotational_part",
"shaft",
"hollow_or_stepped_shaft",
"flanged_rotational_part",
},
}
def contains_any(text: str, terms: tuple[str, ...]) -> bool:
return any(term in text for term in terms)
@@ -358,13 +445,20 @@ def load_experience_library(
if item.strip()
}
normalized_family = family.strip().lower().replace(" ", "_") if family else None
compatible_scopes = (
EXPERIENCE_FAMILY_SCOPE_ALIASES.get(
normalized_family, {normalized_family}
)
if normalized_family
else set()
)
selected: list[object] = []
for item in payload.get("experiences", []):
if not isinstance(item, dict):
continue
scope = set(item.get("scope", []))
if "global" not in scope:
if not normalized_family or normalized_family not in scope:
if not compatible_scopes or scope.isdisjoint(compatible_scopes):
continue
required = set(item.get("when", {}).get("features", []))
if required and not required.issubset(requested_features):
@@ -374,6 +468,7 @@ def load_experience_library(
"schema_version": "2.0",
"context_kind": "generalized_cad_experience_query",
"family": normalized_family,
"compatible_scopes": sorted(compatible_scopes),
"requested_features": sorted(requested_features),
"experiences": selected,
"policy": {
@@ -526,6 +621,7 @@ def route(args: argparse.Namespace) -> dict[str, object]:
"check",
"repair",
"confidence",
"reconstruction_grammar",
)
if key in item
}
@@ -536,6 +632,17 @@ def route(args: argparse.Namespace) -> dict[str, object]:
)
if isinstance(item, dict)
],
"reconstruction_grammars": [
item["reconstruction_grammar"]
for item in (
experience_context.get("experiences", [])
if experience_context
else []
)
if isinstance(item, dict)
and item.get("kind") == "reconstruction_grammar"
and isinstance(item.get("reconstruction_grammar"), dict)
],
"experience_status": (
"pending_source_classification"
if needs_source_classification
@@ -575,9 +682,10 @@ def route(args: argparse.Namespace) -> dict[str, object]:
if edit_context
else [
"Resolve explicit user dimensions and preserve them as authoritative parameters.",
"Instantiate matched reconstruction grammars as symbolic model-spec.json parameters, datums, and canonical feature stages; never copy teacher dimensions.",
"Translate requested feature roles and matched generalized methods into backend operations.",
"Generate the editable source of truth and STEP-first artifact when requested.",
"Validate topology, dimensions, feature relationships, and export integrity.",
"Validate topology, dimensions, feature relationships, surface mix, and export integrity against the grammar validation roles.",
]
),
},