# iAOP-Core · FeatureSpec 声明式特征定义引擎 对应 issue #35(父 EPIC #5「③ AI 模型框架 配置化重构」)与 PRD 5.3「超参包驱动」: 超参包中每个特征的 `spec` 字段是一段**声明式特征定义表达式(FeatureSpec)**,本 模块负责把这段文本**解释**为可执行的特征计算: > `EMA(CLF-01.TEMP, 5m)` → 解析为 AST → 校验 → 依赖分析 → materialize 为时序 `core/model-framework/hyperparam.py`(issue #39)只对 `spec` 做「非空字符串」存在性 校验;本模块补齐其语义层,使: 1. **配置台**(issue #62~#67 Template Console)导入超参包时即可一次性展示每个特征 的解析结果与依赖点位,训练前暴露拼写/语义错误; 2. **训练/推理流水线**(issue #40)拿到 AST 后直接 materialize 为「按点位拉取 → 算子 计算」的特征管道; 3. **切换模板仅改超参包**,特征逻辑零代码(对齐 PRD「配置化」核心目标)。 ## 模块结构 ``` core/model-framework/ ├── feature_spec.py FeatureSpec 引擎(解析/校验/依赖/执行/算子注册) └── tests/ ├── _bootstrap.py 测试引导(目录含连字符,挂载包名 model_framework) └── test_feature_spec.py 解析/校验/依赖/执行/插件注册单元测试 ``` ## 设计要点 * **零外部强依赖**:解析/校验/依赖分析不依赖第三方库;执行(`materialize`)优先用 numpy 向量化,无 numpy 时退化为纯 Python(边缘/离线环境可加载与校验)。 * **不可变 AST + 函数式算子**:每个算子是纯函数 `op(series_map, args)`,注册到 `OPERATORS`;新增算子只需 `register_operator`(对齐 PRD「新增结构走插件注册」, 与 issue #34 Model Recipe 插件接口呼应)。 * **安全解析**:手写递归下降解析器,**绝不使用 `eval`/`exec`**——FeatureSpec 是数据 而非代码,避免任意表达式注入。 ## 语法(对齐 PRD 5.3 示例) ``` (, , ...) # 一元/多元算子 := | | | (...) := 点位名,允许中文/点号/连字符,如 CLF-01.TEMP / 炉压 := 整数或浮点(含负号),如 3、-0.5、1e-3 := <正数><单位>,单位 d/h/m/s,如 5m、180d、10s ``` 内置算子:`EMA / SMA / RollingStd / RollingMax / RollingMin / RateOfChange / Diff / Lag / Log / Scale / Clip / Combine`,覆盖 PRD 5.3 超参包示例的全部特征形态。 ## 使用 ```python from model_framework.feature_spec import ( parse, validate, resolve_inputs, materialize, describe, register_operator, ) ast = parse("EMA(CLF-01.TEMP, 5m)") # 1. 解析 issues = validate(ast) # 2. 语义校验(空列表=通过) tags = resolve_inputs(ast) # 3. 依赖点位:['CLF-01.TEMP'] feat = materialize(ast, {"CLF-01.TEMP": xs}) # 4. 执行 → list[float] print(describe(ast)) # 人类可读描述 ``` 扩展算子(插件注册): ```python register_operator( "Double", min_arity=1, max_arity=1, arg_kinds=(("tag",),), func=lambda s, a: [x * 2 for x in s[a[0].name]], doc="翻倍", ) materialize(parse("Double(A)"), {"A": [1.0, 2.0]}) # → [2.0, 4.0] ``` ## 测试 ```bash cd core/model-framework/tests python -m unittest test_feature_spec ```