# 风险规则可解释流程判断改造方案

## 功能一句话

把风险规则从“自然语言生成一段 JSON”升级为“自然语言、字段本体、可执行 JSON DSL、流程判断图、测试命中路径、版本修改”一致闭环，让业务用户能看懂规则怎么判断，让系统按同一套逻辑执行。

## 背景与问题

当前风险规则已经具备自然语言创建、JSON 风险规则、风险评分、详情页流程图、仿真测试和上线启用能力，但仍有几个关键缺口：

- 规则解释不够稳定。用户输入复杂业务规则后，系统可能把“城市是否一致、日期是否越界、是否存在合理说明”解释成“是否出现关键词”，这会导致业务语义失真。
- 流程图容易变成展示装饰。如果流程图不严格从可执行 JSON DSL 派生，就会出现“页面看起来是 A，后端实际执行是 B”的问题。
- 测试结果缺少路径解释。用户上传票据和输入意图后，需要知道系统识别到了哪些字段、走过哪些判断节点、为什么命中或未命中。
- 规则修改缺少版本化闭环。已上线规则不能直接覆盖，应创建修订版本，旧版本继续生效，新版本测试通过后再替换。
- 常见费控规则需要模板化扩展。预算、票据、差旅、招待、采购/AP、企业卡等规则应进入规则模板库，但仍必须走同一套解释和执行链路。

## 目标与非目标

### 目标

- [G1] 自然语言规则经过 Hermes 语义理解后，生成结构稳定、可校验、可执行的 JSON DSL。
- [G2] 流程判断图必须由 JSON DSL 派生，不能直接由自然语言单独生成。
- [G3] 详情页展示“文字流程解释 + 流程图 + 使用字段 + 风险分数 + 规则状态”，让业务用户能确认系统理解是否正确。
- [G4] 测试规则时展示本次样例或票据仿真的字段识别结果、判断路径、命中节点和最终结论。
- [G5] 用户觉得规则不合理时，通过“创建修订版本”修改，线上版本保持稳定。
- [G6] 常见费控规则模板库可以复用同一套 DSL、流程图和测试机制。

### 非目标

- [NG1] 本期不做流程图编辑器，不允许拖拽、改节点、缩放编辑或在线画图。
- [NG2] 本期不让大模型作为风险命中裁判。Hermes 只负责理解、生成、解释和辅助解析，最终命中由规则执行器决定。
- [NG3] 本期不把所有复杂政策一次性建成完整专家系统，先保证规则表达、解释和执行一致。
- [NG4] 本期不直接覆盖已上线规则，所有线上修改都走修订版本。

## 用户与场景

- 财务规则制定者：创建风险规则，查看系统理解是否正确，修改草稿规则。
- 高级财务人员 / admin：审核、上线、下线、启用、停用、删除未发布规则。
- 普通报销用户：在真实业务命中风险时看到简明原因，可反馈误判或漏判。
- 系统执行链路：报销、费用申请、预算占用、票据识别、采购/AP 等场景只加载已上线且已启用的规则。

核心场景：

1. 新建规则：输入规则标题、费用业务环节、费用领域、是否需要附件、自然语言规则。
2. 生成规则：Hermes 结合字段本体输出 JSON DSL、业务说明、风险评分、流程模型和 SVG。
3. 查看详情：用户确认“系统理解的字段、判断条件、例外说明、命中动作”是否正确。
4. 仿真测试：用户上传附件并输入测试意图，系统统一识别字段，再由执行器判断当前规则。
5. 修改规则：未上线规则直接编辑；已上线规则创建修订版本，测试通过后发布替换。

## 功能能力

### C1. 自然语言输入能力

新建风险规则表单应包含：

- 规则标题。
- 业务环节：费用申请、报销、预算控制、付款/采购等。
- 费用领域：差旅、住宿、交通、招待、办公、培训、会议、软件服务、通讯、福利、预算、发票、采购/AP、通用。
- 是否需要附件：需要时测试弹窗开放附件上传；不需要时隐藏上传入口。
- 自然语言规则描述。

风险等级不允许用户手动选择，由评分模型输出风险分数和等级。

### C2. 语义理解与字段本体映射

Hermes 需要输出一份中间语义计划，而不是直接写死 JSON：

- 规则意图：判断什么业务风险。
- 适用范围：业务环节、费用领域、费用科目、单据类型。
- 所需字段：中文解释、英文字段名、来源、是否必填。
- 票据字段：OCR 或文档智能识别得到的城市、日期、金额、销售方、发票号等。
- 判断步骤：按顺序表达条件、分支、例外说明和命中动作。
- 例外条件：例如延期、改签、跨城办事、临时任务等说明。
- 风险动作：提醒、人工复核、要求补充说明、退回修改、禁止提交。

