Files
Agent-System/internal/intent/recognizer_matchers_kb.go
T

183 lines
6.2 KiB
Go
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.
package intent
import (
"regexp"
"strings"
)
// matchKnowledgeQuery 匹配法规标准、标杆案例与权限查询
func matchKnowledgeQuery(input string) *CandidateIntent {
// 排除事实参数补充的输入场景
excludeKeywords := []string{"客户说", "客户反馈", "客户补充", "补充说", "补充", "修改为", "改为", "增加"}
for _, ek := range excludeKeywords {
if strings.Contains(input, ek) {
return nil
}
}
// 1. 用户权限查询 (IntentQueryUserRights)
userRightsPatterns := []string{
"我的权限", "我有什么权限", "我负责什么", "我的角色", "查看我的职责",
"查询权限", "当前权限", "我在这个项目的角色", "法定角色", "法定职责", "我的职责",
"文档权限", "文档职责", "权限和职责", "职责和权限", "负责哪些文档", "权限",
}
for _, p := range userRightsPatterns {
if strings.Contains(input, p) {
return &CandidateIntent{
Intent: IntentQueryUserRights,
Confidence: 0.95,
FilledSlots: map[string]string{
SlotQueryTopic: "user_rights",
},
Reasoning: "用户查询自身在项目及受控文档中的法定职责与操作权限",
}
}
}
// 2. 标杆/相似案例查询 (IntentQuerySimilarCases)
similarCasesPatterns := []string{
"参考案例", "往期经验", "类似项目", "相似案例", "同类产品",
"同类项目", "以往案例", "标杆案例", "同类获批", "竞品获批案例",
"注册案例", "申报案例",
}
for _, p := range similarCasesPatterns {
if strings.Contains(input, p) {
return &CandidateIntent{
Intent: IntentQuerySimilarCases,
Confidence: 0.92,
FilledSlots: map[string]string{
SlotQueryTopic: "similar_cases",
},
Reasoning: "用户查询以往类似产品的注册申报、上市审评或标杆案例与经验",
}
}
}
// 3. 法规强标查询 (IntentQueryRegulations)
regKeywords := []string{
"gb 9706", "gb9706", "yy 0505", "yy0505", "强制性标准", "强标",
"技术审评指导原则", "指导原则", "合规要求", "注册标准",
}
lower := strings.ToLower(input)
for _, rk := range regKeywords {
if strings.Contains(lower, rk) {
return &CandidateIntent{
Intent: IntentQueryRegulations,
Confidence: 0.92,
FilledSlots: map[string]string{
SlotQueryTopic: "regulations",
},
Reasoning: "用户咨询医疗器械适用的国家标准、行业强标或审评指导原则法规",
}
}
}
if (strings.Contains(lower, "法规") || strings.Contains(lower, "标准") || strings.Contains(lower, "yy") || strings.Contains(lower, "fda") || strings.Contains(lower, "ce")) &&
(strings.Contains(lower, "查") || strings.Contains(lower, "哪些") || strings.Contains(lower, "满足") || strings.Contains(lower, "要求") || strings.Contains(lower, "规范")) {
return &CandidateIntent{
Intent: IntentQueryRegulations,
Confidence: 0.90,
FilledSlots: map[string]string{
SlotQueryTopic: "regulations",
},
Reasoning: "用户咨询医疗器械适用的国家标准、行业强标或审评指导原则法规",
}
}
if cand := matchMaterialRequest(input); cand != nil {
return cand
}
return nil
}
// matchMaterialRequest 识别说明书、操作视频、竞品资料等获取请求。
// 写动词(生成/编写)留给任务触发,避免把「编写说明书」误判成检索。
func matchMaterialRequest(input string) *CandidateIntent {
if hasTaskWriteVerb(input) || hasWeakTaskWriteVerb(input) {
return nil
}
for _, v := range []string{"撰写", "写一", "输出"} {
if strings.Contains(input, v) {
return nil
}
}
patterns := []string{
"说明书", "操作视频", "产品视频", "彩页", "规格书",
"使用手册", "操作手册", "产品手册", "手册",
"上一代", "前代", "上代产品",
"竞品", "同类产品资料",
}
for _, p := range patterns {
if strings.Contains(input, p) {
return &CandidateIntent{
Intent: IntentQuerySimilarCases,
Confidence: 0.82,
FilledSlots: map[string]string{
SlotQueryTopic: "materials",
},
Reasoning: "用户在索取说明书、操作视频、竞品或上一代产品资料,走知识检索",
}
}
}
return nil
}
// extractDocName 从文本或预设映射中提取目标受控文档名称/标识
func extractDocName(input string) string {
reDocID := regexp.MustCompile(`(doc-[a-zA-Z0-9_-]+)`)
if match := reDocID.FindString(input); match != "" {
return match
}
docNames := []string{
"用户初始需求收集表", "用户初始需求表", "用户需求收集表", "需求收集表", "需求表",
"技术与市场调研报告", "调研报告",
"法规与注册论证报告", "法规评估", "注册评估",
"初步设计与架构方案", "初步设计", "设计方案",
"CDO报价单", "初步报价单", "报价单",
}
for _, name := range docNames {
if strings.Contains(input, name) {
return name
}
}
reBa := regexp.MustCompile(`把\s*(.+?)\s*(?:审核驳回|终审驳回|驳回|审核通过|批准|认领|送审|提交审核)`)
if match := reBa.FindStringSubmatch(input); len(match) > 1 {
return strings.TrimSpace(match[1])
}
return ""
}
// extractRejectReason 从用户输入中提取驳回意见或批注内容
func extractRejectReason(input string) string {
reReason := regexp.MustCompile(`(?:意见为|意见是|意见|理由为|理由是|理由|原因|批注为|批注|修改意见)[::\s]\s*(.+)`)
if match := reReason.FindStringSubmatch(input); len(match) > 1 {
res := strings.TrimSpace(match[1])
return strings.Trim(res, ",,。;; ")
}
reAfterReject := regexp.MustCompile(`驳回[,,::\s]+(.+)`)
if match := reAfterReject.FindStringSubmatch(input); len(match) > 1 {
res := strings.TrimSpace(match[1])
res = regexp.MustCompile(`^(?:意见为|意见是|意见|理由为|理由是|理由|原因|批注为|批注|修改意见)[::\s]\s*`).ReplaceAllString(res, "")
res = strings.Trim(res, ",,。;; ")
if res != "" {
return res
}
}
return ""
}
// extractSection 从文本中抽取目标章节线索 (如 "第3节", "3.1节")
func extractSection(input string) string {
reSection := regexp.MustCompile(`(第[0-9一二三四五六七八九十]+[章节条部分]+|[0-9]+\.[0-9]+[节章]*)`)
if match := reSection.FindString(input); match != "" {
return match
}
return ""
}