Files
DEMO-AGENT/docs/4.详细设计/3.产品关键信息提取与申报文件自动填表.md

24 KiB
Raw Permalink Blame History

产品关键信息提取与申报文件自动填表详细设计

文档信息

项目 内容
需求分析文档 docs/1.需求分析/3.产品关键信息提取与申报文件自动填表.md
功能设计文档 docs/2.功能设计/3.产品关键信息提取与申报文件自动填表.md
数据库设计文档 docs/4.数据库设计/3.产品关键信息提取与申报文件自动填表.md
依赖详细设计 docs/3.详细设计/1.自动汇总.mddocs/3.详细设计/2.NMPA注册资料法规核查与整改闭环.md
功能名称 产品关键信息提取与申报文件自动填表
所属模块 审核智能体 review_agent
设计日期 2026-06-07
设计版本 V1.0

一、详细设计目标

本详细设计用于指导“产品关键信息提取与申报文件自动填表”功能开发落地覆盖代码结构、数据库模型、模板配置、独立工作流、字段抽取、字段合并、Word 模板填充、追溯清单导出、飞书通知、接口契约、前端卡片、异常降级和测试建议。

核心约束:

约束 说明
独立工作流 使用 workflow_type=application_form_fill,拥有独立批次和卡片
对话触发 由用户自然语言触发,可指定模板;未指定时按注册类型选择适用模板
文件来源复用 默认使用当前对话最近成功的 FileSummaryBatch;本次带附件时先执行自动汇总
模板配置驱动 模板路径、字段映射、适用条件写入 application_form_fill/templates/application_form_templates_v1.yaml
Word 优先 Demo 阶段主链路只要求生成 Word 和追溯清单
PDF 待办 PDF 转换节点保留,但本期可标记 skipped 并写入待办计划
抽取并行 规则/正则抽取与 LLM 结构化抽取并行执行,再统一合并
冲突可见 说明书优先;冲突字段写入 Word 时黄底红字,并在对话框展示摘要
过程留底 规则抽取、LLM 抽取、合并结果、冲突和追溯清单均保存产物
飞书通知 填表完成后通知上传人,通知失败不阻断下载

二、代码结构设计

2.1 目录结构

第三批独立为 review_agent/application_form_fill/ 模块。Django 模型仍集中在 review_agent/models.py,业务服务放入独立模块。

review_agent/
  models.py
  services.py
  skill_router.py
  application_form_fill/
    __init__.py
    constants.py
    schemas.py
    storage.py
    workflow.py
    views.py
    services/
      __init__.py
      template_config.py
      template_select.py
      template_repository.py
      field_extract.py
      field_merge.py
      word_fill.py
      traceability_export.py
      notifier.py
    templates/
      application_form_templates_v1.yaml
    prompts/
      field_extract.md
      checklist_extract.md

2.2 文件职责

文件 职责
application_form_fill/constants.py 工作流节点、模板编码、状态、输出类型常量
application_form_fill/schemas.py FormFillContext、TemplateSpec、ExtractedField、MergedField 等 dataclass
application_form_fill/storage.py 批次工作目录、模板副本、产物保存、hash 计算
application_form_fill/workflow.py FormFillWorkflowExecutor串行执行独立填表工作流
application_form_fill/views.py 启动、状态查询、后续可选下载或重试接口
services/template_config.py 读取和校验 YAML 模板配置
services/template_select.py 解析用户指定模板、识别注册类型、选择模板
services/template_repository.py 定位原始模板、复制模板、.doc.docx 预留
services/field_extract.py 规则/正则与 LLM 并行字段抽取
services/field_merge.py 字段归一化、来源排序、冲突识别、最终字段输出
services/word_fill.py 使用 python-docx 写入 Word 表格、段落和高亮
services/traceability_export.py 生成 Excel/JSON 追溯清单,创建导出记录
services/notifier.py 包装飞书通知,生成通知记录
prompts/field_extract.md LLM 字段抽取提示词
prompts/checklist_extract.md 安全和性能基本原则清单条目判断提示词

