32 KiB
第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 个模板、字段映射和生成策略 |
| 模板字段化 | 优先使用 Word 内容控件 Tag 或稳定占位符,让代码只写字段值,最大限度保留原格式 |
| 规则 + 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 目录结构
新增模块:
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 逻辑架构
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/第三方库适配器,能力不可用时使用可追溯的 .docx 兜底 |
| 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 固定规则
规则预判关键词:
REGULATORY_INFO_PACKAGE_TRIGGER_KEYWORDS = [
"根据说明书生成第1章监管信息",
"生成监管信息材料包",
"从说明书生成第1章材料",
"第1章监管信息",
"监管信息材料包",
]
规则命中时直接进入本工作流。规则未命中时,继续走 LLM 路由判断,避免自然表达漏触发。
5.3 对话启动
review_agent/services.py::stream_message 增加分支:
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 | 说明书存储路径 |
七、模板配置设计
配置路径:
review_agent/regulatory_info_package/templates/regulatory_info_package_templates_v1.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
prefer_legacy_doc_native: true
allow_docx_fallback: true
include_in_zip: true
字段映射优先级:
| 目标类型 | 说明 |
|---|---|
| content_control_tag | 正式模板优先,代码按 Word 内容控件 Tag 写入 |
| placeholder | 过渡方案,替换稳定占位符并保留原 run/段落格式 |
| table_row_label | 未字段化模板的兜底方案,必须保留原单元格格式 |
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 | 字段映射与替换目标 |
| prefer_legacy_doc_native | .doc 是否优先尝试原生处理能力 |
| allow_docx_fallback | 原生 .doc 能力不可用或失败时是否允许 .docx 兜底 |
八、字段抽取设计
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:
{
"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 定义统一接口:
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 并高亮 |
| 无命中 | 写 / 并黄底 |
| 样例标准 | 不无条件沿用 |
查询建议:
体外诊断试剂 核酸扩增 检测试剂 标准 清单
新型冠状病毒 2019-nCoV 核酸检测试剂盒 荧光PCR 标准
十一、zip 与导出设计
11.1 ExportType 扩展
ExportedSummaryFile.ExportType 增加:
ZIP = "zip", "ZIP"
下载 content type 增加:
"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 增加:
if exported.workflow_type == "regulatory_info_package":
查询 RegulatoryInfoPackageBatch
校验 conversation__user == request.user 且 is_deleted=False
十二、数据模型设计
12.1 RegulatoryInfoPackageBatch
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
GET /api/review-agent/regulatory-info-package/health/
POST /api/review-agent/regulatory-info-package/start/
GET /api/review-agent/regulatory-info-package/<batch_id>/status/
POST /api/review-agent/regulatory-info-package/<batch_id>/select-input/
14.2 start
请求:
{
"conversation_id": 1,
"attachment_id": 10,
"file_summary_batch_id": 20,
"source_summary_item_id": 30
}
响应:
{
"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:
根据说明书生成第1章监管信息
点击后填入 prompt,不自动发送,保持现有交互一致。
15.2 工作流卡片
build_workflow_cards() 增加 RIP 批次,前端复用现有卡片样式,展示:
| 信息 | 说明 |
|---|---|
| 批次号 | RIP-... |
| 状态 | pending/running/success/partial_success/failed |
| 风险摘要 | 缺失字段 N、LLM复核 N、提示 N |
| 节点 | RIP 节点 |
15.3 状态轮询
summaryPanel 增加:
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 |
回归测试:
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;无原生能力时允许可追溯 .docx 兜底 |
| 模板字段化工作量 | 需要先把样例模板整理为代码可识别字段 | 优先覆盖 CH1.4、CH1.5 和声明类关键字段;缺少 Tag 时通过模板审计提前暴露 |
| 样例模板文本碎片 | 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 | 模板字段优先使用内容控件 Tag 或稳定占位符,行标签定位仅作为兜底 |
| D8 | .doc 通过 LegacyWordDocumentService 适配器实现与 .docx 等价接口,原生能力不可用时允许可追溯兜底 |
| D9 | 标准候选复用系统已有知识库/RAG,不新增独立 RAG |
| D10 | 前端只扩展现有对话页、工作流卡片、快捷提示和状态轮询 |
| D11 | 本轮先产出功能设计;数据库设计先在本文档中给出,后续可拆成正式数据库设计文档 |