# 3. 字段抽取与统一字段池详细设计

## 1. 设计目标

本步骤承接“资料包导入与目录汇总”和“法规完整性检查”的输出，目标是从说明书、申请表、产品列表、声明类文件等注册申报资料中抽取产品核心字段，形成可复用、可追溯、可回填、可一致性核查的统一字段池。

本步骤需要完成以下业务结果：

1. 明确本轮字段抽取的资料范围和目标字段范围。
2. 加载注册申报通用字段 schema。
3. 按字段来源优先级选择候选文档。
4. 对固定格式、标题段落、表格字段执行规则抽取。
5. 对长文本字段使用 LLM 辅助归纳。
6. 对字段值进行标准化、去噪和来源绑定。
7. 将字段结果写入统一字段池。
8. 标记字段置信度、冲突状态和待人工确认状态。
9. 输出结构化 `registration_field_extraction_report`。

本步骤不负责最终一致性判定，不负责 Word 文件生成。字段池会为后续“一致性核查”和“Word 回填导出”提供输入。

## 2. 所属模块与边界

### 2.1 Documents

`apps.documents` 提供文档主数据、正文文本、标题结构、表格结构和处理状态。

本步骤读取：

1. 文档 ID。
2. 文件名和相对路径。
3. 章节点。
4. 文档角色。
5. 正文文本。
6. 表格结构。
7. 文档处理状态。
8. 是否待人工复核。

如果某文档尚未完成文本或表格抽取，本步骤应给出业务提示，而不是默认字段缺失。

### 2.2 Agent Core

`agent_core` 是本步骤的执行主体，负责编排字段 schema 加载、抽取范围确认、规则抽取、表格抽取、LLM 归纳、字段标准化、字段池写入和报告生成。

本步骤建议产生以下中文 Skill：

1. `字段抽取编排Skill`
2. `字段抽取范围确认Skill`
3. `字段Schema加载Skill`
4. `规则字段抽取Skill`
5. `表格字段抽取Skill`
6. `长文本字段归纳Skill`
7. `字段标准化Skill`
8. `统一字段池写入Skill`
9. `字段抽取报告生成Skill`

### 2.3 LLM Provider

LLM 只用于长文本归纳和无法通过规则稳定提取的字段。

LLM 可以处理：

1. 适用范围 / 预期用途归纳。
2. 性能指标摘要。
3. 储存条件段落归纳。
4. 检测靶标从说明书长段落中提取。

LLM 不应处理：

1. 明确表格字段的直接读取。
2. 申请表中固定字段的直接抽取。
3. 字段冲突最终裁判。
4. 没有来源证据的字段编造。

所有 LLM 调用必须经过 Provider，并支持 Mock Provider 离线测试。

### 2.4 RAG

RAG 在本步骤中只作为来源片段定位能力使用。

可用于：

1. 从长文档中定位字段候选段落。
2. 为 LLM 归纳提供限定上下文。
3. 为字段来源证据提供片段引用。

RAG 不负责最终字段值裁判。

### 2.5 Audit

`apps.audit` 记录字段抽取任务的执行范围、目标字段、抽取结果、来源证据、LLM 使用情况和失败原因。

审计中必须保留：

1. `batch_id`
2. `scenario_id`
3. `selected_document_ids`
4. `field_schema_version`
5. `extracted_fields`
6. `manual_review_fields`
7. `llm_provider_name`
8. `tool_calls`
9. `evidence_refs`

## 3. 输入输出

### 3.1 输入

```json
{
  "batch_id": 1001,
  "scenario_id": "registration_field_extraction",
  "field_schema_id": "ivd_registration_fields_v1",
  "selected_document_ids": [11, 12, 13],
  "target_field_keys": [
    "product_name",
    "detection_target",
    "intended_use",
    "storage_condition",
    "performance_index"
  ],
  "enable_llm_fallback": true,
  "enable_rag_context": true
}
```

### 3.2 输出

本步骤输出 `registration_field_extraction_report`：

```json
{
  "report_type": "registration_field_extraction_report",
  "batch_id": 1001,
  "field_schema_id": "ivd_registration_fields_v1",
  "field_schema_version": "2026-06-03",
  "summary": {
    "target_field_count": 5,
    "extracted_field_count": 4,
    "manual_review_field_count": 1,
    "conflict_candidate_count": 1,
    "field_pool_status": "partial_completed"
  },
  "field_pool_items": [],
  "manual_review_fields": [],
  "evidence_refs": [],
  "tool_calls": []
}
```

### 3.3 字段池条目结构

