Files
customer-server/service/ragflow_config_service.go
2026-03-14 10:02:49 +08:00

212 lines
7.3 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 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
}