ai对话优化知识库选择

This commit is contained in:
2025-12-29 18:40:26 +08:00
parent a33720b9f6
commit 4b6cb726d2
14 changed files with 249 additions and 81 deletions

View File

@@ -698,10 +698,10 @@ public class DifyApiClient {
String lastId,
Integer limit,
String apiKey) {
StringBuilder urlBuilder = new StringBuilder(difyConfig.getFullApiUrl("/conversations"));
urlBuilder.append("?user=").append(userId);
if (lastId != null && !lastId.isEmpty()) {
urlBuilder.append("&last_id=").append(lastId);
}
@@ -718,7 +718,7 @@ public class DifyApiClient {
try (Response response = httpClient.newCall(httpRequest).execute()) {
String responseBody = response.body() != null ? response.body().string() : "";
if (!response.isSuccessful()) {
logger.error("获取对话列表失败: {} - {}", response.code(), responseBody);
throw new DifyException("获取对话列表失败: " + responseBody);
@@ -732,6 +732,56 @@ public class DifyApiClient {
}
}
/**
* 获取对话变量
* @param conversationId 会话ID
* @param userId 用户标识
* @param lastId 当前页最后面一条记录的ID,默认null
* @param limit 一次请求返回多少条记录,默认20条,最大100条,最小1条
* @param apiKey API密钥
* @return 对话变量响应
*/
public ConversationVariablesResponse getConversationVariables(
String conversationId,
String userId,
String lastId,
Integer limit,
String apiKey) {
StringBuilder urlBuilder = new StringBuilder(
difyConfig.getFullApiUrl("/conversations/" + conversationId + "/variables"));
urlBuilder.append("?user=").append(userId);
if (lastId != null && !lastId.isEmpty()) {
urlBuilder.append("&last_id=").append(lastId);
}
if (limit != null) {
urlBuilder.append("&limit=").append(limit);
}
try {
Request httpRequest = new Request.Builder()
.url(urlBuilder.toString())
.header("Authorization", "Bearer " + getApiKey(apiKey))
.get()
.build();
try (Response response = httpClient.newCall(httpRequest).execute()) {
String responseBody = response.body() != null ? response.body().string() : "";
if (!response.isSuccessful()) {
logger.error("获取对话变量失败: {} - {}", response.code(), responseBody);
throw new DifyException("获取对话变量失败: " + responseBody);
}
return JSON.parseObject(responseBody, ConversationVariablesResponse.class);
}
} catch (IOException e) {
logger.error("获取对话变量异常", e);
throw new DifyException("获取对话变量异常: " + e.getMessage(), e);
}
}
// ===================== 通用 HTTP 方法(用于代理转发)=====================
/**

View File

@@ -0,0 +1,69 @@
package org.xyzh.ai.client.dto;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import java.util.List;
/**
* @description 对话变量响应
* @filename ConversationVariablesResponse.java
* @author AI Assistant
* @copyright xyzh
* @since 2025-12-29
*/
@Data
public class ConversationVariablesResponse {
private Integer limit;
@JSONField(name = "has_more")
private Boolean hasMore;
private List<ConversationVariableItem> data;
/**
* 对话中的变量项
*/
@Data
public static class ConversationVariableItem {
/**
* 变量ID
*/
private String id;
/**
* 变量名称
*/
private String name;
/**
* 变量类型 (string, number, boolean 等)
*/
@JSONField(name = "value_type")
private String valueType;
/**
* 变量值
*/
private String value;
/**
* 变量描述
*/
private String description;
/**
* 创建时间戳
*/
@JSONField(name = "created_at")
private Long createdAt;
/**
* 最后更新时间戳
*/
@JSONField(name = "updated_at")
private Long updatedAt;
}
}

View File

@@ -8,6 +8,7 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.xyzh.ai.client.dto.ConversationVariablesResponse;
import org.xyzh.api.ai.dto.ChatPrepareData;
import org.xyzh.api.ai.dto.TbChat;
import org.xyzh.api.ai.dto.TbChatMessage;
@@ -46,6 +47,9 @@ public class ChatController {
@Autowired
private AIFileUploadService fileUploadService;
@Autowired
private org.xyzh.ai.client.DifyApiClient difyApiClient;
// ====================== 会话管理 ======================
/**
@@ -151,7 +155,7 @@ public class ChatController {
* @since 2025-12-17
*/
@PostMapping("/conversation/page")
public ResultDomain<PageDomain<TbChat>> getChatPage(@RequestBody PageRequest<TbChat> pageRequest, @RequestHeader("Authorization") String token) {
public ResultDomain<TbChat> getChatPage(@RequestBody PageRequest<TbChat> pageRequest, @RequestHeader("Authorization") String token) {
log.info("分页获取会话列表: agentId={}", pageRequest.getFilter().getAgentId());
pageRequest.getFilter().setUserType(false);
@@ -164,6 +168,53 @@ public class ChatController {
return chatService.getChatPage(pageRequest);
}
/**
* @description 获取对话变量
* @param params 请求参数包含agentId, conversationId, userId, lastId, limit
* @author yslg
* @since 2025-12-29
*/
@PostMapping("/conversation/variables")
public ResultDomain<org.xyzh.ai.client.dto.ConversationVariablesResponse> getConversationVariables(
@RequestBody Map<String, Object> params,
@RequestHeader("Authorization") String token) {
// 参数验证
ValidationResult result = ValidationUtils.validateMap(params, Arrays.asList(
ValidationUtils.requiredString("agentId", "智能体ID", 1, 100),
ValidationUtils.requiredString("conversationId", "会话ID", 1, 100),
ValidationUtils.requiredString("userId", "用户ID", 1, 100)
));
if (!result.isValid()) {
return ResultDomain.failure(result.getAllErrors());
}
String agentId = (String) params.get("agentId");
String conversationId = (String) params.get("conversationId");
String userId = (String) params.get("userId");
String lastId = params.containsKey("lastId") ? (String) params.get("lastId") : null;
Integer limit = params.containsKey("limit") ?
Integer.parseInt(params.get("limit").toString()) : 20;
log.info("获取对话变量: agentId={}, conversationId={}, userId={}", agentId, conversationId, userId);
try {
// 获取智能体信息以获取 API Key
// 这里需要根据 agentId 获取对应的 API Key
// 暂时先使用一个占位符,实际使用时需要从数据库或配置中获取
// 或者通过 chatService 获取智能体配置
// 调用 Dify API 获取会话变量
ConversationVariablesResponse response =
difyApiClient.getConversationVariables(conversationId, userId, lastId, limit, agentId);
return ResultDomain.success("获取对话变量成功",response);
} catch (Exception e) {
log.error("获取对话变量失败", e);
return ResultDomain.failure("获取对话变量失败: " + e.getMessage());
}
}
// ====================== 消息管理 ======================
/**

View File

@@ -1,5 +1,6 @@
package org.xyzh.ai.service.impl;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import org.apache.dubbo.config.annotation.DubboService;
@@ -12,6 +13,7 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.xyzh.ai.client.DifyApiClient;
import org.xyzh.ai.client.callback.StreamCallback;
import org.xyzh.ai.client.dto.ChatRequest;
import org.xyzh.ai.config.DifyConfig;
import org.xyzh.ai.mapper.TbChatMapper;
import org.xyzh.ai.mapper.TbChatMessageMapper;
import org.xyzh.api.ai.dto.ChatPrepareData;
@@ -19,17 +21,23 @@ import org.xyzh.api.ai.dto.DifyFileInfo;
import org.xyzh.api.ai.dto.TbAgent;
import org.xyzh.api.ai.dto.TbChat;
import org.xyzh.api.ai.dto.TbChatMessage;
import org.xyzh.api.ai.dto.TbKnowledge;
import org.xyzh.api.ai.service.AgentChatService;
import org.xyzh.api.ai.service.AgentService;
import org.xyzh.api.ai.service.KnowledgeService;
import org.xyzh.api.system.service.GuestService;
import org.xyzh.common.core.domain.LoginDomain;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.page.PageDomain;
import org.xyzh.common.core.page.PageParam;
import org.xyzh.common.core.page.PageRequest;
import org.xyzh.common.redis.service.RedisService;
import org.xyzh.common.utils.NonUtils;
import org.xyzh.common.utils.id.IdUtil;
import org.xyzh.common.auth.utils.LoginUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -69,20 +77,11 @@ public class AgentChatServiceImpl implements AgentChatService {
@Autowired
private RedisService redisService;
/**
* @description 根据 userType 获取用户ID
* @param chat 会话信息(包含 userId 和 userType
* @return 真实的系统用户ID
*/
private String getUserIdByType(TbChat chat) {
if (!chat.getUserType()) {
// 来客userType=false直接返回传入的 userId已经是真正的系统 userId
return chat.getUserId();
} else {
// 员工userType=true从登录信息获取 userId
return LoginUtil.getCurrentUserId();
}
}
@Autowired
private KnowledgeService knowledgeService;
@Autowired
private DifyConfig difyConfig;
/**
* @description 判断智能体是否是outer
@@ -130,7 +129,8 @@ public class AgentChatServiceImpl implements AgentChatService {
}
// 2. 获取用户ID并校验权限
String userId = getUserIdByType(chat);
LoginDomain loginDomain = LoginUtil.getCurrentLogin();
String userId = loginDomain.getUser().getUserId();
if (userId == null) {
return ResultDomain.failure("用户信息获取失败");
}
@@ -164,7 +164,8 @@ public class AgentChatServiceImpl implements AgentChatService {
return ResultDomain.failure("智能体不可用");
}
// 2. 获取用户ID并校验权限
String userId = getUserIdByType(filter);
LoginDomain loginDomain = LoginUtil.getCurrentLogin();
String userId = loginDomain.getUser().getUserId();
if (userId == null) {
return ResultDomain.failure("用户信息获取失败");
}
@@ -189,12 +190,9 @@ public class AgentChatServiceImpl implements AgentChatService {
@Override
public ResultDomain<TbChat> getChatList(TbChat filter) {
// 判断agent是否是outer
if(!isOuterAgent(filter.getAgentId())){
return ResultDomain.failure("智能体不可用");
}
// 获取用户ID
String userId = getUserIdByType(filter);
String userId = LoginUtil.getCurrentUserId();
if (userId == null) {
return ResultDomain.failure("用户信息获取失败");
}
@@ -204,16 +202,16 @@ public class AgentChatServiceImpl implements AgentChatService {
}
@Override
public ResultDomain<PageDomain<TbChat>> getChatPage(PageRequest<TbChat> pageRequest) {
public ResultDomain<TbChat> getChatPage(PageRequest<TbChat> pageRequest) {
TbChat filter = pageRequest.getFilter();
// 判断agent是否是outer来客才需要校验
if (!filter.getUserType() && !isOuterAgent(filter.getAgentId())) {
return ResultDomain.<PageDomain<TbChat>>failure("智能体不可用");
return ResultDomain.<TbChat>failure("智能体不可用");
}
// 获取用户ID
String userId = getUserIdByType(filter);
String userId = LoginUtil.getCurrentUserId();
if (userId == null) {
return ResultDomain.<PageDomain<TbChat>>failure("用户信息获取失败");
return ResultDomain.<TbChat>failure("用户信息获取失败");
}
filter.setUserId(userId);
@@ -224,7 +222,7 @@ public class AgentChatServiceImpl implements AgentChatService {
pageParam.setTotal((int) total);
PageDomain<TbChat> pageDomain = new PageDomain<>(pageParam, chatList);
return ResultDomain.<PageDomain<TbChat>>success("查询成功", pageDomain);
return ResultDomain.<TbChat>success("查询成功", pageDomain);
}
// ====================== 智能体聊天管理 ======================
@@ -241,7 +239,7 @@ public class AgentChatServiceImpl implements AgentChatService {
return ResultDomain.failure("智能体不可用");
}
// 2. 获取用户ID并校验权限
String userId = getUserIdByType(filter);
String userId = LoginUtil.getCurrentUserId();
if (userId == null) {
return ResultDomain.failure("用户信息获取失败");
}
@@ -272,7 +270,8 @@ public class AgentChatServiceImpl implements AgentChatService {
chatFilter.setUserId(prepareData.getUserId());
chatFilter.setUserType(prepareData.getUserType());
String userId = getUserIdByType(chatFilter);
LoginDomain loginDomain = LoginUtil.getCurrentLogin();
String userId = loginDomain.getUser().getUserId();
if (userId == null) {
return ResultDomain.failure("用户信息获取失败");
}
@@ -299,6 +298,8 @@ public class AgentChatServiceImpl implements AgentChatService {
sessionData.put("userId", userId);
sessionData.put("filesData", prepareData.getFiles());
sessionData.put("apiKey", agent.getApiKey());
sessionData.put("outer", agent.getIsOuter());
sessionData.put("service", prepareData.getService());
String cacheKey = CHAT_SESSION_PREFIX + sessionId;
redisService.set(cacheKey, sessionData, SESSION_TTL, TimeUnit.SECONDS);
@@ -332,6 +333,9 @@ public class AgentChatServiceImpl implements AgentChatService {
String query = (String) sessionData.get("query");
String userId = (String) sessionData.get("userId");
String apiKey = (String) sessionData.get("apiKey");
String service = (String) sessionData.get("service");
Boolean outer = (Boolean) sessionData.get("outer");
@SuppressWarnings("unchecked")
List<DifyFileInfo> filesData = (List<DifyFileInfo>) sessionData.get("filesData");
@@ -365,7 +369,23 @@ public class AgentChatServiceImpl implements AgentChatService {
chatRequest.setQuery(query);
chatRequest.setUser(userId);
chatRequest.setResponseMode("streaming");
chatRequest.setInputs(new HashMap<>()); // Dify API 要求 inputs 必传
Map<String, Object> inputsMap = new HashMap<>();
chatRequest.setInputs(inputsMap); // Dify API 要求 inputs 必传
// 处理动态知识库的问题
if(outer && NonUtils.isNotEmpty(service)){
TbKnowledge filter = new TbKnowledge();
filter.setService(service);
filter.setCategory("external");
ResultDomain<TbKnowledge> knowledgeRD = knowledgeService.listKnowledges(filter);
List<String> datasets = new ArrayList<>();
if(knowledgeRD.getSuccess()){
datasets = knowledgeRD.getDataList().stream().map(TbKnowledge::getDifyDatasetId).toList();
}
inputsMap.put("datasets", JSON.toJSONString(datasets));
inputsMap.put("dataset_apikey", difyConfig.getKnowledgeApiKey());
}
if (filesData != null && !filesData.isEmpty()) {
chatRequest.setFiles(filesData);
@@ -454,7 +474,7 @@ public class AgentChatServiceImpl implements AgentChatService {
TbAgent agent = agentResult.getData();
// 2. 获取用户ID
String userId = getUserIdByType(filter);
String userId = LoginUtil.getCurrentUserId();
if (userId == null) {
return ResultDomain.failure("用户信息获取失败");
}
@@ -480,7 +500,7 @@ public class AgentChatServiceImpl implements AgentChatService {
}
// 2. 获取用户ID
String userId = getUserIdByType(filter);
String userId = LoginUtil.getCurrentUserId();
if (userId == null) {
return ResultDomain.failure("用户信息获取失败");
}