```json
{
  "field_key": "product_name",
  "field_label": "产品名称",
  "standard_value": "新型冠状病毒 2019-nCoV 核酸检测试剂盒",
  "raw_value": "新型冠状病毒2019-nCoV核酸检测试剂盒",
  "source_document_id": 11,
  "source_document_name": "目标产品说明书.docx",
  "source_location": {
    "chapter_title": "一、产品名称",
    "table_index": null,
    "page_no": null
  },
  "extract_method": "rule_heading",
  "confidence": "high",
  "conflict_status": "not_checked",
  "manual_review_required": false,
  "fillable": true
}
```

## 4. 主工作流

```text
用户发起字段抽取任务
-> 读取资料包和完整性检查上下文
-> 确认抽取文档范围
-> 加载字段 schema
-> 加载字段来源优先级
-> 读取文档文本和表格结构
-> 执行规则字段抽取
-> 执行表格字段抽取
-> 对长文本字段执行 RAG 定位与 LLM 归纳
-> 标准化字段值
-> 绑定字段来源证据
-> 写入统一字段池
-> 生成字段抽取报告
-> 写入审计留痕
-> 返回字段池视图
```

## 5. 节点详细设计

### 5.1 节点一：抽取任务上下文加载

业务功能：

1. 读取资料包批次。
2. 读取第一步目录汇总。
3. 读取第二步完整性检查报告。
4. 获取命中的申请表、产品列表、说明书等候选文档。
5. 确认当前资料是否满足字段抽取前置条件。

使用技术：

1. Django ORM
2. JSONField 报告快照
3. dataclass/Pydantic schema

产生方法：

1. `load_field_extraction_context(batch_id, scenario_id) -> FieldExtractionContext`
2. `load_candidate_documents(context, selected_document_ids) -> list[DocumentFact]`
3. `validate_extraction_prerequisites(context) -> ExtractionPrerequisiteResult`

对应 Skill：

1. `字段抽取编排Skill`

### 5.2 节点二：字段抽取范围确认

业务功能：

1. 确认参与字段抽取的文档范围。
2. 按文档角色筛选候选资料。
3. 排除法规资料和待处理失败资料。
4. 对待人工复核文档保留可用但低可信状态。

默认候选来源：

1. 申请表。
2. 产品说明书。
3. 产品列表。
4. 声明类文件。
5. 历史沟通说明。

使用技术：

1. 文档角色规则
2. 来源优先级 YAML
3. 文档状态过滤

产生方法：

1. `resolve_extraction_scope(documents, selected_document_ids, target_field_keys) -> ExtractionScope`
2. `filter_extractable_documents(documents) -> list[DocumentFact]`
3. `rank_documents_by_field_source(field_key, documents) -> list[DocumentFact]`

对应 Skill：

1. `字段抽取范围确认Skill`

### 5.3 节点三：字段 Schema 加载

业务功能：

1. 加载注册申报字段 schema。
2. 确认目标字段、字段类型、来源优先级、抽取方式和回填属性。
3. 为后续 Word 回填建立字段映射基础。

建议 schema 目录：

```text
configs/registration/fields/
  ivd_registration_fields_v1.yaml
```

字段 schema 示例：

```yaml
field_schema_id: ivd_registration_fields_v1
version: "2026-06-03"
fields:
  - field_key: product_name
    field_label: 产品名称
    value_type: text
    fillable: true
    consistency_required: true
    source_priority:
      - application_form
      - product_instruction
      - product_list
    extraction_methods:
      - rule_heading
      - table_cell
```

使用技术：

1. YAML
2. Pydantic schema
3. Django cache

产生方法：

1. `load_field_schema(field_schema_id) -> FieldSchema`
2. `validate_field_schema(schema) -> FieldSchemaValidationResult`
3. `select_target_fields(schema, target_field_keys) -> list[FieldDefinition]`

对应 Skill：

1. `字段Schema加载Skill`

### 5.4 节点四：规则字段抽取

业务功能：

1. 从标题、段落、固定标签中提取字段。
2. 优先处理产品名称、申请人名称、储存条件等明确字段。
3. 记录抽取方法和来源片段。

适用字段：

1. 产品名称。
2. 申请人名称。
3. 包装规格。
4. 储存条件。
5. 申报日期。

使用技术：

1. 正则表达式
2. 标题层级解析
3. 标签后取值规则
4. 中文标点标准化

产生方法：

1. `extract_fields_by_rules(document, field_definitions) -> list[FieldCandidate]`
2. `extract_by_heading(text_structure, field_definition) -> FieldCandidate | None`
3. `extract_by_label(text, labels) -> FieldCandidate | None`
4. `build_source_location(document, match) -> SourceLocation`

对应 Skill：

1. `规则字段抽取Skill`

### 5.5 节点五：表格字段抽取

业务功能：

1. 从申请表、产品列表、标准清单等表格中提取字段。
2. 识别表头和字段标签。
3. 抽取规格型号、分类编码、标准清单等结构化字段。

适用字段：

1. 产品名称。
2. 包装规格。
3. 分类编码。
4. 申请人名称。
5. 生产地址。
6. 标准清单。

