# 第1章监管信息材料包生成功能设计 ## 文档信息 | 项目 | 内容 | | --- | --- | | 需求分析文档 | docs/1.需求分析/5.第1章监管信息材料包生成.md | | 参考功能设计 | docs/2.功能设计/3.产品关键信息提取与申报文件自动填表.md | | 功能名称 | 第1章监管信息材料包生成 | | 工作流编码 | regulatory_info_package | | 所属模块 | 审核智能体 review_agent | | 设计日期 | 2026-06-10 | | 设计版本 | V1.0 | --- ## 一、设计目标 新增独立工作流 `regulatory_info_package`,用于根据产品说明书生成第1章监管信息材料包。用户在对话中上传或选择一个产品说明书,发送“根据说明书生成第1章监管信息”等指令后,系统复制 `docs/0.原始材料/第1章 监管信息` 下的 7 个样例模板,抽取说明书中的产品关键信息,生成一套新的第1章监管信息文件,并打包为 `第1章 监管信息(预生成版).zip` 作为主下载入口。 本功能与 `application_form_fill` 平级,不复用其 workflow_type 和批次表;但复用其已形成的服务思想和部分可拆能力,包括字段抽取、LLM 调用、Word 写入、追溯清单、导出下载、通知、工作流事件和前端卡片。 本期重点实现: | 目标 | 说明 | | --- | --- | | 独立工作流 | 新增 `regulatory_info_package` 批次、节点和卡片 | | 单说明书输入 | 直接从当前对话 active 附件中选择唯一说明书;兼容最近成功文件汇总批次 | | 模板驱动 | 通过 YAML 配置维护 7 个模板、字段映射和生成策略 | | 规则 + LLM 并行抽取 | 代码抽取与 LLM 抽取并行,合并后写入模板 | | 待确认高亮 | 系统新填入的 `/`、LLM-only 字段、冲突字段均高亮 | | `.doc` 等价处理 | 设计 `LegacyWordDocumentService`,提供与 `.docx` 一致的文档操作接口 | | zip 主输出 | 扩展 `ExportedSummaryFile.ExportType.ZIP`,统一下载权限 | | LLM 意图路由 | 扩展路由 action,支持固定话术和 LLM 语义判断 | --- ## 二、规范依据与裁决 | 规范来源 | 命中内容 | 设计处理 | | --- | --- | --- | | GYRX 后端开发规范 | 服务层职责清晰、接口响应统一、记录必要日志 | Django 项目沿用现有 JsonResponse/SSE 模式;服务拆入独立模块,记录批次与节点日志 | | GYRX 前端开发规范 | 前端样式复用、交互一致、下载图标语义 | 当前项目为 Django 模板 + 原生 JS,按现有工具 chip、工作流卡片和下载链接风格扩展 | | 既有自动填表设计 | 独立工作流、YAML 配置、字段抽取、追溯清单、导出记录 | 复用模式,不复用批次表和 workflow_type | | 需求分析确认 | `.doc` 不只依赖转换、zip 主入口、LLM-only 高亮 | 在服务抽象和验收标准中作为强约束 | 冲突裁决:GYRX 规范中部分 Java/Spring 约束不适用于当前 Django 项目,按当前项目既有 Django 架构落地;通用原则如服务拆分、日志、权限和前端交互一致性继续采用。 --- ## 三、与既有功能关系 ### 3.1 复用边界 | 能力 | 处理方式 | 现有代码/模块 | | --- | --- | --- | | 对话与消息 | 复用 | `Conversation`、`Message`、`stream_message` | | 附件上传 | 复用 | `FileAttachment`、`file_summary.storage` | | 文件汇总结果 | 兼容复用 | `FileSummaryBatch`、`FileSummaryItem` | | 文本抽取 | 复用并扩展 | `regulatory_review/services/text_extract.py`、`rag_index.py` | | LLM 调用 | 复用 | `review_agent/llm.py` | | 知识库搜索 | 复用系统现有能力 | `knowledge_base.py`、法规 RAG 相关服务 | | 导出下载 | 扩展复用 | `ExportedSummaryFile`、`file_summary.views.export_download` | | 工作流事件 | 复用 | `WorkflowNodeRun`、`WorkflowEvent` | | 通知 | 复用统一通知链路 | `review_agent.notifications` | | 前端卡片 | 扩展复用 | `templates/home.html`、`static/js/app.js` | ### 3.2 新增边界 | 能力 | 说明 | | --- | --- | | 独立批次 | 新增 `RegulatoryInfoPackageBatch`,批次号 `RIP-...` | | 独立产物 | 新增 `RegulatoryInfoPackageArtifact` 记录模板副本、抽取结果、生成文件、zip 和追溯清单 | | 独立通知记录 | 新增 `RegulatoryInfoPackageNotificationRecord`,结构与自动填表通知保持一致 | | 模板配置 | 新增 `regulatory_info_package_templates_v1.yaml` | | 说明书选择 | 新增输入选择服务,优先从 active 附件选择,兼容文件汇总批次 | | 材料包生成 | 新增 7 个文件的生成策略和 zip 打包服务 | | `.doc` 适配 | 新增旧版 Word 文档适配层 | --- ## 四、总体架构 ### 4.1 目录结构 新增模块: ```text review_agent/ regulatory_info_package/ __init__.py constants.py schemas.py storage.py events.py workflow.py views.py services/ __init__.py input_select.py template_config.py template_repository.py instruction_extract.py field_extract.py field_merge.py standard_candidates.py document_writer.py docx_document.py legacy_doc_document.py package_generate.py traceability_export.py zip_export.py summary.py notifier.py templates/ regulatory_info_package_templates_v1.yaml prompts/ field_extract.md router_intent.md standard_candidate.md ``` ### 4.2 逻辑架构 ```mermaid flowchart TD A["AI 对话页"] --> B["意图路由"] B --> C{"action = regulatory_info_package"} C --> D["RegulatoryInfoPackageBatch"] D --> E["RegulatoryInfoPackageWorkflowExecutor"] E --> F["输入说明书选择"] E --> G["模板配置 YAML"] F --> H["说明书文本与表格抽取"] H --> I1["规则/代码抽取"] H --> I2["LLM 结构化抽取"] I1 --> J["字段合并与高亮决策"] I2 --> J J --> K["标准候选服务"] J --> L["材料包生成服务"] K --> L L --> M1["DOCX 文档适配器"] L --> M2["Legacy DOC 文档适配器"] M1 --> N["7 个目标文件"] M2 --> N N --> O["追溯清单"] N --> P["ZIP 打包"] O --> Q["ExportedSummaryFile"] P --> Q E --> R["WorkflowEvent/SSE"] E --> S["通知服务"] ``` ### 4.3 技术选型 | 设计项 | 本期方案 | 说明 | | --- | --- | --- | | Web 框架 | Django | 沿用当前项目 | | 工作流执行 | 轻量 Executor + 后台线程 | 与文件汇总、法规核查、自动填表一致 | | 工作流状态 | `WorkflowNodeRun`、`WorkflowEvent` | 使用 `workflow_type=regulatory_info_package` | | 模板配置 | YAML | 便于维护 7 个模板和字段映射 | | `.docx` 操作 | `python-docx` | 表格、段落、run、底色和字体可控 | | `.doc` 操作 | 适配器抽象 | Python 标准库不支持 `.doc` 二进制 Word 写入;设计为 COM/UNO/第三方库适配器 | | zip 打包 | Python `zipfile` 标准库 | 标准库可满足打包需求 | | Excel 追溯 | `openpyxl` | 复用现有依赖 | | LLM | `review_agent.llm.generate_completion` | 统一模型调用 | | 知识库 | 系统现有知识库/RAG | 不新增单独 RAG 模块 | 关于 `.doc`:Python 自带库不能实现类似 Apache POI HWPF 的 Word 97-2003 二进制文档完整读写。项目依赖中有 `olefile`,可读取 OLE 复合文档结构,但不足以可靠修改 Word 文本、表格和样式。因此设计上必须使用文档适配器屏蔽实现差异,底层可选 Word COM、LibreOffice UNO、专用第三方库或受控转换兜底。 --- ## 五、触发与路由设计 ### 5.1 action 扩展 `skill_router.py` 扩展: | 项 | 设计 | | --- | --- | | 新 action | `regulatory_info_package` | | 新属性 | `starts_regulatory_info_package` | | ROUTE_ACTIONS | 增加 `regulatory_info_package` | | LLM prompt | 描述该 action 用于“根据说明书生成第1章监管信息、监管信息材料包、申请表/产品列表/声明材料包” | ### 5.2 固定规则 规则预判关键词: ```python REGULATORY_INFO_PACKAGE_TRIGGER_KEYWORDS = [ "根据说明书生成第1章监管信息", "生成监管信息材料包", "从说明书生成第1章材料", "第1章监管信息", "监管信息材料包", ] ``` 规则命中时直接进入本工作流。规则未命中时,继续走 LLM 路由判断,避免自然表达漏触发。 ### 5.3 对话启动 `review_agent/services.py::stream_message` 增加分支: ```text if route.starts_regulatory_info_package: -> 选择说明书输入 -> 创建 RegulatoryInfoPackageBatch -> start_regulatory_info_package_workflow -> SSE workflow_started -> 回复“已启动第1章监管信息材料包生成工作流,批次号:RIP-...” ``` 如果没有 active 附件,也没有可复用的最近文件汇总批次,则回复“请先上传产品说明书”。 如果存在多个候选说明书且用户消息无法唯一命中文件名,则不展示选择弹窗,由对话反问用户确认具体文件名后再启动工作流。 --- ## 六、输入选择设计 ### 6.1 选择优先级 | 优先级 | 来源 | 规则 | | --- | --- | --- | | 1 | 用户消息指定文件名 | 按 active 附件名或可复用文件名模糊匹配,唯一命中则使用 | | 2 | 当前对话 active 附件 | 文件名包含“说明书”且扩展名为 `.docx` | | 3 | 当前对话 active 附件 | 唯一 `.docx` 文件 | | 4 | 最近成功 `FileSummaryBatch.items` | 文件名包含“说明书”且扩展名为 `.docx` | | 5 | 无法唯一选择 | 对话反问用户确认使用哪个说明书;必要时批次进入 `waiting_user` | 本期直接输入只支持 `.docx` 产品说明书。`.doc`、PDF、扫描件说明书作为后续扩展;但输出模板中的 `.doc` 必须支持。 ### 6.2 输入绑定 批次记录: | 字段 | 来源 | | --- | --- | | source_attachment | 直接选择的 FileAttachment | | source_summary_batch | 可选,来自最近成功文件汇总 | | source_summary_item | 可选,来自汇总条目 | | source_file_name | 原始说明书文件名 | | source_storage_path | 说明书存储路径 | --- ## 七、模板配置设计 配置路径: ```text review_agent/regulatory_info_package/templates/regulatory_info_package_templates_v1.yaml ``` 配置结构: ```yaml version: regulatory_info_package_templates_v1 source_dir: docs/0.原始材料/第1章 监管信息 output_zip_name: 第1章 监管信息(预生成版).zip templates: - code: ch1_2_directory output_name: CH1.2 监管信息目录.docx source_file: CH1.2 监管信息目录.docx file_format: docx strategy: directory include_in_zip: true fields: - key: product_name targets: - type: paragraph_contains_replace match: 呼吸道合胞病毒、肺炎支原体核酸检测试剂盒(荧光PCR法) - code: ch1_4_application_form output_name: CH1.4 申请表.docx source_file: CH1.4 申请表.docx file_format: docx strategy: application_form include_in_zip: true - code: ch1_9_pre_submission output_name: CH1.9 产品申报前沟通的说明.doc source_file: CH1.9 产品申报前沟通的说明.doc file_format: doc strategy: pre_submission require_legacy_doc_native: true include_in_zip: true ``` ### 7.1 配置项说明 | 配置项 | 说明 | | --- | --- | | version | 配置版本,写入批次 | | source_dir | 样例模板目录 | | output_zip_name | zip 主输出文件名 | | templates | 7 个目标模板 | | code | 模板编码 | | output_name | 生成文件名 | | source_file | 样例文件 | | file_format | docx/doc | | strategy | 生成策略 | | include_in_zip | 是否进入 zip | | fields | 字段映射与替换目标 | | require_legacy_doc_native | `.doc` 是否要求原生处理能力 | --- ## 八、字段抽取设计 ### 8.1 说明书解析 `instruction_extract.py` 输出: | 数据 | 说明 | | --- | --- | | paragraphs | 按顺序提取段落 | | sections | 按 `【章节名】` 切分 | | tables | 提取表格二维数据 | | component_tables | 识别主要组成成分表 | | front_text | 前 4000 字,供 LLM 使用 | ### 8.2 规则抽取 规则抽取覆盖: | 字段 | 规则 | | --- | --- | | product_name | `【产品名称】` 下一段 | | package_specification | `【包装规格】` 到下一章节 | | intended_use | `【预期用途】` 到下一章节 | | detection_principle | `【检测原理】` 到下一章节 | | main_components | `【主要组成成分】` 表格摘要 | | storage_condition_and_validity | `【储存条件及有效期】` 到下一章节 | | sample_type | `样本要求` 中“适用样本类型” | | detection_targets | 从预期用途/检测原理中抽取基因、病原体、靶标 | | applicable_instruments | `【适用仪器】` 到下一章节 | | test_method | `【检验方法】` 摘要 | | standards | 正则抽取 `GB/T`、`YY/T`、`YY`、`GB` 等标准号 | ### 8.3 LLM 抽取 LLM prompt 要求只输出 JSON: ```json { "fields": [ { "key": "product_name", "label": "产品名称", "value": "...", "evidence": "...", "confidence": 0.9 } ], "product_list_rows": [ { "package_specification": "...", "composition": "...", "component_name": "...", "main_component": "...", "quantity": "..." } ], "standards": [] } ``` LLM 不允许填企业信息、分类编码、管理类别、临床评价路径等说明书无法证明的内容。 ### 8.4 字段合并 `field_merge.py` 输出 `MergedField`: | 字段 | 说明 | | --- | --- | | key | 字段编码 | | label | 中文名 | | value | 最终写入值 | | source | rule、llm、missing、conflict | | evidence | 来源片段 | | confidence | 置信度 | | highlight_reason | none、missing、llm_only、conflict、rag_candidate | | needs_review | 是否需人工复核 | 合并规则: | 场景 | 处理 | | --- | --- | | rule 与 LLM 一致 | 采用值,不高亮 | | rule 与 LLM 不一致 | 采用规则优先或配置优先,标记 conflict | | rule 缺失、LLM 命中 | 采用 LLM 值,标记 llm_only | | 全部缺失 | 写 `/`,标记 missing | --- ## 九、文档生成设计 ### 9.1 文档适配器接口 `document_writer.py` 定义统一接口: ```python class DocumentAdapter: def replace_text(self, old: str, new: str, *, highlight: bool = False) -> int: ... def fill_table_cell(self, row_label: str, value: str, *, highlight: bool = False) -> bool: ... def replace_table(self, marker: str, rows: list[dict], *, highlight_columns: list[str] = None) -> bool: ... def highlight_value(self, value: str, reason: str) -> int: ... def save(self, path: Path) -> Path: ... ``` `.docx` 使用 `DocxDocumentAdapter`。`.doc` 使用 `LegacyDocDocumentAdapter`。 ### 9.2 `.docx` 处理 能力: | 能力 | 实现 | | --- | --- | | 段落替换 | 遍历 paragraph runs | | 表格行填充 | 按首列 label 定位 | | 单元格高亮 | `w:shd` 黄色底色 | | 字体颜色 | 冲突项可红色字体 | | 产品列表重建 | 清空目标表格数据行后追加 | | 声明日期替换 | 按日期正则或段落末尾替换 | ### 9.3 `.doc` 处理 设计 `LegacyDocDocumentAdapter`,对外提供与 `.docx` 一致能力。底层按可用性选择适配器: | 适配器 | 定位 | | --- | --- | | `WordComDocAdapter` | Windows + Microsoft Word 环境下优先,直接打开 `.doc`、查找替换、设置高亮并保存 `.doc` | | `LibreOfficeUnoDocAdapter` | LibreOffice UNO/API 环境下使用,直接操作文档模型 | | `OleDocReadOnlyAdapter` | 仅可读取时用于诊断,不满足写入验收 | | `ConversionFallbackAdapter` | 兜底路径,可转换为 `.docx` 后处理,但不能作为唯一实现 | 功能设计约束: | 约束 | 说明 | | --- | --- | | 不静默降级 | `.doc` 原生写入失败时必须记录适配器失败原因,随后尝试 `.docx` 兜底;兜底仍失败时该文件失败并触发 partial_success | | 不只靠转换 | 转换可作为兜底,但设计主路径必须是文档适配器 | | 能力探测 | 启动时或节点执行时检测适配器可用性 | | 追溯记录 | 写入 `.doc` 的适配器类型和失败信息写入 artifact metadata | ### 9.4 7 个文件生成策略 | 模板 | 策略服务 | 关键动作 | | --- | --- | --- | | CH1.2 监管信息目录 | `generate_directory_doc` | 替换产品名称;页码沿用样例 | | CH1.4 申请表 | `generate_application_form_doc` | 填表格行;缺失字段 `/` 黄底 | | CH1.5 产品列表 | `generate_product_list_doc` | 使用样例表头重建产品列表;货号 `/` 黄底 | | CH1.9 申报前沟通说明 | `generate_pre_submission_doc` | `.doc` 原生替换产品名和公司名;原生失败则输出 `.docx` 兜底文件;两者均失败才不进入 zip | | CH1.11.1 符合标准清单 | `generate_standard_list_doc` | 说明书标准号直接写;候选/缺失高亮 | | CH1.11.5 真实性声明 | `generate_authenticity_statement_doc` | 保留正文,替换产品名,公司名 `/` 黄底,日期当天 | | CH1.11.6 符合性声明 | `generate_compliance_statement_doc` | 保留正文,替换产品名,公司名 `/` 黄底,日期当天 | `generate_docs` 节点内部允许多线程并发处理 7 个目标文件。每个文档使用独立模板副本,子线程只返回生成结果,数据库 artifact/export 记录由主线程统一写入,避免并发写库和共享文件冲突。 --- ## 十、标准清单设计 系统中已有知识库/RAG 能力,不新增单独 RAG 模块。本功能只新增 `standard_candidates.py` 作为业务服务,调用既有知识库搜索能力。 处理规则: | 来源 | 处理 | | --- | --- | | 说明书明确标准号 | 写入标准清单,记录 `source=instruction` | | 知识库候选标准 | 可写入候选区或追溯清单,标记 `rag_candidate` 并高亮 | | 无命中 | 写 `/` 并黄底 | | 样例标准 | 不无条件沿用 | 查询建议: ```text 体外诊断试剂 核酸扩增 检测试剂 标准 清单 新型冠状病毒 2019-nCoV 核酸检测试剂盒 荧光PCR 标准 ``` --- ## 十一、zip 与导出设计 ### 11.1 ExportType 扩展 `ExportedSummaryFile.ExportType` 增加: ```python ZIP = "zip", "ZIP" ``` 下载 content type 增加: ```python "zip": "application/zip" ``` ### 11.2 导出记录 | 文件 | export_category | export_type | | --- | --- | --- | | 第1章 监管信息(预生成版).zip | regulatory_info_package | zip | | 7 个生成文件 | generated_document | word 或 legacy_word | | 追溯清单 Excel | traceability | excel | 追溯 JSON 和抽取过程 JSON 只保存到后台 `logs/` 目录和 artifact 记录,不作为用户下载入口。用户侧只提供追溯 Excel 下载。 如果不新增 `legacy_word` export_type,则 `.doc` 也可暂用 `word`,通过文件扩展名和 content type 判断下载 MIME。功能设计建议新增 content type 映射时按扩展名兜底,避免 `.doc` 被当作 `.docx`。 ### 11.3 权限 `file_summary.views._export_for_user` 增加: ```text if exported.workflow_type == "regulatory_info_package": 查询 RegulatoryInfoPackageBatch 校验 conversation__user == request.user 且 is_deleted=False ``` --- ## 十二、数据模型设计 ### 12.1 RegulatoryInfoPackageBatch ```python class RegulatoryInfoPackageBatch(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 | FK Conversation | 所属对话 | | user | FK User | 发起用户 | | trigger_message | FK Message | 触发消息 | | source_attachment | FK FileAttachment | 直接选中的说明书附件 | | source_summary_batch | FK FileSummaryBatch | 可选文件汇总批次 | | source_summary_item_id | PositiveBigIntegerField | 可选汇总条目 ID | | batch_no | CharField unique | RIP 批次号 | | status | CharField | 状态 | | source_file_name | CharField | 说明书原文件名 | | source_storage_path | CharField | 说明书路径 | | product_name | CharField | 抽取产品名 | | output_zip_name | CharField | zip 文件名 | | generated_files | JSONField | 7 个文件状态 | | missing_fields | JSONField | 缺失项 | | llm_only_fields | JSONField | LLM-only 项 | | conflict_fields | JSONField | 冲突项 | | risk_notes | JSONField | 风险提示 | | template_config_version | CharField | 配置版本 | | template_config_hash | CharField | 配置 hash | | adapter_summary | JSONField | `.doc`/`.docx` 适配器信息 | | work_dir | CharField | 工作目录 | | error_message | TextField | 错误信息 | | started_at/finished_at | DateTimeField | 执行时间 | | is_deleted | BooleanField | 软删除 | 索引: | 索引 | 字段 | | --- | --- | | idx_ra_rip_batch_conv_status | conversation, status | | idx_ra_rip_batch_user_created | user, created_at | | idx_ra_rip_batch_attachment | source_attachment | | idx_ra_rip_batch_summary | source_summary_batch | ### 12.2 RegulatoryInfoPackageArtifact 产物类型: | 类型 | 说明 | | --- | --- | | template_copy | 模板副本 | | instruction_extract | 说明书抽取结果 | | field_extract_result | 字段抽取结果 | | merged_fields | 合并字段 | | generated_document | 生成文件 | | traceability | 追溯清单 | | zip_package | zip 包 | | notification_record | 通知记录 | 字段与 `ApplicationFormFillArtifact` 保持一致:`batch`、`artifact_type`、`file_format`、`name`、`file_name`、`storage_path`、`file_size`、`content_hash`、`metadata`、`created_by_node`、`is_deleted`。 `file_format` 增加 `DOC`、`ZIP`。 ### 12.3 RegulatoryInfoPackageNotificationRecord 结构对齐 `ApplicationFormFillNotificationRecord`: | 字段 | 说明 | | --- | --- | | batch | 所属 RIP 批次 | | recipient | 通知对象 | | channel | feishu_cli、feishu_api、mock | | export_ids | 导出 ID | | message_summary | 通知摘要 | | send_status | pending、success、failed | | retry_count | 重试次数 | | external_message_id | 外部消息 ID | | error_message | 错误 | | sent_at | 发送时间 | --- ## 十三、工作流设计 ### 13.1 节点定义 | 节点编码 | 节点名称 | 触发服务 | 成功条件 | 失败处理 | | --- | --- | --- | --- | --- | | prepare | 准备资料 | `RegulatoryInfoPackageWorkflowExecutor` | 找到唯一说明书 | 缺失或多候选进入 waiting_user | | template_copy | 复制模板 | `TemplateRepository` | 7 个模板进入批次目录 | 缺关键模板则 failed | | text_extract | 抽取说明书 | `InstructionExtractService` | 提取文本、章节和表格 | 失败则 failed | | field_extract | 抽取字段 | `FieldExtractionService` | 规则/LLM 结果留底 | LLM 失败可继续 | | field_merge | 合并字段 | `FieldMergeService` | 输出 merged_fields | 无产品名仍继续,产品名 `/` | | generate_docs | 生成材料 | `PackageGenerateService` | 生成 7 个文件 | 单文件失败可 partial_success | | highlight_review_items | 标记待确认 | 文档适配器 | 缺失/LLM-only/冲突完成高亮 | 失败则对应文件失败 | | trace_export | 追溯清单 | `TraceabilityExportService` | 生成 Excel/JSON | 不阻断 zip | | zip_export | 打包下载 | `ZipExportService` | 生成 zip 并创建导出记录 | zip 失败则保留单文件 | | notify | 通知 | `Notifier` | 写通知记录 | 不阻断下载 | | completed | 完成 | Executor | 状态落定、摘要写入对话 | - | ### 13.2 状态落定 | 结果 | 批次状态 | | --- | --- | | 7 个文件、zip、追溯清单均成功 | success | | zip 成功但部分单文件/追溯/通知失败 | partial_success | | 单文件成功但 zip 失败 | partial_success | | 关键输入或模板缺失 | failed 或 waiting_user | | 所有目标文件生成失败 | failed | --- ## 十四、接口设计 ### 14.1 URL ```text GET /api/review-agent/regulatory-info-package/health/ POST /api/review-agent/regulatory-info-package/start/ GET /api/review-agent/regulatory-info-package//status/ POST /api/review-agent/regulatory-info-package//select-input/ ``` ### 14.2 start 请求: ```json { "conversation_id": 1, "attachment_id": 10, "file_summary_batch_id": 20, "source_summary_item_id": 30 } ``` 响应: ```json { "batch_id": 1, "workflow_type": "regulatory_info_package", "batch_no": "RIP-20260610153000-abcdef", "status": "pending" } ``` ### 14.3 status 响应包含: | 字段 | 说明 | | --- | --- | | batch | 批次基础信息、产品名、缺失数、LLM-only 数、冲突数 | | nodes | 工作流节点 | | generated_files | 7 个文件状态 | | exports | zip、单文件、追溯清单下载 | | missing_fields | 缺失项摘要 | | llm_only_fields | LLM-only 摘要 | | conflict_fields | 冲突摘要 | | risk_notes | 风险提示 | | notifications | 通知记录 | --- ## 十五、前端设计 ### 15.1 对话框底部快捷提示 `templates/home.html` 增加 tool chip: ```text 根据说明书生成第1章监管信息 ``` 点击后填入 prompt,不自动发送,保持现有交互一致。 ### 15.2 工作流卡片 `build_workflow_cards()` 增加 RIP 批次,前端复用现有卡片样式,展示: | 信息 | 说明 | | --- | --- | | 批次号 | RIP-... | | 状态 | pending/running/success/partial_success/failed | | 风险摘要 | 缺失字段 N、LLM复核 N、提示 N | | 节点 | RIP 节点 | ### 15.3 状态轮询 `summaryPanel` 增加: ```html data-regulatory-info-package-status-url-template="/api/review-agent/regulatory-info-package/__batch_id__/status/" ``` `static/js/app.js` 在工作流类型判断中增加 `regulatory_info_package`。 ### 15.4 结果展示 状态 payload 中 `exports` 按类别展示: | 类别 | 展示 | | --- | --- | | zip | 主下载按钮 | | generated_document | 单文件下载列表 | | traceability | 追溯清单下载 | --- ## 十六、通知设计 复用统一通知服务,新增 `build_regulatory_info_package_context(batch)`: | 摘要项 | 说明 | | --- | --- | | 工作流 | 第1章监管信息材料包生成 | | 批次号 | RIP-... | | 产品名称 | 抽取产品名 | | 导出文件 | zip + 单文件数量 | | 待确认 | 缺失项、LLM-only、冲突项数量 | | 下载提示 | 进入系统下载 zip | 通知失败不影响下载。 --- ## 十七、异常与降级 | 异常 | 处理 | | --- | --- | | 未找到说明书 | 返回提示,不创建或创建 waiting_user 批次 | | 多说明书候选 | waiting_user,等待选择 | | YAML 配置错误 | failed,提示配置错误 | | 样例模板缺失 | failed,列出缺失模板 | | LLM 失败 | 使用规则抽取继续,写 risk_notes | | 规则抽取为空 | 使用 LLM-only 继续并高亮 | | 知识库不可用 | 标准清单填 `/` 并高亮,写 risk_notes | | `.doc` 适配器不可用 | CH1.9 失败,批次 partial_success 或 failed,明确原因 | | zip 打包失败 | 保留单文件下载,状态 partial_success | | 下载文件不存在 | 返回 404,记录日志 | --- ## 十八、安全与权限 | 控制点 | 设计 | | --- | --- | | 批次访问 | `conversation__user == request.user` | | 附件访问 | 附件必须属于当前对话和当前用户 | | 汇总批次访问 | 批次必须属于当前对话和当前用户 | | 导出下载 | `workflow_type=regulatory_info_package` 时反查 RIP 批次 | | 工作目录 | `media/regulatory_info_package/{user_id}/{conversation_id}/{batch_no}` | | 路径安全 | 所有复制/输出路径必须校验位于批次工作目录内 | | 原始模板保护 | 只读复制,不允许覆盖 `docs/0.原始材料` | --- ## 十九、测试设计 | 测试文件 | 覆盖 | | --- | --- | | `tests/test_regulatory_info_package_models.py` | 批次、产物、通知、zip 导出类型 | | `tests/test_regulatory_info_package_trigger.py` | 固定规则与 LLM 路由 | | `tests/test_regulatory_info_package_input_select.py` | 说明书选择、多候选 waiting_user | | `tests/test_regulatory_info_package_template_config.py` | YAML 加载、模板存在性校验 | | `tests/test_regulatory_info_package_field_extract.py` | 说明书字段、表格、标准号抽取 | | `tests/test_regulatory_info_package_field_merge.py` | missing、llm_only、conflict 高亮决策 | | `tests/test_regulatory_info_package_docx_writer.py` | docx 替换、表格填充、黄底 | | `tests/test_regulatory_info_package_legacy_doc.py` | `.doc` 适配器能力探测和失败提示 | | `tests/test_regulatory_info_package_zip.py` | zip 只包含 success/fallback_success 文件 | | `tests/test_regulatory_info_package_workflow.py` | 工作流节点和状态落定 | | `tests/test_regulatory_info_package_views.py` | start/status/权限 | | `tests/test_regulatory_info_package_frontend.py` | 卡片、快捷提示、状态 URL | 回归测试: ```bash python manage.py check pytest tests/test_application_form_fill_*.py tests/test_file_summary_views.py tests/test_regulatory_*tests.py ``` 实际执行时按项目现有测试命名拆分运行。 --- ## 二十、实施顺序建议 | 阶段 | 内容 | | --- | --- | | RIP-1 | 模型、迁移、ExportType.ZIP、下载权限 | | RIP-2 | 模块骨架、YAML 配置、输入说明书选择 | | RIP-3 | 路由 action、对话启动、工作流节点 | | RIP-4 | 说明书文本/表格抽取、规则 + LLM 字段抽取 | | RIP-5 | docx 文档生成、黄底高亮、产品列表重建 | | RIP-6 | `.doc` 适配器、CH1.9 处理能力 | | RIP-7 | 追溯清单、zip 导出、助手摘要 | | RIP-8 | 前端卡片、快捷提示、状态轮询 | | RIP-9 | 通知、权限、全量回归 | --- ## 二十一、待确认与风险 | 风险 | 说明 | 建议 | | --- | --- | --- | | `.doc` 原生写入难度 | Python 标准库不支持 Word `.doc` 完整写入 | 优先调研 Word COM 或 LibreOffice UNO;设计适配器隔离风险 | | 样例模板文本碎片 | Word run 拆分可能导致简单字符串替换失败 | 文档写入服务需支持跨 run 替换 | | 产品列表结构复杂 | 说明书表格可能存在合并单元格和多规格 | 先覆盖目标说明书结构,再扩展通用表格归一化 | | 标准清单准确性 | 说明书未必包含标准号,知识库候选不能直接作为结论 | 候选全部高亮并进入追溯清单 | | LLM-only 风险 | LLM 推断可能过度补全 | 写入但高亮,追溯清单标记需复核 | --- ## 二十二、设计结论 | 编号 | 结论 | | --- | --- | | D1 | 功能设计文档新增为 `docs/2.功能设计/5.第1章监管信息材料包生成.md` | | D2 | 新增独立模块 `review_agent/regulatory_info_package/` | | D3 | 新建独立批次、产物、通知三张表 | | D4 | 输入选择以 active 附件为主,兼容最近成功文件汇总批次 | | D5 | `ExportedSummaryFile.ExportType` 扩展 `zip` | | D6 | 采用 YAML 配置驱动 7 个模板 | | D7 | `.doc` 通过 `LegacyWordDocumentService` 适配器实现与 `.docx` 等价接口 | | D8 | 标准候选复用系统已有知识库/RAG,不新增独立 RAG | | D9 | 前端只扩展现有对话页、工作流卡片、快捷提示和状态轮询 | | D10 | 本轮先产出功能设计;数据库设计先在本文档中给出,后续可拆成正式数据库设计文档 |