字段展示统一为：

```text
申报目的地[claim.destination_city]
明细发生地点[item.location_city]
交通票行程城市[receipt.transport_route_cities]
住宿发票城市[receipt.hotel_city]
出差开始日期[trip.start_date]
出差结束日期[trip.end_date]
报销事由[claim.reason]
```

### C3. 可执行 JSON DSL

JSON DSL 应表达规则执行逻辑，而不是保存自然语言摘要。建议基本结构：

```json
{
  "rule_id": "risk.travel.city_mismatch",
  "version": "v1",
  "scope": {
    "business_stage": "reimbursement",
    "expense_types": ["travel", "lodging"]
  },
  "required_fields": [
    {
      "label": "申报目的地",
      "field": "claim.destination_city",
      "source": "claim",
      "required": true
    }
  ],
  "conditions": {
    "all": [
      {
        "op": "in_scope",
        "field": "expense.type",
        "values": ["travel", "lodging"]
      },
      {
        "op": "any_present",
        "fields": [
          "receipt.transport_route_cities",
          "receipt.hotel_city",
          "item.location_city"
        ]
      },
      {
        "op": "none_match",
        "left_fields": [
          "receipt.transport_route_cities",
          "receipt.hotel_city"
        ],
        "right_fields": [
          "claim.destination_city",
          "item.location_city",
          "trip.route_cities"
        ],
        "matcher": "city_equivalent"
      },
      {
        "op": "not_contains_any",
        "field": "claim.reason",
        "values": ["延期", "改签", "跨城办事", "临时任务", "绕行"]
      }
    ]
  },
  "action": {
    "risk_level": "high",
    "risk_score": 76,
    "decision": "review_required",
    "message": "票据城市与申报目的地或行程城市不一致，且未说明合理原因。"
  }
}
```

核心要求：

- 城市、日期、金额、人员、供应商等字段必须使用专门比较算子，不能退化成“关键词出现”。
- 复杂规则允许多层条件组合：`all`、`any`、`not`、`branch`、`exists`、`range`、`compare`、`semantic_contains`。
- 例外说明可以使用语义包含，但只能影响“是否进入复核/降级/豁免”，不能替代结构化字段判断。
- DSL 生成后必须通过 schema 校验和执行器 dry-run。

### C4. 流程判断图

流程图不是编辑器，也不是自然语言插图。流程图必须由 JSON DSL 转换成 `flow_model`，再生成 SVG。

建议 `flow_model`：

```json
{
  "nodes": [
    {
      "id": "start",
      "type": "start",
      "title": "开始",
      "description": "进入差旅住宿报销风险检查"
    },
    {
      "id": "scope",
      "type": "decision",
      "title": "是否属于差旅住宿报销",
      "fields": ["expense.type", "claim.business_stage"]
    },
    {
      "id": "city_match",
      "type": "decision",
      "title": "票据城市是否匹配申报或行程城市",
      "fields": [
        "receipt.hotel_city",
        "receipt.transport_route_cities",
        "claim.destination_city",
        "trip.route_cities"
      ]
    },
    {
      "id": "hit",
      "type": "risk",
      "title": "命中高风险",
      "description": "要求补充行程说明或退回修改"
    }
  ],
  "edges": [
    { "from": "start", "to": "scope", "label": "开始检查" },
    { "from": "scope", "to": "end_pass", "label": "否" },
    { "from": "scope", "to": "city_match", "label": "是" },
    { "from": "city_match", "to": "end_pass", "label": "是" },
    { "from": "city_match", "to": "hit", "label": "否" }
  ]
}
```

流程图展示要求：

- 详情页左侧为文字流程解释，右侧为“流程图”。
- 判断分支用“是 / 否 / 通过 / 不通过 / 缺失 / 存在”等明确标签。
- 风险命中框使用风险等级颜色：低风险蓝色，中风险橙色，高风险红色，极高风险深红色。
- 普通节点保持 SaaS 白底、细边框、低饱和样式，不能整张图都染成风险色。
- 图只做展示，不响应拖拽、编辑、缩放和节点点击。
- 节点数量超过 8 个时，需要自动压缩文字、合并说明节点或分页展示，避免图过大。

### C5. 测试命中路径

测试规则弹窗应展示三类信息：

1. 输入与识别结果
   - 用户自然语言测试意图。
   - 上传附件清单。
   - OCR / 文档智能识别字段。
   - Hermes 辅助规范化后的结构化字段。

2. 规则执行结果
   - 是否进入适用范围。
   - 每个判断节点的输入值、比较方式、判断结果。
   - 命中的风险动作。
   - 未命中的原因。

3. 流程图路径高亮
   - 使用同一个 `flow_model`。
   - 本次执行走过的节点和边由执行器输出 `trace`。
   - 前端按 `trace` 高亮路径。

执行 trace 示例：

```json
{
  "trace_id": "run_001",
  "matched": true,
  "risk_level": "high",
  "risk_score": 76,
  "steps": [
    {
      "node_id": "scope",
      "result": true,
      "inputs": {
        "expense.type": "住宿费",
        "claim.business_stage": "reimbursement"
      }
    },
    {
      "node_id": "city_match",
      "result": false,
      "inputs": {
        "receipt.hotel_city": "北京",
        "claim.destination_city": "上海",
        "trip.route_cities": ["武汉", "上海"]
      }
    }
  ]
}
```

### C6. 规则修改与版本化

规则修改分三种：

- 未上线规则：允许创建者或 admin 直接编辑，保存后重新生成 DSL、流程图、评分和说明。
- 已上线规则：不允许直接覆盖，必须点击“创建修订版本”。
- 业务用户反馈：只能提交误判/漏判反馈，由管理员决定是否创建修订版本。

已上线规则修改流程：

```text
线上版本 active
  ↓
创建修订版本 draft_revision
  ↓
编辑自然语言 / 参数 / 附件要求
  ↓
重新生成 JSON DSL + 流程图 + 评分
  ↓
仿真测试通过
  ↓
发布新版本
  ↓
旧版本归档，新版本 active
```

版本记录必须包含：

- 修改人。
- 修改原因。
- 修改前后自然语言差异。
- 修改前后 DSL 差异。
- 测试报告。
- 发布时间。
- 是否替换线上版本。

## 方案设计

### 总体链路

```text
自然语言规则
  ↓
字段本体召回与业务域约束
  ↓
Hermes 生成语义计划 semantic_plan
  ↓
语义计划校验与补全
  ↓
生成 JSON DSL
  ↓
Schema 校验 + 执行器 dry-run
  ↓
风险评分 risk_score / risk_level
  ↓
DSL 转 flow_model
  ↓
flow_model 转 flow_diagram_svg
  ↓
详情展示 + 仿真测试 + 上线执行
```

### 前端设计

涉及入口：

- `AuditRuleDialogs.vue`：新建风险规则表单，后续增加修订版本编辑入口。
- `AuditJsonRiskRuleDetail.vue`：详情页展示基本信息、测试状态、流程解释、流程图、操作按钮。
- `RiskRuleFlowDiagram.vue`：只负责展示 SVG 或由 `flow_model` 派生的静态图，不做编辑。
- `RiskRuleTestDialog.vue`：仿真测试窗口，展示输入识别、执行路径、测试报告。
- `auditViewRiskRuleModel.js` / `auditViewModel.js`：规则详情视图模型、列表字段和状态映射。

详情页建议结构：

```text
Topbar：规则标题、状态、风险分数、风险等级、上线/启用状态

基本信息：费用领域、业务环节、附件要求、创建人、上线时间、最后操作、测试状态

判断流程：
  左侧：文字流程解释
  右侧：流程图

测试与版本：
  最近测试报告
  修订版本 / 历史版本
  操作按钮
```

修改规则界面建议采用左右布局：

- 左侧：自然语言规则编辑、规则标题、费用领域、附件要求。
- 右侧：系统解释预览，包括字段、本体映射、流程解释、风险分数。
- 底部：重新生成、保存草稿、测试规则、提交上线。

### 后端设计

已有相关模块应优先复用：

- `risk_rule_generation.py`：规则生成主流程。
- `risk_rule_generation_prompt.py`：Hermes 提示词。
- `risk_rule_generation_ontology.py`：字段本体和费用领域约束。
- `risk_rule_generation_semantics.py`：自然语言语义解释。
- `risk_rule_generation_interpreter.py`：解释结果到 DSL。
- `risk_rule_scoring.py`：风险评分。
- `risk_rule_flow_diagram.py`：流程图 SVG 生成。
- `risk_rule_manifest_normalizer.py`：规则 manifest 规范化。
- `risk_rule_template_executor.py`：规则执行器。
- `agent_asset_risk_rule_testing.py`：规则测试、删除、发布、启用。
- `agent_asset_risk_rule_simulation.py`：仿真测试对话。

后端需要补齐的能力：

- 生成 `semantic_plan` 并持久化到 `config_json` 或版本内容中。
- 生成并持久化 `flow_model`，再生成 `flow_diagram_svg`。
- 执行器输出 `trace`，用于测试解释和流程图高亮。
- 支持创建修订版本，避免直接覆盖 active 版本。
- 支持从常见模板创建规则，模板也走同一套生成和校验链路。

### 接口设计

建议新增或调整：

```text
POST /agent-assets/risk-rules/generate
  根据自然语言创建生成任务，返回生成中资产。

POST /agent-assets/{asset_id}/risk-rules/regenerate
  对草稿或修订版本重新生成 DSL、评分和流程图。

POST /agent-assets/{asset_id}/risk-rules/revisions
  基于已上线规则创建修订版本。

PATCH /agent-assets/{asset_id}/risk-rules/draft
  保存未上线规则或修订版本的编辑内容。

POST /agent-assets/{asset_id}/risk-rule-tests/simulate
  独立仿真测试，返回字段识别、执行结果、trace。

GET /agent-assets/{asset_id}/risk-rule-tests/latest
  返回最近测试摘要。

POST /agent-assets/{asset_id}/publish
  发布通过测试的规则版本。
```

### 数据设计

建议在风险规则版本内容或 `config_json` 中保留：

```json
{
  "source_text": "用户输入的自然语言规则",
  "semantic_plan": {},
  "dsl": {},
  "flow_model": {},
  "flow_diagram_svg": "<svg>...</svg>",
  "flow_explanation": [],
  "risk_score": 76,
  "risk_level": "high",
  "required_attachment": true,
  "required_fields": [],
  "last_operation": {
    "action": "publish",
    "actor": "admin",
    "at": "2026-05-30T10:00:00+08:00"
  }
}
```

测试记录保留：

```json
{
  "test_type": "simulation",
  "input_text": "我去北京出差 3 天，上传武汉到上海车票",
  "attachments": [],
  "recognized_fields": {},
  "normalized_fields": {},
  "execution_result": {},
  "trace": {},
  "passed": true,
  "tester": "admin",
  "tested_at": "2026-05-30T10:10:00+08:00"
}
```

## 算法与公式

### 风险评分

风险评分由模型辅助判断，但必须结构化输出。建议使用可解释加权模型：

$$
score = \min(100, base + \sum_{i=1}^{n} w_i x_i + c + e)
$$

变量说明：

- $base$：业务领域基础风险分。预算、发票、付款类通常高于普通提示类。
- $x_i$：风险因子是否存在或强度，例如金额影响、附件缺失、字段冲突、越权、历史重复。
- $w_i$：风险因子权重。
- $c$：复杂度修正，例如多字段交叉、跨单据、跨时间窗口、跨附件识别。
- $e$：例外说明修正。存在合理说明时可降低，但不能直接清零。

等级映射：

- 0-30：低风险。
- 31-60：中风险。
- 61-80：高风险。
- 81-100：极高风险。

### 流程复杂度控制

为了避免流程图过大，建议定义流程复杂度：

$$
complexity = node_count + 0.5 \times edge_count + branch_count
$$

处理规则：

- `complexity <= 12`：单图展示。
- `12 < complexity <= 20`：合并说明节点，保留关键判断。
- `complexity > 20`：详情页展示主流程，测试弹窗展示完整 trace。

## 测试方案

### 单元测试

- 语义计划生成：复杂差旅城市规则不能退化为关键词判断。
- DSL schema 校验：缺字段、非法算子、空 action 必须失败。
- 执行器：城市匹配、日期范围、金额阈值、附件缺失、例外说明。
- 流程转换：同一 DSL 生成稳定的 `flow_model` 和 SVG。
- 风险评分：低/中/高/极高边界分数。

### 接口测试

- 新建规则返回生成中资产。
- 生成完成后包含 `dsl`、`flow_model`、`flow_diagram_svg`、`risk_score`。
- 仿真测试返回 `recognized_fields`、`normalized_fields`、`trace`。
- 未测试通过的规则不能发布。
- 已上线规则创建修订版本，不覆盖线上版本。

### 前端测试

- 新建弹窗不再选择风险等级。
- 详情页展示风险分数、流程解释、流程图。
- 流程图不可点击、不可拖拽、无工具栏。
- 测试弹窗显示字段识别结果和判断路径。
- 已上线规则只能创建修订版本修改。

### 容器验证

后续开发验证默认在 Docker 容器内执行：

```bash
docker exec x-financial-main sh -lc "cd /app/server && pytest <target> --timeout=60"
docker exec x-financial-main sh -lc "cd /app/web && npm run build"
```

### 本轮落地结果

已落地接口：