使用技术：

1. `python-docx` 表格解析
2. PDF 表格解析可选 `pdfplumber`
3. 表头标准化
4. 单元格坐标记录

产生方法：

1. `extract_fields_from_tables(document, field_definitions) -> list[FieldCandidate]`
2. `normalize_table_headers(table) -> NormalizedTable`
3. `match_table_field(table, field_definition) -> FieldCandidate | None`
4. `build_table_source_location(table_index, row_index, col_index) -> SourceLocation`

对应 Skill：

1. `表格字段抽取Skill`

### 5.6 节点六：长文本字段归纳

业务功能：

1. 对规则和表格无法稳定抽取的长文本字段进行归纳。
2. 先用 RAG 或关键词定位候选片段。
3. 将有限上下文交给 LLM Provider。
4. 要求 LLM 返回结构化字段值和引用片段。

适用字段：

1. 检测靶标。
2. 适用范围 / 预期用途。
3. 性能指标。
4. 临床评价路径。

使用技术：

1. RAG fallback / Chroma
2. LLM Provider
3. JSON schema 输出约束
4. Mock Provider 测试

产生方法：

1. `locate_field_context(document, field_definition) -> list[EvidenceChunk]`
2. `summarize_long_text_field(field_definition, chunks) -> FieldCandidate`
3. `call_llm_for_field_extraction(prompt, schema) -> dict`
4. `validate_llm_field_output(output) -> FieldCandidate`

对应 Skill：

1. `长文本字段归纳Skill`

### 5.7 节点七：字段标准化

业务功能：

1. 对抽取候选值做清洗和标准化。
2. 合并空格、全半角、中文标点差异。
3. 标准化单位、日期、枚举值。
4. 计算字段置信度。
5. 标记疑似冲突候选，但不做最终一致性裁判。

使用技术：

1. Python 字符串标准化
2. 字段类型规则
3. 日期解析
4. 单位标准化表

产生方法：

1. `normalize_field_candidate(candidate, field_definition) -> NormalizedFieldCandidate`
2. `normalize_text_value(value) -> str`
3. `normalize_date_value(value) -> str`
4. `calculate_field_confidence(candidate, source_priority) -> str`
5. `detect_conflict_candidates(candidates) -> list[ConflictCandidate]`

对应 Skill：

1. `字段标准化Skill`

### 5.8 节点八：统一字段池写入

业务功能：

1. 将字段候选写入统一字段池。
2. 按字段来源优先级选择推荐值。
3. 保留所有候选值和来源证据。
4. 标记字段是否可回填。
5. 标记字段是否需要一致性核查。

建议模型：

```python
class RegistrationFieldPoolItem(models.Model):
    batch = models.ForeignKey(SubmissionBatch, on_delete=models.CASCADE)
    field_key = models.CharField(max_length=128)
    field_label = models.CharField(max_length=255)
    standard_value = models.TextField(blank=True)
    raw_value = models.TextField(blank=True)
    source_document_id = models.IntegerField(null=True)
    source_location = models.JSONField(default=dict)
    extract_method = models.CharField(max_length=64)
    confidence = models.CharField(max_length=32)
    conflict_status = models.CharField(max_length=32, default="not_checked")
    manual_review_required = models.BooleanField(default=False)
    fillable = models.BooleanField(default=False)
```

使用技术：

1. Django ORM
2. JSONField
3. 批量写入
4. 字段池版本号

产生方法：

1. `write_field_pool(batch_id, normalized_candidates, field_schema) -> FieldPoolWriteResult`
2. `select_recommended_field_value(field_key, candidates, source_priority) -> FieldPoolItem`
3. `persist_field_candidates(field_pool_item, candidates) -> None`
4. `mark_manual_review_fields(field_pool_items) -> list[FieldPoolItem]`

对应 Skill：

1. `统一字段池写入Skill`

### 5.9 节点九：字段抽取报告生成

业务功能：

1. 汇总字段抽取结果。
2. 输出字段池表格。
3. 输出待人工复核字段。
4. 输出字段来源证据。
5. 生成页面展示和飞书摘要载荷。
6. 写入审计记录。

使用技术：

1. dataclass/Pydantic
2. JSONField
3. Audit 服务
4. 页面展示 schema

产生方法：

1. `build_field_extraction_report(context, field_pool_items) -> RegistrationFieldExtractionReport`
2. `build_field_pool_display_rows(field_pool_items) -> list[dict]`
3. `build_field_extraction_audit_payload(report) -> dict`
4. `record_field_extraction_audit(report, context) -> AuditLog`

对应 Skill：

1. `字段抽取报告生成Skill`

## 6. Skill 清单

本步骤产生以下 Skill 设计文档：