三、依赖设计

3.1 Python 依赖

依赖 用途 当前项目情况
Django Web、ORM、权限 已使用
python-docx Word 模板读取、表格填充、字体和底色设置 已在项目依赖链中使用
openpyxl 字段来源追溯清单 Excel 导出 已使用
PyYAML YAML 模板配置读取 已用于法规规则
pypdf / python-pptx 文本抽取链路复用 已使用
LibreOffice/soffice .doc.docx、PDF 转换 本期非强依赖,后续待办

3.2 技术边界

能力 本期实现 后续增强
.docx 模板填充 必须支持 支持内容控件、复杂 OOXML patch
.doc 模板处理 可通过预转换模板或标记失败 自动 LibreOffice 转换
PDF 转换 可跳过并提示待生成 LibreOffice 转 PDF + 视觉 QA
字段级入库 不做 新增字段明细表和在线编辑
LLM 抽取 输出 JSON 并留底 增加置信度校准和人工确认

四、数据模型详细设计

模型放在 review_agent/models.py

4.1 ApplicationFormFillBatch

class ApplicationFormFillBatch(models.Model):
    class Status(models.TextChoices):
        PENDING = "pending", "待执行"
        RUNNING = "running", "执行中"
        WAITING_USER = "waiting_user", "等待用户"
        SUCCESS = "success", "成功"
        PARTIAL_SUCCESS = "partial_success", "部分成功"
        FAILED = "failed", "失败"
        CANCELLED = "cancelled", "已取消"

关键字段:

字段 说明
conversation 绑定对话
user 发起用户
trigger_message 触发消息
source_summary_batch 文件来源批次
source_regulatory_batch 可选法规核查批次
batch_no AFF-YYYYMMDDHHMMSS-abcdef
requested_templates 用户指定模板
selected_templates 实际生成模板
output_types 本次请求输出类型Demo 默认 ["word", "excel", "json"]
registration_type 识别出的注册类型
registration_type_source 注册类型来源
product_name 产品名称
conflict_summary 冲突摘要
risk_notes 不适用模板、PDF 待生成等提示
template_config_version 模板配置版本
template_config_hash 模板配置 hash
work_dir 批次工作目录

4.2 ApplicationFormFillArtifact

用于保存过程产物和模板副本元数据。

class ApplicationFormFillArtifact(models.Model):
    class ArtifactType(models.TextChoices):
        TEMPLATE_COPY = "template_copy", "模板副本"
        FIELD_EXTRACT_RESULT = "field_extract_result", "字段抽取结果"
        MERGED_FIELDS = "merged_fields", "字段合并结果"
        TRACEABILITY = "traceability", "追溯清单"
        FILLED_TEMPLATE = "filled_template", "已填模板"
        NOTIFICATION_RECORD = "notification_record", "通知记录"

4.3 ApplicationFormFillNotificationRecord

通知记录字段与第二批法规通知风格一致,支持重试:

字段 说明
batch 自动填表批次
recipient 通知对象
channel feishu_cli、feishu_api、mock
template_codes 涉及模板
export_ids 关联下载文件
message_summary 通知摘要
send_status pending、success、failed
retry_count 重试次数
external_message_id 飞书外部消息 ID
error_message 失败原因
sent_at 发送成功时间

4.4 ExportedSummaryFile 扩展

ExportedSummaryFile.ExportType 增加:

WORD = "word", "Word"
PDF = "pdf", "PDF"

填表导出记录使用:

字段
workflow_type application_form_fill
workflow_batch_id ApplicationFormFillBatch.id
export_category filled_template、traceability、extract_result
export_type word、excel、json、pdf

五、常量设计

5.1 工作流节点

