212 lines
7.3 KiB
Go
212 lines
7.3 KiB
Go
// Package service - RAGFlow配置服务
|
||
// 功能:管理ragflow_config表,对话配置(chatId、提示词)、知识库映射(datasetId)
|
||
package service
|
||
|
||
import (
|
||
"context"
|
||
"customer-server/dao"
|
||
"customer-server/model/dto"
|
||
|
||
"gitea.com/red-future/common/ragflow"
|
||
"github.com/gogf/gf/v2/errors/gerror"
|
||
"github.com/gogf/gf/v2/frame/g"
|
||
"github.com/gogf/gf/v2/os/gtime"
|
||
"github.com/gogf/gf/v2/text/gstr"
|
||
)
|
||
|
||
var RAGFlowConfig = new(ragflowConfig)
|
||
|
||
type ragflowConfig struct{}
|
||
|
||
// Get 获取RAGFlow配置(配置不存在时自动重建)
|
||
// 参数: ctx - 上下文,req - 查询请求(包含客服账号名)
|
||
// 返回: res - RAGFlow配置信息(提示词、参数等),err - 错误信息
|
||
// 功能: 查询客服账号的RAGFlow对话配置,不存在时自动重建
|
||
func (s *ragflowConfig) Get(ctx context.Context, req *dto.GetRAGFlowConfigReq) (res *dto.GetRAGFlowConfigRes, err error) {
|
||
config, err := dao.RAGFlowConfig.FindByAccountName(ctx, req.AccountName)
|
||
if err != nil {
|
||
return nil, gerror.Wrap(err, "查询RAGFlow配置失败")
|
||
}
|
||
|
||
// 配置不存在,尝试自动重建
|
||
if config == nil {
|
||
g.Log().Warningf(ctx, "客服账号 %s 的RAGFlow配置不存在,尝试自动重建...", req.AccountName)
|
||
|
||
// 查询客服账号获取platform
|
||
account, findErr := dao.CustomerServiceAccount.FindByAccountName(ctx, req.AccountName)
|
||
if findErr != nil {
|
||
return nil, gerror.Wrapf(findErr, "查询客服账号失败")
|
||
}
|
||
if account == nil {
|
||
return nil, gerror.Newf("客服账号 %s 不存在,无法自动创建RAGFlow配置", req.AccountName)
|
||
}
|
||
|
||
// 调用重建逻辑
|
||
recreateReq := &dto.RecreateRAGFlowConfigReq{
|
||
AccountName: req.AccountName,
|
||
Platform: account.Platform,
|
||
}
|
||
if recreateErr := CustomerServiceAccount.RecreateRAGFlowConfig(ctx, recreateReq); recreateErr != nil {
|
||
return nil, gerror.Wrapf(recreateErr, "自动重建RAGFlow配置失败")
|
||
}
|
||
|
||
// 重新查询配置
|
||
config, err = dao.RAGFlowConfig.FindByAccountName(ctx, req.AccountName)
|
||
if err != nil {
|
||
return nil, gerror.Wrap(err, "重建后查询配置失败")
|
||
}
|
||
if config == nil {
|
||
return nil, gerror.New("重建后仍无法获取配置")
|
||
}
|
||
|
||
g.Log().Infof(ctx, "成功自动重建客服账号 %s 的RAGFlow配置", req.AccountName)
|
||
}
|
||
|
||
// 返回给前端时去掉自动追加的知识库部分,只显示用户的业务话术
|
||
userPrompt := config.Prompt
|
||
knowledgePart := "\n\n以下是知识库:\n{knowledge}\n以上是知识库。"
|
||
if gstr.Contains(userPrompt, knowledgePart) {
|
||
userPrompt = gstr.Replace(userPrompt, knowledgePart, "")
|
||
}
|
||
|
||
res = &dto.GetRAGFlowConfigRes{
|
||
AccountName: config.AccountName,
|
||
Platform: config.Platform,
|
||
DatasetId: config.DatasetId,
|
||
DatasetName: config.DatasetName,
|
||
ChatId: config.ChatId,
|
||
Prompt: userPrompt, // 只返回用户部分
|
||
DocumentIds: config.DocumentIds,
|
||
SimilarityThreshold: config.SimilarityThreshold,
|
||
KeywordsSimilarityWeight: config.KeywordsSimilarityWeight,
|
||
TopN: config.TopN,
|
||
EmptyResponse: config.EmptyResponse,
|
||
}
|
||
return
|
||
}
|
||
|
||
// UpdatePrompt 更新提示词(配置不存在时自动重建)
|
||
// 参数: ctx - 上下文,req - 更新提示词请求(包含客服账号名和新提示词)
|
||
// 返回: res - 更新结果信息,err - 错误信息
|
||
// 功能: 更新RAGFlow对话的系统提示词并同步到RAGFlow,影响AI回复风格
|
||
func (s *ragflowConfig) UpdatePrompt(ctx context.Context, req *dto.UpdatePromptReq) (res *dto.UpdatePromptRes, err error) {
|
||
// 1. 查询当前配置
|
||
config, err := dao.RAGFlowConfig.FindByAccountName(ctx, req.AccountName)
|
||
if err != nil {
|
||
return nil, gerror.Wrap(err, "查询RAGFlow配置失败")
|
||
}
|
||
|
||
// 配置不存在,尝试自动重建
|
||
if config == nil {
|
||
g.Log().Warningf(ctx, "客服账号 %s 的RAGFlow配置不存在,尝试自动重建...", req.AccountName)
|
||
|
||
// 查询客服账号获取platform
|
||
account, findErr := dao.CustomerServiceAccount.FindByAccountName(ctx, req.AccountName)
|
||
if findErr != nil {
|
||
return nil, gerror.Wrapf(findErr, "查询客服账号失败")
|
||
}
|
||
if account == nil {
|
||
return nil, gerror.Newf("客服账号 %s 不存在,无法自动创建RAGFlow配置", req.AccountName)
|
||
}
|
||
|
||
// 调用重建逻辑
|
||
recreateReq := &dto.RecreateRAGFlowConfigReq{
|
||
AccountName: req.AccountName,
|
||
Platform: account.Platform,
|
||
}
|
||
if recreateErr := CustomerServiceAccount.RecreateRAGFlowConfig(ctx, recreateReq); recreateErr != nil {
|
||
return nil, gerror.Wrapf(recreateErr, "自动重建RAGFlow配置失败")
|
||
}
|
||
|
||
// 重新查询配置
|
||
config, err = dao.RAGFlowConfig.FindByAccountName(ctx, req.AccountName)
|
||
if err != nil {
|
||
return nil, gerror.Wrap(err, "重建后查询配置失败")
|
||
}
|
||
if config == nil {
|
||
return nil, gerror.New("重建后仍无法获取配置")
|
||
}
|
||
|
||
g.Log().Infof(ctx, "成功自动重建客服账号 %s 的RAGFlow配置", req.AccountName)
|
||
}
|
||
|
||
// 2. 更新字段并自动追加知识库引用
|
||
// 用户只需输入业务话术,后端自动在末尾追加标准的知识库引用格式
|
||
userPrompt := req.Prompt
|
||
|
||
// 先移除所有可能的知识库引用部分(使用查找并截断方式,与List方法保持一致)
|
||
knowledgePatterns := []string{
|
||
"\n\n以下是知识库:",
|
||
"\n\n以下是知识库",
|
||
"\n以下是知识库:",
|
||
"\n以下是知识库",
|
||
}
|
||
|
||
// 找到最早出现的知识库引用位置并截断
|
||
for _, pattern := range knowledgePatterns {
|
||
if idx := gstr.Pos(userPrompt, pattern); idx >= 0 {
|
||
userPrompt = gstr.SubStr(userPrompt, 0, idx)
|
||
break
|
||
}
|
||
}
|
||
|
||
// 去除末尾多余的空行
|
||
userPrompt = gstr.TrimRight(userPrompt)
|
||
|
||
// 统一追加标准的知识库引用格式
|
||
userPrompt = userPrompt + "\n\n以下是知识库:\n{knowledge}\n以上是知识库。"
|
||
config.Prompt = userPrompt
|
||
|
||
if req.SimilarityThreshold != nil {
|
||
config.SimilarityThreshold = *req.SimilarityThreshold
|
||
}
|
||
if req.KeywordsSimilarityWeight != nil {
|
||
config.KeywordsSimilarityWeight = *req.KeywordsSimilarityWeight
|
||
}
|
||
if req.TopN != nil {
|
||
config.TopN = *req.TopN
|
||
}
|
||
if req.EmptyResponse != nil {
|
||
config.EmptyResponse = *req.EmptyResponse
|
||
}
|
||
now := gtime.Now().Time
|
||
config.UpdatedAt = &now // 取地址赋值给指针类型
|
||
|
||
// 3. 调用RAGFlow API更新Chat配置
|
||
ragflowClient := ragflow.GetGlobalClient()
|
||
updateReq := &ragflow.UpdateChatReq{
|
||
Prompt: &ragflow.PromptConfig{
|
||
Prompt: config.Prompt,
|
||
SimilarityThreshold: config.SimilarityThreshold,
|
||
KeywordsSimilarityWeight: config.KeywordsSimilarityWeight,
|
||
TopN: config.TopN,
|
||
EmptyResponse: config.EmptyResponse,
|
||
Variables: []map[string]interface{}{
|
||
{
|
||
"key": "knowledge",
|
||
"optional": true,
|
||
},
|
||
},
|
||
},
|
||
DatasetIds: []string{config.DatasetId},
|
||
}
|
||
|
||
if err := ragflowClient.UpdateChat(ctx, config.ChatId, updateReq); err != nil {
|
||
return nil, gerror.Wrapf(err, "调用RAGFlow API更新Chat失败")
|
||
}
|
||
|
||
// 4. 更新MongoDB
|
||
if err := dao.RAGFlowConfig.UpdateEntity(ctx, config); err != nil {
|
||
return nil, gerror.Wrap(err, "更新MongoDB配置失败")
|
||
}
|
||
|
||
g.Log().Infof(ctx, "RAGFlow配置更新成功: account_name=%s, chat_id=%s",
|
||
config.AccountName, config.ChatId)
|
||
|
||
res = &dto.UpdatePromptRes{
|
||
Success: true,
|
||
Message: "提示词更新成功",
|
||
}
|
||
return
|
||
}
|