fix: 拆分系统判断与问题分类判断

This commit is contained in:
fuzhongyun 2026-02-04 16:52:23 +08:00
parent ec41a3d787
commit c9c9bca9ce
2 changed files with 93 additions and 25 deletions

View File

@ -286,10 +286,23 @@ func (d *DingTalkBotBiz) resolveSystemAndIssueType(ctx context.Context, requireD
}) })
// 2. LLM 分类 // 2. LLM 分类
classification, err := d.handle.ClassifyIssue(ctx, sysNames, issueTypeNames, requireData.Req.Text.Content, userHist) // 系统名称
classificationSys, err := d.handle.ClassifyIssueSystem(ctx, sysNames, requireData.Req.Text.Content, userHist)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// 问题类型
classificationIssueType, err := d.handle.ClassifyIssueType(ctx, issueTypeNames, requireData.Req.Text.Content, userHist)
if err != nil {
return nil, err
}
// 合并
classification := &do.IssueClassification{
SysName: classificationSys.SysName,
IssueTypeName: classificationIssueType.IssueTypeName,
Summary: classificationIssueType.Summary,
Reason: fmt.Sprintf("系统名称推断理由:%s\n问题类型推断理由%s", classificationSys.Reason, classificationIssueType.Reason),
}
// 3. 匹配系统 // 3. 匹配系统
var sys model.AiSy var sys model.AiSy

View File

@ -130,41 +130,96 @@ type IssueClassification struct {
Reason string `json:"reason"` Reason string `json:"reason"`
} }
// ClassifyIssue 问题分类分析 // ClassifyIssueSys 问题系统分析
func (r *Handle) ClassifyIssue(ctx context.Context, systems []string, issueTypes []string, userInput string, userHist []model.AiBotChatHi) (*IssueClassification, error) { func (r *Handle) ClassifyIssueSystem(ctx context.Context, systems []string, userInput string, userHist []model.AiBotChatHi) (*IssueClassification, error) {
systemPrompt := fmt.Sprintf(`## 角色 systemPrompt := fmt.Sprintf(`## 角色
你是一个技术支持路由专家你的核心能力是通过深度语义分析和上下文回溯将碎片化的用户输入通过时间先后拼接成完整的意图输出必须是严格的 JSON 格式 你是一个系统类型判定专家你的唯一任务是基于多轮对话识别用户当前讨论的系统sys_name不需要输出问题类型输出必须严格遵守 JSON 格式
## 核心推理引擎关键逻辑 ## 推理规则
请执行以下三步推理不要只看当前这一句话 1. 系统判定逻辑
- 当前输入明确提到系统 直接覆盖历史系统
- 当前输入未提系统但历史对话有 继承最近历史系统
- 当前输入和历史均未出现 "全局"
1. **构建完整意图** 2. 特殊规则
* 当前输入历史对话合并视为用户的完整诉求 - 如果当前输入仅包含系统名称CRM视为系统上下文补充仅更新 sys_name不做其他推断
* **特殊规则**如果当前输入仅包含一个系统名称例如用户只输入了CRM这被视为**上下文补充**而非新问题此时**必须保留最近历史对话中已识别的问题类型**
2. **系统判定 (sys_name)**
* **策略**覆盖式更新
* 如果当前输入提到了系统A sys_name = 系统A不管历史是什么
* 如果当前输入未提系统但历史有则继承最近历史
* 如果都无设为 "全局"
3. **问题类型判定 (issue_type_name)**
* **策略**回溯与推断
* **核心原则**基于合并后的完整意图进行分析推断出最近历史对话中的问题类型
* **严禁清空**除非用户是在闲聊你好否则绝不允许为空如果当前句没提问题但历史有必须继承历史的 issue_type_name
## 背景数据 ## 背景数据
- 可用系统列表: [%s] 可用系统列表[%s]
- 可用问题类型: [%s]
## 输出格式 ## 输出格式
{ {
"sys_name": "系统名称", "sys_name": "系统名称",
"reason": "说明系统来源:当前输入 / 历史继承 / 默认"
}
`, strings.Join(systems, ", "))
historyStr := strings.Builder{}
historyStr.WriteString("### 历史对话:\n")
for _, h := range userHist {
if h.Role == "user" {
historyStr.WriteString(fmt.Sprintf("%s:%s\n", h.CreateAt, h.Content))
}
}
messages := []api.Message{
{Role: "system", Content: systemPrompt},
{Role: "assistant", Content: historyStr.String()},
{Role: "user", Content: userInput},
}
resp, err := r.Ollama.Chat(ctx, messages)
if err != nil {
return nil, err
}
// 尝试清理 JSON 内容(有时模型会返回 markdown 块)
resp = strings.TrimPrefix(resp, "```json")
resp = strings.TrimSuffix(resp, "```")
resp = strings.TrimSpace(resp)
var result IssueClassification
if err := json.Unmarshal([]byte(resp), &result); err != nil {
return nil, fmt.Errorf("解析分类结果失败: %w, 原文: %s", err, resp)
}
return &result, nil
}
// ClassifyIssueType 问题分类分析
func (r *Handle) ClassifyIssueType(ctx context.Context, issueTypes []string, userInput string, userHist []model.AiBotChatHi) (*IssueClassification, error) {
systemPrompt := fmt.Sprintf(`## 角色
你是一个业务问题类型分析专家你的任务是基于多轮对话识别用户讨论的**问题类型issue_type_name**问题类型必须严格来自可用问题类型列表 [%s]
你不负责系统名称判断输出必须严格遵守 JSON 格式
## 推理规则
1. 构建完整问题意图
- 将当前输入与历史对话合并理解为完整问题演进
- 当前输入可能是补充条件追问修正或只给模块名/报错片段
- 不要只看当前一句
2. 问题类型判定逻辑
- 当前输入明确匹配列表中某个类型 使用该类型
- 当前输入未明确但历史已有 继承历史类型
- 当前输入未匹配历史也没有 选择最接近的列表类型尽量匹配意图
- 除非是闲聊你好在吗禁止返回空值
3. 特殊规则
- 当前输入只包含系统名/模块名/参数名 视为问题补充继承历史 issue_type_name
- 输出必须严格匹配列表中的类型不允许生成列表外的自造类型
## 背景数据
可用问题类型列表[%s]
## 输出格式
{
"issue_type_name": "问题类型名称", "issue_type_name": "问题类型名称",
"summary": "15字内标题", "summary": "15字内问题标题",
"reason": "1. 系统:说明来源(当前/历史/默认。2. 问题类型:说明是基于哪句话推断的,或说明是继承了历史意图。" "reason": "说明问题类型是基于哪句话判断,或说明继承自历史,继承自哪条历史"
}`, strings.Join(systems, ", "), strings.Join(issueTypes, ", ")) }`, strings.Join(issueTypes, ", "), strings.Join(issueTypes, ", "))
historyStr := strings.Builder{} historyStr := strings.Builder{}
historyStr.WriteString("### 历史对话:\n") historyStr.WriteString("### 历史对话:\n")