From 4208f29d7799348fa4c2fa4359b9ca243c258bdb Mon Sep 17 00:00:00 2001 From: bruce Date: Wed, 3 Jun 2026 21:00:28 +0800 Subject: [PATCH] =?UTF-8?q?docs(=E8=AF=A6=E7=BB=86=E8=AE=BE=E8=AE=A1):=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AD=97=E6=AE=B5=E6=8A=BD=E5=8F=96=E4=B8=8E?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E6=B1=A0=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/详细设计/3.字段抽取与统一字段池.md | 658 +++++++++++++++++++ docs/详细设计/skill/字段Schema加载Skill.md | 75 +++ docs/详细设计/skill/字段抽取报告生成Skill.md | 89 +++ docs/详细设计/skill/字段抽取编排Skill.md | 114 ++++ docs/详细设计/skill/字段抽取范围确认Skill.md | 79 +++ docs/详细设计/skill/字段标准化Skill.md | 83 +++ docs/详细设计/skill/统一字段池写入Skill.md | 83 +++ docs/详细设计/skill/表格字段抽取Skill.md | 81 +++ docs/详细设计/skill/规则字段抽取Skill.md | 78 +++ docs/详细设计/skill/长文本字段归纳Skill.md | 83 +++ 10 files changed, 1423 insertions(+) create mode 100644 docs/详细设计/3.字段抽取与统一字段池.md create mode 100644 docs/详细设计/skill/字段Schema加载Skill.md create mode 100644 docs/详细设计/skill/字段抽取报告生成Skill.md create mode 100644 docs/详细设计/skill/字段抽取编排Skill.md create mode 100644 docs/详细设计/skill/字段抽取范围确认Skill.md create mode 100644 docs/详细设计/skill/字段标准化Skill.md create mode 100644 docs/详细设计/skill/统一字段池写入Skill.md create mode 100644 docs/详细设计/skill/表格字段抽取Skill.md create mode 100644 docs/详细设计/skill/规则字段抽取Skill.md create mode 100644 docs/详细设计/skill/长文本字段归纳Skill.md diff --git a/docs/详细设计/3.字段抽取与统一字段池.md b/docs/详细设计/3.字段抽取与统一字段池.md new file mode 100644 index 0000000..87be6ea --- /dev/null +++ b/docs/详细设计/3.字段抽取与统一字段池.md @@ -0,0 +1,658 @@ +# 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. 字段池版本管理。 + diff --git a/docs/详细设计/skill/字段Schema加载Skill.md b/docs/详细设计/skill/字段Schema加载Skill.md new file mode 100644 index 0000000..452f2e5 --- /dev/null +++ b/docs/详细设计/skill/字段Schema加载Skill.md @@ -0,0 +1,75 @@ +# 字段Schema加载Skill 设计 + +## 1. Skill 定位 + +`字段Schema加载Skill` 负责加载注册申报字段 schema,提供字段定义、来源优先级、抽取方式、回填属性和一致性要求。 + +英文实现标识建议使用 `FieldSchemaLoadSkill`。 + +## 2. 输入 + +```python +@dataclass +class FieldSchemaLoadInput: + field_schema_id: str + target_field_keys: list[str] = field(default_factory=list) +``` + +## 3. 输出 + +```python +@dataclass +class FieldSchemaLoadOutput: + field_schema_id: str + version: str + fields: list[FieldDefinition] + source_priority: dict + validation_warnings: list[dict] +``` + +## 4. 核心方法 + +### 4.1 `run(input) -> FieldSchemaLoadOutput` + +主入口方法。 + +### 4.2 `load_schema_file(field_schema_id) -> dict` + +从 YAML 读取字段 schema。 + +### 4.3 `validate_field_schema(raw_schema) -> FieldSchemaValidationResult` + +校验字段定义。 + +### 4.4 `select_target_fields(schema, target_field_keys) -> list[FieldDefinition]` + +筛选目标字段。 + +## 5. 技术实现 + +使用技术: + +1. `PyYAML` +2. Pydantic +3. Django cache + +建议路径: + +```text +configs/registration/fields/ivd_registration_fields_v1.yaml +``` + +## 6. 异常处理 + +1. schema 文件不存在:任务失败。 +2. 字段定义缺少 `field_key`:校验失败。 +3. 目标字段不存在:返回业务错误。 +4. 来源优先级缺失:允许执行,但记录警告。 + +## 7. 测试要点 + +1. schema 加载成功。 +2. 目标字段筛选正确。 +3. 缺少必填字段时报错。 +4. 来源优先级输出正确。 + diff --git a/docs/详细设计/skill/字段抽取报告生成Skill.md b/docs/详细设计/skill/字段抽取报告生成Skill.md new file mode 100644 index 0000000..c577230 --- /dev/null +++ b/docs/详细设计/skill/字段抽取报告生成Skill.md @@ -0,0 +1,89 @@ +# 字段抽取报告生成Skill 设计 + +## 1. Skill 定位 + +`字段抽取报告生成Skill` 负责将字段池写入结果组装成稳定的 `registration_field_extraction_report`,并生成页面展示、审计和飞书摘要所需的数据结构。 + +英文实现标识建议使用 `FieldExtractionReportBuildSkill`。 + +## 2. 输入 + +```python +@dataclass +class FieldExtractionReportBuildInput: + context: FieldExtractionContext + field_pool_items: list[FieldPoolItem] + manual_review_fields: list[dict] + tool_calls: list[dict] +``` + +## 3. 输出 + +```python +@dataclass +class FieldExtractionReportBuildOutput: + report: dict + display_sections: list[dict] + audit_payload: dict + feishu_summary_payload: dict +``` + +## 4. 报告结构 + +报告必须包含: + +1. `report_type` +2. `batch_id` +3. `field_schema_id` +4. `field_schema_version` +5. `summary` +6. `field_pool_items` +7. `manual_review_fields` +8. `evidence_refs` +9. `tool_calls` + +## 5. 核心方法 + +### 5.1 `run(input) -> FieldExtractionReportBuildOutput` + +主入口方法。 + +### 5.2 `build_summary(field_pool_items) -> dict` + +汇总字段数量、已抽取数量、待复核数量和冲突候选数量。 + +### 5.3 `build_field_rows(field_pool_items) -> list[dict]` + +生成字段池页面表格。 + +### 5.4 `build_audit_payload(report, context) -> dict` + +生成审计载荷。 + +### 5.5 `build_feishu_summary_payload(report) -> dict` + +生成飞书摘要载荷。 + +## 6. 技术实现 + +使用技术: + +1. dataclass/Pydantic +2. JSONField +3. Audit 服务 +4. 页面展示 schema + +## 7. 异常处理 + +1. 字段池为空:输出空报告并提示无可用字段。 +2. 报告字段缺失:任务失败。 +3. 审计写入失败:报告仍返回,但记录系统警告。 +4. 飞书摘要构建失败:不影响 Web 报告。 + +## 8. 测试要点 + +1. 输出 schema 稳定。 +2. 字段池行展示完整。 +3. 审计载荷包含字段 schema 版本。 +4. 飞书摘要不包含敏感信息。 + diff --git a/docs/详细设计/skill/字段抽取编排Skill.md b/docs/详细设计/skill/字段抽取编排Skill.md new file mode 100644 index 0000000..35d4371 --- /dev/null +++ b/docs/详细设计/skill/字段抽取编排Skill.md @@ -0,0 +1,114 @@ +# 字段抽取编排Skill 设计 + +## 1. Skill 定位 + +`字段抽取编排Skill` 是第三步工作流的总入口 Skill,负责组织字段抽取范围确认、字段 schema 加载、规则抽取、表格抽取、长文本归纳、字段标准化、统一字段池写入和报告生成。 + +英文实现标识建议使用 `FieldExtractionOrchestrateSkill`。 + +本 Skill 不直接完成每一种抽取细节,而是负责执行顺序和结果合并。 + +## 2. 输入 + +```python +@dataclass +class FieldExtractionOrchestrateInput: + batch_id: int + scenario_id: str = "registration_field_extraction" + field_schema_id: str = "ivd_registration_fields_v1" + selected_document_ids: list[int] = field(default_factory=list) + target_field_keys: list[str] = field(default_factory=list) + enable_llm_fallback: bool = True + enable_rag_context: bool = True +``` + +## 3. 输出 + +```python +@dataclass +class FieldExtractionOrchestrateOutput: + report_type: str + batch_id: int + field_schema_id: str + summary: dict + field_pool_items: list[dict] + manual_review_fields: list[dict] + evidence_refs: list[dict] + audit_id: int | None = None +``` + +## 4. 依赖 Skill + +1. `字段抽取范围确认Skill` +2. `字段Schema加载Skill` +3. `规则字段抽取Skill` +4. `表格字段抽取Skill` +5. `长文本字段归纳Skill` +6. `字段标准化Skill` +7. `统一字段池写入Skill` +8. `字段抽取报告生成Skill` + +## 5. 核心方法 + +### 5.1 `run(input) -> FieldExtractionOrchestrateOutput` + +主入口方法。 + +执行顺序: + +1. 加载执行上下文。 +2. 调用 `字段抽取范围确认Skill`。 +3. 调用 `字段Schema加载Skill`。 +4. 调用 `规则字段抽取Skill`。 +5. 调用 `表格字段抽取Skill`。 +6. 按需调用 `长文本字段归纳Skill`。 +7. 调用 `字段标准化Skill`。 +8. 调用 `统一字段池写入Skill`。 +9. 调用 `字段抽取报告生成Skill`。 +10. 写入审计记录。 + +### 5.2 `load_execution_context(input) -> FieldExtractionContext` + +加载批次、文档、完整性检查报告和已有字段池状态。 + +### 5.3 `merge_field_candidates(*candidate_groups) -> list[FieldCandidate]` + +合并规则抽取、表格抽取和长文本归纳结果。 + +### 5.4 `filter_target_fields(schema, target_field_keys) -> list[FieldDefinition]` + +筛选本次需要抽取的字段。 + +## 6. 技术实现 + +使用技术: + +1. Python dataclass 或 Pydantic +2. Tool Registry +3. LLM Provider +4. Django 服务层 +5. Audit 服务 + +建议注册名: + +```python +tool_registry.register( + name="field_extraction_orchestrate", + handler=FieldExtractionOrchestrateSkill().run, +) +``` + +## 7. 异常处理 + +1. 无可抽取文档:返回业务提示。 +2. 字段 schema 不存在:任务失败并写审计。 +3. LLM 不可用:跳过 LLM,保留规则和表格结果。 +4. 所有抽取方式均失败:返回待人工复核报告。 + +## 8. 测试要点 + +1. 能按顺序调用依赖 Skill。 +2. LLM 关闭时仍可执行规则抽取。 +3. 无文档时返回清晰错误。 +4. 输出报告结构稳定。 + diff --git a/docs/详细设计/skill/字段抽取范围确认Skill.md b/docs/详细设计/skill/字段抽取范围确认Skill.md new file mode 100644 index 0000000..cb6d29d --- /dev/null +++ b/docs/详细设计/skill/字段抽取范围确认Skill.md @@ -0,0 +1,79 @@ +# 字段抽取范围确认Skill 设计 + +## 1. Skill 定位 + +`字段抽取范围确认Skill` 负责确定本次字段抽取使用哪些文档,以及每个目标字段优先从哪些文档角色中抽取。 + +英文实现标识建议使用 `FieldExtractionScopeResolveSkill`。 + +## 2. 输入 + +```python +@dataclass +class FieldExtractionScopeResolveInput: + documents: list[DocumentFact] + selected_document_ids: list[int] + target_field_keys: list[str] + field_source_priority: dict +``` + +## 3. 输出 + +```python +@dataclass +class FieldExtractionScopeResolveOutput: + extractable_documents: list[DocumentFact] + excluded_documents: list[dict] + field_document_plan: dict[str, list[DocumentFact]] + warnings: list[dict] +``` + +## 4. 文档筛选规则 + +参与抽取的文档必须满足: + +1. `source_role = submission` +2. 文档处理状态可用。 +3. 文档存在文本或表格结构。 +4. 文档角色属于字段来源配置。 + +排除: + +1. 法规依据资料。 +2. 不支持文件。 +3. 解析失败且无可用文本。 +4. 用户未选择且不在默认来源范围内的文档。 + +## 5. 核心方法 + +### 5.1 `run(input) -> FieldExtractionScopeResolveOutput` + +主入口方法。 + +### 5.2 `filter_extractable_documents(documents) -> list[DocumentFact]` + +筛选可抽取文档。 + +### 5.3 `build_field_document_plan(fields, documents, priority) -> dict` + +为每个字段构建候选文档顺序。 + +### 5.4 `collect_scope_warnings(documents) -> list[dict]` + +收集待复核、解析失败、文本缺失等警告。 + +## 6. 技术实现 + +使用技术: + +1. 文档角色枚举 +2. YAML 来源优先级 +3. Python 排序规则 + +## 7. 测试要点 + +1. 法规资料被排除。 +2. 申请表、说明书、产品列表被纳入。 +3. 用户选择文档时只使用选中范围。 +4. 待复核文档会降低抽取可信度。 + diff --git a/docs/详细设计/skill/字段标准化Skill.md b/docs/详细设计/skill/字段标准化Skill.md new file mode 100644 index 0000000..cbcfde4 --- /dev/null +++ b/docs/详细设计/skill/字段标准化Skill.md @@ -0,0 +1,83 @@ +# 字段标准化Skill 设计 + +## 1. Skill 定位 + +`字段标准化Skill` 负责对字段候选值进行清洗、标准化、置信度计算和冲突候选标记。 + +英文实现标识建议使用 `FieldNormalizeSkill`。 + +## 2. 输入 + +```python +@dataclass +class FieldNormalizeInput: + candidates: list[FieldCandidate] + field_definitions: list[FieldDefinition] + source_priority: dict +``` + +## 3. 输出 + +```python +@dataclass +class FieldNormalizeOutput: + normalized_candidates: list[NormalizedFieldCandidate] + conflict_candidates: list[dict] + manual_review_candidates: list[dict] +``` + +## 4. 标准化规则 + +1. 去除首尾空白。 +2. 合并连续空白。 +3. 全角半角标准化。 +4. 中文标点标准化。 +5. 日期格式标准化。 +6. 单位格式标准化。 +7. 空值和异常长值标记待复核。 + +## 5. 核心方法 + +### 5.1 `run(input) -> FieldNormalizeOutput` + +主入口方法。 + +### 5.2 `normalize_text_value(value) -> str` + +文本清洗。 + +### 5.3 `normalize_date_value(value) -> str` + +日期标准化。 + +### 5.4 `calculate_confidence(candidate, field_definition) -> str` + +计算置信度。 + +### 5.5 `detect_conflict_candidates(candidates) -> list[dict]` + +检测同字段多候选值差异。 + +## 6. 技术实现 + +使用技术: + +1. Python 字符串处理 +2. 正则表达式 +3. 日期解析 +4. 字段类型规则 + +## 7. 异常处理 + +1. 值为空:标记待复核。 +2. 值过长:标记待复核。 +3. 日期无法解析:保留原值并标记低可信。 +4. 多候选不一致:标记 `conflict_candidate`。 + +## 8. 测试要点 + +1. 空白和标点标准化正确。 +2. 日期标准化正确。 +3. 多候选冲突可识别。 +4. 低可信候选进入待复核。 + diff --git a/docs/详细设计/skill/统一字段池写入Skill.md b/docs/详细设计/skill/统一字段池写入Skill.md new file mode 100644 index 0000000..09d35b6 --- /dev/null +++ b/docs/详细设计/skill/统一字段池写入Skill.md @@ -0,0 +1,83 @@ +# 统一字段池写入Skill 设计 + +## 1. Skill 定位 + +`统一字段池写入Skill` 负责将标准化后的字段候选写入统一字段池,并为每个字段选择推荐值、保留候选值和来源证据。 + +英文实现标识建议使用 `UnifiedFieldPoolWriteSkill`。 + +## 2. 输入 + +```python +@dataclass +class UnifiedFieldPoolWriteInput: + batch_id: int + normalized_candidates: list[NormalizedFieldCandidate] + field_definitions: list[FieldDefinition] + source_priority: dict +``` + +## 3. 输出 + +```python +@dataclass +class UnifiedFieldPoolWriteOutput: + field_pool_items: list[FieldPoolItem] + candidate_records: list[dict] + manual_review_fields: list[dict] + write_status: str +``` + +## 4. 推荐值选择规则 + +1. 优先选择高置信候选。 +2. 同置信度时按来源优先级选择。 +3. 来源优先级一致时选择规则抽取结果。 +4. 多候选值明显不同则标记 `conflict_candidate`。 +5. 待人工复核字段不作为无条件回填值。 + +## 5. 核心方法 + +### 5.1 `run(input) -> UnifiedFieldPoolWriteOutput` + +主入口方法。 + +### 5.2 `group_candidates_by_field(candidates) -> dict` + +按 `field_key` 分组。 + +### 5.3 `select_recommended_value(field_key, candidates, priority) -> FieldPoolItem` + +选择推荐值。 + +### 5.4 `persist_field_pool_item(item) -> RegistrationFieldPoolItem` + +写入字段池。 + +### 5.5 `persist_field_candidates(item, candidates) -> None` + +保留所有候选值。 + +## 6. 技术实现 + +使用技术: + +1. Django ORM +2. JSONField +3. 批量写入 +4. 唯一约束:`batch + field_key` + +## 7. 异常处理 + +1. 没有候选值:写入空字段并标记待复核。 +2. 数据库写入失败:任务失败并写审计。 +3. 字段重复写入:更新字段池版本或覆盖当前批次结果。 +4. 候选冲突:保留候选并标记冲突候选。 + +## 8. 测试要点 + +1. 高置信候选被选为推荐值。 +2. 来源优先级生效。 +3. 冲突候选被保留。 +4. 可回填字段标记正确。 + diff --git a/docs/详细设计/skill/表格字段抽取Skill.md b/docs/详细设计/skill/表格字段抽取Skill.md new file mode 100644 index 0000000..d71a62c --- /dev/null +++ b/docs/详细设计/skill/表格字段抽取Skill.md @@ -0,0 +1,81 @@ +# 表格字段抽取Skill 设计 + +## 1. Skill 定位 + +`表格字段抽取Skill` 负责从申请表、产品列表、标准清单等表格结构中抽取字段候选值。 + +英文实现标识建议使用 `TableFieldExtractSkill`。 + +## 2. 输入 + +```python +@dataclass +class TableFieldExtractInput: + documents: list[DocumentContent] + field_definitions: list[FieldDefinition] +``` + +## 3. 输出 + +```python +@dataclass +class TableFieldExtractOutput: + candidates: list[FieldCandidate] + failed_tables: list[dict] + tool_calls: list[dict] +``` + +## 4. 适用字段 + +1. 产品名称。 +2. 包装规格。 +3. 申请人名称。 +4. 分类编码。 +5. 生产地址。 +6. 标准清单。 + +## 5. 核心方法 + +### 5.1 `run(input) -> TableFieldExtractOutput` + +主入口方法。 + +### 5.2 `normalize_table(table) -> NormalizedTable` + +标准化表头、空单元格和合并单元格。 + +### 5.3 `match_table_header(table, field_definition) -> TableMatch | None` + +匹配表头。 + +### 5.4 `extract_cell_value(table, match) -> FieldCandidate` + +抽取单元格值。 + +### 5.5 `build_table_source_location(table_index, row_index, col_index) -> SourceLocation` + +记录表格来源位置。 + +## 6. 技术实现 + +使用技术: + +1. `python-docx` +2. `pdfplumber` +3. 表头关键词映射 +4. 合并单元格兼容处理 + +## 7. 异常处理 + +1. 无表格:跳过。 +2. 表头无法识别:记录待复核。 +3. 合并单元格解析失败:记录表格失败。 +4. 多行多值:保留所有候选。 + +## 8. 测试要点 + +1. 能从申请表抽取产品名称。 +2. 能从产品列表抽取包装规格。 +3. 能记录表格坐标。 +4. 表格解析失败不影响规则抽取。 + diff --git a/docs/详细设计/skill/规则字段抽取Skill.md b/docs/详细设计/skill/规则字段抽取Skill.md new file mode 100644 index 0000000..4c0d786 --- /dev/null +++ b/docs/详细设计/skill/规则字段抽取Skill.md @@ -0,0 +1,78 @@ +# 规则字段抽取Skill 设计 + +## 1. Skill 定位 + +`规则字段抽取Skill` 负责从标题、段落和固定标签中抽取字段候选值,适合处理格式稳定、标签明确的注册申报字段。 + +英文实现标识建议使用 `RuleFieldExtractSkill`。 + +## 2. 输入 + +```python +@dataclass +class RuleFieldExtractInput: + documents: list[DocumentContent] + field_definitions: list[FieldDefinition] +``` + +## 3. 输出 + +```python +@dataclass +class RuleFieldExtractOutput: + candidates: list[FieldCandidate] + failed_fields: list[dict] + tool_calls: list[dict] +``` + +## 4. 抽取方式 + +1. 标题后取值。 +2. 标签后取值。 +3. 固定段落规则。 +4. 正则匹配。 + +## 5. 核心方法 + +### 5.1 `run(input) -> RuleFieldExtractOutput` + +主入口方法。 + +### 5.2 `extract_by_heading(document, field_definition) -> FieldCandidate | None` + +从标题结构中抽取。 + +### 5.3 `extract_by_label(document, field_definition) -> FieldCandidate | None` + +从标签字段中抽取。 + +### 5.4 `extract_by_regex(document, field_definition) -> FieldCandidate | None` + +使用字段配置中的正则规则抽取。 + +### 5.5 `build_candidate(field, value, source) -> FieldCandidate` + +构建字段候选。 + +## 6. 技术实现 + +使用技术: + +1. `re` +2. 文本结构解析结果 +3. 中文标点标准化 + +## 7. 异常处理 + +1. 文本为空:跳过该文档。 +2. 多个候选:全部保留。 +3. 正则异常:记录工具失败。 +4. 候选值过长:标记待复核。 + +## 8. 测试要点 + +1. 能从标题抽取产品名称。 +2. 能从标签抽取储存条件。 +3. 多候选值全部保留。 +4. 空文本不报错。 + diff --git a/docs/详细设计/skill/长文本字段归纳Skill.md b/docs/详细设计/skill/长文本字段归纳Skill.md new file mode 100644 index 0000000..9deadf9 --- /dev/null +++ b/docs/详细设计/skill/长文本字段归纳Skill.md @@ -0,0 +1,83 @@ +# 长文本字段归纳Skill 设计 + +## 1. Skill 定位 + +`长文本字段归纳Skill` 负责对规则和表格无法稳定抽取的长文本字段进行证据限定后的 LLM 归纳。 + +英文实现标识建议使用 `LongTextFieldSummarizeSkill`。 + +本 Skill 必须通过 LLM Provider 调用模型,并支持 Mock Provider。 + +## 2. 输入 + +```python +@dataclass +class LongTextFieldSummarizeInput: + documents: list[DocumentContent] + field_definitions: list[FieldDefinition] + enable_rag_context: bool = True +``` + +## 3. 输出 + +```python +@dataclass +class LongTextFieldSummarizeOutput: + candidates: list[FieldCandidate] + evidence_refs: list[EvidenceRef] + tool_calls: list[dict] + failed_fields: list[dict] +``` + +## 4. 处理字段 + +1. 检测靶标。 +2. 适用范围 / 预期用途。 +3. 性能指标。 +4. 临床评价路径。 + +## 5. 核心方法 + +### 5.1 `run(input) -> LongTextFieldSummarizeOutput` + +主入口方法。 + +### 5.2 `locate_field_context(document, field_definition) -> list[EvidenceChunk]` + +通过 RAG 或关键词定位候选片段。 + +### 5.3 `build_llm_prompt(field_definition, chunks) -> str` + +构造限定上下文提示词。 + +### 5.4 `call_provider(prompt, output_schema) -> dict` + +调用 LLM Provider。 + +### 5.5 `validate_output(output) -> FieldCandidate` + +校验结构化输出。 + +## 6. 技术实现 + +使用技术: + +1. RAG fallback / Chroma +2. LLM Provider +3. JSON schema +4. Mock Provider + +## 7. 异常处理 + +1. 找不到候选片段:字段标记待人工复核。 +2. Provider 不可用:跳过 LLM。 +3. 输出 JSON 非法:丢弃结果。 +4. 输出没有来源片段:标记低可信。 + +## 8. 测试要点 + +1. Mock Provider 可返回固定字段。 +2. 找不到上下文时不会编造字段。 +3. 非法 JSON 被拦截。 +4. LLM 关闭时主流程仍可完成。 +