fix: 拆分系统判断与问题分类判断
This commit is contained in:
parent
ec41a3d787
commit
c9c9bca9ce
|
|
@ -286,10 +286,23 @@ func (d *DingTalkBotBiz) resolveSystemAndIssueType(ctx context.Context, requireD
|
|||
})
|
||||
|
||||
// 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 {
|
||||
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. 匹配系统
|
||||
var sys model.AiSy
|
||||
|
|
|
|||
|
|
@ -130,41 +130,96 @@ type IssueClassification struct {
|
|||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
// ClassifyIssue 问题分类分析
|
||||
func (r *Handle) ClassifyIssue(ctx context.Context, systems []string, issueTypes []string, userInput string, userHist []model.AiBotChatHi) (*IssueClassification, error) {
|
||||
// ClassifyIssueSys 问题系统分析
|
||||
func (r *Handle) ClassifyIssueSystem(ctx context.Context, systems []string, userInput string, userHist []model.AiBotChatHi) (*IssueClassification, error) {
|
||||
systemPrompt := fmt.Sprintf(`## 角色
|
||||
你是一个技术支持路由专家。你的核心能力是通过深度语义分析和上下文回溯,将碎片化的用户输入通过时间先后拼接成完整的意图。输出必须是严格的 JSON 格式。
|
||||
你是一个系统类型判定专家。你的唯一任务是基于多轮对话识别用户当前讨论的系统(sys_name)。不需要输出问题类型。输出必须严格遵守 JSON 格式。
|
||||
|
||||
## 核心推理引擎(关键逻辑)
|
||||
## 推理规则
|
||||
|
||||
请执行以下三步推理,不要只看当前这一句话:
|
||||
1. 系统判定逻辑:
|
||||
- 当前输入明确提到系统 → 直接覆盖历史系统
|
||||
- 当前输入未提系统,但历史对话有 → 继承最近历史系统
|
||||
- 当前输入和历史均未出现 → "全局"
|
||||
|
||||
1. **构建完整意图**:
|
||||
* 将“当前输入”与“历史对话”合并视为用户的完整诉求。
|
||||
* **特殊规则**:如果“当前输入”仅包含一个系统名称(例如用户只输入了“CRM”),这被视为**“上下文补充”**,而非新问题。此时,**必须保留最近历史对话中已识别的问题类型**。
|
||||
|
||||
2. **系统判定 (sys_name)**
|
||||
* **策略**:覆盖式更新。
|
||||
* 如果当前输入提到了系统A,则 sys_name = 系统A(不管历史是什么)。
|
||||
* 如果当前输入未提系统,但历史有,则继承最近历史。
|
||||
* 如果都无,设为 "全局"。
|
||||
|
||||
3. **问题类型判定 (issue_type_name)**
|
||||
* **策略**:回溯与推断。
|
||||
* **核心原则**:基于合并后的完整意图进行分析。推断出最近历史对话中的问题类型。
|
||||
* **严禁清空**:除非用户是在闲聊(如“你好”),否则绝不允许为空。如果当前句没提问题,但历史有,必须继承历史的 issue_type_name。
|
||||
2. 特殊规则:
|
||||
- 如果当前输入仅包含系统名称(如“CRM”),视为系统上下文补充,仅更新 sys_name,不做其他推断
|
||||
|
||||
## 背景数据
|
||||
- 可用系统列表: [%s]
|
||||
- 可用问题类型: [%s]
|
||||
可用系统列表:[%s]
|
||||
|
||||
## 输出格式
|
||||
{
|
||||
"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": "问题类型名称",
|
||||
"summary": "15字内标题",
|
||||
"reason": "1. 系统:说明来源(当前/历史/默认)。2. 问题类型:说明是基于哪句话推断的,或说明是继承了历史意图。"
|
||||
}`, strings.Join(systems, ", "), strings.Join(issueTypes, ", "))
|
||||
"summary": "15字内问题标题",
|
||||
"reason": "说明问题类型是基于哪句话判断,或说明继承自历史,继承自哪条历史"
|
||||
}`, strings.Join(issueTypes, ", "), strings.Join(issueTypes, ", "))
|
||||
|
||||
historyStr := strings.Builder{}
|
||||
historyStr.WriteString("### 历史对话:\n")
|
||||
|
|
|
|||
Loading…
Reference in New Issue