1. [字段抽取编排Skill](skill/字段抽取编排Skill.md)
2. [字段抽取范围确认Skill](skill/字段抽取范围确认Skill.md)
3. [字段Schema加载Skill](skill/字段Schema加载Skill.md)
4. [规则字段抽取Skill](skill/规则字段抽取Skill.md)
5. [表格字段抽取Skill](skill/表格字段抽取Skill.md)
6. [长文本字段归纳Skill](skill/长文本字段归纳Skill.md)
7. [字段标准化Skill](skill/字段标准化Skill.md)
8. [统一字段池写入Skill](skill/统一字段池写入Skill.md)
9. [字段抽取报告生成Skill](skill/字段抽取报告生成Skill.md)

## 7. 字段 Schema 设计

### 7.1 V1 目标字段

| 字段编码 | 中文名 | 是否回填 | 是否强一致 |
|---|---|---|---|
| `product_name` | 产品名称 | 是 | 是 |
| `detection_target` | 检测靶标 | 是 | 是 |
| `intended_use` | 适用范围 / 预期用途 | 是 | 是 |
| `storage_condition` | 储存条件 | 是 | 是 |
| `performance_index` | 性能指标 | 是 | 否 |
| `package_specification` | 包装规格 | 是 | 是 |
| `applicant_name` | 申请人名称 | 是 | 是 |
| `classification_code` | 分类编码 | 是 | 是 |

### 7.2 字段来源优先级

| 字段 | 来源优先级 |
|---|---|
| 产品名称 | 申请表 > 说明书 > 产品列表 |
| 检测靶标 | 说明书 > 产品列表 > 申请表 |
| 适用范围 | 说明书 > 申请表 |
| 储存条件 | 说明书 > 标签样稿 |
| 性能指标 | 说明书 > 性能研究资料 |
| 包装规格 | 产品列表 > 申请表 > 说明书 |

## 8. 页面展示

字段抽取结果页面建议展示：

1. 当前字段 schema 版本。
2. 抽取文档范围。
3. 字段总数。
4. 已抽取字段数。
5. 待人工复核字段数。
6. 字段池表格。
7. 字段来源证据。
8. 工具调用记录。
9. 审计入口。

字段池表格字段：

1. 字段名。
2. 推荐值。
3. 原始值。
4. 来源文档。
5. 来源位置。
6. 抽取方法。
7. 置信度。
8. 是否待人工复核。
9. 是否可回填。

## 9. 异常处理

1. 无可抽取文档：返回业务提示，不写空字段池。
2. 文档未完成文本抽取：标记前置条件不足。
3. 字段 schema 缺失：任务不可执行，写失败审计。
4. 表格解析失败：跳过表格抽取，保留规则抽取和 LLM 归纳。
5. LLM 不可用：仅输出规则和表格抽取结果。
6. LLM 输出非法 JSON：丢弃该候选并记录工具失败。
7. 多候选值不一致：写入候选值，字段状态标记 `conflict_candidate`。
8. 来源文档待复核：字段置信度不超过 `medium`。

## 10. 与后续步骤的接口

后续一致性核查读取：

1. `field_key`
2. `standard_value`
3. `raw_value`
4. `source_document_id`
5. `source_location`
6. `confidence`
7. `conflict_status`
8. `manual_review_required`

后续 Word 回填读取：

1. `field_key`
2. `standard_value`
3. `fillable`
4. `manual_review_required`
5. `conflict_status`
6. `template_field_refs`

## 11. 测试设计

### 11.1 单元测试

1. 字段 schema 加载成功。
2. 字段来源优先级排序正确。
3. 标题字段抽取正确。
4. 表格字段抽取正确。
5. LLM 输出 schema 校验正确。
6. 字段标准化正确。
7. 推荐值选择正确。

### 11.2 服务层测试

1. 基于说明书抽取产品名称。
2. 基于说明书抽取检测靶标。
3. 基于申请表抽取申请人名称。
4. 多来源候选写入字段池。
5. LLM 不可用时任务仍能完成部分结果。
6. 字段池报告写入审计。

### 11.3 页面测试

1. 页面展示字段池表格。
2. 页面展示字段来源文档。
3. 页面展示待人工复核字段。
4. 页面展示工具调用记录。
5. 页面展示审计入口。

## 12. V1 实现建议

V1 建议先完成以下最小闭环：

1. 建立字段 schema YAML。
2. 从 `目标产品说明书.docx` 抽取产品名称、检测靶标、适用范围、储存条件、性能指标。
3. 从 `CH1.4 申请表.docx` 和 `CH1.5 产品列表.docx` 抽取可比对字段。
4. 写入统一字段池。
5. 输出字段抽取报告。
6. 支持 Mock Provider 离线测试。

增强阶段再补齐：

1. 更多字段类型。
2. PDF 表格抽取。
3. OCR 兜底。
4. 后台人工修正字段池。
5. 字段池版本管理。