- `GET /agent-assets/risk-rules/templates`：返回预算、票据、差旅、招待、采购/AP、企业卡、通用模板分组，包含默认自然语言、字段清单、附件要求和 DSL 样例。
- `PATCH /agent-assets/{asset_id}/risk-rules/draft`：编辑未上线风险规则草稿。
- `POST /agent-assets/{asset_id}/risk-rules/revisions`：为已上线规则创建修订草稿。
- `POST /agent-assets/{asset_id}/risk-rules/regenerate`：重新生成 DSL、流程图、风险评分和业务说明。
- `POST /agent-assets/{asset_id}/risk-rules/feedback`、`GET /agent-assets/{asset_id}/risk-rules/feedback`：记录和查看误判/漏判反馈。

关键文件：

- 后端模板库与契约：`risk_rule_template_catalog.py`、`agent_asset.py`、`agent_asset_risk_rules.py`。
- 后端生成、修订、发布、反馈、仿真：`risk_rule_generation*`、`agent_asset_risk_rule_revision.py`、`agent_asset_risk_rule_regeneration.py`、`agent_asset_risk_rule_publish.py`、`agent_asset_risk_rule_feedback.py`、`agent_asset_risk_rule_simulation.py`。
- 前端新建、详情、测试：`AuditRuleDialogs.vue`、`AuditJsonRiskRuleDetail.vue`、`RiskRuleFlowDiagram.vue`、`RiskRuleTestDialog.vue`、`auditViewDetailTopBar.js`、`useAuditRiskRuleActions.js`、`useAuditAssetData.js`。
- 测试：`test_risk_rule_template_catalog.py`、`test_risk_rule_feedback.py`、`test_risk_rule_revision_endpoints.py`、`test_risk_rule_explainability.py`、`risk-rule-detail-experience.test.mjs`。

已执行验证命令：

```bash
docker exec x-financial-main bash -lc "cd /app/server && timeout 60 /tmp/x-financial-server-venv/bin/python -m pytest tests/test_risk_rule_template_catalog.py tests/test_openapi_schema.py -q"
docker exec x-financial-main bash -lc "cd /app/server && timeout 60 /tmp/x-financial-server-venv/bin/python -m pytest tests/test_risk_rule_feedback.py tests/test_risk_rule_revision_endpoints.py tests/test_openapi_schema.py -q"
docker exec x-financial-main bash -lc "cd /app/web && timeout 60 node --test tests/risk-rule-detail-experience.test.mjs"
docker exec x-financial-main bash -lc "cd /app/web && timeout 60 npm run build"
```

## 指标与验收

- [A1] 新建复杂差旅规则后，详情页流程解释不能出现“检查是否包含风险关键词”这类错误表达。
- [A2] 详情页流程图与 JSON DSL 条件数量、分支方向、命中动作一致。
- [A3] 仿真测试能显示票据识别字段，并说明为什么命中或未命中。
- [A4] 同一条测试样例的执行 trace 可以高亮流程图路径。
- [A5] 已上线规则修改时不会改变当前线上执行结果，只有发布修订版本后才替换。
- [A6] 低、中、高、极高风险都能由评分模型产出，不应默认集中在中高风险。
- [A7] 前端构建通过，后端定向测试 60s 内完成。

## 风险与开放问题

- LLM 语义理解仍可能出错，因此必须有 schema 校验、执行器 dry-run、详情解释和仿真测试兜底。
- 字段本体不完整会限制规则表达，需要持续扩展费用、票据、预算、采购/AP 字段。
- 复杂规则可能产生过大的流程图，需要主流程和完整 trace 分层展示。
- 老规则没有 `semantic_plan` 或 `flow_model`，需要兼容展示并允许重新生成。
- 常见规则模板要避免写成定制逻辑。模板只能提供默认文本、字段和 DSL 样例，最终仍走通用生成链路。

当前仍需持续演进的点：

- 企业卡、采购/AP、预算场景的字段本体还偏少，后续应补充企业卡交易流水、供应商、采购订单、合同、预算期间等字段。
- 复杂规则的准确性仍依赖 Hermes 语义计划质量，执行前必须继续保留 DSL validator、执行器 dry-run 和仿真测试。
- 模板库只作为规则编写入口的业务参考，不作为规则执行捷径；新增模板时必须同时提供 DSL 样例和 validator 测试。

## 实现确认

当前实现仍围绕“解释图和执行逻辑一致”推进：自然语言先经字段本体和语义计划形成受控 JSON DSL，详情页流程图、文字流程解释、测试 trace、上线版本均围绕同一份 DSL 展示和执行，没有新增流程图编辑器或绕过规则执行器的判断链路。