FORM_FILL_NODE_DEFINITIONS = [
    ("prepare", "准备资料", "form_fill"),
    ("template_select", "选择模板", "form_fill"),
    ("template_copy", "复制模板", "form_fill"),
    ("field_extract", "抽取字段", "form_fill"),
    ("conflict_merge", "冲突归并", "form_fill"),
    ("word_fill", "填写 Word", "form_fill"),
    ("pdf_convert", "转换 PDF", "form_fill"),
    ("trace_export", "追溯清单", "form_fill"),
    ("output_export", "输出下载", "form_fill"),
    ("notify", "飞书通知", "form_fill"),
    ("completed", "完成", "completed"),
]

5.2 模板编码

TEMPLATE_REGISTRATION_CERTIFICATE = "registration_certificate"
TEMPLATE_CHANGE_REGISTRATION = "change_registration"
TEMPLATE_ESSENTIAL_PRINCIPLES = "essential_principles"

5.3 触发关键词

FORM_FILL_TRIGGER_KEYWORDS = [
    "填注册证",
    "对应的表格",
    "生成申报模板",
    "安全和性能基本原则清单",
    "填到申报模板",
    "自动填表",
    "生成表格",
]

六、核心数据结构

6.1 FormFillContext

@dataclass
class FormFillContext:
    batch: ApplicationFormFillBatch
    source_summary_batch: FileSummaryBatch
    source_regulatory_batch: RegulatoryReviewBatch | None
    template_config: dict[str, Any]
    selected_templates: list["TemplateSpec"]
    document_texts: dict[str, str]
    regex_results: dict[str, Any]
    llm_results: dict[str, Any]
    merged_fields: dict[str, "MergedField"]
    checklist_items: dict[str, Any]
    conflicts: list[dict[str, Any]]
    exports: list[ExportedSummaryFile]

6.2 TemplateSpec

@dataclass(frozen=True)
class TemplateSpec:
    code: str
    name: str
    source_file: str
    output_label: str
    applies_when: dict[str, Any]
    file_format: str
    fields: list[dict[str, Any]]
    checklist_items: list[dict[str, Any]]

6.3 ExtractedField

@dataclass(frozen=True)
class ExtractedField:
    key: str
    label: str
    value: str
    source_file: str
    source_role: str
    evidence: str
    extractor: str
    confidence: float

6.4 MergedField

@dataclass(frozen=True)
class MergedField:
    key: str
    label: str
    value: str
    source_file: str
    evidence: str
    confidence: float
    has_conflict: bool = False
    conflict_values: list[dict[str, Any]] = field(default_factory=list)

七、模板配置详细设计

7.1 配置路径

review_agent/application_form_fill/templates/application_form_templates_v1.yaml

7.2 初始配置示例

version: application_form_templates_v1
source_dir: docs/0.原始材料/关于公布体外诊断试剂注册申报资料要求和批准证明文件格式的公告
templates:
  - code: registration_certificate
    name: 中华人民共和国医疗器械注册证(体外诊断试剂)(格式)
    source_file: 中华人民共和国医疗器械注册证(体外诊断试剂)(格式).docx
    output_label: 注册证格式
    applies_when:
      registration_type: ["首次注册"]
    file_format: docx
    fields:
      - key: applicant_name
        label: 注册人名称
        target:
          type: table_row
          row_label: 注册人名称
        source_roles: ["申请表", "说明书", "企业信息"]
      - key: product_name
        label: 产品名称
        target:
          type: table_row
          row_label: 产品名称
        source_roles: ["说明书", "产品技术要求", "注册检验报告"]
      - key: intended_use
        label: 预期用途
        target:
          type: table_row
          row_label: 预期用途
        source_roles: ["说明书", "临床评价资料", "产品技术要求"]

7.3 配置校验

TemplateConfigService 启动时校验:

校验项 失败处理
version 存在 批次 failed
source_dir 存在 批次 failed
templates 非空 批次 failed
code 唯一 批次 failed
source_file 存在 对应模板不可用
target.type 支持 对应字段跳过并记录

