feat: 先进智能体功能上线

- 基于 agent-runtime 打造,默认 ReAct agent
- 支持 agent 能力对接,已对接工作流、插件、知识库等 tool 能力
- 全新 agent 编排界面,支持可视化便捷配置 agent
- 全新 agent 聊天界面,支持快捷操作、额外知识库选择等
This commit is contained in:
2026-05-28 11:29:18 +08:00
parent 11e595b088
commit 1c205c3720
39 changed files with 3546 additions and 217 deletions

View File

@@ -78,7 +78,7 @@ public class AgentCategoryController extends BaseCurdController<AgentCategorySer
for (Serializable id : ids) {
QueryWrapper queryWrapper = QueryWrapper.create().eq(Agent::getCategoryId, id);
List<Agent> agents = agentMapper.selectListByQuery(queryWrapper);
if (!agents.isEmpty()) {
if (agents != null && !agents.isEmpty()) {
throw new BusinessException("请先删除该分类下的所有 Agent");
}
}

View File

@@ -14,6 +14,7 @@ import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.common.web.jsonbody.JsonBody;
import java.math.BigInteger;
import java.util.List;
/**
* Agent 管理端会话控制器。
@@ -104,6 +105,19 @@ public class AgentSessionController {
return Result.ok();
}
/**
* 保存 Agent 会话临时知识库。
*
* @param sessionId 会话 ID
* @param knowledgeIds 临时知识库 ID
* @return 操作结果
*/
@PostMapping("/{sessionId}/extraKnowledges")
public Result<ChatWorkspaceSessionDetailView> saveExtraKnowledges(@PathVariable BigInteger sessionId,
@JsonBody(value = "knowledgeIds") List<BigInteger> knowledgeIds) {
return Result.ok(agentSessionService.saveCurrentUserExtraKnowledges(currentAccount(), sessionId, knowledgeIds));
}
/**
* 删除 Agent 会话。
*

View File

@@ -10,13 +10,12 @@ import tech.easyflow.agent.service.AgentService;
import tech.easyflow.ai.entity.DocumentCollection;
import tech.easyflow.ai.enums.PublishStatus;
import tech.easyflow.ai.service.DocumentCollectionService;
import tech.easyflow.chatlog.domain.dto.ChatHistoryPage;
import tech.easyflow.chatlog.domain.dto.ChatMessageRecord;
import tech.easyflow.chatlog.domain.dto.ChatSessionPage;
import tech.easyflow.chatlog.domain.dto.ChatSessionSummary;
import tech.easyflow.chatlog.domain.command.ChatSessionUpsertCommand;
import tech.easyflow.chatlog.domain.dto.*;
import tech.easyflow.chatlog.domain.query.ChatPageQuery;
import tech.easyflow.chatlog.service.ChatSessionCommandService;
import tech.easyflow.chatlog.service.ChatSessionQueryService;
import tech.easyflow.chatlog.support.ChatJsonSupport;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.system.enums.CategoryResourceType;
@@ -40,6 +39,7 @@ public class AgentSessionService {
private final DocumentCollectionService documentCollectionService;
private final ResourceAccessService resourceAccessService;
private final AgentRuntimeStateCleanupService agentRuntimeStateCleanupService;
private final ChatJsonSupport chatJsonSupport;
/**
* 创建 Agent 管理端会话服务。
@@ -50,19 +50,22 @@ public class AgentSessionService {
* @param documentCollectionService 知识库服务
* @param resourceAccessService 资源访问服务
* @param agentRuntimeStateCleanupService Agent 运行态清理服务
* @param chatJsonSupport 聊天 JSON 工具
*/
public AgentSessionService(ChatSessionQueryService chatSessionQueryService,
ChatSessionCommandService chatSessionCommandService,
AgentService agentService,
DocumentCollectionService documentCollectionService,
ResourceAccessService resourceAccessService,
AgentRuntimeStateCleanupService agentRuntimeStateCleanupService) {
AgentRuntimeStateCleanupService agentRuntimeStateCleanupService,
ChatJsonSupport chatJsonSupport) {
this.chatSessionQueryService = chatSessionQueryService;
this.chatSessionCommandService = chatSessionCommandService;
this.agentService = agentService;
this.documentCollectionService = documentCollectionService;
this.resourceAccessService = resourceAccessService;
this.agentRuntimeStateCleanupService = agentRuntimeStateCleanupService;
this.chatJsonSupport = chatJsonSupport;
}
/**
@@ -103,6 +106,12 @@ public class AgentSessionService {
Agent displayAgent = availability == null ? null : availability.displayAgent();
detail.setAssistant(toAssistantView(displayAgent, summary));
detail.setBoundKnowledges(resolveBoundKnowledges(displayAgent));
ExtraKnowledgeResolution extraKnowledgeResolution = resolveExtraKnowledges(summary);
detail.setExtraKnowledges(extraKnowledgeResolution.validKnowledges());
detail.setRemovedExtraKnowledgeNames(extraKnowledgeResolution.removedNames());
if (extraKnowledgeResolution.shouldSync()) {
syncSessionExtraKnowledges(summary, extraKnowledgeResolution.validKnowledgeIds(), account.getId());
}
return detail;
}
@@ -150,6 +159,26 @@ public class AgentSessionService {
chatSessionCommandService.renameSession(sessionId, account.getId(), title.trim(), account.getId());
}
/**
* 保存当前用户 Agent 会话的临时知识库。
*
* @param account 当前登录账号
* @param sessionId 会话 ID
* @param knowledgeIds 临时知识库 ID
* @return 更新后的会话详情
*/
public ChatWorkspaceSessionDetailView saveCurrentUserExtraKnowledges(LoginAccount account,
BigInteger sessionId,
List<BigInteger> knowledgeIds) {
ChatSessionSummary summary = requireUserAgentSession(account, sessionId);
ExtraKnowledgeResolution resolution = resolveVisibleKnowledgeViews(normalizeExtraKnowledgeIds(knowledgeIds));
if (!resolution.removedNames().isEmpty()) {
throw new BusinessException("所选知识库已失效或无权限使用");
}
syncSessionExtraKnowledges(summary, resolution.validKnowledgeIds(), account.getId());
return getCurrentUserSession(account, sessionId);
}
/**
* 删除当前用户的 Agent 会话。
*
@@ -295,8 +324,97 @@ public class AgentSessionService {
return view;
}
private ExtraKnowledgeResolution resolveExtraKnowledges(ChatSessionSummary summary) {
ChatSessionExtPayload payload = chatJsonSupport.fromJson(summary.getExtJson(), ChatSessionExtPayload.class);
List<BigInteger> extraKnowledgeIds = payload == null ? List.of() : payload.getExtraKnowledgeIds();
return resolveVisibleKnowledgeViews(extraKnowledgeIds);
}
private ExtraKnowledgeResolution resolveVisibleKnowledgeViews(List<BigInteger> knowledgeIds) {
if (knowledgeIds == null || knowledgeIds.isEmpty()) {
return new ExtraKnowledgeResolution(List.of(), List.of(), List.of(), false);
}
List<BigInteger> normalizedIds = normalizeExtraKnowledgeIds(knowledgeIds);
if (normalizedIds.isEmpty()) {
return new ExtraKnowledgeResolution(List.of(), List.of(), List.of(), false);
}
List<DocumentCollection> collections = documentCollectionService.listByIds(normalizedIds);
Map<BigInteger, DocumentCollection> collectionMap = new LinkedHashMap<>();
for (DocumentCollection collection : collections) {
collectionMap.put(collection.getId(), collection);
}
List<ChatWorkspaceKnowledgeView> validKnowledges = new ArrayList<>();
List<BigInteger> validKnowledgeIds = new ArrayList<>();
List<String> removedNames = new ArrayList<>();
boolean changed = false;
for (BigInteger knowledgeId : normalizedIds) {
DocumentCollection current = collectionMap.get(knowledgeId);
if (current == null) {
removedNames.add("知识库#" + knowledgeId);
changed = true;
continue;
}
if (PublishStatus.from(current.getPublishStatus()) != PublishStatus.PUBLISHED) {
removedNames.add(current.getTitle());
changed = true;
continue;
}
if (!resourceAccessService.canAccess(CategoryResourceType.KNOWLEDGE, current, ResourceAction.USE)) {
removedNames.add(current.getTitle());
changed = true;
continue;
}
validKnowledges.add(toKnowledgeView(documentCollectionService.toPublishedView(current)));
validKnowledgeIds.add(current.getId());
}
if (!Objects.equals(normalizedIds, validKnowledgeIds)) {
changed = true;
}
return new ExtraKnowledgeResolution(validKnowledges, validKnowledgeIds, removedNames, changed);
}
private List<BigInteger> normalizeExtraKnowledgeIds(List<BigInteger> knowledgeIds) {
if (knowledgeIds == null || knowledgeIds.isEmpty()) {
return List.of();
}
List<BigInteger> normalizedIds = new ArrayList<>();
for (BigInteger knowledgeId : knowledgeIds) {
if (knowledgeId != null && !normalizedIds.contains(knowledgeId)) {
normalizedIds.add(knowledgeId);
}
}
if (normalizedIds.size() > 3) {
throw new BusinessException("临时知识库最多选择 3 个");
}
return normalizedIds;
}
private void syncSessionExtraKnowledges(ChatSessionSummary summary, List<BigInteger> validKnowledgeIds, BigInteger operatorId) {
ChatSessionExtPayload payload = new ChatSessionExtPayload();
payload.setExtraKnowledgeIds(validKnowledgeIds);
ChatSessionUpsertCommand command = new ChatSessionUpsertCommand();
command.setSessionId(summary.getId());
command.setTenantId(summary.getTenantId());
command.setDeptId(summary.getDeptId());
command.setUserId(summary.getUserId());
command.setUserAccount(summary.getUserAccount());
command.setAssistantId(summary.getAssistantId());
command.setAssistantCode(summary.getAssistantCode());
command.setAssistantName(summary.getAssistantName());
command.setTitle(summary.getTitle());
command.setExtJson(chatJsonSupport.toJson(payload));
command.setOperatorId(operatorId);
chatSessionCommandService.createOrTouchSession(command);
}
private record AgentAvailability(boolean continuable,
ChatWorkspaceReadOnlyReason reason,
Agent displayAgent) {
}
private record ExtraKnowledgeResolution(List<ChatWorkspaceKnowledgeView> validKnowledges,
List<BigInteger> validKnowledgeIds,
List<String> removedNames,
boolean shouldSync) {
}
}