Files
DEMO-AGENT/docs/2.功能设计/5.第1章监管信息材料包生成.md

861 lines
31 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 第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/<batch_id>/status/
POST /api/review-agent/regulatory-info-package/<batch_id>/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 | 本轮先产出功能设计;数据库设计先在本文档中给出,后续可拆成正式数据库设计文档 |