// 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 }