diff --git a/Partner-Main/src/main/java/work/slhaf/partner/core/action/ActionCapability.java b/Partner-Main/src/main/java/work/slhaf/partner/core/action/ActionCapability.java index 2bd97016..a887145f 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/core/action/ActionCapability.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/core/action/ActionCapability.java @@ -8,7 +8,6 @@ import work.slhaf.partner.core.action.entity.MetaActionInfo; import work.slhaf.partner.core.action.entity.cache.CacheAdjustData; import java.util.List; -import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Phaser; @@ -30,8 +29,6 @@ public interface ActionCapability { ExecutorService getExecutor(ActionCore.ExecutorType type); - Set getExistedMetaActions(); - void putPhaserRecord(Phaser phaser, ActionData actionData); void removePhaserRecord(Phaser phaser); @@ -44,6 +41,8 @@ public interface ActionCapability { MetaActionInfo loadMetaActionInfo(@NonNull String actionKey); + List listAvailableActions(); + boolean checkExists(String... actionKeys); void execute(MetaAction metaAction); diff --git a/Partner-Main/src/main/java/work/slhaf/partner/core/action/ActionCore.java b/Partner-Main/src/main/java/work/slhaf/partner/core/action/ActionCore.java index bfbbb7f9..5ecc235c 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/core/action/ActionCore.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/core/action/ActionCore.java @@ -53,7 +53,7 @@ public class ActionCore extends PartnerCore { /** * 已存在的行动程序,键为目录名,值为从目录加载的行动程序元信息 */ - private final LinkedHashMap existedMetaActions = new LinkedHashMap<>(); + private final Map existedMetaActions = new HashMap<>(); private final List phaserRecords = new ArrayList<>(); private final SandboxRunnerClient sandboxRunnerClient = new SandboxRunnerClient(); @@ -177,8 +177,8 @@ public class ActionCore extends PartnerCore { } @CapabilityMethod - public Set getExistedMetaActions() { - return existedMetaActions.keySet(); + public List listAvailableActions() { + return existedMetaActions.values().stream().toList(); } @CapabilityMethod diff --git a/Partner-Main/src/main/java/work/slhaf/partner/core/action/ActionWatchService.java b/Partner-Main/src/main/java/work/slhaf/partner/core/action/ActionWatchService.java index 27c72ff2..9b265f0e 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/core/action/ActionWatchService.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/core/action/ActionWatchService.java @@ -11,8 +11,8 @@ import java.io.IOException; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.ExecutorService; import static work.slhaf.partner.common.Constant.Path.ACTION_PROGRAM; @@ -23,10 +23,10 @@ import static work.slhaf.partner.common.Constant.Path.ACTION_PROGRAM; class ActionWatchService { private final HashMap registeredPaths = new HashMap<>(); - private final LinkedHashMap existedMetaActions; + private final Map existedMetaActions; private final ExecutorService virtualExecutor; - public ActionWatchService(LinkedHashMap existedMetaActions, ExecutorService virtualExecutor) { + public ActionWatchService(Map existedMetaActions, ExecutorService virtualExecutor) { this.existedMetaActions = existedMetaActions; this.virtualExecutor = virtualExecutor; } diff --git a/Partner-Main/src/main/java/work/slhaf/partner/core/action/entity/ActionData.java b/Partner-Main/src/main/java/work/slhaf/partner/core/action/entity/ActionData.java index a2362e4c..cdc63892 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/core/action/entity/ActionData.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/core/action/entity/ActionData.java @@ -4,8 +4,8 @@ import cn.hutool.json.JSONObject; import lombok.Data; import java.util.ArrayList; -import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; /** * 行动模块传递的行动数据,包含行动uuid、倾向、状态、行动链、结果、发起原因、行动描述等信息。 @@ -28,7 +28,7 @@ public abstract class ActionData { /** * 行动链 */ - protected LinkedHashMap> actionChain = new LinkedHashMap<>(); + protected Map> actionChain; /** * 行动阶段(当前阶段) */ diff --git a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/dispatcher/executor/ActionExecutor.java b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/dispatcher/executor/ActionExecutor.java index 8155d5ca..e5d143f1 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/dispatcher/executor/ActionExecutor.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/dispatcher/executor/ActionExecutor.java @@ -13,8 +13,8 @@ import work.slhaf.partner.core.action.entity.ImmediateActionData; import work.slhaf.partner.core.action.entity.MetaAction; import java.util.ArrayList; -import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Phaser; @@ -45,7 +45,7 @@ public class ActionExecutor extends AgentRunningSubModule { actionData.setStatus(ActionData.ActionStatus.EXECUTING); - LinkedHashMap> actionChain = actionData.getActionChain(); + Map> actionChain = actionData.getActionChain(); List virtual = new ArrayList<>(); List platform = new ArrayList<>(); Phaser phaser = new Phaser(); @@ -64,7 +64,7 @@ public class ActionExecutor extends AgentRunningSubModule virtual, List platform, - LinkedHashMap> actionChain, Phaser phaser) { + Phaser phaser) { runGroupAction(virtual, virtualExecutor, phaser); runGroupAction(platform, platformExecutor, phaser); } @@ -89,6 +89,9 @@ public class ActionExecutor extends AgentRunningSubModule { try { + //TODO 使用 LLM 填充行动参数信息 + + actionCapability.execute(action); MetaAction.Result result = action.getResult(); do { // 该循环对应LLM的调整参数后重试 @@ -97,7 +100,7 @@ public class ActionExecutor extends AgentRunningSubModule> actionChain = actionData.getActionChain(); + Map> actionChain = actionData.getActionChain(); actionChain.put(order, actions); if (order == actionData.getExecutingStage()) { @@ -159,7 +159,7 @@ public class InterventionHandler extends AgentRunningSubModule actions) { if (order <= actionData.getExecutingStage()) return; - LinkedHashMap> actionChain = actionData.getActionChain(); + Map> actionChain = actionData.getActionChain(); if (actionChain.containsKey(order)) { actionChain.get(order).removeAll(actions); if (actionChain.get(order).isEmpty()) { @@ -174,7 +174,7 @@ public class InterventionHandler extends AgentRunningSubModule actions) { - LinkedHashMap> actionChain = actionData.getActionChain(); + Map> actionChain = actionData.getActionChain(); actionChain.put(order, actions); } diff --git a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/ActionPlanner.java b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/ActionPlanner.java index 60b390a2..fb834340 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/ActionPlanner.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/ActionPlanner.java @@ -1,6 +1,7 @@ package work.slhaf.partner.module.modules.action.planner; import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability; import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule; import work.slhaf.partner.api.agent.factory.module.annotation.Init; @@ -9,10 +10,7 @@ import work.slhaf.partner.api.chat.pojo.Message; import work.slhaf.partner.common.vector.VectorClient; import work.slhaf.partner.core.action.ActionCapability; import work.slhaf.partner.core.action.ActionCore; -import work.slhaf.partner.core.action.entity.ActionData; -import work.slhaf.partner.core.action.entity.ImmediateActionData; -import work.slhaf.partner.core.action.entity.MetaAction; -import work.slhaf.partner.core.action.entity.ScheduledActionData; +import work.slhaf.partner.core.action.entity.*; import work.slhaf.partner.core.action.entity.cache.CacheAdjustData; import work.slhaf.partner.core.action.entity.cache.CacheAdjustMetaData; import work.slhaf.partner.core.cognation.CognationCapability; @@ -33,6 +31,7 @@ import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowCon import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; +import java.util.concurrent.atomic.AtomicBoolean; /** * 负责针对本次输入生成基础的行动计划,在主模型传达意愿后,执行行动或者放入计划池 @@ -92,14 +91,15 @@ public class ActionPlanner extends PreRunningModule { return null; } EvaluatorInput evaluatorInput = assemblyHelper.buildEvaluatorInput(extractorResult, context.getUserId()); - List evaluatorResults = actionEvaluator.execute(evaluatorInput); //并发操作均为访问 - setupActionInfo(evaluatorResults, context); + List evaluatorResults = actionEvaluator.execute(evaluatorInput); // 并发操作均为访问 + putActionData(evaluatorResults, context); updateTendencyCache(evaluatorResults, context.getInput(), extractorResult); return null; }); } - private void updateTendencyCache(List evaluatorResults, String input, ExtractorResult extractorResult) { + private void updateTendencyCache(List evaluatorResults, String input, + ExtractorResult extractorResult) { if (!VectorClient.status) { return; } @@ -137,7 +137,7 @@ public class ActionPlanner extends PreRunningModule { } private void setupConfirmedActionInfo(PartnerRunningFlowContext context, ConfirmerResult result) { - //TODO 需考虑未确认任务的失效或者拒绝时机,在action core中实现 + // TODO 需考虑未确认任务的失效或者拒绝时机,在action core中实现 List uuids = result.getUuids(); if (uuids == null) { return; @@ -151,10 +151,9 @@ public class ActionPlanner extends PreRunningModule { } } - - private void setupActionInfo(List evaluatorResults, PartnerRunningFlowContext context) { + private void putActionData(List evaluatorResults, PartnerRunningFlowContext context) { for (EvaluatorResult evaluatorResult : evaluatorResults) { - ActionData actionData = assemblyHelper.buildMetaActionInfo(evaluatorResult); + ActionData actionData = assemblyHelper.buildActionData(evaluatorResult); if (evaluatorResult.isNeedConfirm()) { actionCapability.putPendingActions(context.getUserId(), actionData); } else { @@ -163,7 +162,6 @@ public class ActionPlanner extends PreRunningModule { } } - @Override protected Map getPromptDataMap(PartnerRunningFlowContext context) { HashMap map = new HashMap<>(); @@ -233,15 +231,12 @@ public class ActionPlanner extends PreRunningModule { return input; } - private ActionData buildMetaActionInfo(EvaluatorResult evaluatorResult) { - LinkedHashMap> actionChain = new LinkedHashMap<>(); - for (MetaAction metaAction : evaluatorResult.getActionChain()) { - actionChain.computeIfAbsent(metaAction.getOrder(), k -> new ArrayList<>()).add(metaAction); - } + private ActionData buildActionData(EvaluatorResult evaluatorResult) { + Map> actionChain = getActionChain(evaluatorResult); return switch (evaluatorResult.getType()) { case PLANNING -> { ScheduledActionData actionInfo = new ScheduledActionData(); - actionInfo.getActionChain().putAll(actionChain); + actionInfo.setActionChain(actionChain); actionInfo.setScheduleContent(evaluatorResult.getScheduleContent()); actionInfo.setStatus(ActionData.ActionStatus.PREPARE); actionInfo.setUuid(UUID.randomUUID().toString()); @@ -249,7 +244,7 @@ public class ActionPlanner extends PreRunningModule { } case IMMEDIATE -> { ImmediateActionData actionInfo = new ImmediateActionData(); - actionInfo.getActionChain().putAll(actionChain); + actionInfo.setActionChain(actionChain); actionInfo.setStatus(ActionData.ActionStatus.PREPARE); actionInfo.setUuid(UUID.randomUUID().toString()); yield actionInfo; @@ -257,6 +252,82 @@ public class ActionPlanner extends PreRunningModule { }; } + private @NotNull Map> getActionChain(EvaluatorResult evaluatorResult) { + Map> actionChain = new HashMap<>(); + Map> primaryActionChain = evaluatorResult.getPrimaryActionChain(); + fixDependencies(primaryActionChain); + primaryActionChain.forEach((order, actionKeys) -> { + List metaActions = actionKeys.stream() + .map(actionKey -> actionCapability.loadMetaAction(actionKey)) + .toList(); + actionChain.put(order, metaActions); + }); + return actionChain; + } + + private void fixDependencies(Map> primaryActionChain) { + // 先将 primaryActionChain 的节点序号修正为从1开始依次增大 + fixOrder(primaryActionChain); + List fixedOrders = new ArrayList<>(primaryActionChain.keySet().stream().toList()); + AtomicBoolean fixed = new AtomicBoolean(false); + do { + Set tempOrders = new HashSet<>(); + fixedOrders.sort(Integer::compareTo); + for (Integer fixedOrder : fixedOrders) { + int lastOrder = fixedOrder - 1; + List actionKeys = primaryActionChain.get(fixedOrder); + for (String actionKey : actionKeys) { + // 根据 actionKey 加载行动信息,并检查是否存在必需前置依赖 + MetaActionInfo metaActionInfo = actionCapability.loadMetaActionInfo(actionKey); + List preActions = metaActionInfo.getPreActions(); + boolean preActionsExist = preActions != null && !preActions.isEmpty(); + if (!preActionsExist) { + continue; + } + if (!metaActionInfo.isStrictDependencies()) { + continue; + } + if (checkDependenciesExist(lastOrder, preActions, primaryActionChain)) { + continue; + } + + // 如果存在前置依赖,则将其放置在当前order之前的位置, + // 放置位置优先选择已存在的上一节点,如果不存在(行动链的头节点时)则需要向行动链新增order + // 不需要检查行动链的当前节点的已存在 Action 是否为新 Action 的依赖项,因为这些 Action 实际来自 LLM + // 的评估结果,并非作为依赖项存在 + fixed.set(true); + List actionsInChain = primaryActionChain.computeIfAbsent(lastOrder, + list -> new ArrayList<>()); + preActions = new ArrayList<>(preActions); + preActions.removeAll(actionsInChain); + actionsInChain.addAll(preActions); + tempOrders.add(lastOrder); + } + } + fixedOrders.clear(); + fixedOrders.addAll(tempOrders); + } while (fixed.getAndSet(false)); + } + + private void fixOrder(Map> primaryActionChain) { + Map> tempChain = new HashMap<>(primaryActionChain); + primaryActionChain.clear(); + int chainSize = tempChain.size(); + for (int i = 0; i < chainSize; i++) { + primaryActionChain.put(i, tempChain.get(i)); + } + } + + private boolean checkDependenciesExist(int lastOrder, List preActions, + Map> primaryActionChain) { + if (!primaryActionChain.containsKey(lastOrder)) { + return false; + } + List existActions = primaryActionChain.get(lastOrder); + //noinspection SlowListContainsAll + return existActions.containsAll(preActions); + } + private ConfirmerInput buildConfirmerInput(PartnerRunningFlowContext context) { ConfirmerInput confirmerInput = new ConfirmerInput(); confirmerInput.setInput(context.getInput()); diff --git a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/evaluator/ActionEvaluator.java b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/evaluator/ActionEvaluator.java index 5fd56b9b..0ca828aa 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/evaluator/ActionEvaluator.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/evaluator/ActionEvaluator.java @@ -1,24 +1,34 @@ package work.slhaf.partner.module.modules.action.planner.evaluator; import cn.hutool.core.bean.BeanUtil; +import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; +import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability; import work.slhaf.partner.api.agent.factory.module.annotation.AgentSubModule; import work.slhaf.partner.api.agent.factory.module.annotation.Init; import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.ActivateModel; import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningSubModule; import work.slhaf.partner.api.chat.pojo.ChatResponse; import work.slhaf.partner.common.thread.InteractionThreadPoolExecutor; +import work.slhaf.partner.core.action.ActionCapability; +import work.slhaf.partner.core.action.entity.MetaActionInfo; +import work.slhaf.partner.core.memory.pojo.EvaluatedSlice; import work.slhaf.partner.module.modules.action.planner.evaluator.entity.EvaluatorBatchInput; import work.slhaf.partner.module.modules.action.planner.evaluator.entity.EvaluatorInput; import work.slhaf.partner.module.modules.action.planner.evaluator.entity.EvaluatorResult; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.Callable; @AgentSubModule public class ActionEvaluator extends AgentRunningSubModule> implements ActivateModel { + @InjectCapability + private ActionCapability actionCapability; + private InteractionThreadPoolExecutor executor; @Init @@ -30,7 +40,7 @@ public class ActionEvaluator extends AgentRunningSubModule execute(EvaluatorInput data) { @@ -39,12 +49,11 @@ public class ActionEvaluator extends AgentRunningSubModule> getTasks(List batchInputs) { List> list = new ArrayList<>(); for (EvaluatorBatchInput batchInput : batchInputs) { list.add(() -> { - ChatResponse response = this.singleChat(JSONObject.toJSONString(batchInput)); + ChatResponse response = this.singleChat(buildPrompt(batchInput)); EvaluatorResult evaluatorResult = JSONObject.parseObject(response.getMessage(), EvaluatorResult.class); evaluatorResult.setTendency(batchInput.getTendency()); return evaluatorResult; @@ -59,11 +68,34 @@ public class ActionEvaluator extends AgentRunningSubModule availableActions = new HashMap<>(); + for (MetaActionInfo metaActionInfo : actionCapability.listAvailableActions()) { + availableActions.put(metaActionInfo.getKey(), metaActionInfo.getDescription()); + } + temp.setAvailableActions(availableActions); list.add(temp); } return list; } + private String buildPrompt(EvaluatorBatchInput batchInput) { + JSONObject prompt = new JSONObject(); + prompt.put("[行动倾向]", batchInput.getTendency()); + + JSONArray memoryData = prompt.putArray("[相关记忆切片]"); + for (EvaluatedSlice evaluatedSlice : batchInput.getActivatedSlices()) { + JSONObject memory = memoryData.addObject(); + memory.put("[日期]", evaluatedSlice.getDate()); + memory.put("[摘要]", evaluatedSlice.getSummary()); + + } + + JSONObject availableActionData = prompt.putObject("[可用行动单元]"); + availableActionData.putAll(batchInput.getAvailableActions()); + + return prompt.toString(); + } + @Override public String modelKey() { return "action_evaluator"; diff --git a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/evaluator/entity/EvaluatorBatchInput.java b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/evaluator/entity/EvaluatorBatchInput.java index 33114b9a..78ee229e 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/evaluator/entity/EvaluatorBatchInput.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/evaluator/entity/EvaluatorBatchInput.java @@ -5,10 +5,12 @@ import work.slhaf.partner.api.chat.pojo.Message; import work.slhaf.partner.core.memory.pojo.EvaluatedSlice; import java.util.List; +import java.util.Map; @Data public class EvaluatorBatchInput { private List recentMessages; private List activatedSlices; + private Map availableActions; private String tendency; } diff --git a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/evaluator/entity/EvaluatorResult.java b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/evaluator/entity/EvaluatorResult.java index 76289180..1db2a03c 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/evaluator/entity/EvaluatorResult.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/evaluator/entity/EvaluatorResult.java @@ -1,9 +1,9 @@ package work.slhaf.partner.module.modules.action.planner.evaluator.entity; import lombok.Data; -import work.slhaf.partner.core.action.entity.MetaAction; import java.util.List; +import java.util.Map; @Data public class EvaluatorResult { @@ -11,7 +11,7 @@ public class EvaluatorResult { private boolean needConfirm; private ActionType type; private String scheduleContent; - private List actionChain; + private Map> primaryActionChain; private String tendency; public enum ActionType {