# Phase 1（事项图）实施清单

## Context

Phase 0（治理图）已完成并通过全部 75 个测试。现在实现 Phase 1（事项图），新增 5 种实体（Matter, Condition, Material, TimeLimit, TargetGroup）和 7 种关系（GOVERNS, HAS_CONDITION, REQUIRES_MATERIAL, HAS_TIME_LIMIT, APPLIES_TO_TARGET, HANDLED_BY, APPLIES_TO_REGION for Matter→Region），并提供 3 个事项知识卡 API 端点。

**修订要点**（相较初版）：
1. Matter 也自动生成 `matter_id`
2. 内部 `*_id` 基于归一化后的 name 生成
3. 事项详情接口使用 `matter_id` 而不是 `{name}`
4. `get_matter_card()` 采用分查询组合，避免单个超级大查询
5. Phase 1 prompt 明确"无明确要素时不要虚构实体/关系"
6. `APPLIES_TO_REGION (Matter→Region)` 仅显式地域约束时抽取
7. 返回模型使用明确的 Pydantic 子模型，不用裸 `list[dict]`
8. 测试中明确 404/空列表语义

---

## Step 1: 激活 Phase 1 schema

**文件**: `backend/app/config/graph_schema.yaml`

取消 `active_phases` 中 `phase_1` 的注释：
```yaml
active_phases:
  - phase_0
  - phase_1
```

Phase 1 实体/关系定义已存在于 YAML 中，无需新增配置。
启用后现有依赖 `active_phases` 的测试需同步修正预期。

---

## Step 2: 增强 LLM 抽取提示词

**文件**: `backend/app/prompts/entity_extraction.py`

### 2.1 更新静态 fallback prompt

在 `ENTITY_EXTRACTION_SYSTEM` 中追加：
- 实体：Matter, Condition, Material, TimeLimit, TargetGroup（含描述）
- 关系：GOVERNS, HAS_CONDITION, REQUIRES_MATERIAL, HAS_TIME_LIMIT, APPLIES_TO_TARGET, HANDLED_BY, **APPLIES_TO_REGION**（Matter→Region，仅显式地域约束时抽取）
- 规则：Matter粒度控制、Condition必须具体可判断、Material保留is_required/format_requirement、TimeLimit含数字单位结构化为duration/unit/context（duration 优先解析为数值字符串，无法稳定解析时保留原始文本于 name/context）、TargetGroup≠具体机构、APPLIES_TO_REGION仅显式地域约束、**无明确证据时不虚构实体/关系**、**不要求每次输出都包含全部 5 类 Phase 1 实体，仅输出有明确证据支持的实体与关系**
- HANDLED_BY vs ISSUED_BY 语义区分说明

### 2.2 增强 `build_system_prompt()` 动态生成

当检测到 Matter 或任一 Phase 1 相关实体启用时，在"重要规则"后追加事项图专属规则段落（同 2.1 规则内容），其中需显式包含 APPLIES_TO_REGION (Matter→Region) 的抽取约束。

### 2.3 更新 JSON 输出示例

追加 1 个 Matter + 关联实体/关系示例（不要全量，避免模型误认为每次必须产出全部类型）。

---

## Step 3: 自动生成 `*_id` 字段

**文件**: `backend/app/core/graph_builder.py`

### 3.1 ID 字段映射（含 Matter）

```python
_AUTO_ID_FIELDS = {
    "Matter": "matter_id",
    "Condition": "condition_id",
    "Material": "material_id",
    "TimeLimit": "time_limit_id",
    "TargetGroup": "target_group_id",
}
```

### 3.2 ID 生成函数（基于归一化后 name）

```python
def _generate_entity_id(label: str, normalized_name: str) -> str:
    import hashlib
    h = hashlib.md5(normalized_name.encode("utf-8")).hexdigest()[:12]
    return f"{label.lower()}_{h}"
```

### 3.3 写入时机

在 `_write_to_neo4j()` 构建 `neo_entities` 时，实体已经过归一化后：
- 检查 label 是否在 `_AUTO_ID_FIELDS`
- 若对应 `*_id` 未显式存在，则自动补充
- `*_id` 不参与当前 merge key（merge key 仍为 `name`）