八、服务详细设计

8.1 TemplateConfigService

def load_template_config() -> dict:
    """读取 YAML 模板配置。"""

def validate_template_config(config: dict) -> list[str]:
    """返回配置错误列表。"""

def compute_config_hash(path: Path) -> str:
    """计算模板配置 SHA-256。"""

8.2 TemplateSelectionService

def parse_requested_templates(message: str) -> list[str]:
    """从用户话语中识别指定模板。"""

def detect_registration_type(batch: ApplicationFormFillBatch, message: str) -> tuple[str, str]:
    """按用户话语、法规核查批次、文件抽取结果识别注册类型及来源。"""

def select_templates(
    config: dict,
    requested_templates: list[str],
    registration_type: str,
) -> tuple[list[TemplateSpec], list[dict]]:
    """输出模板列表和风险提示。"""

注册类型优先级:

用户话语明确指定
-> source_regulatory_batch.condition_json / confirmed_conditions
-> source_summary_batch 文件内容抽取候选
-> unknown

8.3 TemplateRepository

def resolve_source_template(spec: TemplateSpec) -> Path:
    """返回原始模板路径或预转换工作模板路径。"""

def copy_template_to_batch(spec: TemplateSpec, batch: ApplicationFormFillBatch) -> Path:
    """复制模板到批次 work_dir/templates。"""

def convert_doc_to_docx(source: Path, target_dir: Path) -> Path:
    """P1 能力:使用 soffice 转 docx。"""

.doc 模板本期处理:

场景 处理
存在 working_template docx 使用工作模板
仅有 .doc 且无 soffice 对应模板失败,其他模板继续
具备 soffice 转换为 .docx 后继续

8.4 FieldExtractionService

def collect_document_texts(summary_batch: FileSummaryBatch) -> dict[str, str]:
    """复用 text_extract 读取文件文本。"""

def extract_by_rules(texts: dict[str, str], specs: list[TemplateSpec]) -> dict:
    """规则/正则抽取字段。"""

def extract_by_llm(texts: dict[str, str], specs: list[TemplateSpec]) -> dict:
    """LLM 结构化抽取字段。"""

def run_parallel_extract(texts: dict[str, str], specs: list[TemplateSpec]) -> tuple[dict, dict]:
    """并行执行规则/正则与 LLM 抽取。"""

并行实现可使用 ThreadPoolExecutor(max_workers=2)。LLM 超时或失败时,保留规则/正则结果继续。

8.5 FieldMergeService

def normalize_field_value(value: str) -> str:
    """字段值归一化。"""

def rank_source(source_role: str, source_file: str) -> int:
    """说明书优先,其次产品技术要求、检测报告、性能研究等。"""

def merge_fields(regex_results: dict, llm_results: dict) -> tuple[dict[str, MergedField], list[dict]]:
    """合并字段并输出冲突。"""

来源优先级:

排名 来源
1 说明书
2 产品技术要求
3 注册检验报告/检测报告
4 性能研究资料
5 其他注册资料

8.6 WordTemplateFillService

def fill_template(
    template_path: Path,
    output_path: Path,
    spec: TemplateSpec,
    fields: dict[str, MergedField],
    checklist_items: dict[str, Any],
) -> Path:
    """填充 Word 模板并保存。"""

def fill_table_row(document: Document, row_label: str, value: str, conflict: bool) -> bool:
    """根据表格行首字段名定位并填入第二列。"""

def replace_placeholders(document: Document, fields: dict[str, MergedField]) -> None:
    """替换段落中的 {{field_key}}。"""

def apply_conflict_style(cell_or_run) -> None:
    """应用黄色底色和红色字体。"""

冲突样式:

样式 说明
字体颜色 红色 FF0000
底色 黄色 FFFF00
适用范围 单元格或字段值 run

8.7 TraceabilityExportService

def build_traceability_workbook(batch, merged_fields, conflicts, specs) -> Workbook:
    """生成追溯清单 Excel。"""

