Files
meida/docs/开发任务包/T7-规则引擎.md
T
xsl e511b6a66f 收尾两批并行开发的文档回写与任务包
- Sprint 执行计划 v1.1:§1.1 补第一批交付实据;T9 SPIKE 结论回写 Sprint 1 表
  (T-P0-16 通过 2.8ms;T-P0-12 有条件;T-P0-10 原型 6/6 + 真实照片重验前置);
  Sprint 2 表标注 T-P2-01~06 交付;新增 §9 两批交付记录
- 开发任务拆解 v1.5:交付回写 + 新风险登记(RTMPose 域差异、BiRefNet 异步化)
- 新增 开发任务包/:三批多 agent 并行的协作规程与 14 份任务契约
- 新增 前置开通清单-云资源与资质.md
- 清理已用毕的评审报告(文档评审 2026-08-13、项目整体评审 2026-08-14),
  README 中相应引用改为留痕表述
2026-08-14 21:07:20 +08:00

90 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# T7 · 知识库·规则引擎
> 对应任务:`T-P2-02`(规则求值 p95 < 50ms;硬约束可拦截)| 需求:`FR-KB-02`、架构 §8.2 rules-engine、`TD-10` | 分支:`task/t7-rules-engine` | worktree:`/home/xsl/meida_backend-t7`
> 先读《README.md(协作规程)》,遵守全部纪律。
## 1. 目标
自研数据驱动决策表(TD-10):`kb_rule` 的 JSON DSL 解析 + 纯域求值引擎。**核心结论由规则引擎产出,LLM 只负责表达**(防幻觉红线)——这是整个产品"专业可信"的根基,代码质量按"钱与正确性"标准写。
## 2. 已就绪的契约(协调提交已提供,禁改 models/migrations)
### 表 `kb_rule`(ORM `KbRule` 已加)
`rule_id` PK 雪花、`rule_key` varchar(64) UNIQUE(如 `R-BODY-A-002`)、`category` varchar(32)、`version` int、`status` draft/published/archived、`priority` int、`conditions` JSONB、`effects` JSONB、`is_hard` bool、`confidence` Numeric(4,3)、`evidence` varchar(255)、`author`/`reviewer` varchar(64)、`published_at`;Index(status, priority)。
(注:架构 §6.2 写的列名 `conclusions`,协调提交统一为 **`effects`**——与"决策表"术语一致,任务文档以 models.py 实际代码为准。)
### DSL 规格(知识库文档 §3.2⑩ 原文结构)
```json
{
"rule_key": "R-BODY-A-002",
"category": "body_shape",
"priority": 90,
"conditions": {
"body_shape": "A型",
"features": { "include": ["溜肩"] },
"goals": { "include": ["修饰溜肩"] }
},
"effects": {
"recommend": [ { "slot": "top", "attrs": { "shoulder": ["垫肩","自然肩"], "sleeve": ["泡泡袖"] } } ],
"avoid": [ { "slot": "top", "attrs": { "shoulder": ["落肩"], "silhouette": ["修身"] } } ],
"explanation": "溜肩需要在肩部建立结构感……"
},
"is_hard": false,
"confidence": 0.95
}
```
### 优先级分组(知识库文档 §3.2⑩,语义:**数字越大越优先**)
合规 100 / 用户禁忌 95 / 体型 90 / 色彩 85 / 场景 80 / 温度 75 / 风格 70 / 偏好 60 / 趋势 50。
### 分层位置
`packages/rules` 已在 import-linter 第 4 层(kb|retrieval|rules|memory|profile),现只有 README + 空 `__init__`。只准 import `packages.shared`/`packages.domain`。
## 3. 实现要点
允许改动:`packages/rules/**`、测试文件。
1. **`packages/rules/dsl.py`**——纯逻辑(无 IO,重点单测):
- `RuleCondition` / `RuleEffect` / `Rule` pydantic 模型(解析校验 DSL;`conditions` 支持的字段:等值匹配(str)、`include`/`exclude` 列表、`min`/`max` 数值区间;未识别的键**拒绝**而非忽略——静默忽略会让规则悄悄失效);
- `match(condition: RuleCondition, ctx: RuleContext) -> bool`:`RuleContext` 是 frozen dataclass(`body_shape/season/face_shape/temperature/features/goals/occasion/style/user_taboos…`,缺字段 = 不匹配该子句);
- 所有子句 AND 语义。
2. **`packages/rules/engine.py`**——纯域求值:
- `evaluate(rules, ctx) -> RuleVerdict`:返回 `recommend/avoid/explanation 汇总 + rule_hits`(每条含 rule_key/priority/category/is_hard/confidence/explanation);
- 排序:priority 降序,同 priority 按 confidence 降序;
- **硬约束语义**:`is_hard=true` 且 avoid 命中 → `RuleVerdict.hard_blocks` 非空,调用方必须用它做硬过滤(禁忌违反 = 0 是发布红线);**用户禁忌(priority ≥95 的 avoid)永远压过专业推荐**——同 slot 冲突时用户禁忌胜出并从 recommend 中剔除冲突项;
- p95 < 50ms:求值是纯内存操作,规则量 400 条时远低于此;写一个 400 条规则 × 1000 次求值的基准单测(`time.perf_counter`,断言均值 < 5ms/千次的量级即可,CI 机器差异留裕量)。
3. **`packages/rules/service.py` + `repo.py`**——DB 侧:按 status='published' 载入规则(内存缓存 + `invalidate()`;量级 400,直接整表载入),CRUD(draft→published 状态机,同 T6 语义),DSL 写入前用 pydantic 校验。
4. **黄金集雏形**(架构 §1081 明确要求):`tests/unit/test_rules_golden.py` 固定 8~10 组「输入画像 → 期望 recommend/avoid/hard_blocks」样本,其中**必须包含**:一条硬禁忌场景(用户禁忌压过专业推荐的用例)、一条多规则叠加场景。
## 4. 测试要求
- 单测:DSL 解析(合法/非法结构/未识别键拒绝)、match 矩阵(等值/include/exclude/min-max/缺字段)、排序、硬约束剔除、用户禁忌优先、基准测试、黄金集。
- 集成 `tests/integration/test_rules_engine.py`(新文件):插 3 条规则(含 1 条 is_hard)→ service 载入 → 求值命中与拦截正确;draft 规则不被载入。
## 5. 禁改清单
通用禁改之外:`packages/kb/**`(表共享但包不共享——**repo 只碰 kb_rule 表**,通过 ORM 模型访问,不改 T6 的文件)、`packages/retrieval/**`、`packages/identity/**`。
## 6. 验收标准(T-P2-02)
1. 求值 p95 满足 400 条规则量级远低于 50ms(基准测试证明);
2. 硬约束可拦截(hard_blocks 语义 + 黄金集用例);
3. 用户禁忌永远压过专业推荐(黄金集用例);
4. DSL 非法结构 100% 拒绝(不会静默失效);
5. 全部检查绿(mypy 范围同 T6 列表 + `packages/rules`)。
## 7. 提交信息
```
feat(rules): data-driven decision table engine with hard constraints
kb_rule DSL 解析 + 纯域求值(优先级分组/硬约束/用户禁忌压过专业推荐)
+ 400 条基准 + 黄金集雏形(T-P2-02,TD-10)。
偏差说明:<如有写在这里,无则写"无">
```