---

## Step 4: 添加 Phase 1 索引

**文件**: `backend/app/infrastructure/neo4j_client.py`

在 `init_schema()` 中添加 Matter 全文索引：
```python
await session.run(
    "CREATE FULLTEXT INDEX matter_fulltext IF NOT EXISTS "
    "FOR (m:Matter) ON EACH [m.name, m.description]"
)
```
唯一约束由现有动态逻辑自动处理。

**注意**：当前版本 `search_matters()` 仍采用 CONTAINS 查询，`matter_fulltext` 索引主要作为后续优化预留。Neo4j 全文索引是独立的全文检索能力，不会被 CONTAINS 自动复用。若后续要利用全文索引，需同步改造 `search_matters()` 查询实现。

---

## Step 5: 添加事项查询方法

**文件**: `backend/app/core/graph_query_service.py`

### 5.1 `search_matters(query, limit=20) -> list[dict]`

CONTAINS 搜索 Matter，返回 matter_id/name/description/matter_type/status/sample_doc_ids。
每条结果必须包含稳定的 `matter_id`，前端通过该字段跳转事项详情与 requirements 接口，不再以 name 作为详情访问标识。
**排序**：搜索结果默认按 name 升序返回，确保接口稳定。

### 5.2 `get_matter_card(matter_id) -> dict | None`

**采用分查询组合**（不用单个超级大查询）：
- 查 Matter 基本信息
- 查 conditions (HAS_CONDITION)
- 查 materials (REQUIRES_MATERIAL)
- 查 time_limits (HAS_TIME_LIMIT)
- 查 target_groups (APPLIES_TO_TARGET)
- 查 handled_by (HANDLED_BY)
- 查 governing_docs (GOVERNS ← Document) — **默认排除 is_placeholder = true 的占位文档**，优先展示状态为"有效/部分失效"的文件，按 publish_date DESC 排序，无日期时按 title 排序
- 查 regions (APPLIES_TO_REGION)

找不到 matter_id → 返回 None（API 层映射 404）。

### Matter.status 枚举

沿用 Document.status 枚举体系：`有效/部分失效/已废止/失效/待确认`。当前阶段建议枚举但不严格校验（LLM 抽取结果可能不含 status），后续可在 `_validate_doc_enum` 类似机制中扩展 Matter 枚举校验。

### 5.3 `get_matter_requirements(matter_id) -> dict | None`

聚焦 conditions + materials + time_limits。
找不到 → 返回 None（API 层映射 404）。
**排序策略**：在无显式顺序字段时，conditions/materials/time_limits 默认按 name 排序返回，确保接口结果稳定。

---

## Step 6: 添加事项 API 端点

**文件**: `backend/app/api/v1/graph.py`

### 6.1 Pydantic 模型

所有子维度使用明确模型（ConditionItem, MaterialItem, TimeLimitItem, TargetGroupItem, OrganizationItem, RegionItem, GoverningDocItem），不用裸 `list[dict]`。
MatterListItem, MatterCardResponse, MatterRequirementsResponse 均含 `matter_id` 字段。

### 6.2 端点

```
GET /api/v1/graph/matters?query=...&limit=20   → list[MatterListItem]
GET /api/v1/graph/matters/{matter_id}           → MatterCardResponse (404 if not found)
GET /api/v1/graph/matters/{matter_id}/requirements → MatterRequirementsResponse (404 if not found)
```

所有端点需 auth。搜索空结果 → 200 + []。详情/requirements 找不到 → 404。
所有事项相关 API 响应均使用明确的 Pydantic BaseModel 子模型定义，以确保响应结构稳定、Swagger 文档清晰、前后端联调一致。

---

## Step 7: 测试

### 7.1 新建 `tests/test_phase1_unit.py`

- Schema 激活：phase_1 后 entity_type_names 含 5 种新实体，rel_type_names 含 7 种新关系
- Prompt 生成：Phase 1 激活时包含 Matter 粒度规则、防幻觉规则
- `_generate_entity_id()` 确定性 + 基于归一化 name
- `_AUTO_ID_FIELDS` 包含 Matter/Condition/Material/TimeLimit/TargetGroup
- **相同名称不同类型不冲突**：同名 Matter 和 TargetGroup 生成的 `*_id` 前缀不同（`matter_xxx` vs `targetgroup_xxx`）
- **未显式地域约束时不生成 Matter→Region**：输入仅 Document 层有 Region、Matter 层无显式地域限制的样本，验证 Document→Region 存在但 Matter→Region 不存在