def save_traceability_excel(batch, workbook) -> ExportedSummaryFile:
    """保存 Excel 并写导出记录。"""

def save_extract_json(batch, payload: dict) -> ApplicationFormFillArtifact:
    """保存字段抽取 JSON 过程产物。"""

Excel Sheet

Sheet 内容
字段追溯 模板、字段、填入值、来源文件、证据、冲突状态
冲突字段 字段、采用值、冲突值、处理方式
低置信度条目 安全和性能基本原则清单候选判断
生成结果 模板文件、Word 状态、PDF 状态、错误说明

8.8 FormFillNotifier

def notify_completion(batch: ApplicationFormFillBatch, exports: list[ExportedSummaryFile]) -> ApplicationFormFillNotificationRecord:
    """发送填表完成通知。"""

通知摘要包含:

内容 说明
批次号 填表批次
产品名称 如已识别
生成模板 模板名称列表
冲突数量 提示需下载核对
下载提示 提示回到系统对话下载,不直接暴露敏感全文

九、工作流执行器详细设计

9.1 启动入口

def start_application_form_fill_workflow(batch: ApplicationFormFillBatch, *, async_run: bool = True) -> None:
    executor = FormFillWorkflowExecutor(batch)
    if async_run:
        Thread(target=executor.run, daemon=True).start()
    else:
        executor.run()

9.2 执行伪代码

class FormFillWorkflowExecutor:
    def run(self) -> None:
        self.mark_batch_running()
        try:
            for node in self.nodes():
                if node.status == "success":
                    continue
                self.run_node(node)
            self.complete_or_partial()
        except WorkflowPausedForUser:
            self.mark_waiting_user()
        except Exception as exc:
            self.mark_failed(exc)

9.3 节点处理要点

节点 处理
prepare 校验 source_summary_batch 成功且属于当前对话
template_select 读取 YAML、识别注册类型、选择模板
template_copy 复制模板到 work_dir/templates
field_extract 抽取文本,规则/正则与 LLM 并行,保存 JSON
conflict_merge 合并字段,写 conflict_summary
word_fill 逐模板生成 WordExportedSummaryFile(word)
pdf_convert 本期 skippedrisk_notes
trace_export 生成追溯 Excel 和 JSON
output_export 生成 AI 对话 Markdown 摘要
notify 写飞书通知记录,失败不阻断
completed 标记 success 或 partial_success

9.4 批次状态决策

条件 状态
所有目标 Word 均成功,追溯清单成功,通知成功或跳过 success
至少一个 Word 成功但部分模板、追溯清单、PDF 或通知失败 partial_success
所有目标 Word 均失败 failed
无来源文件汇总批次 waiting_user

十、接口详细设计

10.1 发起自动填表

POST /api/review-agent/application-form-fill/start/

请求:

参数 类型 必填 说明
conversation_id integer 当前对话
message_id integer 触发消息
file_summary_batch_id integer 指定文件来源批次
template_codes array 指定模板
output_types array 输出类型,默认 word、excel、json

响应:

{
  "batch_id": 3001,
  "workflow_type": "application_form_fill",
  "status": "pending",
  "selected_templates": ["registration_certificate", "essential_principles"]
}

10.2 查询状态

GET /api/review-agent/application-form-fill/{batch_id}/

响应:

{
  "batch": {
    "id": 3001,
    "batch_no": "AFF-20260607153000-a1b2c3",
    "status": "success",
    "product_name": "甲胎蛋白检测试剂盒",
    "selected_templates": ["registration_certificate"]
  },
  "nodes": [],
  "conflicts": [],
  "exports": []
}

10.3 下载文件

继续复用既有导出下载接口:

GET /api/review-agent/file-summary/exports/{export_id}/download/

下载权限通过 workflow_type=application_form_fillworkflow_batch_id 反查填表批次。


十一、前端详细设计

