feat(regulatory-info-package): 接入对话和前端卡片

This commit is contained in:
2026-06-10 19:50:03 +08:00
parent dac8ce3c14
commit dcd829e821
6 changed files with 156 additions and 3 deletions

View File

@@ -11,6 +11,10 @@ from .file_summary.workflow_trigger import (
from .application_form_fill.constants import FORM_FILL_TRIGGER_KEYWORDS, WORKFLOW_TYPE as FORM_FILL_WORKFLOW_TYPE
from .llm import LLMConfigurationError, LLMRequestError, generate_completion
from .models import Conversation, FileAttachment
from .regulatory_info_package.constants import (
REGULATORY_INFO_PACKAGE_TRIGGER_KEYWORDS,
WORKFLOW_TYPE as REGULATORY_INFO_PACKAGE_WORKFLOW_TYPE,
)
logger = logging.getLogger(__name__)
@@ -18,6 +22,7 @@ logger = logging.getLogger(__name__)
ROUTE_ACTIONS = {"normal_chat", "attachment_reader", "file_summary"}
ROUTE_ACTIONS.add("regulatory_review")
ROUTE_ACTIONS.add(FORM_FILL_WORKFLOW_TYPE)
ROUTE_ACTIONS.add(REGULATORY_INFO_PACKAGE_WORKFLOW_TYPE)
@dataclass(frozen=True)
@@ -45,6 +50,10 @@ class SkillRoute:
def starts_application_form_fill(self) -> bool:
return self.action == FORM_FILL_WORKFLOW_TYPE
@property
def starts_regulatory_info_package(self) -> bool:
return self.action == REGULATORY_INFO_PACKAGE_WORKFLOW_TYPE
@property
def is_normal_chat(self) -> bool:
return self.action == "normal_chat"
@@ -80,6 +89,14 @@ def route_message_intent(conversation: Conversation, content: str) -> SkillRoute
def _deterministic_workflow_route(conversation: Conversation, content: str) -> SkillRoute | None:
if _matches_regulatory_info_package(content):
return SkillRoute(
action=REGULATORY_INFO_PACKAGE_WORKFLOW_TYPE,
workflow_type=REGULATORY_INFO_PACKAGE_WORKFLOW_TYPE,
confidence=0.9,
reason="命中明确第1章监管信息材料包生成关键词。",
source="rule_preflight",
)
if _matches_application_form_fill(content):
return SkillRoute(
action=FORM_FILL_WORKFLOW_TYPE,
@@ -144,7 +161,9 @@ def _route_with_llm(
return SkillRoute(
action=action,
skill_name="attachment_reader" if action == "attachment_reader" else "",
workflow_type=action if action in {"file_summary", "regulatory_review", FORM_FILL_WORKFLOW_TYPE} else "",
workflow_type=action
if action in {"file_summary", "regulatory_review", FORM_FILL_WORKFLOW_TYPE, REGULATORY_INFO_PACKAGE_WORKFLOW_TYPE}
else "",
confidence=_float_or_zero(payload.get("confidence")),
reason=str(payload.get("reason") or ""),
source="llm",
@@ -152,6 +171,15 @@ def _route_with_llm(
def _route_with_rules(conversation: Conversation, content: str) -> SkillRoute:
if _matches_regulatory_info_package(content):
return SkillRoute(
action=REGULATORY_INFO_PACKAGE_WORKFLOW_TYPE,
workflow_type=REGULATORY_INFO_PACKAGE_WORKFLOW_TYPE,
confidence=0.7,
reason="命中第1章监管信息材料包生成关键词。",
source="rule_fallback",
)
if _matches_application_form_fill(content):
return SkillRoute(
action=FORM_FILL_WORKFLOW_TYPE,
@@ -210,11 +238,12 @@ def _router_system_prompt() -> str:
return (
"你是审核智能体的工具路由器,只判断是否需要调用工具,不直接回答用户。"
"你必须只输出 JSON 对象,不要输出 Markdown。"
"可选 actionnormal_chat、attachment_reader、file_summary、regulatory_review、application_form_fill。"
"可选 actionnormal_chat、attachment_reader、file_summary、regulatory_review、application_form_fill、regulatory_info_package"
"attachment_reader 用于用户要求阅读、提取、分析、总结、查看上传附件内容。"
"file_summary 用于用户要求自动汇总文件目录、页数、清单或生成目录页数报告。"
"regulatory_review 用于用户要求法规核查、NMPA核查、完整性核查、章节一致性核查、风险预警或整改建议。"
"application_form_fill 用于用户要求填注册证、生成申报模板、填写对应表格、安全和性能基本原则清单或自动填表。"
"regulatory_info_package 用于用户要求根据说明书生成第1章监管信息、监管信息材料包、申请表、产品列表或声明材料包。"
"normal_chat 用于不需要读取附件或执行工作流的一般问答。"
"输出字段action、confidence、reason。"
)
@@ -268,6 +297,11 @@ def _matches_regulatory_review(content: str) -> bool:
return any(keyword in normalized for keyword in keywords)
def _matches_regulatory_info_package(content: str) -> bool:
normalized = "".join((content or "").lower().split())
return any("".join(keyword.lower().split()) in normalized for keyword in REGULATORY_INFO_PACKAGE_TRIGGER_KEYWORDS)
def _matches_application_form_fill(content: str) -> bool:
normalized = content.lower()
return any(keyword.lower() in normalized for keyword in FORM_FILL_TRIGGER_KEYWORDS)