21 KiB
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、节点状态和导出记录能力的通用化抽取,不是为法规核查重建一套并行事件体系。
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 | 新增,可选,用于法规核查卡片主节点聚合 |
唯一约束调整为:
unique(workflow_type, workflow_batch_id, node_code)
文件汇总旧逻辑写入时同步设置:
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
节点间传递统一上下文,避免每个服务重复组装状态。
@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。
@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 统一去重、分级和落库。
@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 启动流程
POST /regulatory-review/start/
-> 创建 RegulatoryReviewBatch(status=pending)
-> 查找当前对话最近一次 success FileSummaryBatch
-> 如有则绑定并异步启动法规核查
-> 如无则创建 FileSummaryBatch 并启动自动汇总
-> 自动汇总 success 后回填 file_summary_batch_id
-> 继续法规核查 prepare 节点
如果用户明确说“重新核查最新上传资料”,系统强制创建新的 FileSummaryBatch,再创建新的 RegulatoryReviewBatch。
5.2 暂停与恢复
当适用条件缺失或解析冲突时:
RegulatoryWorkflowExecutor
-> 写入 condition_confirm 节点 status=waiting_user
-> RegulatoryReviewBatch.status=waiting_user
-> 发送 workflow SSE
-> 后台任务结束
用户确认后:
POST /regulatory-review/{batch_id}/confirm-condition/
-> LLM 解析自然语言为结构化 JSON
-> 字段校验器校验必填字段
-> 如仍缺失,继续追问并保持 waiting_user
-> 如完整,写入 batch 核心字段和 condition_json
-> 重新唤起 RegulatoryWorkflowExecutor,从 rule_scope 节点继续
5.3 节点调度
prepare
-> info_extract
-> condition_confirm 或 rule_scope
-> rule_scope
-> completeness_check
-> text_extract
-> 并行执行 structure_check 和 consistency_check
-> risk_assess
-> report_export
-> notify
-> completed
章节核查和一致性核查通过后台线程池并行:
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
流程:
读取当前 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 字符串。
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 |
响应示例:
{
"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 |
如果解析完整:
{
"status": "accepted",
"next_node": "rule_scope"
}
如果仍缺失:
{
"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 自然语言确认
对话框中用户可以用自然语言确认,例如:
按体外诊断试剂首次注册处理,临床评价路径走同品种比对,产品名称是 XXX,型号规格是 YYY,预期用途是 ZZZ。
后端解析并校验后继续工作流。原始输入写入 condition_json.raw_user_input。
9.3 整改复核触发
Demo 阶段通过对话指令触发:
我已补充注册检验报告,请复核阻断项。
系统识别后调用复核接口,要求用户上传补充文件或选择已上传文件。
十、过程产物与报告
10.1 文件命名
过程产物和最终报告采用固定模板:
{batch_no}_{artifact_type}.{ext}
示例:
RRB202606060001_rule_matrix.xlsx
RRB202606060001_risk_list.json
RRB202606060001_final_report.md
10.2 文件保存
路径:
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 能力,再落完整工作流:
- 构建本地法规材料 RAG 索引,并实现
RagCitationService。 - 实现适用条件解析和低置信度字段抽取的 LLM 调用封装。
- 完成数据库模型和通用 workflow/export 表改造。
- 实现
RuleLoader与规则 hash 校验。 - 实现
RegulatoryWorkflowExecutor、RegulatoryContext、NodeResult。 - 实现完整性、文本抽取、章节核查、一致性核查和风险归并。
- 实现报告导出、过程产物 hash 和导出重试。
- 接入飞书 CLI 通知和 3 次重试。
- 改造前端多工作流卡片和适用条件确认交互。
- 实现整改复核和 Issue 状态流转。