11.1 工作流卡片

新增卡片类型 application_form_fill

节点 展示
prepare 准备资料
template_select 选择模板
template_copy 复制模板
field_extract 抽取字段
conflict_merge 冲突归并
word_fill 填写 Word
pdf_convert 转换 PDF
trace_export 追溯清单
output_export 输出下载
notify 飞书通知
completed 已完成

PDF 本期显示为“已跳过/待增强”,不显示为失败。

11.2 AI 回复摘要

已生成申报模板自动填表文件。

| 文件 | Word | PDF |
| --- | --- | --- |
| 注册证格式 | 下载 | 待增强 |
| 安全和性能基本原则清单 | 下载 | 待增强 |

| 冲突字段 | 采用值 | 冲突来源 | 处理 |
| --- | --- | --- | --- |
| 储存条件 | 2-8℃保存 | 产品技术要求:-20℃保存 | 已按说明书填入,并在模板中高亮 |

[下载字段来源追溯清单](download-url)

十二、异常与降级

场景 处理
无成功汇总批次 批次 waiting_user对话提示上传资料
模板配置不存在 批次 failed
指定模板不存在 忽略无效模板并提示;若无有效模板则 failed
.doc 模板无可用工作模板 该模板失败,其他模板继续
文本抽取失败 对应文件跳过,记录在追溯清单
LLM 抽取失败 使用规则/正则结果继续
字段缺失 Word 留空
字段冲突 说明书优先并高亮
追溯清单失败 Word 成功时批次 partial_success
飞书通知失败 批次 partial_success 或 success取决于核心产物是否成功
PDF 未实现 节点 skipped写入待增强提示

十三、测试设计

13.1 单元测试

用例 目标
test_form_fill_trigger_keywords 触发语句识别为自动填表
test_template_config_loads YAML 配置可加载并校验
test_select_default_templates_initial_registration 首次注册默认选择注册证和基本原则清单
test_select_user_requested_mismatch 用户指定不适用模板仍允许生成并提示
test_field_merge_prefers_instructions 说明书字段优先
test_field_merge_marks_conflict 冲突字段进入 conflict_summary
test_word_fill_table_row 能按表格行名写入 Word
test_word_fill_conflict_highlight 冲突字段黄底红字
test_traceability_excel 追溯清单包含字段、来源和冲突
test_notify_records_failure 飞书失败写通知记录但不阻断

13.2 集成测试

场景 验证
最近汇总批次触发填表 无附件时复用最近 success FileSummaryBatch
新附件触发填表 先自动汇总再启动填表
注册证模板填充 生成 Word 导出文件
LLM 失败降级 LLM 超时后规则抽取仍可生成 Word
部分模板失败 至少一个 Word 成功时批次 partial_success
权限隔离 不能查询或下载他人填表批次产物

13.3 前端验证

场景 验证
自动填表卡片 节点状态随 SSE 更新
指定模板展示 卡片展示本次选择模板
PDF 跳过显示 PDF 节点显示待增强而非失败
下载链接 Word 和追溯清单链接可点击下载
冲突摘要 冲突字段表格正常渲染

十四、实施顺序建议

  1. 修改功能设计中的模板配置路径为 review_agent/application_form_fill/templates/application_form_templates_v1.yaml
  2. 新增数据库模型和 ExportedSummaryFile.ExportType 扩展。
  3. 新增 application_form_fill 模块目录和常量、schemas、storage。
  4. 新增模板配置 YAML先录入注册证 .docx 的已识别字段。
  5. 实现模板选择、模板复制和 Word 表格行填充。
  6. 实现规则/正则字段抽取和 LLM 抽取降级。
  7. 实现字段合并、冲突高亮和追溯清单。
  8. 实现工作流执行器、节点事件和状态接口。
  9. 改造路由和前端工作流卡片。
  10. 接入飞书通知记录。
  11. 将字段级数据库表和 PDF 转换写入待办计划。