From 63840acf1465dddbbab5086611d141d495f22929 Mon Sep 17 00:00:00 2001 From: slhafzjw Date: Wed, 4 Jun 2025 23:28:57 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E7=AC=AC=E4=BA=8C=E9=98=B6?= =?UTF-8?q?=E6=AE=B5=E8=B0=83=E8=AF=95=E4=BF=AE=E5=A4=8D=EF=BC=9A=E8=BE=B9?= =?UTF-8?q?=E8=81=8A=E8=BE=B9=E4=BF=AE=E6=8C=BA=E6=9C=89=E6=84=8F=E6=80=9D?= =?UTF-8?q?=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 由于更改了上下文认知补充机制,所以将原来的CoreContext、ModuleContext从单一的jsonObject重构为了独立的类 - 移除了CoreModel中的baseMessageCache,当前消息分为三段,baseMessage固定,不再需要缓存 - 在CoreModel中添加了新的认知注入机制,并且模块状态也会显示给Partner(是否活跃) - 在MemoryManager挑取记忆时,将在获取到MemoryResult后与dialogMap对比,去重切片,但还是有较多重复,单用户时应该可以去掉userDialogMap的展示? - 在MemoryManager中添加了几个获取相应字符串的方法,为了适应新的上下文注入机制 - 调整对话列表更新为保留前1/3,确保防止上下文断裂,但应该改为1/4也行 - log.debug输出日志时将先包装为json对象,防止换行导致影响控制台效果 - 调整了MemoryUpdater中清理互动消息列表的逻辑 - PreprocessExecutor适配新的上下文注入机制 - InteractionContext的某些字段应提供默认值而非创建对象后手动赋值,已调整 - 移除了挺多目前用不到的注释,反正还有版本控制 --- .gitignore | 1 + qodana.yaml | 31 +++++ src/main/java/work/slhaf/agent/Agent.java | 5 +- .../slhaf/agent/common/chat/pojo/Message.java | 2 +- .../agent/common/chat/pojo/MetaMessage.java | 2 +- .../slhaf/agent/common/config/Config.java | 3 - .../pojo/GlobalException.java | 2 +- .../pojo/GlobalExceptionData.java | 7 +- .../agent/common/monitor/DebugMonitor.java | 2 +- .../PersistableObject.java | 2 +- .../InteractionThreadPoolExecutor.java | 2 +- .../work/slhaf/agent/core/InteractionHub.java | 12 +- .../core/interaction/InteractionModule.java | 9 -- .../{ => agent_interface}/InputReceiver.java | 2 +- .../{ => agent_interface}/TaskCallback.java | 2 +- .../interaction/data/InteractionContext.java | 76 ----------- .../data/context/InteractionContext.java | 62 +++++++++ .../data/context/subcontext/CoreContext.java | 28 ++++ .../context/subcontext/ModuleContext.java | 15 ++ .../interaction/module/InteractionModule.java | 9 ++ .../InteractionModulesLoader.java | 2 +- .../slhaf/agent/core/memory/MemoryGraph.java | 39 ++---- .../agent/core/memory/MemoryManager.java | 80 +++++------ .../agent/core/memory/node/MemoryNode.java | 2 +- .../agent/core/memory/node/TopicNode.java | 2 +- .../agent/core/memory/pojo/MemoryResult.java | 8 +- .../agent/core/memory/pojo/MemorySlice.java | 2 +- .../core/memory/pojo/MemorySliceResult.java | 11 +- .../slhaf/agent/core/memory/pojo/User.java | 2 +- .../agent/core/session/SessionManager.java | 7 +- .../agent/gateway/AgentWebSocketServer.java | 4 +- .../agent/module/common/AppendPrompt.java | 10 -- .../agent/module/common/AppendPromptData.java | 2 +- .../work/slhaf/agent/module/common/Model.java | 14 -- .../agent/module/common/PreModuleActions.java | 11 ++ .../agent/module/modules/core/CoreModel.java | 91 +++++++----- .../memory/selector/MemorySelector.java | 83 ++++------- .../evaluator/SliceSelectEvaluator.java | 27 +--- .../extractor/MemorySelectExtractor.java | 4 +- .../modules/memory/updater/MemoryUpdater.java | 129 +++++++++--------- .../updater/summarizer/MemorySummarizer.java | 9 +- .../updater/summarizer/MultiSummarizer.java | 2 +- .../updater/summarizer/SingleSummarizer.java | 2 +- .../StaticPerceiveExtractor.java | 3 +- .../preprocess/PreprocessExecutor.java | 27 ++-- .../module/modules/task/TaskEvaluator.java | 4 +- .../module/modules/task/TaskExecutor.java | 2 +- .../module/modules/task/TaskScheduler.java | 8 +- .../agent/shared/memory/EvaluatedSlice.java | 2 +- .../module/memory/total_summarizer.json | 2 +- 50 files changed, 441 insertions(+), 424 deletions(-) create mode 100644 qodana.yaml rename src/main/java/work/slhaf/agent/common/{pojo => serialize}/PersistableObject.java (69%) rename src/main/java/work/slhaf/agent/{core/interaction => common/thread}/InteractionThreadPoolExecutor.java (96%) delete mode 100644 src/main/java/work/slhaf/agent/core/interaction/InteractionModule.java rename src/main/java/work/slhaf/agent/core/interaction/{ => agent_interface}/InputReceiver.java (81%) rename src/main/java/work/slhaf/agent/core/interaction/{ => agent_interface}/TaskCallback.java (60%) delete mode 100644 src/main/java/work/slhaf/agent/core/interaction/data/InteractionContext.java create mode 100644 src/main/java/work/slhaf/agent/core/interaction/data/context/InteractionContext.java create mode 100644 src/main/java/work/slhaf/agent/core/interaction/data/context/subcontext/CoreContext.java create mode 100644 src/main/java/work/slhaf/agent/core/interaction/data/context/subcontext/ModuleContext.java create mode 100644 src/main/java/work/slhaf/agent/core/interaction/module/InteractionModule.java rename src/main/java/work/slhaf/agent/core/interaction/{ => module}/InteractionModulesLoader.java (98%) delete mode 100644 src/main/java/work/slhaf/agent/module/common/AppendPrompt.java create mode 100644 src/main/java/work/slhaf/agent/module/common/PreModuleActions.java diff --git a/.gitignore b/.gitignore index fdf0a7dc..32121f62 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,4 @@ build/ /src/test/java/memory/result/input4.json /src/test/java/memory/result/primary_input.json /src/main/resources/prompt/module/memory/topic_extractor.json.bak +/backup/ diff --git a/qodana.yaml b/qodana.yaml new file mode 100644 index 00000000..bf267604 --- /dev/null +++ b/qodana.yaml @@ -0,0 +1,31 @@ +#-------------------------------------------------------------------------------# +# Qodana analysis is configured by qodana.yaml file # +# https://www.jetbrains.com/help/qodana/qodana-yaml.html # +#-------------------------------------------------------------------------------# +version: "1.0" + +#Specify inspection profile for code analysis +profile: + name: qodana.starter + +#Enable inspections +#include: +# - name: + +#Disable inspections +#exclude: +# - name: +# paths: +# - + +projectJDK: "21" #(Applied in CI/CD pipeline) + +#Execute shell command before Qodana execution (Applied in CI/CD pipeline) +#bootstrap: sh ./prepare-qodana.sh + +#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline) +#plugins: +# - id: #(plugin id can be found at https://plugins.jetbrains.com) + +#Specify Qodana linter for analysis (Applied in CI/CD pipeline) +linter: jetbrains/qodana-jvm:2025.1 diff --git a/src/main/java/work/slhaf/agent/Agent.java b/src/main/java/work/slhaf/agent/Agent.java index f69b568c..bde57978 100644 --- a/src/main/java/work/slhaf/agent/Agent.java +++ b/src/main/java/work/slhaf/agent/Agent.java @@ -5,8 +5,8 @@ import lombok.extern.slf4j.Slf4j; import work.slhaf.agent.common.config.Config; import work.slhaf.agent.common.monitor.DebugMonitor; import work.slhaf.agent.core.InteractionHub; -import work.slhaf.agent.core.interaction.InputReceiver; -import work.slhaf.agent.core.interaction.TaskCallback; +import work.slhaf.agent.core.interaction.agent_interface.InputReceiver; +import work.slhaf.agent.core.interaction.agent_interface.TaskCallback; import work.slhaf.agent.core.interaction.data.InteractionInputData; import work.slhaf.agent.core.interaction.data.InteractionOutputData; import work.slhaf.agent.gateway.AgentWebSocketServer; @@ -36,7 +36,6 @@ public class Agent implements TaskCallback, InputReceiver { server.launch(); agent.setMessageSender(server); log.info("Agent 加载完毕.."); - //启动监测线程 DebugMonitor.initialize(); } diff --git a/src/main/java/work/slhaf/agent/common/chat/pojo/Message.java b/src/main/java/work/slhaf/agent/common/chat/pojo/Message.java index 5d84b640..c7b169ff 100644 --- a/src/main/java/work/slhaf/agent/common/chat/pojo/Message.java +++ b/src/main/java/work/slhaf/agent/common/chat/pojo/Message.java @@ -1,7 +1,7 @@ package work.slhaf.agent.common.chat.pojo; import lombok.*; -import work.slhaf.agent.common.pojo.PersistableObject; +import work.slhaf.agent.common.serialize.PersistableObject; import java.io.Serial; diff --git a/src/main/java/work/slhaf/agent/common/chat/pojo/MetaMessage.java b/src/main/java/work/slhaf/agent/common/chat/pojo/MetaMessage.java index 293a3f77..e0fc3358 100644 --- a/src/main/java/work/slhaf/agent/common/chat/pojo/MetaMessage.java +++ b/src/main/java/work/slhaf/agent/common/chat/pojo/MetaMessage.java @@ -3,7 +3,7 @@ package work.slhaf.agent.common.chat.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; -import work.slhaf.agent.common.pojo.PersistableObject; +import work.slhaf.agent.common.serialize.PersistableObject; import java.io.Serial; diff --git a/src/main/java/work/slhaf/agent/common/config/Config.java b/src/main/java/work/slhaf/agent/common/config/Config.java index dacbb6b2..ca8ebb85 100644 --- a/src/main/java/work/slhaf/agent/common/config/Config.java +++ b/src/main/java/work/slhaf/agent/common/config/Config.java @@ -48,9 +48,6 @@ public class Config { System.out.print("输入智能体名称: "); config.setAgentId(scanner.nextLine()); -// System.out.print("输入智能体基础角色设定: "); -// config.setBasicCharacter(scanner.nextLine()); - System.out.println("(注意! 设定角色之后修改主配置文件将不会影响现有记忆,除非同时更换agentId)"); System.out.println("\r\n--------模型配置--------\r\n"); diff --git a/src/main/java/work/slhaf/agent/common/exception_handler/pojo/GlobalException.java b/src/main/java/work/slhaf/agent/common/exception_handler/pojo/GlobalException.java index c5adfce3..8564b494 100644 --- a/src/main/java/work/slhaf/agent/common/exception_handler/pojo/GlobalException.java +++ b/src/main/java/work/slhaf/agent/common/exception_handler/pojo/GlobalException.java @@ -3,7 +3,7 @@ package work.slhaf.agent.common.exception_handler.pojo; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; -import work.slhaf.agent.core.interaction.data.InteractionContext; +import work.slhaf.agent.core.interaction.data.context.InteractionContext; import work.slhaf.agent.core.memory.MemoryManager; import work.slhaf.agent.core.session.SessionManager; diff --git a/src/main/java/work/slhaf/agent/common/exception_handler/pojo/GlobalExceptionData.java b/src/main/java/work/slhaf/agent/common/exception_handler/pojo/GlobalExceptionData.java index 3705f5e6..34cdce24 100644 --- a/src/main/java/work/slhaf/agent/common/exception_handler/pojo/GlobalExceptionData.java +++ b/src/main/java/work/slhaf/agent/common/exception_handler/pojo/GlobalExceptionData.java @@ -2,12 +2,13 @@ package work.slhaf.agent.common.exception_handler.pojo; import lombok.Data; import lombok.EqualsAndHashCode; -import work.slhaf.agent.common.pojo.PersistableObject; -import work.slhaf.agent.core.interaction.data.InteractionContext; +import work.slhaf.agent.common.serialize.PersistableObject; +import work.slhaf.agent.core.interaction.data.context.InteractionContext; import work.slhaf.agent.core.memory.MemoryManager; import work.slhaf.agent.core.session.SessionManager; import java.io.Serial; +import java.util.HashMap; @EqualsAndHashCode(callSuper = true) @Data @@ -18,7 +19,7 @@ public class GlobalExceptionData extends PersistableObject { private String exceptionMessage; - protected InteractionContext context; + protected HashMap context; protected SessionManager sessionManager; protected MemoryManager memoryManager; protected Long exceptionTime; diff --git a/src/main/java/work/slhaf/agent/common/monitor/DebugMonitor.java b/src/main/java/work/slhaf/agent/common/monitor/DebugMonitor.java index 3aa3c66a..0d35c06f 100644 --- a/src/main/java/work/slhaf/agent/common/monitor/DebugMonitor.java +++ b/src/main/java/work/slhaf/agent/common/monitor/DebugMonitor.java @@ -1,7 +1,7 @@ package work.slhaf.agent.common.monitor; import lombok.extern.slf4j.Slf4j; -import work.slhaf.agent.core.interaction.InteractionThreadPoolExecutor; +import work.slhaf.agent.common.thread.InteractionThreadPoolExecutor; @Slf4j public class DebugMonitor { diff --git a/src/main/java/work/slhaf/agent/common/pojo/PersistableObject.java b/src/main/java/work/slhaf/agent/common/serialize/PersistableObject.java similarity index 69% rename from src/main/java/work/slhaf/agent/common/pojo/PersistableObject.java rename to src/main/java/work/slhaf/agent/common/serialize/PersistableObject.java index 5b125d5d..ddee853e 100644 --- a/src/main/java/work/slhaf/agent/common/pojo/PersistableObject.java +++ b/src/main/java/work/slhaf/agent/common/serialize/PersistableObject.java @@ -1,4 +1,4 @@ -package work.slhaf.agent.common.pojo; +package work.slhaf.agent.common.serialize; import java.io.Serializable; diff --git a/src/main/java/work/slhaf/agent/core/interaction/InteractionThreadPoolExecutor.java b/src/main/java/work/slhaf/agent/common/thread/InteractionThreadPoolExecutor.java similarity index 96% rename from src/main/java/work/slhaf/agent/core/interaction/InteractionThreadPoolExecutor.java rename to src/main/java/work/slhaf/agent/common/thread/InteractionThreadPoolExecutor.java index ab704faf..d085df65 100644 --- a/src/main/java/work/slhaf/agent/core/interaction/InteractionThreadPoolExecutor.java +++ b/src/main/java/work/slhaf/agent/common/thread/InteractionThreadPoolExecutor.java @@ -1,4 +1,4 @@ -package work.slhaf.agent.core.interaction; +package work.slhaf.agent.common.thread; import lombok.Getter; diff --git a/src/main/java/work/slhaf/agent/core/InteractionHub.java b/src/main/java/work/slhaf/agent/core/InteractionHub.java index 9fe2e94c..5367ef25 100644 --- a/src/main/java/work/slhaf/agent/core/InteractionHub.java +++ b/src/main/java/work/slhaf/agent/core/InteractionHub.java @@ -5,11 +5,11 @@ import lombok.ToString; import lombok.extern.slf4j.Slf4j; import work.slhaf.agent.common.exception_handler.GlobalExceptionHandler; import work.slhaf.agent.common.exception_handler.pojo.GlobalException; -import work.slhaf.agent.core.interaction.InteractionModule; -import work.slhaf.agent.core.interaction.InteractionModulesLoader; -import work.slhaf.agent.core.interaction.TaskCallback; -import work.slhaf.agent.core.interaction.data.InteractionContext; +import work.slhaf.agent.core.interaction.agent_interface.TaskCallback; import work.slhaf.agent.core.interaction.data.InteractionInputData; +import work.slhaf.agent.core.interaction.data.context.InteractionContext; +import work.slhaf.agent.core.interaction.module.InteractionModule; +import work.slhaf.agent.core.interaction.module.InteractionModulesLoader; import work.slhaf.agent.module.modules.core.CoreModel; import work.slhaf.agent.module.modules.preprocess.PreprocessExecutor; import work.slhaf.agent.module.modules.task.TaskScheduler; @@ -43,7 +43,7 @@ public class InteractionHub { return interactionHub; } - public void call(InteractionInputData inputData) throws IOException, ClassNotFoundException, InterruptedException { + public void call(InteractionInputData inputData) throws IOException, ClassNotFoundException { InteractionContext interactionContext = PreprocessExecutor.getInstance().execute(inputData); try { //预处理 @@ -55,7 +55,7 @@ public class InteractionHub { interactionContext.getCoreResponse().put("text", "[ERROR] " + e.getMessage()); } finally { callback.onTaskFinished(interactionContext.getUserInfo(), interactionContext.getCoreResponse().getString("text")); - InteractionContext.clearUp(); + interactionContext.clearUp(); } } } diff --git a/src/main/java/work/slhaf/agent/core/interaction/InteractionModule.java b/src/main/java/work/slhaf/agent/core/interaction/InteractionModule.java deleted file mode 100644 index 21e633ad..00000000 --- a/src/main/java/work/slhaf/agent/core/interaction/InteractionModule.java +++ /dev/null @@ -1,9 +0,0 @@ -package work.slhaf.agent.core.interaction; - -import work.slhaf.agent.core.interaction.data.InteractionContext; - -import java.io.IOException; - -public interface InteractionModule { - void execute(InteractionContext context) throws IOException, ClassNotFoundException, InterruptedException; -} diff --git a/src/main/java/work/slhaf/agent/core/interaction/InputReceiver.java b/src/main/java/work/slhaf/agent/core/interaction/agent_interface/InputReceiver.java similarity index 81% rename from src/main/java/work/slhaf/agent/core/interaction/InputReceiver.java rename to src/main/java/work/slhaf/agent/core/interaction/agent_interface/InputReceiver.java index 806cf78b..4c82afe4 100644 --- a/src/main/java/work/slhaf/agent/core/interaction/InputReceiver.java +++ b/src/main/java/work/slhaf/agent/core/interaction/agent_interface/InputReceiver.java @@ -1,4 +1,4 @@ -package work.slhaf.agent.core.interaction; +package work.slhaf.agent.core.interaction.agent_interface; import work.slhaf.agent.core.interaction.data.InteractionInputData; diff --git a/src/main/java/work/slhaf/agent/core/interaction/TaskCallback.java b/src/main/java/work/slhaf/agent/core/interaction/agent_interface/TaskCallback.java similarity index 60% rename from src/main/java/work/slhaf/agent/core/interaction/TaskCallback.java rename to src/main/java/work/slhaf/agent/core/interaction/agent_interface/TaskCallback.java index 8c424661..e96759ad 100644 --- a/src/main/java/work/slhaf/agent/core/interaction/TaskCallback.java +++ b/src/main/java/work/slhaf/agent/core/interaction/agent_interface/TaskCallback.java @@ -1,4 +1,4 @@ -package work.slhaf.agent.core.interaction; +package work.slhaf.agent.core.interaction.agent_interface; public interface TaskCallback { void onTaskFinished(String userInfo,String output); diff --git a/src/main/java/work/slhaf/agent/core/interaction/data/InteractionContext.java b/src/main/java/work/slhaf/agent/core/interaction/data/InteractionContext.java deleted file mode 100644 index 995cbc02..00000000 --- a/src/main/java/work/slhaf/agent/core/interaction/data/InteractionContext.java +++ /dev/null @@ -1,76 +0,0 @@ -package work.slhaf.agent.core.interaction.data; - -import com.alibaba.fastjson2.JSONArray; -import com.alibaba.fastjson2.JSONObject; -import lombok.Data; -import lombok.EqualsAndHashCode; -import work.slhaf.agent.common.pojo.PersistableObject; -import work.slhaf.agent.module.common.AppendPromptData; - -import java.io.Serial; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; - -@EqualsAndHashCode(callSuper = true) -@Data -public class InteractionContext extends PersistableObject { - - @Serial - private static final long serialVersionUID = 1L; - - private static InteractionContext currentContext; - - protected String userId; - protected String userNickname; - protected String userInfo; - protected LocalDateTime dateTime; - protected boolean single; - - protected String input; - - protected JSONObject coreContext; - protected JSONObject moduleContext; - protected JSONObject coreResponse; - - public InteractionContext() { - currentContext = this; - this.moduleContext = new JSONObject(); - this.moduleContext.put(Constant.APPENDED_PROMPT,new JSONArray()); - } - - public void setFinished(boolean finished) { - moduleContext.put(Constant.FINISHED,finished); - } - - public boolean isFinished(){ - return moduleContext.getBooleanValue(Constant.FINISHED); - } - - public void setAppendedPrompt(AppendPromptData appendedPrompt){ - moduleContext.getJSONArray(Constant.APPENDED_PROMPT).add(appendedPrompt); - } - - public List getAppendedPrompt(){ - List list = new ArrayList<>(); - for (Object o : moduleContext.getJSONArray(Constant.APPENDED_PROMPT)) { - JSONObject object = (JSONObject) o; - list.add(object.to(AppendPromptData.class)); - } - return list; - } - - public static InteractionContext getInstance() { - return currentContext; - } - - public static void clearUp(){ - currentContext = null; - } - - private static class Constant{ - private static final String FINISHED = "finished"; - private static final String APPENDED_PROMPT = "appendedPrompt"; - } - -} diff --git a/src/main/java/work/slhaf/agent/core/interaction/data/context/InteractionContext.java b/src/main/java/work/slhaf/agent/core/interaction/data/context/InteractionContext.java new file mode 100644 index 00000000..4c279198 --- /dev/null +++ b/src/main/java/work/slhaf/agent/core/interaction/data/context/InteractionContext.java @@ -0,0 +1,62 @@ +package work.slhaf.agent.core.interaction.data.context; + +import com.alibaba.fastjson2.JSONObject; +import lombok.Data; +import lombok.EqualsAndHashCode; +import work.slhaf.agent.common.serialize.PersistableObject; +import work.slhaf.agent.core.interaction.data.context.subcontext.CoreContext; +import work.slhaf.agent.core.interaction.data.context.subcontext.ModuleContext; +import work.slhaf.agent.module.common.AppendPromptData; + +import java.io.Serial; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +public class InteractionContext extends PersistableObject { + + @Serial + private static final long serialVersionUID = 1L; + + private static HashMap activeContext = new HashMap<>(); + + protected String userId; + protected String userNickname; + protected String userInfo; + protected LocalDateTime dateTime; + protected boolean single; + + protected String input; + + protected CoreContext coreContext = new CoreContext(); + protected ModuleContext moduleContext = new ModuleContext(); + protected JSONObject coreResponse = new JSONObject(); + + public InteractionContext() { + activeContext.put(userId, this); + } + + public void setFinished(boolean finished) { + moduleContext.setFinished(finished); + } + + public boolean isFinished() { + return moduleContext.isFinished(); + } + + public void setAppendedPrompt(AppendPromptData appendedPrompt) { + List appendPromptList = moduleContext.getAppendedPrompt(); + appendPromptList.addFirst(appendedPrompt); + } + + public static HashMap getInstance() { + return activeContext; + } + + public void clearUp() { + activeContext.remove(userId); + } + +} diff --git a/src/main/java/work/slhaf/agent/core/interaction/data/context/subcontext/CoreContext.java b/src/main/java/work/slhaf/agent/core/interaction/data/context/subcontext/CoreContext.java new file mode 100644 index 00000000..1f448ac7 --- /dev/null +++ b/src/main/java/work/slhaf/agent/core/interaction/data/context/subcontext/CoreContext.java @@ -0,0 +1,28 @@ +package work.slhaf.agent.core.interaction.data.context.subcontext; + +import com.alibaba.fastjson2.JSONObject; +import lombok.Data; + +import java.util.HashMap; + +@Data +public class CoreContext { + private String text; + private String dateTime; + private String userNick; + private String userId; + private HashMap activeModules = new HashMap<>(); + + @Override + public String toString() { + return JSONObject.toJSONString(this); + } + + public void addActiveModule(String moduleName) { + activeModules.put(moduleName, false); + } + + public void activateModule(String moduleName){ + activeModules.put(moduleName, true); + } +} diff --git a/src/main/java/work/slhaf/agent/core/interaction/data/context/subcontext/ModuleContext.java b/src/main/java/work/slhaf/agent/core/interaction/data/context/subcontext/ModuleContext.java new file mode 100644 index 00000000..44fdde97 --- /dev/null +++ b/src/main/java/work/slhaf/agent/core/interaction/data/context/subcontext/ModuleContext.java @@ -0,0 +1,15 @@ +package work.slhaf.agent.core.interaction.data.context.subcontext; + +import com.alibaba.fastjson2.JSONObject; +import lombok.Data; +import work.slhaf.agent.module.common.AppendPromptData; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class ModuleContext { + private List appendedPrompt = new ArrayList<>(); + private JSONObject extraContext = new JSONObject(); + private boolean finished = false; +} diff --git a/src/main/java/work/slhaf/agent/core/interaction/module/InteractionModule.java b/src/main/java/work/slhaf/agent/core/interaction/module/InteractionModule.java new file mode 100644 index 00000000..2d0b98d8 --- /dev/null +++ b/src/main/java/work/slhaf/agent/core/interaction/module/InteractionModule.java @@ -0,0 +1,9 @@ +package work.slhaf.agent.core.interaction.module; + +import work.slhaf.agent.core.interaction.data.context.InteractionContext; + +import java.io.IOException; + +public interface InteractionModule { + void execute(InteractionContext context) throws IOException, ClassNotFoundException; +} diff --git a/src/main/java/work/slhaf/agent/core/interaction/InteractionModulesLoader.java b/src/main/java/work/slhaf/agent/core/interaction/module/InteractionModulesLoader.java similarity index 98% rename from src/main/java/work/slhaf/agent/core/interaction/InteractionModulesLoader.java rename to src/main/java/work/slhaf/agent/core/interaction/module/InteractionModulesLoader.java index f6403764..e904bb2b 100644 --- a/src/main/java/work/slhaf/agent/core/interaction/InteractionModulesLoader.java +++ b/src/main/java/work/slhaf/agent/core/interaction/module/InteractionModulesLoader.java @@ -1,4 +1,4 @@ -package work.slhaf.agent.core.interaction; +package work.slhaf.agent.core.interaction.module; import work.slhaf.agent.common.config.Config; import work.slhaf.agent.common.config.ModuleConfig; diff --git a/src/main/java/work/slhaf/agent/core/memory/MemoryGraph.java b/src/main/java/work/slhaf/agent/core/memory/MemoryGraph.java index 02283dbd..4385adfc 100644 --- a/src/main/java/work/slhaf/agent/core/memory/MemoryGraph.java +++ b/src/main/java/work/slhaf/agent/core/memory/MemoryGraph.java @@ -7,7 +7,7 @@ import org.apache.commons.io.FileUtils; import work.slhaf.agent.common.chat.pojo.Message; import work.slhaf.agent.common.exception_handler.GlobalExceptionHandler; import work.slhaf.agent.common.exception_handler.pojo.GlobalException; -import work.slhaf.agent.common.pojo.PersistableObject; +import work.slhaf.agent.common.serialize.PersistableObject; import work.slhaf.agent.core.memory.exception.UnExistedDateIndexException; import work.slhaf.agent.core.memory.exception.UnExistedTopicException; import work.slhaf.agent.core.memory.node.MemoryNode; @@ -72,17 +72,6 @@ public class MemoryGraph extends PersistableObject { */ private ConcurrentHashMap> userDialogMap; - /** - * 当前对话的活动性总结, 拥有比dialogMap更丰富的全文细节, 作为当前对话token超限时的必要上下文压缩存储 - */ -// private List currentCompressedSessionContext; - - /** - * 存储确定性记忆, 如'用户爱好'等确定性信息 - * 该部分作为'主LLM'system prompt常驻 - */ -// private HashMap> staticMemory; - /** * memorySliceCache计数器,每日清空 */ @@ -104,8 +93,6 @@ public class MemoryGraph extends PersistableObject { */ private HashMap modelPrompt; -// private String character; - /** * 主模型的聊天记录 */ @@ -126,17 +113,15 @@ public class MemoryGraph extends PersistableObject { this.topicNodes = new HashMap<>(); this.existedTopics = new HashMap<>(); this.currentDateDialogSlices = new HashMap<>(); -// this.staticMemory = new HashMap<>(); this.memoryNodeCacheCounter = new ConcurrentHashMap<>(); this.memorySliceCache = new ConcurrentHashMap<>(); this.modelPrompt = new HashMap<>(); this.selectedSlices = new HashSet<>(); this.users = new ArrayList<>(); this.userDialogMap = new ConcurrentHashMap<>(); -// this.currentCompressedSessionContext = new ArrayList<>(); this.dialogMap = new HashMap<>(); -// this.character = basicCharacter; this.dateIndex = new HashMap<>(); + this.chatMessages = new ArrayList<>(); } public static MemoryGraph getInstance(String id) throws IOException, ClassNotFoundException { @@ -200,7 +185,7 @@ public class MemoryGraph extends PersistableObject { } } - public void insertMemory(List topicPath, MemorySlice slice) throws IOException, ClassNotFoundException { + public void insertMemory(List topicPath, MemorySlice slice) { try { //检查是否存在当天对应的memorySlice并确定是否插入 @@ -297,17 +282,13 @@ public class MemoryGraph extends PersistableObject { //更新userDialogMap //移除两天前上下文缓存(切片总结) List keysToRemove = new ArrayList<>(); - userDialogMap.forEach((k, v) -> { - v.forEach((i, j) -> { - if (now.minusDays(2).isAfter(i)) { - keysToRemove.add(i); - } - }); - }); + userDialogMap.forEach((k, v) -> v.forEach((i, j) -> { + if (now.minusDays(2).isAfter(i)) { + keysToRemove.add(i); + } + })); for (LocalDateTime dateTime : keysToRemove) { - userDialogMap.forEach((k, v) -> { - v.remove(dateTime); - }); + userDialogMap.forEach((k, v) -> v.remove(dateTime)); } //放入新缓存 userDialogMap @@ -342,7 +323,7 @@ public class MemoryGraph extends PersistableObject { } - public MemoryResult selectMemory(String topicPathStr) throws IOException, ClassNotFoundException { + public MemoryResult selectMemory(String topicPathStr) { MemoryResult memoryResult = new MemoryResult(); List topicPath = List.of(topicPathStr.split("->")); try { diff --git a/src/main/java/work/slhaf/agent/core/memory/MemoryManager.java b/src/main/java/work/slhaf/agent/core/memory/MemoryManager.java index 2aef5ce7..666fb8ad 100644 --- a/src/main/java/work/slhaf/agent/core/memory/MemoryManager.java +++ b/src/main/java/work/slhaf/agent/core/memory/MemoryManager.java @@ -5,9 +5,10 @@ import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; import work.slhaf.agent.common.chat.pojo.Message; import work.slhaf.agent.common.config.Config; -import work.slhaf.agent.common.pojo.PersistableObject; +import work.slhaf.agent.common.serialize.PersistableObject; import work.slhaf.agent.core.memory.pojo.MemoryResult; import work.slhaf.agent.core.memory.pojo.MemorySlice; +import work.slhaf.agent.core.memory.pojo.MemorySliceResult; import work.slhaf.agent.core.memory.pojo.User; import work.slhaf.agent.shared.memory.EvaluatedSlice; @@ -17,6 +18,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -66,12 +68,23 @@ public class MemoryManager extends PersistableObject { })); } - public MemoryResult selectMemory(String path) throws IOException, ClassNotFoundException { - return memoryGraph.selectMemory(path); + public MemoryResult selectMemory(String path) { + return cacheFilter(memoryGraph.selectMemory(path)); } public MemoryResult selectMemory(LocalDate date) throws IOException, ClassNotFoundException { - return memoryGraph.selectMemory(date); + return cacheFilter(memoryGraph.selectMemory(date)); + } + + private MemoryResult cacheFilter(MemoryResult memoryResult) { + //过滤掉与缓存重复的切片 + CopyOnWriteArrayList memorySliceResult = memoryResult.getMemorySliceResult(); + List relatedMemorySliceResult = memoryResult.getRelatedMemorySliceResult(); + getDialogMap().forEach((k,v) -> { + memorySliceResult.removeIf(m -> m.getMemorySlice().getSummary().equals(v)); + relatedMemorySliceResult.removeIf(m -> m.getSummary().equals(v)); + }); + return memoryResult; } public void cleanSelectedSliceFilter() { @@ -115,10 +128,6 @@ public class MemoryManager extends PersistableObject { return memoryGraph.getTopicTree(); } -/* public ConcurrentHashMap getStaticMemory(String userId) { - return memoryGraph.getStaticMemory().get(userId); - }*/ - public HashMap getDialogMap() { return memoryGraph.getDialogMap(); } @@ -127,11 +136,7 @@ public class MemoryManager extends PersistableObject { return memoryGraph.getUserDialogMap().get(userId); } -/* public String getCharacter() { - return memoryGraph.getCharacter(); - }*/ - - public void insertSlice(MemorySlice memorySlice, String topicPath) throws IOException, ClassNotFoundException { + public void insertSlice(MemorySlice memorySlice, String topicPath) { sliceInsertLock.lock(); List topicPathList = Arrays.stream(topicPath.split("->")).toList(); memoryGraph.insertMemory(topicPathList, memorySlice); @@ -145,13 +150,6 @@ public class MemoryManager extends PersistableObject { messageCleanLock.unlock(); } -/* public void insertStaticMemory(String userId, Map newStaticMemory) { - if (!memoryGraph.getStaticMemory().containsKey(userId)) { - memoryGraph.getStaticMemory().put(userId, new ConcurrentHashMap<>()); - } - memoryGraph.getStaticMemory().get(userId).putAll(newStaticMemory); - }*/ - public void updateDialogMap(LocalDateTime dateTime, String newDialogCache) { memoryGraph.updateDialogMap(dateTime, newDialogCache); } @@ -175,35 +173,37 @@ public class MemoryManager extends PersistableObject { } public String getActivatedSlicesStr(String userId) { - StringBuilder str = new StringBuilder(); if (memoryManager.getActivatedSlices().containsKey(userId)) { - memoryManager.getActivatedSlices().get(userId).forEach(slice -> { - str.append("\n\n").append("[").append(slice.getDate()).append("]\n") - .append(slice.getSummary()); - }); + StringBuilder str = new StringBuilder(); + memoryManager.getActivatedSlices().get(userId).forEach(slice -> str.append("\n\n").append("[").append(slice.getDate()).append("]\n") + .append(slice.getSummary())); + return str.toString(); + }else { + return null; } - return str.toString(); } public String getDialogMapStr() { StringBuilder str = new StringBuilder(); - memoryGraph.getDialogMap().forEach((dateTime, dialog) -> { - str.append("\n\n").append("[").append(dateTime).append("]\n") - .append(dialog); - }); + memoryGraph.getDialogMap().forEach((dateTime, dialog) -> str.append("\n\n").append("[").append(dateTime).append("]\n") + .append(dialog)); return str.toString(); } public String getUserDialogMapStr(String userId) { - StringBuilder str = new StringBuilder(); - Collection dialogMapValues = memoryGraph.getDialogMap().values(); - memoryGraph.getUserDialogMap().get(userId).forEach((dateTime, dialog) -> { - if (dialogMapValues.contains(dialog)) { - return; - } - str.append("\n\n").append("[").append(dateTime).append("]\n") - .append(dialog); - }); - return str.toString(); + if (memoryGraph.getUserDialogMap().containsKey(userId)) { + StringBuilder str = new StringBuilder(); + Collection dialogMapValues = memoryGraph.getDialogMap().values(); + memoryGraph.getUserDialogMap().get(userId).forEach((dateTime, dialog) -> { + if (dialogMapValues.contains(dialog)) { + return; + } + str.append("\n\n").append("[").append(dateTime).append("]\n") + .append(dialog); + }); + return str.toString(); + }else { + return null; + } } } diff --git a/src/main/java/work/slhaf/agent/core/memory/node/MemoryNode.java b/src/main/java/work/slhaf/agent/core/memory/node/MemoryNode.java index 458d499d..f3c438cd 100644 --- a/src/main/java/work/slhaf/agent/core/memory/node/MemoryNode.java +++ b/src/main/java/work/slhaf/agent/core/memory/node/MemoryNode.java @@ -3,7 +3,7 @@ package work.slhaf.agent.core.memory.node; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; -import work.slhaf.agent.common.pojo.PersistableObject; +import work.slhaf.agent.common.serialize.PersistableObject; import work.slhaf.agent.core.memory.exception.NullSliceListException; import work.slhaf.agent.core.memory.pojo.MemorySlice; diff --git a/src/main/java/work/slhaf/agent/core/memory/node/TopicNode.java b/src/main/java/work/slhaf/agent/core/memory/node/TopicNode.java index 95af2487..f6e1dbdb 100644 --- a/src/main/java/work/slhaf/agent/core/memory/node/TopicNode.java +++ b/src/main/java/work/slhaf/agent/core/memory/node/TopicNode.java @@ -2,7 +2,7 @@ package work.slhaf.agent.core.memory.node; import lombok.Data; import lombok.EqualsAndHashCode; -import work.slhaf.agent.common.pojo.PersistableObject; +import work.slhaf.agent.common.serialize.PersistableObject; import java.io.Serial; import java.util.concurrent.ConcurrentHashMap; diff --git a/src/main/java/work/slhaf/agent/core/memory/pojo/MemoryResult.java b/src/main/java/work/slhaf/agent/core/memory/pojo/MemoryResult.java index 7d4285f6..c1322926 100644 --- a/src/main/java/work/slhaf/agent/core/memory/pojo/MemoryResult.java +++ b/src/main/java/work/slhaf/agent/core/memory/pojo/MemoryResult.java @@ -2,7 +2,7 @@ package work.slhaf.agent.core.memory.pojo; import lombok.Data; import lombok.EqualsAndHashCode; -import work.slhaf.agent.common.pojo.PersistableObject; +import work.slhaf.agent.common.serialize.PersistableObject; import java.io.Serial; import java.util.List; @@ -17,4 +17,10 @@ public class MemoryResult extends PersistableObject { private CopyOnWriteArrayList memorySliceResult; private List relatedMemorySliceResult; + + public boolean isEmpty(){ + boolean a = memorySliceResult == null || memorySliceResult.isEmpty(); + boolean b = relatedMemorySliceResult == null || relatedMemorySliceResult.isEmpty(); + return a && b; + } } diff --git a/src/main/java/work/slhaf/agent/core/memory/pojo/MemorySlice.java b/src/main/java/work/slhaf/agent/core/memory/pojo/MemorySlice.java index 2d77f60d..f3e42cf4 100644 --- a/src/main/java/work/slhaf/agent/core/memory/pojo/MemorySlice.java +++ b/src/main/java/work/slhaf/agent/core/memory/pojo/MemorySlice.java @@ -4,7 +4,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; import work.slhaf.agent.common.chat.pojo.Message; -import work.slhaf.agent.common.pojo.PersistableObject; +import work.slhaf.agent.common.serialize.PersistableObject; import java.io.Serial; import java.util.List; diff --git a/src/main/java/work/slhaf/agent/core/memory/pojo/MemorySliceResult.java b/src/main/java/work/slhaf/agent/core/memory/pojo/MemorySliceResult.java index 2adb91e3..ea947a06 100644 --- a/src/main/java/work/slhaf/agent/core/memory/pojo/MemorySliceResult.java +++ b/src/main/java/work/slhaf/agent/core/memory/pojo/MemorySliceResult.java @@ -1,9 +1,18 @@ package work.slhaf.agent.core.memory.pojo; import lombok.Data; +import lombok.EqualsAndHashCode; +import work.slhaf.agent.common.serialize.PersistableObject; +import java.io.Serial; + +@EqualsAndHashCode(callSuper = true) @Data -public class MemorySliceResult { +public class MemorySliceResult extends PersistableObject { + + @Serial + private static final long serialVersionUID = 1L; + private MemorySlice sliceBefore; private MemorySlice memorySlice; private MemorySlice sliceAfter; diff --git a/src/main/java/work/slhaf/agent/core/memory/pojo/User.java b/src/main/java/work/slhaf/agent/core/memory/pojo/User.java index ac81c718..6c3bf3fb 100644 --- a/src/main/java/work/slhaf/agent/core/memory/pojo/User.java +++ b/src/main/java/work/slhaf/agent/core/memory/pojo/User.java @@ -2,7 +2,7 @@ package work.slhaf.agent.core.memory.pojo; import lombok.Data; import lombok.EqualsAndHashCode; -import work.slhaf.agent.common.pojo.PersistableObject; +import work.slhaf.agent.common.serialize.PersistableObject; import java.io.Serial; import java.util.List; diff --git a/src/main/java/work/slhaf/agent/core/session/SessionManager.java b/src/main/java/work/slhaf/agent/core/session/SessionManager.java index 4c1c0a53..494b18a6 100644 --- a/src/main/java/work/slhaf/agent/core/session/SessionManager.java +++ b/src/main/java/work/slhaf/agent/core/session/SessionManager.java @@ -1,12 +1,13 @@ package work.slhaf.agent.core.session; +import com.alibaba.fastjson2.JSONObject; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; import work.slhaf.agent.common.chat.pojo.Message; import work.slhaf.agent.common.chat.pojo.MetaMessage; import work.slhaf.agent.common.config.Config; -import work.slhaf.agent.common.pojo.PersistableObject; +import work.slhaf.agent.common.serialize.PersistableObject; import java.io.*; import java.nio.file.Files; @@ -67,14 +68,14 @@ public class SessionManager extends PersistableObject { } public void addMetaMessage(String userId, MetaMessage metaMessage) { - log.debug("[SessionManager] 当前会话历史: {}", singleMetaMessageMap); + log.debug("[SessionManager] 当前会话历史: {}", JSONObject.toJSONString(singleMetaMessageMap)); if (singleMetaMessageMap.containsKey(userId)) { singleMetaMessageMap.get(userId).add(metaMessage); } else { singleMetaMessageMap.put(userId, new java.util.ArrayList<>()); singleMetaMessageMap.get(userId).add(metaMessage); } - log.debug("[SessionManager] 会话历史更新: {}", singleMetaMessageMap); + log.debug("[SessionManager] 会话历史更新: {}", JSONObject.toJSONString(singleMetaMessageMap)); } public List unpackAndClear(String userId) { diff --git a/src/main/java/work/slhaf/agent/gateway/AgentWebSocketServer.java b/src/main/java/work/slhaf/agent/gateway/AgentWebSocketServer.java index 48557a28..e2a21ceb 100644 --- a/src/main/java/work/slhaf/agent/gateway/AgentWebSocketServer.java +++ b/src/main/java/work/slhaf/agent/gateway/AgentWebSocketServer.java @@ -8,8 +8,8 @@ import org.java_websocket.WebSocket; import org.java_websocket.framing.Framedata; import org.java_websocket.handshake.ClientHandshake; import org.java_websocket.server.WebSocketServer; -import work.slhaf.agent.core.interaction.InputReceiver; -import work.slhaf.agent.core.interaction.InteractionThreadPoolExecutor; +import work.slhaf.agent.common.thread.InteractionThreadPoolExecutor; +import work.slhaf.agent.core.interaction.agent_interface.InputReceiver; import work.slhaf.agent.core.interaction.data.InteractionInputData; import work.slhaf.agent.core.interaction.data.InteractionOutputData; diff --git a/src/main/java/work/slhaf/agent/module/common/AppendPrompt.java b/src/main/java/work/slhaf/agent/module/common/AppendPrompt.java deleted file mode 100644 index 73cd9964..00000000 --- a/src/main/java/work/slhaf/agent/module/common/AppendPrompt.java +++ /dev/null @@ -1,10 +0,0 @@ -package work.slhaf.agent.module.common; - -import work.slhaf.agent.core.interaction.data.InteractionContext; - -/** - * 用于在前置模块设置追加提示词 - */ -public interface AppendPrompt { - void setAppendedPrompt(InteractionContext context); -} diff --git a/src/main/java/work/slhaf/agent/module/common/AppendPromptData.java b/src/main/java/work/slhaf/agent/module/common/AppendPromptData.java index c280364e..c72fa6ac 100644 --- a/src/main/java/work/slhaf/agent/module/common/AppendPromptData.java +++ b/src/main/java/work/slhaf/agent/module/common/AppendPromptData.java @@ -6,6 +6,6 @@ import java.util.HashMap; @Data public class AppendPromptData { - private String comment; + private String moduleName; private HashMap appendedPrompt; } diff --git a/src/main/java/work/slhaf/agent/module/common/Model.java b/src/main/java/work/slhaf/agent/module/common/Model.java index a703811e..3dd200c3 100644 --- a/src/main/java/work/slhaf/agent/module/common/Model.java +++ b/src/main/java/work/slhaf/agent/module/common/Model.java @@ -20,20 +20,6 @@ public class Model { protected static void setModel(Model model, String model_key, String promptModule, boolean withAwareness) { ModelConfig modelConfig = ModelConfig.load(model_key); - /*if (memoryGraph.getModelPrompt().containsKey(model_key)) { - model.setPrompt(memoryGraph.getModelPrompt().get(model_key)); - } else { - model.setPrompt(prompt); - memoryGraph.getModelPrompt().put(model_key, prompt); - } - if (memoryGraph.getChatMessages() == null) { - List tempMessages = new ArrayList<>(); - tempMessages.add(new Message(ChatConstant.Character.SYSTEM, model.getPrompt())); - model.setMessages(tempMessages); - memoryGraph.setChatMessages(tempMessages); - } else { - model.setMessages(memoryGraph.getChatMessages()); - }*/ model.setBaseMessages(withAwareness ? ResourcesUtil.Prompt.loadPromptWithSelfAwareness(model_key, promptModule) : ResourcesUtil.Prompt.loadPrompt(model_key, promptModule)); model.setChatClient(new ChatClient(modelConfig.getBaseUrl(), modelConfig.getApikey(), modelConfig.getModel())); } diff --git a/src/main/java/work/slhaf/agent/module/common/PreModuleActions.java b/src/main/java/work/slhaf/agent/module/common/PreModuleActions.java new file mode 100644 index 00000000..e7da6b7f --- /dev/null +++ b/src/main/java/work/slhaf/agent/module/common/PreModuleActions.java @@ -0,0 +1,11 @@ +package work.slhaf.agent.module.common; + +import work.slhaf.agent.core.interaction.data.context.InteractionContext; + +/** + * 用于在前置模块设置追加提示词 + */ +public interface PreModuleActions { + void setAppendedPrompt(InteractionContext context); + void setActiveModule(InteractionContext context); +} diff --git a/src/main/java/work/slhaf/agent/module/modules/core/CoreModel.java b/src/main/java/work/slhaf/agent/module/modules/core/CoreModel.java index 5a385857..90786f1f 100644 --- a/src/main/java/work/slhaf/agent/module/modules/core/CoreModel.java +++ b/src/main/java/work/slhaf/agent/module/modules/core/CoreModel.java @@ -8,8 +8,8 @@ import work.slhaf.agent.common.chat.constant.ChatConstant; import work.slhaf.agent.common.chat.pojo.ChatResponse; import work.slhaf.agent.common.chat.pojo.Message; import work.slhaf.agent.common.chat.pojo.MetaMessage; -import work.slhaf.agent.core.interaction.InteractionModule; -import work.slhaf.agent.core.interaction.data.InteractionContext; +import work.slhaf.agent.core.interaction.data.context.InteractionContext; +import work.slhaf.agent.core.interaction.module.InteractionModule; import work.slhaf.agent.core.memory.MemoryManager; import work.slhaf.agent.core.session.SessionManager; import work.slhaf.agent.module.common.AppendPromptData; @@ -17,7 +17,10 @@ import work.slhaf.agent.module.common.Model; import work.slhaf.agent.module.common.ModelConstant; import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import static work.slhaf.agent.common.util.ExtractUtil.extractJson; @@ -29,7 +32,6 @@ public class CoreModel extends Model implements InteractionModule { public static final String MODEL_KEY = "core_model"; private static volatile CoreModel coreModel; - private static List baseMessagesCache; private MemoryManager memoryManager; private SessionManager sessionManager; @@ -45,9 +47,9 @@ public class CoreModel extends Model implements InteractionModule { coreModel = new CoreModel(); coreModel.memoryManager = MemoryManager.getInstance(); coreModel.chatMessages = coreModel.memoryManager.getChatMessages(); + coreModel.appendedMessages = new ArrayList<>(); coreModel.sessionManager = SessionManager.getInstance(); setModel(coreModel, MODEL_KEY, ModelConstant.Prompt.CORE, true); - baseMessagesCache = coreModel.getBaseMessages(); coreModel.updateChatClientSettings(); log.info("[CoreModel] CoreModel注册完毕..."); } @@ -58,18 +60,20 @@ public class CoreModel extends Model implements InteractionModule { @Override public void execute(InteractionContext interactionContext) { - log.debug("[CoreModel] 主对话流程开始..."); - List appendedPrompt = interactionContext.getAppendedPrompt(); - if (!appendedPrompt.isEmpty()) { + String userId = interactionContext.getUserId(); + log.debug("[CoreModel] 主对话流程开始: {}", userId); + List appendedPrompt = interactionContext.getModuleContext().getAppendedPrompt(); + int appendedPromptSize = getAppendedPromptSize(appendedPrompt); + if (appendedPromptSize > 0) { setAppendedPromptMessage(appendedPrompt); } + activateModule(interactionContext); setMessageCount(interactionContext); log.debug("[CoreModel] 当前消息列表大小: {}", this.chatMessages.size()); log.debug("[CoreModel] 当前核心prompt内容: {}", interactionContext.getCoreContext().toString()); -// Message strengthenMessage = new Message(ChatConstant.Character.SYSTEM, STRENGTHEN_PROMPT); - setMessage(/*strengthenMessage, */interactionContext.getCoreContext().toString()); + setMessage(interactionContext.getCoreContext().toString()); JSONObject response = new JSONObject(); int count = 0; @@ -81,10 +85,9 @@ public class CoreModel extends Model implements InteractionModule { } catch (Exception e) { log.warn("主模型回复格式出错, 将直接作为消息返回, 建议尝试更换主模型..."); handleExceptionResponse(response, chatResponse.getMessage(), interactionContext); - break; } log.debug("[CoreModel] CoreModel 响应内容: {}", response); - handleResponse(interactionContext, response, chatResponse); + updateModuleContextAndChatMessages(interactionContext, response.getString("text"), chatResponse); break; } catch (Exception e) { count++; @@ -95,18 +98,35 @@ public class CoreModel extends Model implements InteractionModule { break; } } finally { -// this.chatMessages.remove(strengthenMessage); - interactionContext.setCoreResponse(response); - resetBaseAndAppendedMessages(); + updateCoreResponse(interactionContext, response); + resetAppendedMessages(); log.debug("[CoreModel] 消息列表更新大小: {}", this.chatMessages.size()); } } - log.debug("[CoreModel] 主对话流程结果: {}", interactionContext); + log.debug("[CoreModel] 主对话流程({})结束...", userId); } - private void resetBaseAndAppendedMessages() { - this.baseMessages.clear(); - this.baseMessages.addAll(baseMessagesCache); + private int getAppendedPromptSize(List appendedPrompt) { + int size = 0; + for (AppendPromptData data : appendedPrompt) { + size += data.getAppendedPrompt().size(); + } + return size; + } + + private void activateModule(InteractionContext context) { + HashMap activeModules = context.getCoreContext().getActiveModules(); + for (AppendPromptData data : context.getModuleContext().getAppendedPrompt()) { + if (data.getAppendedPrompt().isEmpty()) continue; + activeModules.put(data.getModuleName(), true); + } + } + + private void updateCoreResponse(InteractionContext interactionContext, JSONObject response) { + interactionContext.getCoreResponse().put("text", response.getString("text")); + } + + private void resetAppendedMessages() { this.appendedMessages.clear(); } @@ -118,14 +138,16 @@ public class CoreModel extends Model implements InteractionModule { return this.chatClient.runChat(temp); } - private void handleResponse(InteractionContext interactionContext, JSONObject response, ChatResponse chatResponse) { + private void updateModuleContextAndChatMessages(InteractionContext interactionContext, String response, ChatResponse chatResponse) { this.chatMessages.removeLast(); - Message primaryUserMessage = new Message(ChatConstant.Character.USER, interactionContext.getCoreContext().getString("text")); + //添加时间标志 + String dateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("\r\n**[yyyy-MM-dd HH:mm:ss]")); + Message primaryUserMessage = new Message(ChatConstant.Character.USER, interactionContext.getCoreContext().getText() + dateTime); this.chatMessages.add(primaryUserMessage); - Message assistantMessage = new Message(ChatConstant.Character.ASSISTANT, response.getString("text")); + Message assistantMessage = new Message(ChatConstant.Character.ASSISTANT, response); this.chatMessages.add(assistantMessage); //设置上下文 - interactionContext.getModuleContext().put("total_token", chatResponse.getUsageBean().getTotal_tokens()); + interactionContext.getModuleContext().getExtraContext().put("total_token", chatResponse.getUsageBean().getTotal_tokens()); //区分单人聊天场景 if (interactionContext.isSingle()) { MetaMessage metaMessage = new MetaMessage(primaryUserMessage, assistantMessage); @@ -133,8 +155,7 @@ public class CoreModel extends Model implements InteractionModule { } } - private void setMessage(/*Message strengthenMessage,*/ String coreContextStr) { -// this.chatMessages.add(strengthenMessage); + private void setMessage(String coreContextStr) { Message userMessage = new Message(ChatConstant.Character.USER, coreContextStr); this.chatMessages.add(userMessage); } @@ -142,25 +163,24 @@ public class CoreModel extends Model implements InteractionModule { private void handleExceptionResponse(JSONObject response, String chatResponse, InteractionContext interactionContext) { response.put("text", chatResponse); interactionContext.setFinished(true); + } private void setMessageCount(InteractionContext interactionContext) { - int moduleMessageCount = appendedMessages.size(); - int messageCount = chatMessages.size() - moduleMessageCount; - interactionContext.getModuleContext().put("message_count", messageCount); + interactionContext.getModuleContext().getExtraContext().put("message_count", chatMessages.size()); } private void setAppendedPromptMessage(List appendPrompt) { Message appendDeclareMessage = Message.builder() .role(ChatConstant.Character.USER) -// .content(ModelConstant.CharacterPrefix.SYSTEM + "以下为追加字段声明,可能包含用户的输入字段和你需要在回应中添加的输出字段.") - .content(ModelConstant.CharacterPrefix.SYSTEM + "以下为你的相关认知内容,可在对话中参考") + .content(ModelConstant.CharacterPrefix.SYSTEM + "以下为‘你’的相关认知内容,可在对话中参考") .build(); this.appendedMessages.add(appendDeclareMessage); for (AppendPromptData data : appendPrompt) { setStartMessage(data); setContentMessage(data); setEndMessage(data); + setAssistantMessage(); } Message appendEndMessage = Message.builder() .role(ChatConstant.Character.USER) @@ -169,10 +189,17 @@ public class CoreModel extends Model implements InteractionModule { this.appendedMessages.add(appendEndMessage); } + private void setAssistantMessage() { + appendedMessages.add(Message.builder() + .role(ChatConstant.Character.ASSISTANT) + .content("明白了") + .build()); + } + private void setEndMessage(AppendPromptData data) { Message endMessage = Message.builder() .role(ChatConstant.Character.USER) - .content(ModelConstant.CharacterPrefix.SYSTEM + data.getComment() + "认知补充结束.") + .content(ModelConstant.CharacterPrefix.SYSTEM + data.getModuleName() + "认知补充结束.") .build(); appendedMessages.add(endMessage); } @@ -181,7 +208,7 @@ public class CoreModel extends Model implements InteractionModule { data.getAppendedPrompt().forEach((k, v) -> { Message contentMessage = Message.builder() .role(ChatConstant.Character.USER) - .content(ModelConstant.CharacterPrefix.SYSTEM + k + v) + .content(ModelConstant.CharacterPrefix.SYSTEM + k + v + "\r\n") .build(); appendedMessages.add(contentMessage); }); @@ -190,7 +217,7 @@ public class CoreModel extends Model implements InteractionModule { private void setStartMessage(AppendPromptData data) { Message startMessage = Message.builder() .role(ChatConstant.Character.USER) - .content(ModelConstant.CharacterPrefix.SYSTEM + data.getComment() + "以下为" + data.getComment() + "相关认知.") + .content(ModelConstant.CharacterPrefix.SYSTEM + data.getModuleName() + "以下为" + data.getModuleName() + "相关认知.") .build(); appendedMessages.add(startMessage); } diff --git a/src/main/java/work/slhaf/agent/module/modules/memory/selector/MemorySelector.java b/src/main/java/work/slhaf/agent/module/modules/memory/selector/MemorySelector.java index 5c22bbb6..d016928e 100644 --- a/src/main/java/work/slhaf/agent/module/modules/memory/selector/MemorySelector.java +++ b/src/main/java/work/slhaf/agent/module/modules/memory/selector/MemorySelector.java @@ -1,18 +1,19 @@ package work.slhaf.agent.module.modules.memory.selector; +import com.alibaba.fastjson2.JSONObject; import lombok.Data; import lombok.extern.slf4j.Slf4j; import work.slhaf.agent.common.exception_handler.GlobalExceptionHandler; import work.slhaf.agent.common.exception_handler.pojo.GlobalException; -import work.slhaf.agent.core.interaction.InteractionModule; -import work.slhaf.agent.core.interaction.data.InteractionContext; +import work.slhaf.agent.core.interaction.data.context.InteractionContext; +import work.slhaf.agent.core.interaction.module.InteractionModule; import work.slhaf.agent.core.memory.MemoryManager; import work.slhaf.agent.core.memory.exception.UnExistedDateIndexException; import work.slhaf.agent.core.memory.exception.UnExistedTopicException; import work.slhaf.agent.core.memory.pojo.MemoryResult; import work.slhaf.agent.core.memory.pojo.MemorySlice; -import work.slhaf.agent.module.common.AppendPrompt; import work.slhaf.agent.module.common.AppendPromptData; +import work.slhaf.agent.module.common.PreModuleActions; import work.slhaf.agent.module.modules.memory.selector.evaluator.SliceSelectEvaluator; import work.slhaf.agent.module.modules.memory.selector.evaluator.data.EvaluatorInput; import work.slhaf.agent.module.modules.memory.selector.extractor.MemorySelectExtractor; @@ -29,38 +30,10 @@ import java.util.List; @Data @Slf4j -public class MemorySelector implements InteractionModule, AppendPrompt { +public class MemorySelector implements InteractionModule, PreModuleActions { private static volatile MemorySelector memorySelector; -/* public static final String appendPrompt = """ - 新增输入字段示例: - - "memory_slices": [{ //记忆切片,可能为多个 - "chatMessages": [{ - "role": "user"/"assistant", //该信息发送者 - "content": "消息内容" - }], - "date": "2024-03-20", //切片日期 - "summary": "切片总结" - }], - "static_memory": "对于该用户的常识性记忆,如爱好、住处、生日", - "dialog_map": { //近两日的与所有用户的对话缓存 - "2023-01-01T11:30": "用户a[dawgbi-dwa-ccc] 尝试分享生活点滴并营造氛围感", - "2023-01-02T11:30": "用户b[dawgbi-dwa-ccc] 尝试分享生活点滴并营造氛围感" - } - "user_dialog_map": { //与当前用户的近两日对话缓存 - "2023-01-01T11:30": "与用户讨论了...", - "2023-01-02T11:30": "与用户讨论了..." - } - - 无新增输出字段 - - ##注意 - a. 这些字段中可能出现的第一人称描述都是指`Partner`,即你所属的智能体,当前用户正在对话的对象 - b. `dialog_map`和`user_dialog_map`中,值都将以`用户昵称[用户uuid]`开头,你需要正确区分不同用户 - c. 若`text`字段,即用户的真正输入内容未涉及`dialog_map`, `user_dialog_map`等字段中的内容,你需要仅根据用户的输入来确定如何回复.当用户未提及时,这两个字段中的内容时,你不需要主动提起. - d. 做出回应时,你需要考虑上述新增字段与当前的时间差异 - """;*/ + private static final String MODULE_NAME = "[记忆模块]"; private MemoryManager memoryManager; private SliceSelectEvaluator sliceSelectEvaluator; @@ -84,25 +57,26 @@ public class MemorySelector implements InteractionModule, AppendPrompt { } @Override - public void execute(InteractionContext interactionContext) throws IOException, ClassNotFoundException, InterruptedException { + public void execute(InteractionContext interactionContext) throws IOException, ClassNotFoundException { log.debug("[MemorySelector] 记忆回溯流程开始..."); String userId = interactionContext.getUserId(); //获取主题路径 ExtractorResult extractorResult = memorySelectExtractor.execute(interactionContext); if (extractorResult.isRecall() || !extractorResult.getMatches().isEmpty()) { - memoryManager.getActivatedSlices().get(userId).clear(); + if (memoryManager.getActivatedSlices().get(userId) != null) { + memoryManager.getActivatedSlices().get(userId).clear(); + } List evaluatedSlices = selectAndEvaluateMemory(interactionContext, extractorResult); memoryManager.updateActivatedSlices(userId, evaluatedSlices); } - //设置上下文 -// setCoreContext(interactionContext); //设置追加提示词 setAppendedPrompt(interactionContext); setModuleContextRecall(interactionContext); - log.debug("[MemorySelector] 记忆回溯结果: {}", interactionContext); + setActiveModule(interactionContext); + log.debug("[MemorySelector] 记忆回溯完成..."); } - private List selectAndEvaluateMemory(InteractionContext interactionContext, ExtractorResult extractorResult) throws IOException, ClassNotFoundException, InterruptedException { + private List selectAndEvaluateMemory(InteractionContext interactionContext, ExtractorResult extractorResult) throws IOException, ClassNotFoundException { log.debug("[MemorySelector] 触发记忆回溯..."); //查找切片 String userId = interactionContext.getUserId(); @@ -114,20 +88,12 @@ public class MemorySelector implements InteractionModule, AppendPrompt { .memoryResults(memoryResultList) .messages(memoryManager.getChatMessages()) .build(); - log.debug("[MemorySelector] 切片评估输入: {}", evaluatorInput); + log.debug("[MemorySelector] 切片评估输入: {}", JSONObject.toJSONString(evaluatorInput)); List memorySlices = sliceSelectEvaluator.execute(evaluatorInput); - log.debug("[MemorySelector] 切片评估结果: {}", memorySlices); + log.debug("[MemorySelector] 切片评估结果: {}", JSONObject.toJSONString(memorySlices)); return memorySlices; } - /*private void setCoreContext(InteractionContext interactionContext) { - String userId = interactionContext.getUserId(); - interactionContext.getCoreContext().put("memory_slices", memoryManager.getActivatedSlices().get(userId)); -// interactionContext.getCoreContext().put("static_memory", memoryManager.getStaticMemory(userId)); - interactionContext.getCoreContext().put("dialog_map", memoryManager.getDialogMap()); - interactionContext.getCoreContext().put("user_dialog_map", memoryManager.getUserDialogMap(userId)); - }*/ - private void setModuleContextRecall(InteractionContext interactionContext) { String userId = interactionContext.getUserId(); boolean recall; @@ -136,9 +102,9 @@ public class MemorySelector implements InteractionModule, AppendPrompt { } else { recall = !memoryManager.getActivatedSlices().get(userId).isEmpty(); } - interactionContext.getModuleContext().put("recall", recall); + interactionContext.getModuleContext().getExtraContext().put("recall", recall); if (recall) { - interactionContext.getModuleContext().put("recall_count", memoryManager.getActivatedSlices().get(userId).size()); + interactionContext.getModuleContext().getExtraContext().put("recall_count", memoryManager.getActivatedSlices().get(userId).size()); } } @@ -152,7 +118,7 @@ public class MemorySelector implements InteractionModule, AppendPrompt { memoryManager.selectMemory(LocalDate.parse(match.getText())); default -> null; }; - if (memoryResult == null) continue; + if (memoryResult == null || memoryResult.isEmpty()) continue; removeDuplicateSlice(memoryResult); memoryResultList.add(memoryResult); } catch (UnExistedDateIndexException | UnExistedTopicException e) { @@ -190,11 +156,16 @@ public class MemorySelector implements InteractionModule, AppendPrompt { String userId = context.getUserId(); HashMap map = getPromptDataMap(userId); AppendPromptData data = new AppendPromptData(); - data.setComment("[记忆模块]"); + data.setModuleName(MODULE_NAME); data.setAppendedPrompt(map); context.setAppendedPrompt(data); } + @Override + public void setActiveModule(InteractionContext context) { + context.getCoreContext().addActiveModule(MODULE_NAME); + } + private HashMap getPromptDataMap(String userId) { HashMap map = new HashMap<>(); String dialogMapStr = memoryManager.getDialogMapStr(); @@ -203,12 +174,12 @@ public class MemorySelector implements InteractionModule, AppendPrompt { } String userDialogMapStr = memoryManager.getUserDialogMapStr(userId); - if (!userDialogMapStr.isEmpty()) { - map.put("[用户记忆缓存] <与最新一条消息的发送者的近两天对话记忆印象, 可能与[记忆缓存]稍有重复>", "与当前用户的近两日对话缓存"); + if (userDialogMapStr != null && !userDialogMapStr.isEmpty()) { + map.put("[用户记忆缓存] <与最新一条消息的发送者的近两天对话记忆印象, 可能与[记忆缓存]稍有重复>", userDialogMapStr); } String sliceStr = memoryManager.getActivatedSlicesStr(userId); - if (!sliceStr.isEmpty()){ + if (sliceStr != null && !sliceStr.isEmpty()) { map.put("[记忆切片] <你与最新一条消息的发送者的相关回忆, 不会与[记忆缓存]重复, 如果有重复你也可以指出来()>", sliceStr); } return map; diff --git a/src/main/java/work/slhaf/agent/module/modules/memory/selector/evaluator/SliceSelectEvaluator.java b/src/main/java/work/slhaf/agent/module/modules/memory/selector/evaluator/SliceSelectEvaluator.java index 665fc605..aa085320 100644 --- a/src/main/java/work/slhaf/agent/module/modules/memory/selector/evaluator/SliceSelectEvaluator.java +++ b/src/main/java/work/slhaf/agent/module/modules/memory/selector/evaluator/SliceSelectEvaluator.java @@ -6,7 +6,7 @@ import com.alibaba.fastjson2.JSONObject; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; -import work.slhaf.agent.core.interaction.InteractionThreadPoolExecutor; +import work.slhaf.agent.common.thread.InteractionThreadPoolExecutor; import work.slhaf.agent.core.memory.MemoryManager; import work.slhaf.agent.core.memory.pojo.MemoryResult; import work.slhaf.agent.core.memory.pojo.MemorySlice; @@ -55,7 +55,7 @@ public class SliceSelectEvaluator extends Model { return sliceSelectEvaluator; } - public List execute(EvaluatorInput evaluatorInput) throws InterruptedException { + public List execute(EvaluatorInput evaluatorInput) { log.debug("[SliceSelectEvaluator] 切片评估模块开始..."); List memoryResultList = evaluatorInput.getMemoryResults(); List> tasks = new ArrayList<>(); @@ -78,9 +78,9 @@ public class SliceSelectEvaluator extends Model { .memory_slices(sliceSummaryList) .history(evaluatorInput.getMessages()) .build(); - log.debug("[SliceSelectEvaluator] 评估[{}]输入: {}", thisCount, batchInput); + log.debug("[SliceSelectEvaluator] 评估[{}]输入: {}", thisCount, JSONObject.toJSONString(batchInput)); EvaluatorResult evaluatorResult = JSONObject.parseObject(extractJson(singleChat(JSONUtil.toJsonStr(batchInput)).getMessage()), EvaluatorResult.class); - log.debug("[SliceSelectEvaluator] 评估[{}]结果: {}", thisCount, evaluatorResult); + log.debug("[SliceSelectEvaluator] 评估[{}]结果: {}", thisCount, JSONObject.toJSONString(evaluatorResult)); for (Long result : evaluatorResult.getResults()) { SliceSummary sliceSummary = map.get(result); EvaluatedSlice evaluatedSlice = EvaluatedSlice.builder() @@ -99,25 +99,10 @@ public class SliceSelectEvaluator extends Model { executor.invokeAll(tasks, 30, TimeUnit.SECONDS); log.debug("[SliceSelectEvaluator] 评估模块结束, 输出队列: {}", queue); - return queue.stream().toList(); + List temp = queue.stream().toList(); + return new ArrayList<>(temp); } -/* private void setEvaluatedSliceMessages(EvaluatedSlice evaluatedSlice, MemoryResult memoryResult, Long id) { - //补充消息列表 - for (MemorySliceResult memorySliceResult : memoryResult.getMemorySliceResult()) { - if (memorySliceResult.getMemorySlice().getTimestamp().equals(id)) { - evaluatedSlice.setChatMessages(memorySliceResult.getMemorySlice().getChatMessages()); - return; - } - } - for (MemorySlice memorySlice : memoryResult.getRelatedMemorySliceResult()) { - if (memorySlice.getTimestamp().equals(id)) { - evaluatedSlice.setChatMessages(memorySlice.getChatMessages()); - return; - } - } - }*/ - private void setSliceSummaryList(MemoryResult memoryResult, List sliceSummaryList, Map map) { for (MemorySliceResult memorySliceResult : memoryResult.getMemorySliceResult()) { diff --git a/src/main/java/work/slhaf/agent/module/modules/memory/selector/extractor/MemorySelectExtractor.java b/src/main/java/work/slhaf/agent/module/modules/memory/selector/extractor/MemorySelectExtractor.java index 8396b1e4..b77d8be9 100644 --- a/src/main/java/work/slhaf/agent/module/modules/memory/selector/extractor/MemorySelectExtractor.java +++ b/src/main/java/work/slhaf/agent/module/modules/memory/selector/extractor/MemorySelectExtractor.java @@ -9,7 +9,7 @@ import work.slhaf.agent.common.chat.pojo.Message; import work.slhaf.agent.common.chat.pojo.MetaMessage; import work.slhaf.agent.common.exception_handler.GlobalExceptionHandler; import work.slhaf.agent.common.exception_handler.pojo.GlobalException; -import work.slhaf.agent.core.interaction.data.InteractionContext; +import work.slhaf.agent.core.interaction.data.context.InteractionContext; import work.slhaf.agent.core.memory.MemoryManager; import work.slhaf.agent.core.session.SessionManager; import work.slhaf.agent.module.common.Model; @@ -75,7 +75,7 @@ public class MemorySelectExtractor extends Model { .topic_tree(memoryManager.getTopicTree()) .activatedMemorySlices(activatedMemorySlices) .build(); - log.debug("[MemorySelectExtractor] 主题提取输入: {}", extractorInput); + log.debug("[MemorySelectExtractor] 主题提取输入: {}", JSONObject.toJSONString(extractorInput)); String responseStr = extractJson(singleChat(JSONUtil.toJsonPrettyStr(extractorInput)).getMessage()); extractorResult = JSONObject.parseObject(responseStr, ExtractorResult.class); log.debug("[MemorySelectExtractor] 主题提取结果: {}", extractorResult); diff --git a/src/main/java/work/slhaf/agent/module/modules/memory/updater/MemoryUpdater.java b/src/main/java/work/slhaf/agent/module/modules/memory/updater/MemoryUpdater.java index 199aa97e..6885138a 100644 --- a/src/main/java/work/slhaf/agent/module/modules/memory/updater/MemoryUpdater.java +++ b/src/main/java/work/slhaf/agent/module/modules/memory/updater/MemoryUpdater.java @@ -5,14 +5,13 @@ import lombok.Data; import lombok.extern.slf4j.Slf4j; import work.slhaf.agent.common.chat.constant.ChatConstant; import work.slhaf.agent.common.chat.pojo.Message; -import work.slhaf.agent.core.interaction.InteractionModule; -import work.slhaf.agent.core.interaction.InteractionThreadPoolExecutor; -import work.slhaf.agent.core.interaction.data.InteractionContext; +import work.slhaf.agent.common.thread.InteractionThreadPoolExecutor; +import work.slhaf.agent.core.interaction.data.context.InteractionContext; +import work.slhaf.agent.core.interaction.module.InteractionModule; import work.slhaf.agent.core.memory.MemoryManager; import work.slhaf.agent.core.memory.pojo.MemorySlice; import work.slhaf.agent.core.session.SessionManager; import work.slhaf.agent.module.modules.memory.selector.extractor.MemorySelectExtractor; -import work.slhaf.agent.module.modules.memory.updater.exception.UnExpectedMessageCountException; import work.slhaf.agent.module.modules.memory.updater.summarizer.MemorySummarizer; import work.slhaf.agent.module.modules.memory.updater.summarizer.data.SummarizeInput; import work.slhaf.agent.module.modules.memory.updater.summarizer.data.SummarizeResult; @@ -22,6 +21,7 @@ import java.time.LocalDateTime; import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -33,18 +33,21 @@ public class MemoryUpdater implements InteractionModule { private static final String USERID_REGEX = "\\[.*\\(([^)]+)\\)\\]"; private static final long SCHEDULED_UPDATE_INTERVAL = 10 * 1000; - private static final long UPDATE_TRIGGER_INTERVAL = 30 * 60 * 1000; + private static final long UPDATE_TRIGGER_INTERVAL = 60 * 60 * 1000; // private static final int TRIGGER_TOKEN_LIMIT = 5 * 1000; private static final int TOKEN_PER_RECALL = 230; - private static final int TRIGGER_ROLL_LIMIT = 32; + private static final int TRIGGER_ROLL_LIMIT = 24; private MemoryManager memoryManager; private InteractionThreadPoolExecutor executor; private MemorySelectExtractor memorySelectExtractor; private MemorySummarizer memorySummarizer; private SessionManager sessionManager; -// private StaticMemoryExtractor staticMemoryExtractor; - private int moduleMessageCount = 0; + /** + * 用于临时存储完整对话记录,在MemoryManager的分离后 + */ + private List tempMessage; + private final ReentrantLock messageUpdateLock = new ReentrantLock(); private MemoryUpdater() { } @@ -58,7 +61,6 @@ public class MemoryUpdater implements InteractionModule { memoryUpdater.setMemorySelectExtractor(MemorySelectExtractor.getInstance()); memoryUpdater.setMemorySummarizer(MemorySummarizer.getInstance()); memoryUpdater.setSessionManager(SessionManager.getInstance()); -// memoryUpdater.setStaticMemoryExtractor(StaticMemoryExtractor.getInstance()); memoryUpdater.setExecutor(InteractionThreadPoolExecutor.getInstance()); memoryUpdater.setScheduledUpdater(); } @@ -77,13 +79,14 @@ public class MemoryUpdater implements InteractionModule { int chatCount = memoryManager.getChatMessages().size(); if (lastUpdatedTime != 0 && currentTime - lastUpdatedTime > UPDATE_TRIGGER_INTERVAL && chatCount > 1) { updateMemory(); + memoryManager.getChatMessages().clear(); //重置MemoryId sessionManager.refreshMemoryId(); log.info("[MemoryUpdater] 记忆更新: 自动触发"); } Thread.sleep(SCHEDULED_UPDATE_INTERVAL); } catch (Exception e) { - log.error("[MemoryUpdater] 记忆自动更新线程出错: {}", e.getLocalizedMessage()); + log.error("[MemoryUpdater] 记忆自动更新线程出错: ", e); } } log.info("[MemoryUpdater] 记忆自动更新线程结束"); @@ -98,7 +101,7 @@ public class MemoryUpdater implements InteractionModule { } executor.execute(() -> { //如果token 大于阈值,则更新记忆 - JSONObject moduleContext = interactionContext.getModuleContext(); + JSONObject moduleContext = interactionContext.getModuleContext().getExtraContext(); boolean recall = moduleContext.getBoolean("recall"); if (recall) { log.debug("[MemoryUpdater] 存在回忆"); @@ -106,10 +109,12 @@ public class MemoryUpdater implements InteractionModule { log.debug("[MemoryUpdater] 记忆切片数量 [{}]", recallCount); } int messageCount = memoryManager.getChatMessages().size(); - if (messageCount > TRIGGER_ROLL_LIMIT) { + if (messageCount >= TRIGGER_ROLL_LIMIT) { try { log.debug("[MemoryUpdater] 记忆更新: 已达{}轮", TRIGGER_ROLL_LIMIT); updateMemory(); + //清空chatMessages + clearChatMessages(); } catch (Exception e) { log.error("[MemoryUpdater] 记忆更新线程出错: ", e); } @@ -120,13 +125,12 @@ public class MemoryUpdater implements InteractionModule { private void updateMemory() { log.debug("[MemoryUpdater] 记忆更新流程开始..."); + tempMessage = new ArrayList<>(memoryManager.getChatMessages()); HashMap singleMemorySummary = new HashMap<>(); - //更新单聊记忆以及该场景中对应的确定性记忆,同时从chatMessages中去掉单聊记忆 + //更新单聊记忆,同时从chatMessages中去掉单聊记忆 updateSingleChatSlices(singleMemorySummary); //更新多人场景下的记忆及相关的确定性记忆 updateMultiChatSlices(singleMemorySummary); - //清空chatMessages - clearChatMessages(); } private void updateMultiChatSlices(HashMap singleMemorySummary) { @@ -134,46 +138,58 @@ public class MemoryUpdater implements InteractionModule { //对剩下的多人聊天记录进行进行摘要 executor.execute(() -> { log.debug("[MemoryUpdater] 多人聊天记忆更新流程开始..."); - try { - List chatMessages = new ArrayList<>(memoryManager.getChatMessages()); - chatMessages.removeFirst(); - if (!chatMessages.isEmpty()) { - log.debug("[MemoryUpdater] 存在多人聊天记录, 流程正常进行..."); - //以第一条user对应的id为发起用户 - Pattern pattern = Pattern.compile(USERID_REGEX); - Matcher matcher = pattern.matcher(chatMessages.getFirst().getContent()); - if (!matcher.find()) { - throw new RuntimeException("未匹配到 userId!"); - } - String userId = matcher.group(1); - SummarizeInput summarizeInput = new SummarizeInput(chatMessages, memoryManager.getTopicTree()); - log.debug("[MemoryUpdater] 多人聊天记忆更新-总结流程-输入: {}", summarizeInput); - SummarizeResult summarizeResult = memorySummarizer.execute(summarizeInput); - log.debug("[MemoryUpdater] 多人聊天记忆更新-总结流程-输出: {}", summarizeResult); - MemorySlice memorySlice = getMemorySlice(userId, summarizeResult, chatMessages); - //设置involvedUserId - setInvolvedUserId(userId, memorySlice, chatMessages); - memoryManager.insertSlice(memorySlice, summarizeResult.getTopicPath()); - - memoryManager.updateDialogMap(LocalDateTime.now(), summarizeResult.getSummary()); - - } else { - log.debug("[MemoryUpdater] 不存在多人聊天记录, 将以单聊总结为对话缓存的主要输入: {}", singleMemorySummary); - memoryManager.updateDialogMap(LocalDateTime.now(), memorySummarizer.executeTotalSummary(singleMemorySummary)); + List chatMessages; + messageUpdateLock.lock(); + chatMessages = new ArrayList<>(memoryManager.getChatMessages()); + messageUpdateLock.unlock(); + cleanMessage(chatMessages); + if (!chatMessages.isEmpty()) { + log.debug("[MemoryUpdater] 存在多人聊天记录, 流程正常进行..."); + //以第一条user对应的id为发起用户 + Pattern pattern = Pattern.compile(USERID_REGEX); + Matcher matcher = pattern.matcher(chatMessages.getFirst().getContent()); + if (!matcher.find()) { + throw new RuntimeException("未匹配到 userId!"); } - log.debug("[MemoryUpdater] 对话缓存更新完毕"); - log.debug("[MemoryUpdater] 多人聊天记忆更新流程结束..."); - } catch (IOException | ClassNotFoundException | InterruptedException e) { - log.error("[MemoryUpdater] 多人场景记忆更新失败: ", e); + String userId = matcher.group(1); + SummarizeInput summarizeInput = new SummarizeInput(chatMessages, memoryManager.getTopicTree()); + log.debug("[MemoryUpdater] 多人聊天记忆更新-总结流程-输入: {}", summarizeInput); + SummarizeResult summarizeResult = memorySummarizer.execute(summarizeInput); + log.debug("[MemoryUpdater] 多人聊天记忆更新-总结流程-输出: {}", summarizeResult); + MemorySlice memorySlice = getMemorySlice(userId, summarizeResult, chatMessages); + //设置involvedUserId + setInvolvedUserId(userId, memorySlice, chatMessages); + memoryManager.insertSlice(memorySlice, summarizeResult.getTopicPath()); + + memoryManager.updateDialogMap(LocalDateTime.now(), summarizeResult.getSummary()); + + } else { + log.debug("[MemoryUpdater] 不存在多人聊天记录, 将以单聊总结为对话缓存的主要输入: {}", singleMemorySummary); + memoryManager.updateDialogMap(LocalDateTime.now(), memorySummarizer.executeTotalSummary(singleMemorySummary)); } + log.debug("[MemoryUpdater] 对话缓存更新完毕"); + log.debug("[MemoryUpdater] 多人聊天记忆更新流程结束..."); }); } - private void clearChatMessages() { - if (moduleMessageCount < 1) { - throw new UnExpectedMessageCountException("ModuleMessageCount 异常: " + moduleMessageCount); + private void cleanMessage(List chatMessages) { + //清理时间标识 + for (Message message : chatMessages) { + if (message.getRole().equals(ChatConstant.Character.ASSISTANT)) { + continue; + } + String time = Arrays.stream(message.getContent().split("\\*\\*")).toList().getLast(); + message.getContent().replace("\r\n**" + time, ""); } + } + + private void clearChatMessages() { + //不全部清空,保留前1/3的输入防止上下文割裂 + messageUpdateLock.lock(); + List temp = new ArrayList<>(tempMessage.subList(0, TRIGGER_ROLL_LIMIT / 3)); memoryManager.getChatMessages().clear(); + memoryManager.getChatMessages().addAll(temp); + messageUpdateLock.unlock(); } private void setInvolvedUserId(String startUserId, MemorySlice memorySlice, List chatMessages) { @@ -213,9 +229,9 @@ public class MemoryUpdater implements InteractionModule { try { //单聊记忆更新 SummarizeInput summarizeInput = new SummarizeInput(messages, memoryManager.getTopicTree()); - log.debug("[MemoryUpdater] 单聊记忆[{}]更新-总结流程-输入: {}", thisCount, summarizeInput); + log.debug("[MemoryUpdater] 单聊记忆[{}]更新-总结流程-输入: {}", thisCount, JSONObject.toJSONString(summarizeInput)); SummarizeResult summarizeResult = memorySummarizer.execute(summarizeInput); - log.debug("[MemoryUpdater] 单聊记忆[{}]更新-总结流程-输出: {}", thisCount, summarizeResult); + log.debug("[MemoryUpdater] 单聊记忆[{}]更新-总结流程-输出: {}", thisCount, JSONObject.toJSONString(summarizeResult)); MemorySlice memorySlice = getMemorySlice(id, summarizeResult, messages); //插入时userDialogMap已经进行更新 memoryManager.insertSlice(memorySlice, summarizeResult.getTopicPath()); @@ -231,19 +247,6 @@ public class MemoryUpdater implements InteractionModule { return null; }); - /*tasks.add(() -> { - log.debug("[MemoryUpdater] 静态记忆更新开始..."); - StaticMemoryExtractInput input = StaticMemoryExtractInput.builder() - .userId(id) - .messages(messages) - .existedStaticMemory(memoryManager.getStaticMemory(id)) - .build(); - log.debug("[MemoryUpdater] 静态记忆更新输入: {}", input); - Map staticMemoryResult = staticMemoryExtractor.execute(input); - log.debug("[MemoryUpdater] 静态记忆更新结果: {}", staticMemoryResult); - memoryManager.insertStaticMemory(id, staticMemoryResult); - return null; - });*/ } executor.invokeAll(tasks); log.debug("[MemoryUpdater] 单聊记忆更新结束..."); diff --git a/src/main/java/work/slhaf/agent/module/modules/memory/updater/summarizer/MemorySummarizer.java b/src/main/java/work/slhaf/agent/module/modules/memory/updater/summarizer/MemorySummarizer.java index 9e416cd7..f0f413e4 100644 --- a/src/main/java/work/slhaf/agent/module/modules/memory/updater/summarizer/MemorySummarizer.java +++ b/src/main/java/work/slhaf/agent/module/modules/memory/updater/summarizer/MemorySummarizer.java @@ -2,11 +2,10 @@ package work.slhaf.agent.module.modules.memory.updater.summarizer; import lombok.Data; import lombok.extern.slf4j.Slf4j; -import work.slhaf.agent.core.interaction.InteractionThreadPoolExecutor; +import work.slhaf.agent.common.thread.InteractionThreadPoolExecutor; import work.slhaf.agent.module.modules.memory.updater.summarizer.data.SummarizeInput; import work.slhaf.agent.module.modules.memory.updater.summarizer.data.SummarizeResult; -import java.io.IOException; import java.util.HashMap; @Data @@ -21,7 +20,7 @@ public class MemorySummarizer { private MultiSummarizer multiSummarizer; private TotalSummarizer totalSummarizer; - public static MemorySummarizer getInstance() throws IOException, ClassNotFoundException { + public static MemorySummarizer getInstance() { if (memorySummarizer == null) { synchronized (MemorySummarizer.class) { if (memorySummarizer == null) { @@ -36,11 +35,11 @@ public class MemorySummarizer { return memorySummarizer; } - public SummarizeResult execute(SummarizeInput input) throws InterruptedException { + public SummarizeResult execute(SummarizeInput input) { //进行长文本批量摘要 singleSummarizer.execute(input.getChatMessages()); //进行整体摘要并返回结果 - return memorySummarizer.execute(input); + return multiSummarizer.execute(input); } public String executeTotalSummary(HashMap singleMemorySummary) { diff --git a/src/main/java/work/slhaf/agent/module/modules/memory/updater/summarizer/MultiSummarizer.java b/src/main/java/work/slhaf/agent/module/modules/memory/updater/summarizer/MultiSummarizer.java index b4853804..ef252be7 100644 --- a/src/main/java/work/slhaf/agent/module/modules/memory/updater/summarizer/MultiSummarizer.java +++ b/src/main/java/work/slhaf/agent/module/modules/memory/updater/summarizer/MultiSummarizer.java @@ -37,7 +37,7 @@ public class MultiSummarizer extends Model { public SummarizeResult execute(SummarizeInput input) { log.debug("[MemorySummarizer] 整体摘要开始..."); ChatResponse response = this.singleChat(JSONUtil.toJsonPrettyStr(input)); - log.debug("[MemorySummarizer] 整体摘要结果: {}", response); + log.debug("[MemorySummarizer] 整体摘要结果: {}", JSONObject.toJSONString(response)); return JSONObject.parseObject(extractJson(response.getMessage()), SummarizeResult.class); } } diff --git a/src/main/java/work/slhaf/agent/module/modules/memory/updater/summarizer/SingleSummarizer.java b/src/main/java/work/slhaf/agent/module/modules/memory/updater/summarizer/SingleSummarizer.java index 4d1b1fa8..5900b3a9 100644 --- a/src/main/java/work/slhaf/agent/module/modules/memory/updater/summarizer/SingleSummarizer.java +++ b/src/main/java/work/slhaf/agent/module/modules/memory/updater/summarizer/SingleSummarizer.java @@ -7,7 +7,7 @@ import lombok.extern.slf4j.Slf4j; import work.slhaf.agent.common.chat.constant.ChatConstant; import work.slhaf.agent.common.chat.pojo.ChatResponse; import work.slhaf.agent.common.chat.pojo.Message; -import work.slhaf.agent.core.interaction.InteractionThreadPoolExecutor; +import work.slhaf.agent.common.thread.InteractionThreadPoolExecutor; import work.slhaf.agent.module.common.Model; import work.slhaf.agent.module.common.ModelConstant; diff --git a/src/main/java/work/slhaf/agent/module/modules/perceive/static_extractor/StaticPerceiveExtractor.java b/src/main/java/work/slhaf/agent/module/modules/perceive/static_extractor/StaticPerceiveExtractor.java index 9b581266..cc0c97e9 100644 --- a/src/main/java/work/slhaf/agent/module/modules/perceive/static_extractor/StaticPerceiveExtractor.java +++ b/src/main/java/work/slhaf/agent/module/modules/perceive/static_extractor/StaticPerceiveExtractor.java @@ -9,7 +9,6 @@ import work.slhaf.agent.module.common.Model; import work.slhaf.agent.module.common.ModelConstant; import work.slhaf.agent.module.modules.perceive.static_extractor.data.StaticExtractInput; -import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -22,7 +21,7 @@ public class StaticPerceiveExtractor extends Model { public static final String MODEL_KEY = "static_extractor"; - public static StaticPerceiveExtractor getInstance() throws IOException, ClassNotFoundException { + public static StaticPerceiveExtractor getInstance() { if (staticPerceiveExtractor == null) { synchronized (StaticPerceiveExtractor.class) { if (staticPerceiveExtractor == null) { diff --git a/src/main/java/work/slhaf/agent/module/modules/preprocess/PreprocessExecutor.java b/src/main/java/work/slhaf/agent/module/modules/preprocess/PreprocessExecutor.java index bdbe5315..98235287 100644 --- a/src/main/java/work/slhaf/agent/module/modules/preprocess/PreprocessExecutor.java +++ b/src/main/java/work/slhaf/agent/module/modules/preprocess/PreprocessExecutor.java @@ -1,10 +1,9 @@ package work.slhaf.agent.module.modules.preprocess; -import com.alibaba.fastjson2.JSONObject; import lombok.Data; import lombok.extern.slf4j.Slf4j; -import work.slhaf.agent.core.interaction.data.InteractionContext; import work.slhaf.agent.core.interaction.data.InteractionInputData; +import work.slhaf.agent.core.interaction.data.context.InteractionContext; import work.slhaf.agent.core.memory.MemoryManager; import work.slhaf.agent.core.session.SessionManager; import work.slhaf.agent.module.common.AppendPromptData; @@ -60,19 +59,14 @@ public class PreprocessExecutor { context.setUserNickname(inputData.getUserNickName()); context.setUserInfo(inputData.getUserInfo()); context.setDateTime(inputData.getLocalDateTime()); + context.setSingle(inputData.isSingle()); - context.setFinished(false); String user = "[" + inputData.getUserNickName() + "(" + userId + ")]"; String input = user + " " + inputData.getContent(); context.setInput(input); - context.setCoreContext(new JSONObject()); - setCoreContext(inputData, context, input, userId); setAppendedPrompt(context); - context.setModuleContext(new JSONObject()); - - context.setSingle(inputData.isSingle()); - context.setFinished(false); + setCoreContext(inputData, context, input, userId); log.debug("[PreprocessExecutor] 预处理结果: {}", context); return context; @@ -81,20 +75,21 @@ public class PreprocessExecutor { private void setAppendedPrompt(InteractionContext context) { HashMap map = new HashMap<>(); map.put("text", "用户输入内容"); - map.put("datetime", "当前时间"); + map.put("datetime", "本次用户输入对应的当前时间"); map.put("user_nick", "用户昵称"); map.put("user_id", "用户id, 与user_nick区分, 这是用户的唯一标识"); + map.put("active_modules","已激活的模块, 为false时为激活但未活跃; 为true时为激活且活跃"); + map.put("其他", "历史对话中将在用户消息的最后一行标注时间"); AppendPromptData data = new AppendPromptData(); - data.setComment("[system] 基础字段"); + data.setModuleName("[基础模块]"); data.setAppendedPrompt(map); context.setAppendedPrompt(data); } private void setCoreContext(InteractionInputData inputData, InteractionContext context, String input, String userId) { - context.getCoreContext().put("text", input); - context.getCoreContext().put("datetime", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); -// context.getCoreContext().put("character", memoryManager.getCharacter()); - context.getCoreContext().put("user_nick", inputData.getUserNickName()); - context.getCoreContext().put("user_id", userId); + context.getCoreContext().setText(input); + context.getCoreContext().setDateTime(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); + context.getCoreContext().setUserNick(inputData.getUserNickName()); + context.getCoreContext().setUserId(userId); } } diff --git a/src/main/java/work/slhaf/agent/module/modules/task/TaskEvaluator.java b/src/main/java/work/slhaf/agent/module/modules/task/TaskEvaluator.java index 3aa748d7..32dba713 100644 --- a/src/main/java/work/slhaf/agent/module/modules/task/TaskEvaluator.java +++ b/src/main/java/work/slhaf/agent/module/modules/task/TaskEvaluator.java @@ -5,8 +5,6 @@ import lombok.EqualsAndHashCode; import work.slhaf.agent.module.common.Model; import work.slhaf.agent.module.common.ModelConstant; -import java.io.IOException; - @EqualsAndHashCode(callSuper = true) @Data public class TaskEvaluator extends Model { @@ -15,7 +13,7 @@ public class TaskEvaluator extends Model { private TaskEvaluator (){} - public static TaskEvaluator getInstance() throws IOException, ClassNotFoundException { + public static TaskEvaluator getInstance() { if (taskEvaluator == null) { taskEvaluator = new TaskEvaluator(); setModel(taskEvaluator,MODEL_KEY, ModelConstant.Prompt.SCHEDULE,true); diff --git a/src/main/java/work/slhaf/agent/module/modules/task/TaskExecutor.java b/src/main/java/work/slhaf/agent/module/modules/task/TaskExecutor.java index 42614b39..dd234017 100644 --- a/src/main/java/work/slhaf/agent/module/modules/task/TaskExecutor.java +++ b/src/main/java/work/slhaf/agent/module/modules/task/TaskExecutor.java @@ -1,7 +1,7 @@ package work.slhaf.agent.module.modules.task; import lombok.Data; -import work.slhaf.agent.core.interaction.InteractionThreadPoolExecutor; +import work.slhaf.agent.common.thread.InteractionThreadPoolExecutor; @Data public class TaskExecutor { diff --git a/src/main/java/work/slhaf/agent/module/modules/task/TaskScheduler.java b/src/main/java/work/slhaf/agent/module/modules/task/TaskScheduler.java index 849c5e17..0e6f4960 100644 --- a/src/main/java/work/slhaf/agent/module/modules/task/TaskScheduler.java +++ b/src/main/java/work/slhaf/agent/module/modules/task/TaskScheduler.java @@ -2,10 +2,8 @@ package work.slhaf.agent.module.modules.task; import lombok.Data; import lombok.extern.slf4j.Slf4j; -import work.slhaf.agent.core.interaction.InteractionModule; -import work.slhaf.agent.core.interaction.data.InteractionContext; - -import java.io.IOException; +import work.slhaf.agent.core.interaction.data.context.InteractionContext; +import work.slhaf.agent.core.interaction.module.InteractionModule; @Data @Slf4j @@ -14,7 +12,7 @@ public class TaskScheduler implements InteractionModule { private TaskScheduler(){} - public static TaskScheduler getInstance() throws IOException, ClassNotFoundException { + public static TaskScheduler getInstance() { if (taskScheduler == null) { taskScheduler = new TaskScheduler(); log.info("TaskScheduler注册完毕..."); diff --git a/src/main/java/work/slhaf/agent/shared/memory/EvaluatedSlice.java b/src/main/java/work/slhaf/agent/shared/memory/EvaluatedSlice.java index de92d9c3..45b4e07a 100644 --- a/src/main/java/work/slhaf/agent/shared/memory/EvaluatedSlice.java +++ b/src/main/java/work/slhaf/agent/shared/memory/EvaluatedSlice.java @@ -3,7 +3,7 @@ package work.slhaf.agent.shared.memory; import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; -import work.slhaf.agent.common.pojo.PersistableObject; +import work.slhaf.agent.common.serialize.PersistableObject; import java.io.Serial; import java.time.LocalDate; diff --git a/src/main/resources/prompt/module/memory/total_summarizer.json b/src/main/resources/prompt/module/memory/total_summarizer.json index b12e9589..0a47796e 100644 --- a/src/main/resources/prompt/module/memory/total_summarizer.json +++ b/src/main/resources/prompt/module/memory/total_summarizer.json @@ -33,6 +33,6 @@ }, { "role": "user", - "content": "谢谢。接下来的这些输入将来自真正的‘Partner’,务必按照上面的要求回应,但请铭记:以‘你’的感受或者用户的意图出发——因为‘你’也是Partner." + "content": "谢谢。接下来这些输入将是真正的输入,务必按照上面的要求回应,但请铭记:以‘你’的感受或者用户的意图出发——因为‘你’也是Partner." } ] \ No newline at end of file