### 7.2 更新 `tests/test_api_graph.py`

- TestMatterSearch：200/auth 401/空结果 []
- TestMatterCard：200/不存在 404/**返回体中 matter_id 与路径参数一致**
- TestMatterRequirements：200/不存在 404/**返回体中 matter_id 与路径参数一致**

### 7.3 更新现有测试

修正因启用 phase_1 导致的断言变化（如 entity_type_names 数量增加）。

---

## 关键文件清单

| 文件 | 操作 |
|------|------|
| `backend/app/config/graph_schema.yaml` | 修改 |
| `backend/app/prompts/entity_extraction.py` | 修改 |
| `backend/app/core/graph_builder.py` | 修改 |
| `backend/app/infrastructure/neo4j_client.py` | 修改 |
| `backend/app/core/graph_query_service.py` | 修改 |
| `backend/app/api/v1/graph.py` | 修改 |
| `backend/tests/test_phase1_unit.py` | 新建 |
| `backend/tests/test_api_graph.py` | 修改 |

---

## 验证方案

1. 单元测试：`pytest tests/test_phase1_unit.py tests/test_graph_builder_unit.py tests/test_graph_schema_unit.py tests/test_neo4j_enum_unit.py -v`
2. 集成测试：`pytest tests/test_api_graph.py -v --base-url http://localhost:8900`
3. 手动验证：Swagger UI 访问 3 个 /graph/matters 端点

---

# ↓↓↓ 以下为原始 PRD 参考文档 ↓↓↓

# 公文知识图谱优化与应用落地方案

## 1. 文档目标

本文档用于对当前"公文文件检索系统"的知识图谱建设方案进行正式收敛，形成一版**可执行、可分阶段落地、适合全量重建**的技术方案。

系统背景：

- 检索底座：OpenSearch 混合检索
- 问答模式：RAG
- 图谱底座：Neo4j GraphRAG
- 数据来源：公文全文、元数据、chunk
- 图谱更新方式：**清除旧数据后全量重建**
- 抽取约束：**单轮 LLM 抽取**
- Schema 管理方式：**配置文件驱动**
- 当前图谱现状：7 种节点 + 11 种关系，以 `Document` 为中心的星型结构

本文档在保留原方案总体方向的基础上，对以下方面进行优化：

1. 收缩低价值节点，降低 schema 污染风险
2. 明确节点边界，避免 `Subject / Keyword / Matter / PolicyTheme` 混淆
3. 调整抽取策略，避免对单轮 LLM 能力过度乐观
4. 优化应用场景优先级，优先建设最有业务价值的能力
5. 将图谱建设分为"治理图 → 事项图 → 条款图"三阶段推进

---

## 2. 方案结论摘要

### 2.1 总体建设路线

1. **Phase 0：治理图增强** — 文件依据、修订、废止、适用地域、主题归属、文档有效性
2. **Phase 1：事项图增强** — 事项、条件、材料、时限、适用对象、办理部门
3. **Phase 2：条款图增强** — 条款级证据定位、可解释问答、精细化治理分析

### 2.2 核心设计取舍

以下对象**不作为核心图节点**：

- `DocCategory` → 改为 `Document.doc_type` 属性
- `Subject` → 改为 `Document.subject_summary` 属性
- `Keyword` → 改为 `Document.keywords[]` 属性
- `Person` → 降级为可选域特化实体，默认不纳入主 schema

### 2.3 核心建模原则

- 图谱核心以 `Document / Organization / Region / PolicyTheme / Matter / Article` 为主
- 价值重点不在"实体多"，而在"治理关系准、事项关系准、条款证据可回链"
- 所有结构化结论原则上要能回链到原始 Document → Article → Chunk
- `Article` 采用**规则切分条款 + LLM 补充条款语义**

### 2.4 优先落地应用能力

1. 文档推荐与依据链/修订链
2. 对话增强问答
3. 事项知识卡与办事问答
4. 治理型分析接口
5. 主题地图
6. Research 专题研究

---

## 3. 设计原则

### 3.1 以业务价值驱动 schema
判断某类对象是否建模为节点，看是否支撑核心查询、支撑稳定关系、适合图遍历、值得维护归一化。

### 3.2 属性优先于弱节点
弱结构、低稳定性、低遍历价值的数据优先作为属性：文种、关键词、文件主旨摘要、发布/生效/失效日期。

### 3.3 强关系优先于弱标签
优先建设：BASED_ON, AMENDS, REPEALS, ISSUED_BY, APPLIES_TO_REGION, GOVERNS, REQUIRES_MATERIAL, HAS_CONDITION, HAS_TIME_LIMIT

### 3.4 图谱必须支持证据回链
每个结构化关系应尽量追踪到：来源文档、来源条款、来源chunk、证据文本、抽取置信度。

### 3.5 分阶段建设
不追求一步到位的大而全 schema，按阶段控制复杂度。

---

## 4. Phase 0：治理图

### 4.1 目标
支持文件依据链、修订/废止历史、同主题推荐、地域适用性、文件有效性判断辅助。

### 4.2 核心节点

#### `Document`
属性：doc_id, title, normalized_title, doc_code, doc_type, status, publish_date, effective_date, expiry_date, admin_level, subject_summary, keywords[], knowledge_category, knowledge_category_code, source, full_text_url, is_current, created_at, updated_at

**knowledge_category 说明**：上传时指定的文档管理分类，作为 Document 属性存储（非独立节点）。

| 分类名称 | 编码 |
|----------|------|
| 国家/省领导讲话 | leader_speech_national_provincial |
| 市领导讲话稿 | leader_speech_city |
| 政策与法规 | policy_regulation |
| 报道材料 | news_report |
| 全会报告与规划 | plenary_report_planning |
| 政府工作报告 | government_work_report |
| 各单位公文 | official_document |
| 清远本地知识 | local_knowledge_qingyuan |
| 经济数据 | economic_data |
| 档案资料 | archive_material |

**与 doc_type / PolicyTheme 的边界**：
- `knowledge_category`：文档属于哪类资料（管理分类）
- `doc_type`：文档是什么文种（通知/决定/批复等）
- `PolicyTheme`：文档讲的是什么主题（营商环境/数字政府等）

三者不可互相替代，同一份文件可同时具备三者。

**ES 中的检索应用**：根据问题意图对 knowledge_category 做召回加权：
- 政策依据类问题 → 优先 policy_regulation
- 领导讲话类问题 → 优先 leader_speech_*
- 数据类问题 → 优先 economic_data
- 地方知识类问题 → 优先 local_knowledge_qingyuan

**升级为图节点的判定标准**：仅在需要分类导航页、分类层级树、分类与主题/事项显式关系分析时考虑。当前属性存储即可满足需求。

#### `Organization`
属性：org_id, name, normalized_name, short_name, org_type, admin_level, aliases[], region_code

#### `Region`
属性：region_id, name, full_name, region_code, region_level, parent_region_code, aliases[]

#### `PolicyTheme`
属性：theme_id, name, description, keywords[], parent_theme_id

### 4.3 核心关系

- `(:Document)-[:ISSUED_BY]->(:Organization)`
- `(:Document)-[:APPLIES_TO_REGION]->(:Region)`
- `(:Document)-[:BELONGS_TO_THEME]->(:PolicyTheme)`
- `(:Document)-[:BASED_ON]->(:Document)` — 依据上位文件
- `(:Document)-[:AMENDS]->(:Document)` — 修订
- `(:Document)-[:REPEALS]->(:Document)` — 废止
- `(:Document)-[:REFERENCES]->(:Document)` — 兜底引用关系

### 4.4 不进入主图的对象
- `DocCategory` → `Document.doc_type`
- `Subject` → `Document.subject_summary`
- `Keyword` → `Document.keywords[]`
- `Person` → 暂不纳入默认 schema

---

## 5. Phase 1：事项图

### 5.1 目标
支持办事问答、事项知识卡、结构化事项检索。

### 5.2 新增核心节点

#### `Matter`
属性：matter_id, name, normalized_name, matter_type, description, aliases[], status
示例：政府采购供应商资格审查、建设用地审批、差旅报销、档案归档

#### `Condition`
属性：condition_id, name, description, condition_type, structured_value, operator

#### `Material`
属性：material_id, name, normalized_name, material_type, description, is_required, format_requirement

#### `TimeLimit`
属性：time_limit_id, name, duration, unit, context, time_type

#### `TargetGroup`
属性：target_group_id, name, normalized_name, group_type, description, aliases[]
示例：企业法人、中小企业、事业单位、机关单位、申请人、供应商

### 5.3 核心关系

- `(:Document)-[:GOVERNS]->(:Matter)`
- `(:Matter)-[:HAS_CONDITION]->(:Condition)`
- `(:Matter)-[:REQUIRES_MATERIAL]->(:Material)`
- `(:Matter)-[:HAS_TIME_LIMIT]->(:TimeLimit)`
- `(:Matter)-[:APPLIES_TO_TARGET]->(:TargetGroup)`
- `(:Matter)-[:HANDLED_BY]->(:Organization)`
- `(:Matter)-[:APPLIES_TO_REGION]->(:Region)`

---

## 6. Phase 2：条款图

### 6.1 目标
支持条款级证据定位、可解释问答、精细化治理分析。

### 6.2 新增核心节点

#### `Article`
属性：article_id, article_number, title, content, order, norm_type, anchor, created_at, updated_at

`norm_type` 枚举：定义/要求/禁止/许可/程序/处罚/附则

### 6.3 生成策略

**Step 1：规则切分** — 基于"第X条"结构识别条款边界，输出 article_number, content, order

**Step 2：LLM 语义补充** — 对已切分条款标注 norm_type、条款标题、关联事项/条件/材料/时限/部门

### 6.4 核心关系

- `(:Document)-[:HAS_ARTICLE]->(:Article)`
- `(:Article)-[:GOVERNS]->(:Matter)`
- `(:Article)-[:SETS_CONDITION]->(:Condition)`
- `(:Article)-[:REQUIRES_MATERIAL]->(:Material)`
- `(:Article)-[:SETS_TIME_LIMIT]->(:TimeLimit)`
- `(:Article)-[:ASSIGNS_TO]->(:Organization)`

---

## 7. 配置驱动 Schema 设计

### 7.1 设计目标
将类型定义、关系定义、归一化规则统一配置化，支持 schema 低成本增减、提示词自动生成、Neo4j 类型校验、前端显示配置统一。

### 7.2 新建文件
- `backend/app/config/graph_schema.yaml` — 完整 Schema 配置
- `backend/app/core/graph_schema_loader.py` — YAML 加载器

### 7.3 配置结构

```yaml
entity_types:
  - name: Organization
    description: "政府机关、主管部门、责任部门"
    icon: bank
    color: "#52c41a"
    allow_as_node: true
    extraction_mode: llm
    key_property: name
  # ... 其他类型

relationship_types:
  - name: ISSUED_BY
    source_labels: [Document]
    target_labels: [Organization]
    description: "文件由某机构发布"
  # ... 其他关系

normalization_rules:
  Organization:
    strip_punctuation: true
    trim_whitespace: true
  PolicyTheme:
    strip_punctuation: true
    max_length: 30
  # ... 其他规则
```

### 7.4 `graph_schema_loader.py` 要求
提供接口：load_graph_schema(), get_entity_types(), get_relationship_types(), get_normalization_rules()
支持：内存缓存、配置合法性校验、启动时自动加载、缺失时清晰报错

### 7.5 改造文件
- `backend/app/core/graph_admin_service.py` — 默认类型从配置加载
- `backend/app/core/graph_builder.py` — 归一化逻辑配置驱动
- `backend/app/infrastructure/neo4j_client.py` — 标签/关系从配置加载
- `backend/app/prompts/entity_extraction.py` — 提示词按 schema 自动构建

---

## 8. 抽取策略设计

### 8.1 Phase 0 单轮 LLM 抽取
Organization, Region, PolicyTheme + BASED_ON/AMENDS/REPEALS/REFERENCES
文档属性从元数据直接获取。

### 8.2 Phase 1 单轮 LLM 抽取
在 Phase 0 基础上增加：Matter, Condition, Material, TimeLimit, TargetGroup + GOVERNS/HAS_CONDITION/REQUIRES_MATERIAL/HAS_TIME_LIMIT/APPLIES_TO_TARGET/HANDLED_BY

### 8.3 Phase 2 条款抽取
规则切分条款边界，LLM 仅做语义补标（norm_type、关联实体）。

### 8.4 组织层级关系
SUBORDINATE_TO / LOCATED_IN 保留为增强关系，不作为当前阶段主建设目标。来源优先级：组织主数据 > 行政区划字典 > 文档抽取补充。

---

## 9. 应用场景落地方案

### 9.1 场景 A：文档详情推荐与治理链（Phase 0 后最高优先级）

**新增方法** (`graph_query_service.py`):
- `get_document_recommendations(doc_id)`
- `get_policy_chain(doc_id)`
- `get_revision_history(doc_id)`
- `get_same_theme_documents(doc_id)`

**新增 API**:
- `GET /api/v1/document/{doc_id}/recommendations`
- `GET /api/v1/document/{doc_id}/policy-chain`
- `GET /api/v1/document/{doc_id}/revision-history`

### 9.2 场景 B：对话增强问答（第二优先级）

轻量固定模板的图谱查询规划，不做通用 Cypher 自动生成。

```
用户提问 → LLM 提取问题类型 + 关键实体 → 图谱查询模板匹配 → 执行 Cypher → 合并 ES 结果 → LLM 生成答案
```

**新增文件**: `graph_query_planner.py`, `prompts/query_planning.py`
**修改文件**: `research_engine.py`, `prompts/research_prompts.py`

### 9.3 场景 C：事项知识卡与办事问答（Phase 1 后）

围绕 Matter 构建结构化知识卡：事项名称、适用对象、办理部门、办理条件、所需材料、办理时限、适用地域、依据文件。

**新增 API**: `GET /api/v1/matters`, `GET /api/v1/matters/{name}`, `GET /api/v1/matters/{name}/requirements`

### 9.4 场景 D：治理型分析接口（Phase 1 后）

优先建设：
1. 失效引用检测
2. 主题时间线
3. 部门发文统计
4. 依据链覆盖分析

**新增文件**: `graph_analytics_service.py`
**新增 API**: `GET /api/v1/analytics/org/{name}`, `GET /api/v1/analytics/theme/{name}`, `GET /api/v1/analytics/invalid-references`, `GET /api/v1/analytics/theme-timeline/{name}`

后置能力（不作为首批交付）：全局 PageRank、overview 大屏、地区复杂对比、跨层级传播评分

### 9.5 场景 E：主题地图（事项图稳定后）

构建 PolicyTheme → Matter → Document 层级导航结构。

**新增 API**: `GET /api/v1/topics`, `GET /api/v1/topics/{theme_name}`

### 9.6 场景 F：Research 专题研究（最后建设）

依赖治理关系准确 + 事项结构完整 + 条款回链稳定。基于主题图与事项图组织专题研究报告。

**新增文件**: `topic_research_engine.py`, `prompts/topic_research.py`
**新增 API**: `POST /api/v1/research/topic`

---

## 10. 实施计划

```
Step 1: 配置文件外部化 (graph_schema.yaml + loader)
  ↓
Step 2: Phase 0 治理图建设
  ↓ 全量重建 + 验证
Step 3: 文档推荐 / 依据链 / 修订链 (场景A)
  ↓
Step 4: 对话增强轻量版 (场景B)
  ↓
Step 5: Phase 1 事项图建设
  ↓ 全量重建 + 验证
Step 6: 事项知识卡 / 办事问答 (场景C)
  ↓
Step 7: 治理型分析接口 (场景D)
  ↓
Step 8: Phase 2 条款图建设
  ↓ 全量重建 + 验证
Step 9: 主题地图 (场景E)
  ↓
Step 10: Research 专题研究 (场景F)
```

---

## 11. 关键文件清单

| 文件 | 操作 | 涉及步骤 |
|------|------|---------|
| `backend/app/config/graph_schema.yaml` | 新建 | Step 1 |
| `backend/app/core/graph_schema_loader.py` | 新建 | Step 1 |
| `backend/app/core/graph_admin_service.py` | 修改 | Step 1-2, 5, 8 |
| `backend/app/core/graph_builder.py` | 修改 | Step 1-2, 5, 8 |
| `backend/app/infrastructure/neo4j_client.py` | 修改 | Step 1-2, 5, 8 |
| `backend/app/prompts/entity_extraction.py` | 修改 | Step 2, 5, 8 |
| `backend/app/core/graph_query_service.py` | 扩展 | Step 3, 6, 9 |
| `backend/app/core/graph_query_planner.py` | 新建 | Step 4 |
| `backend/app/core/research_engine.py` | 修改 | Step 4, 10 |
| `backend/app/prompts/query_planning.py` | 新建 | Step 4 |
| `backend/app/core/graph_analytics_service.py` | 新建 | Step 7 |
| `backend/app/api/v1/analytics.py` | 新建 | Step 7 |
| `backend/app/api/v1/topics.py` | 新建 | Step 9 |
| `backend/app/core/topic_research_engine.py` | 新建 | Step 10 |
| `backend/app/prompts/topic_research.py` | 新建 | Step 10 |

---

## 12. 验证方案

### Phase 0 验证
- Document 是否具有 status/effective_date/expiry_date
- BASED_ON/AMENDS/REPEALS 关系是否存在
- 依据链查询、同主题推荐是否正常

### Phase 1 验证
- Matter/Condition/Material/TimeLimit/TargetGroup 是否写入成功
- 事项知识卡结果是否结构完整

### Phase 2 验证
- Article 切分是否正确
- 条款是否可回链到事项/条件/材料/时限

### 端到端问答测试
治理类："这份文件依据什么？""是否已被废止？""当前有效版本？"
事项类："XX事项需要哪些材料？""办理时限？""哪个部门负责？"
条款类："依据哪一条？""哪条规定了这一要求？"

---

## 13. 风险与应对

| 风险 | 应对 |
|------|------|
| 单轮抽取质量 | 严格控制每阶段启用的实体与关系数量 |
| 归一化污染 | 配置规则 + 核心实体人工抽样校验 |
| 条款切分误差 | 先覆盖标准"第X条"格式；非标准允许不生成条款图 |
| 图谱复杂度膨胀 | 每阶段只引入明确服务于应用场景的节点与关系 |
| 分析结果可解释性 | 优先建设可解释的治理分析，不先上复杂评分模型 |

---

## 14. 数据重建策略

每阶段完成后：更新 graph_schema.yaml → 重启服务 → 清除旧图谱 → POST /admin/graph/rebuild-all → Cypher 验证 → API 验证

重建注意事项：文档主键规则必须稳定、归一化规则重建前冻结、新属性与关系同步更新写库逻辑、重建期间建议禁用外部图查询接口。

---

## 15. 补充：knowledge_category 落地要点

### 15.1 上传流程改造
- 文件上传接口增加 knowledge_category 字段校验
- 分类编码映射（中文名 → code）
- 非法分类拦截 + 默认值处理

### 15.2 ES 写入
- 文档索引写入时同步写入 knowledge_category / knowledge_category_code
- 配置为 keyword 类型，支持精确过滤和聚合

### 15.3 Neo4j 写入
- Document 节点 merge 时同步写入 knowledge_category / knowledge_category_code 属性

### 15.4 检索层改造
- 在 graph_query_planner 或关键词抽取后处理阶段，根据问题类型对 knowledge_category 做召回加权和过滤
- 搜索结果支持按 knowledge_category 分组展示和聚合统计

### 15.5 涉及文件
- `backend/app/core/graph_builder.py`: merge 时传递分类属性
- `backend/app/infrastructure/neo4j_client.py`: doc_props 添加分类字段
- `backend/app/core/ingest_pipeline.py`: 上传时分类校验和编码映射
- ES 索引 mapping: 添加 knowledge_category 字段
