fix:1.调整钉钉单聊问题路由负责人整体逻辑 2.增加机器人中间回复 3. 单元测试,提示词调整
This commit is contained in:
parent
c1971e71c1
commit
c174ab683a
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"ai_scheduler/internal/data/constants"
|
"ai_scheduler/internal/data/constants"
|
||||||
"ai_scheduler/internal/data/impl"
|
"ai_scheduler/internal/data/impl"
|
||||||
"ai_scheduler/internal/data/model"
|
"ai_scheduler/internal/data/model"
|
||||||
|
"ai_scheduler/internal/domain/tools/common/knowledge_base"
|
||||||
"ai_scheduler/internal/entitys"
|
"ai_scheduler/internal/entitys"
|
||||||
"ai_scheduler/internal/pkg"
|
"ai_scheduler/internal/pkg"
|
||||||
"ai_scheduler/internal/tools"
|
"ai_scheduler/internal/tools"
|
||||||
|
|
@ -162,22 +163,27 @@ func (d *DingTalkBotBiz) Do(ctx context.Context, requireData *entitys.RequireDat
|
||||||
// 先不接意图识别-仅提供问题处理
|
// 先不接意图识别-仅提供问题处理
|
||||||
func (d *DingTalkBotBiz) handleSingleChat(ctx context.Context, requireData *entitys.RequireDataDingTalkBot) (err error) {
|
func (d *DingTalkBotBiz) handleSingleChat(ctx context.Context, requireData *entitys.RequireDataDingTalkBot) (err error) {
|
||||||
// 1. 获取用户信息
|
// 1. 获取用户信息
|
||||||
requireData.UserInfo, err = d.dingTalkUser.GetUserInfoFromBot(ctx, requireData.Req.SenderStaffId, dingtalk.WithId(1))
|
user, err := d.botUserImpl.GetByStaffId(requireData.Req.SenderStaffId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
requireData.ID = int32(requireData.UserInfo.UserId)
|
requireData.ID = int32(user.UserID)
|
||||||
|
requireData.UserInfo = &entitys.DingTalkUserInfo{
|
||||||
|
UserId: int(user.UserID),
|
||||||
|
StaffId: user.StaffID,
|
||||||
|
Name: user.Name,
|
||||||
|
}
|
||||||
|
|
||||||
// 2. 检查会话状态 (Redis)
|
// 2. 检查会话状态 (Redis)
|
||||||
statusKey := fmt.Sprintf("ai_bot:session:status:%s", requireData.Req.SenderStaffId)
|
// statusKey := fmt.Sprintf("ai_bot:session:status:%s", requireData.Req.SenderStaffId)
|
||||||
status, _ := d.redisCli.Get(ctx, statusKey).Result()
|
// status, _ := d.redisCli.Get(ctx, statusKey).Result()
|
||||||
|
|
||||||
if status == "WAITING_FOR_SYS_CONFIRM" {
|
// if status == "WAITING_FOR_SYS_CONFIRM" {
|
||||||
// 用户回复了系统名称
|
// // 用户回复了系统名称
|
||||||
sysName := requireData.Req.Text.Content
|
// sysName := requireData.Req.Text.Content
|
||||||
d.redisCli.Del(ctx, statusKey)
|
// d.redisCli.Del(ctx, statusKey)
|
||||||
return d.handleWithSpecificSys(ctx, requireData, sysName)
|
// return d.handleWithSpecificSys(ctx, requireData, sysName)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 3. 获取历史记录 (最近6轮用户输入)
|
// 3. 获取历史记录 (最近6轮用户输入)
|
||||||
userHist, err := d.getRecentUserHistory(ctx, constants.ConversationTypeSingle, requireData.ID, 6)
|
userHist, err := d.getRecentUserHistory(ctx, constants.ConversationTypeSingle, requireData.ID, 6)
|
||||||
|
|
@ -192,76 +198,96 @@ func (d *DingTalkBotBiz) handleSingleChat(ctx context.Context, requireData *enti
|
||||||
queryText = rewrittenQuery
|
queryText = rewrittenQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构造识别对象
|
// 分类
|
||||||
rec := &entitys.Recognize{
|
resolveResult, err := d.resolveSystemAndIssueType(ctx, requireData, queryText)
|
||||||
Ch: requireData.Ch,
|
|
||||||
SystemPrompt: d.defaultPrompt(),
|
|
||||||
UserContent: &entitys.RecognizeUserContent{
|
|
||||||
Text: queryText,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. 调用知识库
|
|
||||||
isRetrieved, err := d.groupConfigBiz.handleKnowledge(ctx, rec, nil, requireData.Req)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch resolveResult.IssueType.Code {
|
||||||
|
case "knowledge_qa":
|
||||||
|
// 知识库问答
|
||||||
|
return d.handleKnowledgeQA(ctx, requireData, queryText, resolveResult)
|
||||||
|
default: // 其他问题类型
|
||||||
|
// 系统为空,再次询问
|
||||||
|
if resolveResult.Sys.SysID == 0 {
|
||||||
|
entitys.ResText(requireData.Ch, "", "\n抱歉,我无法确定您咨询的是哪个系统。请告诉我具体系统名称(如:直连天下系统、货易通系统),以便我为您准确解答或安排对应的技术支持。")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return d.fallbackToGroupCreation(ctx, requireData, resolveResult)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 知识库问答
|
||||||
|
func (d *DingTalkBotBiz) handleKnowledgeQA(ctx context.Context, requireData *entitys.RequireDataDingTalkBot, queryText string, resolveResult *resolveSystemAndIssueTypeResult) error {
|
||||||
|
// 获取租户ID
|
||||||
|
tenantId := constants.KnowledgeTenantIdDefault
|
||||||
|
if resolveResult.Sys.KnowlegeTenantKey != "" {
|
||||||
|
tenantId = resolveResult.Sys.KnowlegeTenantKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取知识库结果
|
||||||
|
isRetrieved, err := d.getKnowledgeAnswer(ctx, requireData, tenantId, queryText)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if isRetrieved {
|
if isRetrieved {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. Fallback: 分类 -> 规则 -> 拉群
|
// 未匹配&全局 -> 明确具体系统
|
||||||
return d.fallbackToGroupCreation(ctx, requireData)
|
if !isRetrieved && resolveResult.Sys.SysID == 0 {
|
||||||
}
|
entitys.ResText(requireData.Ch, "", "\n抱歉,知识库未命中,无法回答您的问题。\n若您的问题是某一具体系统的,请告诉我具体系统名称(如:直连天下系统、货易通系统),以便我为您准确解答。")
|
||||||
|
return nil
|
||||||
// handleWithSpecificSys 处理用户明确指定的系统
|
}
|
||||||
func (d *DingTalkBotBiz) handleWithSpecificSys(ctx context.Context, requireData *entitys.RequireDataDingTalkBot, sysName string) error {
|
// 未匹配&指定系统 -> 拉群卡片
|
||||||
// 1. 查找系统
|
if !isRetrieved && resolveResult.Sys.SysID != 0 {
|
||||||
var sys model.AiSy
|
entitys.ResText(requireData.Ch, "", fmt.Sprintf("\n抱歉,%s知识库未命中,无法回答您的问题。即将为您创建群聊解答。", resolveResult.Sys.SysName))
|
||||||
cond := builder.NewCond().And(builder.Eq{"sys_name": sysName})
|
return d.fallbackToGroupCreation(ctx, requireData, resolveResult)
|
||||||
err := d.sysImpl.GetOneBySearchToStrut(&cond, &sys)
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
|
||||||
entitys.ResText(requireData.Ch, "", "抱歉,我还是没有找到名为“"+sysName+"”的系统。请联系管理员确认系统名称。")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 既然已经明确了系统,直接尝试拉群(这里假设问题类型为“其他”或由LLM再次分析)
|
return nil
|
||||||
// 为简化,这里再次调用分类逻辑,但带上已确定的系统
|
|
||||||
return d.fallbackToGroupCreationWithSys(ctx, requireData, &sys)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getRecentUserHistory 获取最近的用户输入历史
|
// 获取知识库问答结果
|
||||||
func (d *DingTalkBotBiz) getRecentUserHistory(ctx context.Context, conversationType constants.ConversationType, id int32, limit int) ([]model.AiBotChatHi, error) {
|
func (d *DingTalkBotBiz) getKnowledgeAnswer(ctx context.Context, requireData *entitys.RequireDataDingTalkBot, tenantId string, queryText string) (bool, error) {
|
||||||
var his []model.AiBotChatHi
|
// 请求知识库工具
|
||||||
cond := builder.NewCond().
|
knowledgeBase := knowledge_base.New(d.conf.KnowledgeConfig)
|
||||||
And(builder.Eq{"his_type": conversationType}).
|
knowledgeResp, err := knowledgeBase.Query(&knowledge_base.QueryRequest{
|
||||||
And(builder.Eq{"id": id}).
|
TenantID: tenantId, // 后续动态接参
|
||||||
And(builder.Eq{"role": "user"})
|
Query: queryText,
|
||||||
|
Mode: constants.KnowledgeModeMix,
|
||||||
_, err := d.chatHis.GetListToStruct(&cond, &dataTemp.ReqPageBo{Limit: limit}, &his, "his_id desc")
|
Stream: true,
|
||||||
|
Think: false,
|
||||||
|
OnlyRAG: true,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return false, fmt.Errorf("请求知识库工具失败,err: %v", err)
|
||||||
}
|
}
|
||||||
return his, nil
|
|
||||||
|
// 读取知识库SSE数据
|
||||||
|
return d.groupConfigBiz.readKnowledgeSSE(knowledgeResp, requireData.Ch, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallbackToGroupCreation 分类并拉群
|
type resolveSystemAndIssueTypeResult struct {
|
||||||
func (d *DingTalkBotBiz) fallbackToGroupCreation(ctx context.Context, requireData *entitys.RequireDataDingTalkBot) error {
|
Sys model.AiSy
|
||||||
|
IssueType model.AiIssueType
|
||||||
|
Classification *do.IssueClassification
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析系统和问题类型
|
||||||
|
func (d *DingTalkBotBiz) resolveSystemAndIssueType(ctx context.Context, requireData *entitys.RequireDataDingTalkBot, queryText string) (*resolveSystemAndIssueTypeResult, error) {
|
||||||
// 1. 获取所有系统和问题类型用于分类
|
// 1. 获取所有系统和问题类型用于分类
|
||||||
allSys, err := d.sysImpl.FindAll()
|
allSys, err := d.sysImpl.FindAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
sysNames := slice.Map(allSys, func(_ int, sys model.AiSy) string {
|
sysNames := slice.Map(allSys, func(_ int, sys model.AiSy) string {
|
||||||
return sys.SysName
|
return sys.SysName
|
||||||
})
|
})
|
||||||
allIssueTypes, err := d.issueImpl.IssueType.FindAll()
|
allIssueTypes, err := d.issueImpl.IssueType.FindAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
issueTypeNames := slice.Map(allIssueTypes, func(_ int, it model.AiIssueType) string {
|
issueTypeNames := slice.Map(allIssueTypes, func(_ int, it model.AiIssueType) string {
|
||||||
return it.Name
|
return it.Name
|
||||||
|
|
@ -270,8 +296,7 @@ func (d *DingTalkBotBiz) fallbackToGroupCreation(ctx context.Context, requireDat
|
||||||
// 2. LLM 分类
|
// 2. LLM 分类
|
||||||
classification, err := d.handle.ClassifyIssue(ctx, sysNames, issueTypeNames, requireData.Req.Text.Content)
|
classification, err := d.handle.ClassifyIssue(ctx, sysNames, issueTypeNames, requireData.Req.Text.Content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// 分类失败,使用兜底
|
return nil, err
|
||||||
return d.createDefaultGroup(ctx, requireData, "系统无法识别")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 匹配系统
|
// 3. 匹配系统
|
||||||
|
|
@ -292,68 +317,58 @@ func (d *DingTalkBotBiz) fallbackToGroupCreation(ctx context.Context, requireDat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if sys.SysID == 0 {
|
return &resolveSystemAndIssueTypeResult{
|
||||||
|
Sys: sys,
|
||||||
// 判断全局是否存在该规则
|
IssueType: issueType,
|
||||||
_, found, _ := d.issueImpl.IssueAssignRule.FindOne(
|
Classification: classification,
|
||||||
d.issueImpl.WithSysID(0),
|
}, nil
|
||||||
d.issueImpl.WithIssueTypeID(issueType.ID),
|
|
||||||
d.issueImpl.WithStatus(1),
|
|
||||||
)
|
|
||||||
if !found {
|
|
||||||
// 无法明确系统,且全局无该能力,询问用户
|
|
||||||
statusKey := fmt.Sprintf("ai_bot:session:status:%s", requireData.Req.SenderStaffId)
|
|
||||||
d.redisCli.Set(ctx, statusKey, "WAITING_FOR_SYS_CONFIRM", time.Hour)
|
|
||||||
entitys.ResText(requireData.Ch, "", "抱歉,我无法确定您咨询的是哪个系统。请告诉我具体系统名称(如:直连天下系统、货易通系统),以便我为您安排对应的技术支持。")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return d.fallbackToGroupCreationWithSys(ctx, requireData, &sys)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallbackToGroupCreationWithSys 在已知系统的情况下进行分类并拉群
|
// handleWithSpecificSys 处理用户明确指定的系统
|
||||||
func (d *DingTalkBotBiz) fallbackToGroupCreationWithSys(ctx context.Context, requireData *entitys.RequireDataDingTalkBot, sys *model.AiSy) error {
|
// func (d *DingTalkBotBiz) handleWithSpecificSys(ctx context.Context, requireData *entitys.RequireDataDingTalkBot, sysName string) error {
|
||||||
// 1. 获取所有问题类型
|
// // 1. 查找系统
|
||||||
allIssueTypes, err := d.issueImpl.IssueType.FindAll()
|
// var sys model.AiSy
|
||||||
if err != nil {
|
// cond := builder.NewCond().And(builder.Eq{"sys_name": sysName})
|
||||||
return err
|
// err := d.sysImpl.GetOneBySearchToStrut(&cond, &sys)
|
||||||
}
|
// if err != nil {
|
||||||
issueTypeNames := slice.Map(allIssueTypes, func(_ int, it model.AiIssueType) string {
|
// if errors.Is(err, sql.ErrNoRows) {
|
||||||
return it.Name
|
// entitys.ResText(requireData.Ch, "", "抱歉,我还是没有找到名为“"+sysName+"”的系统。请联系管理员确认系统名称。")
|
||||||
})
|
// return nil
|
||||||
|
// }
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
// 2. LLM 再次分类(确定问题类型和简述)
|
// // 2. 既然已经明确了系统,直接尝试拉群(这里假设问题类型为“其他”或由LLM再次分析)
|
||||||
classification, err := d.handle.ClassifyIssue(ctx, []string{sys.SysName}, issueTypeNames, requireData.Req.Text.Content)
|
// // 为简化,这里再次调用分类逻辑,但带上已确定的系统
|
||||||
if err != nil {
|
// return d.fallbackToGroupCreationWithSys(ctx, requireData, &sys)
|
||||||
return d.createDefaultGroup(ctx, requireData, "问题类型识别失败")
|
// }
|
||||||
}
|
|
||||||
issueType, found, err := d.issueImpl.IssueType.FindOne(d.issueImpl.WithName(classification.IssueTypeName))
|
|
||||||
if !found {
|
|
||||||
log.Errorf("issue type %s not found; err: %v", classification.IssueTypeName, err)
|
|
||||||
return fmt.Errorf("问题类型 %s 不存在", classification.IssueTypeName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 查找分配规则
|
// getRecentUserHistory 获取最近的用户输入历史
|
||||||
rule, found, err := d.issueImpl.IssueAssignRule.FindOne(
|
func (d *DingTalkBotBiz) getRecentUserHistory(ctx context.Context, conversationType constants.ConversationType, id int32, limit int) ([]model.AiBotChatHi, error) {
|
||||||
d.issueImpl.WithSysID(sys.SysID),
|
var his []model.AiBotChatHi
|
||||||
d.issueImpl.WithIssueTypeID(issueType.ID),
|
cond := builder.NewCond().
|
||||||
|
And(builder.Eq{"his_type": conversationType}).
|
||||||
|
And(builder.Eq{"id": id}).
|
||||||
|
And(builder.Eq{"role": "user"})
|
||||||
|
|
||||||
|
_, err := d.chatHis.GetListToStruct(&cond, &dataTemp.ReqPageBo{Limit: limit}, &his, "his_id desc")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return his, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在已知系统&问题类型的情况下进行分类并拉群
|
||||||
|
func (d *DingTalkBotBiz) fallbackToGroupCreation(ctx context.Context, requireData *entitys.RequireDataDingTalkBot, resolveResult *resolveSystemAndIssueTypeResult) error {
|
||||||
|
// 查找分配规则
|
||||||
|
rule, found, _ := d.issueImpl.IssueAssignRule.FindOne(
|
||||||
|
d.issueImpl.WithSysID(resolveResult.Sys.SysID),
|
||||||
|
d.issueImpl.WithIssueTypeID(resolveResult.IssueType.ID),
|
||||||
d.issueImpl.WithStatus(1),
|
d.issueImpl.WithStatus(1),
|
||||||
)
|
)
|
||||||
if !found {
|
if !found {
|
||||||
// 创建默认分配规则 - 暂不考虑并发,有唯一索引
|
entitys.ResText(requireData.Ch, "", fmt.Sprintf("\n抱歉,当前系统未配置路由规则 %s-%s,请联系管理员配置。", resolveResult.Sys.SysName, resolveResult.IssueType.Name))
|
||||||
rule = model.AiIssueAssignRule{
|
return nil
|
||||||
SysID: sys.SysID,
|
|
||||||
IssueTypeID: issueType.ID,
|
|
||||||
Status: 1,
|
|
||||||
}
|
|
||||||
if err := d.issueImpl.IssueAssignRule.Create(&rule); err != nil {
|
|
||||||
log.Errorf("create assign rule for sys %s and issue type %s failed; err: %v", sys.SysName, issueType.Name, err)
|
|
||||||
return fmt.Errorf("创建分配规则 %s-%s 失败", sys.SysName, issueType.Name)
|
|
||||||
} else {
|
|
||||||
log.Infof("create assign rule for sys %s and issue type %s success; rule id: %d", sys.SysName, issueType.Name, rule.ID)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var staffIds []string
|
var staffIds []string
|
||||||
|
|
@ -392,15 +407,15 @@ func (d *DingTalkBotBiz) fallbackToGroupCreationWithSys(ctx context.Context, req
|
||||||
// 合并提问者
|
// 合并提问者
|
||||||
staffIds = append([]string{requireData.Req.SenderStaffId}, staffIds...)
|
staffIds = append([]string{requireData.Req.SenderStaffId}, staffIds...)
|
||||||
|
|
||||||
// 4. 发送确认卡片
|
// 发送确认卡片
|
||||||
groupName := fmt.Sprintf("[%s]-%s", classification.IssueTypeName, classification.Summary)
|
groupName := fmt.Sprintf("[%s]-%s", resolveResult.IssueType.Name, resolveResult.Classification.Summary)
|
||||||
return d.SendGroupCreationConfirmCard(ctx, &SendGroupCreationConfirmCardParams{
|
return d.SendGroupCreationConfirmCard(ctx, &SendGroupCreationConfirmCardParams{
|
||||||
RobotCode: requireData.Req.RobotCode,
|
RobotCode: requireData.Req.RobotCode,
|
||||||
ConversationId: requireData.Req.ConversationId,
|
ConversationId: requireData.Req.ConversationId,
|
||||||
SenderStaffId: requireData.Req.SenderStaffId,
|
SenderStaffId: requireData.Req.SenderStaffId,
|
||||||
UserIds: staffIds,
|
UserIds: staffIds,
|
||||||
GroupName: groupName,
|
GroupName: groupName,
|
||||||
Summary: classification.Summary,
|
Summary: resolveResult.Classification.Summary,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -759,7 +774,7 @@ func (d *DingTalkBotBiz) SendGroupCreationConfirmCard(ctx context.Context, param
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建卡片 OutTrackId
|
// 构建卡片 OutTrackId
|
||||||
outTrackId := constants.BuildCardOutTrackId(params.ConversationId, params.RobotCode)
|
outTrackId := constants.BuildCardOutTrackId(params.SenderStaffId, params.RobotCode)
|
||||||
|
|
||||||
// 准备可见人员列表
|
// 准备可见人员列表
|
||||||
var recipients []*string
|
var recipients []*string
|
||||||
|
|
@ -804,13 +819,13 @@ func (d *DingTalkBotBiz) SendGroupCreationConfirmCard(ctx context.Context, param
|
||||||
"target_user_ids": tea.String(strings.Join(params.UserIds, ",")),
|
"target_user_ids": tea.String(strings.Join(params.UserIds, ",")),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ImGroupOpenSpaceModel: &card_1_0.CreateAndDeliverRequestImGroupOpenSpaceModel{
|
OpenSpaceId: tea.String("dtv1.card//IM_ROBOT." + params.SenderStaffId),
|
||||||
SupportForward: tea.Bool(false),
|
ImRobotOpenDeliverModel: &card_1_0.CreateAndDeliverRequestImRobotOpenDeliverModel{
|
||||||
|
SpaceType: tea.String("IM_ROBOT"),
|
||||||
|
RobotCode: tea.String(params.RobotCode),
|
||||||
},
|
},
|
||||||
OpenSpaceId: tea.String("dtv1.card//im_group." + params.ConversationId),
|
ImRobotOpenSpaceModel: &card_1_0.CreateAndDeliverRequestImRobotOpenSpaceModel{
|
||||||
ImGroupOpenDeliverModel: &card_1_0.CreateAndDeliverRequestImGroupOpenDeliverModel{
|
SupportForward: tea.Bool(false),
|
||||||
RobotCode: tea.String(params.RobotCode),
|
|
||||||
Recipients: recipients,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -132,15 +132,23 @@ type IssueClassification struct {
|
||||||
|
|
||||||
// ClassifyIssue 问题分类分析
|
// ClassifyIssue 问题分类分析
|
||||||
func (r *Handle) ClassifyIssue(ctx context.Context, systems []string, issueTypes []string, userInput string) (*IssueClassification, error) {
|
func (r *Handle) ClassifyIssue(ctx context.Context, systems []string, issueTypes []string, userInput string) (*IssueClassification, error) {
|
||||||
systemPrompt := fmt.Sprintf(`你是一个技术支持路由专家。请分析用户的输入,并将其归类到最合适的系统和问题类型中。
|
systemPrompt := fmt.Sprintf(`## 角色
|
||||||
|
你是一个技术支持路由专家。输出必须是 JSON 格式。
|
||||||
|
## 任务
|
||||||
|
请分析用户的输入,并将其归类到最合适的系统和问题类型中。
|
||||||
|
- 系统名称:必须是可用系统列表中的一个,若未提及可用系统关键词,则为"全局",不要臆想!
|
||||||
|
- 问题类型名称:必须是可用问题类型列表中的一个,若未提及可用问题类型关键词,则为空字符串
|
||||||
|
- 问题简述:15字以内的问题简述(用于群聊命名)
|
||||||
|
- 分类判断理由:对系统名称和问题类型名称的判断理由
|
||||||
|
## 背景与材料:
|
||||||
可用系统列表: [%s]
|
可用系统列表: [%s]
|
||||||
可用问题类型: [%s]
|
可用问题类型: [%s]
|
||||||
|
## 输出
|
||||||
请仅以 JSON 格式回复,包含以下字段:
|
请仅以 JSON 格式回复,包含以下字段:
|
||||||
- sys_name: 系统名称,若未提及系统关键词,则为"全局"
|
- sys_name: 系统名称
|
||||||
- issue_type_name: 问题类型名称
|
- issue_type_name: 问题类型名称
|
||||||
- summary: 15字以内的问题简述(用于群命名)
|
- summary: 问题简述
|
||||||
- reason: 分类判断理由;系统名称判断理由`, strings.Join(systems, ", "), strings.Join(issueTypes, ", "))
|
- reason: 分类判断理由`, strings.Join(systems, ", "), strings.Join(issueTypes, ", "))
|
||||||
|
|
||||||
messages := []api.Message{
|
messages := []api.Message{
|
||||||
{Role: "system", Content: systemPrompt},
|
{Role: "system", Content: systemPrompt},
|
||||||
|
|
|
||||||
|
|
@ -542,7 +542,7 @@ func (g *GroupConfigBiz) readKnowledgeSSE(resp io.ReadCloser, channel chan entit
|
||||||
|
|
||||||
// 知识库未命中 输出提示后中断
|
// 知识库未命中 输出提示后中断
|
||||||
if delta.XRagStatus == constants.KnowledgeRagStatusMiss {
|
if delta.XRagStatus == constants.KnowledgeRagStatusMiss {
|
||||||
var missContent string = "知识库未检测到匹配信息,即将为您创建群聊解决问题。"
|
var missContent string = "知识库未检测到匹配信息。"
|
||||||
entitys.ResStream(channel, "", missContent)
|
entitys.ResStream(channel, "", missContent)
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,10 @@ func (k BotUserImpl) GetByStaffId(staffId string) (*model.AiBotUser, error) {
|
||||||
func (k BotUserImpl) GetByUserIds(userIds []int32) ([]model.AiBotUser, error) {
|
func (k BotUserImpl) GetByUserIds(userIds []int32) ([]model.AiBotUser, error) {
|
||||||
var data []model.AiBotUser
|
var data []model.AiBotUser
|
||||||
cond := builder.NewCond()
|
cond := builder.NewCond()
|
||||||
cond = cond.And(builder.In("user_id", userIds))
|
for _, userId := range userIds {
|
||||||
_, err := k.GetListToStruct2(&cond, nil, &data)
|
cond = cond.Or(builder.Eq{"user_id": userId})
|
||||||
|
}
|
||||||
|
_, err := k.GetListToStruct(&cond, nil, &data, "user_id")
|
||||||
|
|
||||||
return data, err
|
return data, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue