Files
DEMO-AGENT/docs/3.详细设计/2.NMPA注册资料法规核查与整改闭环.md

667 lines
21 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.
# NMPA 注册资料法规核查与整改闭环工作流详细设计
## 文档信息
| 项目 | 内容 |
| --- | --- |
| 需求分析文档 | docs/1.需求分析/2.NMPA注册资料法规核查与整改闭环.md |
| 功能设计文档 | docs/2.功能设计/2.NMPA注册资料法规核查与整改闭环.md |
| 数据库设计文档 | docs/4.数据库设计/2.NMPA注册资料法规核查与整改闭环.md |
| 依赖详细设计 | docs/3.详细设计/1.自动汇总.md |
| 功能名称 | NMPA 注册资料法规核查与整改闭环 |
| 所属模块 | 审核智能体 review_agent |
| 设计日期 | 2026-06-06 |
| 设计版本 | V1.0 |
---
## 一、详细设计目标
本详细设计用于指导“NMPA 注册资料法规核查与整改闭环”功能开发落地,覆盖代码结构、通用工作流改造、法规核查执行器、规则/RAG/LLM 调用边界、服务拆分、接口契约、前端交互、飞书 CLI 通知、过程产物留底、异常重试和测试建议。
核心约束:
| 约束 | 说明 |
| --- | --- |
| 复用自动汇总 | 不重复实现上传、解压、扫描和页数统计,法规核查基于 `FileSummaryBatch` 执行 |
| 独立工作流 | 法规核查有独立 `RegulatoryReviewBatch` 和卡片,事件机制与文件汇总共用 |
| 通用事件模型 | `WorkflowNodeRun``WorkflowEvent``ExportedSummaryFile` 增加 workflow_type 和 workflow_batch_id |
| 异步执行 | 启动接口立即返回 batch_id后台执行并通过 SSE 更新卡片 |
| 暂停恢复 | 遇到 waiting_user 时后台任务结束,用户确认后重新唤起执行器继续 |
| 规则优先 | 结构化规则负责合规判断RAG 只补充依据LLM 只用于低置信度字段抽取和建议润色 |
| 过程留底 | 文本抽取、RAG 结果、LLM 输出、通知和复核记录均生成过程产物 |
---
## 二、代码结构设计
### 2.1 目录结构
`review_agent` 应用内新增 `regulatory_review/` 模块。法规核查与文件汇总并列,通过共享工作流事件和导出服务协同。`review_agent/workflow/` 是对模块 1 中 `file_summary/events.py`、节点状态和导出记录能力的通用化抽取,不是为法规核查重建一套并行事件体系。
```text
review_agent/
models.py
urls.py
views.py
file_summary/
...
workflow/
__init__.py
constants.py
events.py
node_runs.py
exports.py
regulatory_review/
__init__.py
constants.py
schemas.py
urls.py
views.py
workflow.py
storage.py
services/
__init__.py
rule_loader.py
rag_citation.py
info_extract.py
text_extract.py
completeness_check.py
structure_check.py
consistency_check.py
risk_assess.py
export.py
feishu_notifier.py
rectification_review.py
condition_parser.py
rules/
nmpa_ivd_registration_v1.yaml
prompts/
condition_parse.md
field_extract.md
suggestion_polish.md
```
### 2.2 文件职责
| 文件 | 职责 |
| --- | --- |
| workflow/constants.py | 通用 workflow_type、节点状态、事件类型 |
| workflow/events.py | 通用 SSE 事件持久化和格式化 |
| workflow/node_runs.py | 通用节点状态创建、更新和恢复 |
| workflow/exports.py | 通用导出记录和下载权限校验 |
| regulatory_review/constants.py | 法规核查节点、风险等级、问题状态常量 |
| regulatory_review/schemas.py | RegulatoryContext、NodeResult、Finding 等 dataclass |
| regulatory_review/workflow.py | RegulatoryWorkflowExecutor负责编排节点和暂停恢复 |
| regulatory_review/storage.py | 法规核查过程产物路径、hash、文件保存 |
| services/rule_loader.py | 加载规则版本、校验 hash、裁剪适用规则 |
| services/rag_citation.py | 基于 findings 批量检索法规依据 |
| services/info_extract.py | 从文件清单和文本片段抽取适用条件候选值 |
| services/condition_parser.py | 将用户自然语言确认解析为结构化字段 |
| services/text_extract.py | 统一抽取关键文件文本并缓存为 JSON 产物 |
| services/completeness_check.py | 完整性核查,生成 findings |
| services/structure_check.py | 章节结构核查,生成 findings |
| services/consistency_check.py | 跨文件一致性核查,生成 findings |
| services/risk_assess.py | 去重、风险分级、RAG 依据引用、写入 RegulatoryIssue |
| services/export.py | 生成最终报告和过程产物,支持重试 |
| services/feishu_notifier.py | 通过飞书 CLI 发送通知,支持 3 次重试 |
| services/rectification_review.py | 补充资料后的问题复核和状态更新 |
---
## 三、通用工作流改造
### 3.1 WorkflowNodeRun 改造
现有节点状态表需要兼容多类工作流。
| 字段 | 处理 |
| --- | --- |
| batch_id | 保留,兼容文件汇总旧逻辑 |
| workflow_type | 新增file_summary、regulatory_review |
| workflow_batch_id | 新增,保存对应工作流批次 ID |
| node_group | 新增,可选,用于法规核查卡片主节点聚合 |
唯一约束调整为:
```text
unique(workflow_type, workflow_batch_id, node_code)
```
文件汇总旧逻辑写入时同步设置:
```text
workflow_type = file_summary
workflow_batch_id = file_summary_batch.id
batch_id = file_summary_batch.id
```
### 3.2 WorkflowEvent 改造
事件表同样新增:
| 字段 | 说明 |
| --- | --- |
| workflow_type | file_summary、regulatory_review |
| workflow_batch_id | 对应工作流批次 ID |
| conversation_id | 冗余记录对话 ID便于 SSE 查询 |
SSE 查询时按 `conversation_id` 获取多个工作流事件,前端根据 `workflow_type + workflow_batch_id` 更新对应卡片。
### 3.3 ExportedSummaryFile 改造
最终下载文件表通用化:
| 字段 | 说明 |
| --- | --- |
| workflow_type | file_summary、regulatory_review |
| workflow_batch_id | 对应工作流批次 ID |
| export_category | summary_report、risk_report、excel_list、json_package |
法规核查最终 Markdown、Excel、JSON 结果包进入 `ExportedSummaryFile`;过程产物进入 `RegulatoryArtifact`
---
## 四、核心数据结构
### 4.1 RegulatoryContext
节点间传递统一上下文,避免每个服务重复组装状态。
```python
@dataclass
class RegulatoryContext:
regulatory_batch: RegulatoryReviewBatch
file_summary_batch: FileSummaryBatch | None
rule_version: RegulatoryRuleVersion | None
rules: dict[str, Any]
scoped_rules: list[dict[str, Any]]
conditions: dict[str, Any]
file_items: list[FileSummaryItem]
text_artifacts: dict[str, Any]
findings: list["Finding"]
issues: list[RegulatoryIssue]
artifacts: list[RegulatoryArtifact]
reference_only: bool = False
```
### 4.2 NodeResult
每个节点统一返回 `NodeResult`
```python
@dataclass
class NodeResult:
status: str
message: str = ""
payload: dict[str, Any] = field(default_factory=dict)
findings: list["Finding"] = field(default_factory=list)
artifacts: list[RegulatoryArtifact] = field(default_factory=list)
next_node: str | None = None
```
### 4.3 Finding
核查服务只返回 findings不直接写 `RegulatoryIssue`。Issue 由 `RiskAssessService` 统一去重、分级和落库。
```python
@dataclass
class Finding:
finding_key: str
issue_type: str
initial_risk_level: str
title: str
description: str
rule_id: str | None = None
file_item_id: int | None = None
file_path: str | None = None
page_no: int | None = None
field_name: str | None = None
evidence: dict[str, Any] = field(default_factory=dict)
suggestion_template: str | None = None
source_node: str | None = None
```
---
## 五、工作流执行设计
### 5.1 启动流程
```text
POST /regulatory-review/start/
-> 创建 RegulatoryReviewBatch(status=pending)
-> 查找当前对话最近一次 success FileSummaryBatch
-> 如有则绑定并异步启动法规核查
-> 如无则创建 FileSummaryBatch 并启动自动汇总
-> 自动汇总 success 后回填 file_summary_batch_id
-> 继续法规核查 prepare 节点
```
如果用户明确说“重新核查最新上传资料”,系统强制创建新的 `FileSummaryBatch`,再创建新的 `RegulatoryReviewBatch`
### 5.2 暂停与恢复
当适用条件缺失或解析冲突时:
```text
RegulatoryWorkflowExecutor
-> 写入 condition_confirm 节点 status=waiting_user
-> RegulatoryReviewBatch.status=waiting_user
-> 发送 workflow SSE
-> 后台任务结束
```
用户确认后:
```text
POST /regulatory-review/{batch_id}/confirm-condition/
-> LLM 解析自然语言为结构化 JSON
-> 字段校验器校验必填字段
-> 如仍缺失,继续追问并保持 waiting_user
-> 如完整,写入 batch 核心字段和 condition_json
-> 重新唤起 RegulatoryWorkflowExecutor从 rule_scope 节点继续
```
### 5.3 节点调度
```text
prepare
-> info_extract
-> condition_confirm 或 rule_scope
-> rule_scope
-> completeness_check
-> text_extract
-> 并行执行 structure_check 和 consistency_check
-> risk_assess
-> report_export
-> notify
-> completed
```
章节核查和一致性核查通过后台线程池并行:
```python
with ThreadPoolExecutor(max_workers=2) as pool:
structure_future = pool.submit(structure_service.run, context)
consistency_future = pool.submit(consistency_service.run, context)
```
### 5.4 关键节点
关键节点失败时终止批次:
| 节点 | 失败处理 |
| --- | --- |
| prepare | 无法绑定文件汇总批次,批次 failed |
| rule_scope | 规则 hash 不一致,批次 failed规则加载失败可降级 reference_only |
| report_export | 最终报告重试失败,批次 failed |
非关键节点失败时生成 `Finding``RegulatoryIssue`,工作流尽量继续:
| 节点 | 失败处理 |
| --- | --- |
| text_extract | 对相关文件生成待确认 finding |
| structure_check | 生成章节核查失败 finding |
| consistency_check | 生成一致性待确认 finding |
| notify | 写通知失败记录,批次可 partial_success |
---
## 六、规则、RAG 与 LLM 设计
### 6.1 RuleLoader
流程:
```text
读取当前 active RegulatoryRuleVersion
-> 读取 rule_file_path
-> 计算文件 hash
-> 与 rule_file_hash 比对
-> hash 一致则解析规则
-> 按适用条件裁剪 scoped_rules
```
处理策略:
| 场景 | 处理 |
| --- | --- |
| 规则文件 hash 不一致 | 停止执行并标记 failed |
| 规则文件不存在或解析失败 | 降级 RAG 辅助核查batch.status=reference_only |
| RAG 索引版本缺失 | 记录提示项,但规则核查可继续 |
### 6.2 RagCitationService
RAG 在 `RiskAssessService` 阶段批量调用,而不是每个核查节点实时调用。
输入:
| 字段 | 说明 |
| --- | --- |
| findings | 所有核查 findings |
| rule_version | 当前法规规则版本 |
| scoped_rules | 本次适用规则 |
输出:
| 字段 | 说明 |
| --- | --- |
| citations_by_finding | finding_key 到法规依据列表的映射 |
| rag_result_json | RAG 检索结果过程产物 |
### 6.3 LLM 调用边界
| 场景 | 是否调用 LLM | 说明 |
| --- | --- | --- |
| 自然语言适用条件解析 | 是 | 解析为结构化 JSON再由字段校验器校验 |
| 低置信度字段抽取 | 是 | 规则/正则失败或置信度低时调用 |
| 整改建议润色 | 是 | 规则模板生成标准动作LLM 润色表达 |
| 风险等级判断 | 否 | 风险等级由规则和 RiskAssess 决定 |
| 法规结论判断 | 否 | 合规判断不交给 LLM |
LLM 抽取结果需写入过程产物,可使用 `llm_extract_json` 或并入 `text_extract_json`
---
## 七、服务详细设计
### 7.1 RegulatoryWorkflowExecutor
| 方法 | 说明 |
| --- | --- |
| start(batch_id) | 创建后台任务并返回 |
| run(batch_id, start_node=None) | 运行法规核查节点 |
| build_context(batch_id) | 组装 RegulatoryContext |
| run_node(node_code, context) | 执行单个节点并处理 NodeResult |
| run_parallel_checks(context) | 并行执行章节和一致性核查 |
| pause_for_user(batch, node_code, message) | 写 waiting_user 状态并结束任务 |
| complete(batch) | 标记批次完成 |
| fail(batch, error) | 标记批次失败 |
### 7.2 ConditionParserService
| 方法 | 说明 |
| --- | --- |
| parse(raw_user_input, previous_conditions) | 使用 LLM 解析自然语言 |
| validate(parsed_json) | 校验产品类别、注册类型、临床路径、产品名称、型号规格、预期用途 |
| merge(batch, parsed_json) | 写入批次字段和 condition_json |
### 7.3 RiskAssessService
| 方法 | 说明 |
| --- | --- |
| deduplicate(findings) | 按 finding_key、rule_id、file_item_id 去重 |
| attach_citations(findings) | 批量调用 RAG 获取法规依据 |
| resolve_risk(finding) | 统一风险等级,处理升级/降级 |
| generate_suggestion(finding) | 规则模板 + LLM 润色 |
| create_issues(batch, findings) | 统一写入 RegulatoryIssue |
| build_risk_summary(batch) | 写入 risk_summary_json |
### 7.4 RegulatoryExportService
| 方法 | 说明 |
| --- | --- |
| export_final_markdown(batch) | 生成最终 Markdown 核查报告 |
| export_final_excel(batch) | 生成 Excel 缺失清单 |
| export_json_package(batch) | 生成结构化 JSON 结果包 |
| create_artifact(batch, artifact_type, path) | 写 RegulatoryArtifact 并计算 hash |
| create_export_record(batch, path, category) | 写 ExportedSummaryFile |
| retry_export(fn, max_retry=3) | 导出失败重试 |
重试策略:
| 产物 | 重试后仍失败 |
| --- | --- |
| 最终 Markdown/Excel/JSON | 批次 failed |
| 非关键过程产物 | 批次 partial_success |
### 7.5 FeishuNotifier
调用方式必须使用参数数组,不拼接 shell 字符串。
```python
subprocess.run(
[cli_path, "send", "--user", feishu_user_id, "--message", message],
check=True,
capture_output=True,
text=True,
)
```
处理策略:
| 场景 | 处理 |
| --- | --- |
| 用户无 feishu_user_id | 写通知失败记录,不阻断 |
| CLI 执行失败 | 最多重试 3 次 |
| 仍失败 | send_status=failed批次可 partial_success |
| 成功 | 写 external_message_id 和 sent_at |
通知内容包含系统内风险报告链接,不附原始文件。
---
## 八、接口详细设计
### 8.1 发起法规核查
| 项目 | 内容 |
| --- | --- |
| URL | POST /api/review-agent/regulatory-review/start/ |
| 请求 | conversation_id、file_summary_batch_id 可选、force_resummary 可选 |
| 响应 | regulatory_batch_id、workflow_type、status |
响应示例:
```json
{
"regulatory_batch_id": 2001,
"workflow_type": "regulatory_review",
"status": "pending"
}
```
### 8.2 确认适用条件
| 项目 | 内容 |
| --- | --- |
| URL | POST /api/review-agent/regulatory-review/{batch_id}/confirm-condition/ |
| 请求 | raw_user_input、可选结构化字段 |
| 响应 | status、missing_fields、next_question |
如果解析完整:
```json
{
"status": "accepted",
"next_node": "rule_scope"
}
```
如果仍缺失:
```json
{
"status": "need_more_info",
"missing_fields": ["clinical_evaluation_path"],
"next_question": "请确认临床评价路径:临床试验、免临床,还是同品种比对?"
}
```
### 8.3 查询状态
| 项目 | 内容 |
| --- | --- |
| URL | GET /api/review-agent/regulatory-review/{batch_id}/ |
| 响应 | 批次、节点、风险摘要、导出文件、过程产物 |
### 8.4 发起整改复核
| 项目 | 内容 |
| --- | --- |
| URL | POST /api/review-agent/regulatory-review/{batch_id}/rectify-review/ |
| 请求 | issue_ids、file_summary_batch_id 或 uploaded_file_ids |
| 响应 | review_status、updated_issues、review_artifact_id |
补充文件必须复用自动汇总上传与汇总能力。上传后先生成新的 `FileSummaryBatch`,再由 `RectificationReviewService` 对原批次问题执行复核。复核不创建新的 `RegulatoryReviewBatch`
---
## 九、前端与对话交互
### 9.1 工作流卡片
| 设计点 | 说明 |
| --- | --- |
| 卡片切换 | 多工作流卡片使用轮播切换 |
| 卡片识别 | 使用 workflow_type + workflow_batch_id |
| 状态来源 | SSE workflow 事件 |
| 法规卡片 | 展示主节点和可展开子节点 |
| waiting_user | 卡片显示等待确认,对话框给出选择和追问 |
### 9.2 自然语言确认
对话框中用户可以用自然语言确认,例如:
```text
按体外诊断试剂首次注册处理,临床评价路径走同品种比对,产品名称是 XXX型号规格是 YYY预期用途是 ZZZ。
```
后端解析并校验后继续工作流。原始输入写入 `condition_json.raw_user_input`
### 9.3 整改复核触发
Demo 阶段通过对话指令触发:
```text
我已补充注册检验报告,请复核阻断项。
```
系统识别后调用复核接口,要求用户上传补充文件或选择已上传文件。
---
## 十、过程产物与报告
### 10.1 文件命名
过程产物和最终报告采用固定模板:
```text
{batch_no}_{artifact_type}.{ext}
```
示例:
```text
RRB202606060001_rule_matrix.xlsx
RRB202606060001_risk_list.json
RRB202606060001_final_report.md
```
### 10.2 文件保存
路径:
```text
media/regulatory_review/{user_id}/{conversation_id}/{batch_id}/
```
所有 `RegulatoryArtifact` 必须计算 SHA-256 hash。
### 10.3 报告内容
最终 Markdown 报告包含:
| 模块 | 说明 |
| --- | --- |
| 核查概览 | 批次、规则版本、RAG 版本、上传人 |
| 适用条件 | 系统抽取和用户确认结果 |
| 风险清单 | 五级风险、状态、责任人、建议 |
| 法规核查矩阵 | 应有文件、实际文件、缺失情况 |
| 章节核查结果 | 缺失章节、异常章节 |
| 一致性核查结果 | 字段冲突和来源文件 |
| 飞书通知记录 | 发送对象、状态、失败原因 |
| 整改复核记录 | 复核方式、复核结果、关闭确认 |
---
## 十一、异常与重试
| 场景 | 处理 |
| --- | --- |
| 无成功 FileSummaryBatch | 自动启动文件汇总,成功后继续 |
| 文件汇总失败 | 法规核查批次 failed |
| 规则 hash 不一致 | 法规核查批次 failed |
| 规则加载失败 | 降级 reference_only仅输出参考性结果 |
| 用户确认信息缺失 | waiting_user追问缺失字段 |
| 文本抽取失败 | 生成待确认 finding继续后续节点 |
| 章节或一致性节点失败 | 生成对应 issue继续风险汇总 |
| RAG 检索无结果 | 规则问题仍输出,依据标记原文待补充 |
| LLM 调用失败 | 回退规则/正则结果,低置信度项待确认 |
| 飞书失败 | 重试 3 次,仍失败写通知失败记录 |
| 最终报告导出失败 | 重试 3 次,仍失败 batch failed |
| 非关键产物导出失败 | 重试 3 次,仍失败 batch partial_success |
---
## 十二、测试建议
### 12.1 单元测试
| 模块 | 测试点 |
| --- | --- |
| RuleLoader | hash 校验、规则解析、规则裁剪、加载失败降级 |
| ConditionParserService | 自然语言解析、缺失字段追问、原始输入留痕 |
| TextExtractService | 首页文本、章节文本、抽取失败产物 |
| CompletenessCheckService | 文件名/目录名/首页内容三层匹配 |
| StructureCheckService | 必需章节缺失识别 |
| ConsistencyCheckService | 字段冲突、低置信度 LLM 辅助 |
| RiskAssessService | findings 去重、风险升级/降级、Issue 落库 |
| RegulatoryExportService | 文件命名、hash、导出重试 |
| FeishuNotifier | 参数数组调用、3 次重试、失败记录 |
### 12.2 集成测试
| 场景 | 验证 |
| --- | --- |
| 已有汇总批次发起核查 | 默认复用最近 success 批次 |
| 无汇总批次发起核查 | 自动串联文件汇总后继续 |
| waiting_user 暂停恢复 | 用户确认后从 rule_scope 继续 |
| 章节和一致性并行 | 两个节点均完成后进入 risk_assess |
| 规则加载失败 | batch.status=reference_only |
| 飞书失败 | 不阻断报告,通知记录 failed |
| 补充文件复核 | 新 FileSummaryBatch 生成,原 Issue 状态更新 |
### 12.3 验收测试
| 序号 | 验收项 | 标准 |
| --- | --- | --- |
| 1 | 多工作流卡片 | 文件汇总和法规核查卡片可切换且状态独立 |
| 2 | 条件确认 | 用户自然语言确认后能结构化入库 |
| 3 | 完整性核查 | 能识别缺失注册检验报告等问题 |
| 4 | 章节核查 | 能识别关键章节缺失 |
| 5 | 一致性核查 | 能识别产品名称、型号规格、预期用途冲突 |
| 6 | 风险报告 | 输出 Markdown、Excel、JSON 结果包 |
| 7 | 飞书通知 | 阻断项、高风险、中风险能 @ 上传人 |
| 8 | 过程留底 | RAG、文本抽取、通知、复核均有 artifact |
| 9 | 整改复核 | 补充文件后原 Issue 可进入复核通过或复核不通过 |
---
## 十三、实施顺序建议
结合当前优先级,建议先打通 RAG 和 LLM 能力,再落完整工作流:
1. 构建本地法规材料 RAG 索引,并实现 `RagCitationService`
2. 实现适用条件解析和低置信度字段抽取的 LLM 调用封装。
3. 完成数据库模型和通用 workflow/export 表改造。
4. 实现 `RuleLoader` 与规则 hash 校验。
5. 实现 `RegulatoryWorkflowExecutor``RegulatoryContext``NodeResult`
6. 实现完整性、文本抽取、章节核查、一致性核查和风险归并。
7. 实现报告导出、过程产物 hash 和导出重试。
8. 接入飞书 CLI 通知和 3 次重试。
9. 改造前端多工作流卡片和适用条件确认交互。
10. 实现整改复核和 Issue 状态流转。