diff --git a/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/evaluator/SliceSelectEvaluator.java b/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/evaluator/SliceSelectEvaluator.java index c23c8b2f..b1413d47 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/evaluator/SliceSelectEvaluator.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/evaluator/SliceSelectEvaluator.java @@ -1,92 +1,148 @@ package work.slhaf.partner.module.memory.selector.evaluator; -import cn.hutool.json.JSONUtil; -import com.alibaba.fastjson2.JSONObject; +import kotlin.Unit; import lombok.Data; import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability; import work.slhaf.partner.api.agent.factory.component.abstracts.AbstractAgentModule; import work.slhaf.partner.api.agent.factory.component.abstracts.ActivateModel; import work.slhaf.partner.api.agent.factory.component.annotation.Init; import work.slhaf.partner.api.chat.pojo.Message; -import work.slhaf.partner.common.thread.InteractionThreadPoolExecutor; +import work.slhaf.partner.core.action.ActionCapability; +import work.slhaf.partner.core.action.ActionCore; +import work.slhaf.partner.core.cognition.CognitionCapability; +import work.slhaf.partner.core.cognition.ContextBlock; import work.slhaf.partner.core.memory.pojo.ActivatedMemorySlice; +import work.slhaf.partner.module.TaskBlock; import work.slhaf.partner.module.memory.selector.evaluator.entity.EvaluatorBatchInput; +import work.slhaf.partner.module.memory.selector.evaluator.entity.EvaluatorBatchResult; import work.slhaf.partner.module.memory.selector.evaluator.entity.EvaluatorInput; -import work.slhaf.partner.module.memory.selector.evaluator.entity.EvaluatorResult; -import work.slhaf.partner.module.memory.selector.evaluator.entity.SliceSummary; -import java.util.*; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentLinkedDeque; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; @EqualsAndHashCode(callSuper = true) @Data public class SliceSelectEvaluator extends AbstractAgentModule.Sub> implements ActivateModel { - private InteractionThreadPoolExecutor executor; + + @InjectCapability + private ActionCapability actionCapability; + @InjectCapability + private CognitionCapability cognitionCapability; + + private ExecutorService executor; @Init public void init() { - executor = InteractionThreadPoolExecutor.getInstance(); + executor = actionCapability.getExecutor(ActionCore.ExecutorType.VIRTUAL); } @Override public List execute(EvaluatorInput evaluatorInput) { - log.debug("[SliceSelectEvaluator] 切片评估模块开始..."); - List memorySlices = evaluatorInput.getMemorySlices(); - List> tasks = new ArrayList<>(); - Queue queue = new ConcurrentLinkedDeque<>(); - AtomicInteger count = new AtomicInteger(0); - if (memorySlices == null || memorySlices.isEmpty()) { - return List.of(); - } - tasks.add(() -> { - int thisCount = count.incrementAndGet(); - log.debug("[SliceSelectEvaluator] 评估[{}]开始", thisCount); - List sliceSummaryList = new ArrayList<>(); - Map map = new HashMap<>(); - try { - setSliceSummaryList(memorySlices, sliceSummaryList, map); - EvaluatorBatchInput batchInput = EvaluatorBatchInput.builder() - .text(evaluatorInput.getInput()) - .memory_slices(sliceSummaryList) - .history(evaluatorInput.getMessages()) - .build(); - log.debug("[SliceSelectEvaluator] 评估[{}]输入: {}", thisCount, JSONObject.toJSONString(batchInput)); - EvaluatorResult evaluatorResult = formattedChat( - List.of(new Message(Message.Character.USER, JSONUtil.toJsonStr(batchInput))), - EvaluatorResult.class - ); - log.debug("[SliceSelectEvaluator] 评估[{}]结果: {}", thisCount, JSONObject.toJSONString(evaluatorResult)); - for (Long result : evaluatorResult.getResults()) { - ActivatedMemorySlice slice = map.get(result); - if (slice != null) { - queue.offer(slice); + log.debug("切片评估模块开始..."); + List preparedSlices = evaluatorInput.getMemorySlices(); + List result = new ArrayList<>(); + CountDownLatch latch = new CountDownLatch(preparedSlices.size()); + + Message contextMessage = cognitionCapability.contextWorkspace().resolve(List.of( + ContextBlock.VisibleDomain.COGNITION, + ContextBlock.VisibleDomain.MEMORY + )).encodeToMessage(); + + for (ActivatedMemorySlice slice : preparedSlices) { + executor.execute(() -> { + try { + EvaluatorBatchInput batchInput = new EvaluatorBatchInput(evaluatorInput.getInputs(), slice); + List messages = List.of( + contextMessage, + resolveTaskMessage(batchInput) + ); + EvaluatorBatchResult batchResult = formattedChat(messages, EvaluatorBatchResult.class); + if (batchResult.isPassed()) { + synchronized (result) { + result.add(slice); + } } + } catch (Exception ignore) { + } finally { + latch.countDown(); } - } catch (Exception e) { - log.error("[SliceSelectEvaluator] 评估[{}]出现错误: {}", thisCount, e.getLocalizedMessage()); - } - return null; - }); - executor.invokeAll(tasks, 30, TimeUnit.SECONDS); - log.debug("[SliceSelectEvaluator] 评估模块结束, 输出队列: {}", queue); - return new ArrayList<>(queue); - } - - private void setSliceSummaryList(List memorySlices, List sliceSummaryList, - Map map) { - for (ActivatedMemorySlice memorySlice : memorySlices) { - SliceSummary sliceSummary = new SliceSummary(); - sliceSummary.setId(memorySlice.getTimestamp()); - sliceSummary.setSummary(memorySlice.getSummary()); - sliceSummary.setDate(memorySlice.getDate()); - sliceSummaryList.add(sliceSummary); - map.put(memorySlice.getTimestamp(), memorySlice); + }); } + + try { + latch.await(); + } catch (InterruptedException ignored) { + } + log.debug("切片评估模块结束..."); + + return result; } + private Message resolveTaskMessage(EvaluatorBatchInput batchInput) { + return new TaskBlock() { + @Override + protected void fillXml(@NotNull Document document, @NotNull Element root) { + appendListElement(document, root, "new_inputs", "input", batchInput.getInputs().entrySet(), (inputElement, input) -> { + inputElement.setAttribute("datetime", input.getKey().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); + inputElement.setTextContent(input.getValue()); + return Unit.INSTANCE; + }); + appendChildElement(document, root, "memory_slice", (element) -> { + ActivatedMemorySlice slice = batchInput.getActivatedMemorySlice(); + appendTextElement(document, element, "slice_summary", slice.getSummary()); + appendChildElement(document, element, "source_messages", (messagesElement) -> { + List messages = slice.getMessages(); + int size = messages.size(); + if (size > 10) { + // 展示前两条 + appendMessageElement(document, messagesElement, messages.subList(0, 2)); + + // 中间省略说明 + int middleStart = Math.max(2, (size - 4) / 2); + int middleEnd = Math.min(size - 2, middleStart + 4); + int omittedBeforeMiddle = middleStart - 2; + appendTextElement(document, messagesElement, "omitted_messages", "省略了 " + omittedBeforeMiddle + " 条消息"); + + // 中间四条 + appendMessageElement(document, messagesElement, messages.subList(middleStart, middleEnd)); + + // 中间到结尾前的省略说明 + int omittedAfterMiddle = (size - 2) - middleEnd; + if (omittedAfterMiddle > 0) { + appendTextElement(document, messagesElement, "omitted_messages", "省略了 " + omittedAfterMiddle + " 条消息"); + } + + // 展示末尾两条 + appendMessageElement(document, messagesElement, messages.subList(size - 2, size)); + } else { + appendMessageElement(document, messagesElement, messages); + } + return Unit.INSTANCE; + }); + return Unit.INSTANCE; + }); + } + + private void appendMessageElement(Document document, Element parent, List messages) { + appendRepeatedElements(document, parent, "message", messages, (messageElement, message) -> { + messageElement.setAttribute("role", message.getRole().name().toLowerCase(Locale.ROOT)); + messageElement.setTextContent(message.getContent()); + return Unit.INSTANCE; + }); + } + }.encodeToMessage(); + } + + @Override + @NotNull public String modelKey() { return "slice_evaluator"; } diff --git a/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/evaluator/entity/EvaluatorBatchInput.java b/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/evaluator/entity/EvaluatorBatchInput.java index 32efddfb..fa20cd52 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/evaluator/entity/EvaluatorBatchInput.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/evaluator/entity/EvaluatorBatchInput.java @@ -1,15 +1,15 @@ package work.slhaf.partner.module.memory.selector.evaluator.entity; -import lombok.Builder; +import lombok.AllArgsConstructor; import lombok.Data; -import work.slhaf.partner.api.chat.pojo.Message; +import work.slhaf.partner.core.memory.pojo.ActivatedMemorySlice; -import java.util.List; +import java.time.LocalDateTime; +import java.util.Map; @Data -@Builder +@AllArgsConstructor public class EvaluatorBatchInput { - private String text; - private List history; - private List memory_slices; + private Map inputs; + private ActivatedMemorySlice activatedMemorySlice; } diff --git a/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/evaluator/entity/EvaluatorResult.java b/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/evaluator/entity/EvaluatorBatchResult.java similarity index 52% rename from Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/evaluator/entity/EvaluatorResult.java rename to Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/evaluator/entity/EvaluatorBatchResult.java index 59d49438..eb8a8db5 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/evaluator/entity/EvaluatorResult.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/evaluator/entity/EvaluatorBatchResult.java @@ -2,9 +2,7 @@ package work.slhaf.partner.module.memory.selector.evaluator.entity; import lombok.Data; -import java.util.List; - @Data -public class EvaluatorResult { - private List results; +public class EvaluatorBatchResult { + private boolean passed; } diff --git a/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/evaluator/entity/EvaluatorInput.java b/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/evaluator/entity/EvaluatorInput.java index 8860cefc..1dfcd59f 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/evaluator/entity/EvaluatorInput.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/evaluator/entity/EvaluatorInput.java @@ -2,15 +2,15 @@ package work.slhaf.partner.module.memory.selector.evaluator.entity; import lombok.Builder; import lombok.Data; -import work.slhaf.partner.api.chat.pojo.Message; import work.slhaf.partner.core.memory.pojo.ActivatedMemorySlice; +import java.time.LocalDateTime; import java.util.List; +import java.util.Map; @Data @Builder public class EvaluatorInput { - private String input; - private List messages; + private Map inputs; private List memorySlices; } diff --git a/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/extractor/MemorySelectExtractor.java b/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/extractor/MemorySelectExtractor.java index ed276327..08669ee1 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/extractor/MemorySelectExtractor.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/extractor/MemorySelectExtractor.java @@ -1,54 +1,47 @@ package work.slhaf.partner.module.memory.selector.extractor; -import cn.hutool.json.JSONUtil; import lombok.Data; import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; +import org.w3c.dom.Document; +import org.w3c.dom.Element; import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability; import work.slhaf.partner.api.agent.factory.component.abstracts.AbstractAgentModule; import work.slhaf.partner.api.agent.factory.component.abstracts.ActivateModel; import work.slhaf.partner.api.agent.factory.component.annotation.InjectModule; import work.slhaf.partner.api.chat.pojo.Message; import work.slhaf.partner.core.cognition.CognitionCapability; -import work.slhaf.partner.core.memory.MemoryCapability; -import work.slhaf.partner.core.memory.pojo.ActivatedMemorySlice; +import work.slhaf.partner.core.cognition.ContextBlock; +import work.slhaf.partner.module.TaskBlock; import work.slhaf.partner.module.memory.runtime.MemoryRuntime; import work.slhaf.partner.module.memory.selector.extractor.entity.ExtractorInput; import work.slhaf.partner.module.memory.selector.extractor.entity.ExtractorMatchData; import work.slhaf.partner.module.memory.selector.extractor.entity.ExtractorResult; -import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowContext; +import java.time.format.DateTimeFormatter; import java.util.List; import static work.slhaf.partner.common.util.ExtractUtil.fixTopicPath; @EqualsAndHashCode(callSuper = true) @Data -public class MemorySelectExtractor extends AbstractAgentModule.Sub - implements ActivateModel { - @InjectCapability - private MemoryCapability memoryCapability; +public class MemorySelectExtractor extends AbstractAgentModule.Sub implements ActivateModel { @InjectCapability private CognitionCapability cognitionCapability; @InjectModule private MemoryRuntime memoryRuntime; @Override - public ExtractorResult execute(PartnerRunningFlowContext context) { + public ExtractorResult execute(ExtractorInput input) { log.debug("[MemorySelectExtractor] 主题提取模块开始..."); - List chatMessages = cognitionCapability.snapshotChatMessages(); ExtractorResult extractorResult; try { - List activatedMemorySlices = memoryCapability.getActivatedSlices(); - ExtractorInput extractorInput = ExtractorInput.builder() - .text(context.getInput()) - .date(context.getInfo().getDateTime().toLocalDate()) - .history(chatMessages) - .topic_tree(memoryRuntime.getTopicTree()) - .activatedMemorySlices(activatedMemorySlices) - .build(); - log.debug("[MemorySelectExtractor] 主题提取输入: {}", JSONUtil.toJsonStr(extractorInput)); + List messages = List.of( + resolveContextMessage(), + resolveTaskMessage(input) + ); extractorResult = formattedChat( - List.of(new Message(Message.Character.USER, JSONUtil.toJsonPrettyStr(extractorInput))), + messages, ExtractorResult.class ); log.debug("[MemorySelectExtractor] 主题提取结果: {}", extractorResult); @@ -61,6 +54,23 @@ public class MemorySelectExtractor extends AbstractAgentModule.Sub { if (m.getType().equals(ExtractorMatchData.Constant.DATE)) { diff --git a/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/extractor/entity/ExtractorInput.java b/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/extractor/entity/ExtractorInput.java index 5dbd2e13..768466f3 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/extractor/entity/ExtractorInput.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/module/memory/selector/extractor/entity/ExtractorInput.java @@ -1,19 +1,14 @@ package work.slhaf.partner.module.memory.selector.extractor.entity; -import lombok.Builder; +import lombok.AllArgsConstructor; import lombok.Data; -import work.slhaf.partner.api.chat.pojo.Message; -import work.slhaf.partner.core.memory.pojo.ActivatedMemorySlice; import java.time.LocalDate; -import java.util.List; @Data -@Builder +@AllArgsConstructor public class ExtractorInput { - private String text; + private String input; private String topic_tree; private LocalDate date; - private List history; - private List activatedMemorySlices; }