diff --git a/.gitignore b/.gitignore index 8c21e18a..a33458b2 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,4 @@ build/ /CLAUDE.md /config/ /data/ +/generated-classes/ diff --git a/.idea/misc.xml b/.idea/misc.xml index d7b37c98..0281dc35 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,7 +1,7 @@ - + @@ -11,10 +11,11 @@ - - - - + + + + + diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/Agent.java b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/Agent.java index ad06328d..4b5ec3ad 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/Agent.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/Agent.java @@ -1,5 +1,6 @@ package work.slhaf.partner.api.agent; +import lombok.extern.slf4j.Slf4j; import work.slhaf.partner.api.agent.factory.AgentRegisterFactory; import work.slhaf.partner.api.agent.runtime.config.AgentConfigManager; import work.slhaf.partner.api.agent.runtime.exception.AgentExceptionCallback; @@ -9,6 +10,7 @@ import work.slhaf.partner.api.agent.runtime.interaction.AgentGateway; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -16,6 +18,7 @@ import java.util.concurrent.Executors; *

Agent 启动入口

* 详细启动流程请参阅{@link AgentRegisterFactory} */ +@Slf4j public final class Agent { public static AgentConfigManagerStep newAgent(Class clazz) { @@ -38,7 +41,7 @@ public final class Agent { AgentStep addAfterLaunchRunners(Runnable... runners); - AgentStep setAgentExceptionCallback(Class agentExceptionCallback); + AgentStep setAgentExceptionCallback(Class agentExceptionCallback); AgentStep addScanPackage(String packageName); @@ -59,6 +62,8 @@ public final class Agent { private Class gatewayClass; private Class agentExceptionCallbackClass; + private final CountDownLatch latch = new CountDownLatch(1); + private AgentApp(Class clazz) { this.applicationClass = clazz; } @@ -115,9 +120,15 @@ public final class Agent { private void afterLaunch() { try { this.gateway = gatewayClass.getDeclaredConstructor().newInstance(); - executorService.execute(() -> gateway.launch()); + executorService.execute(() -> { + gateway.launch(); + latch.countDown(); + log.info("Gateway 启动完毕: {}", gatewayClass.getSimpleName()); + }); + latch.await(); launchRunners(afterLaunchRunners); - }catch (Exception e){ + log.info("后置任务启动完毕"); + } catch (Exception e) { throw new AgentLaunchFailedException("Agent 后置任务启动失败", e); } } @@ -125,8 +136,11 @@ public final class Agent { private void beforeLaunch() { try { AgentConfigManager.setINSTANCE(agentConfigManagerClass.getDeclaredConstructor().newInstance()); + log.info("配置管理器设置完毕: {}",agentConfigManagerClass.getSimpleName()); GlobalExceptionHandler.setExceptionCallback(agentExceptionCallbackClass.getDeclaredConstructor().newInstance()); + log.info("异常处理回调设置完毕: {}",agentExceptionCallbackClass.getSimpleName()); launchRunners(beforeLaunchRunners); + log.info("前置任务启动完毕"); } catch (Exception e) { throw new AgentLaunchFailedException("Agent 前置任务启动失败", e); } diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/capability/CapabilityCheckFactory.java b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/capability/CapabilityCheckFactory.java index 94c15c0d..91d3ec74 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/capability/CapabilityCheckFactory.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/capability/CapabilityCheckFactory.java @@ -1,12 +1,10 @@ package work.slhaf.partner.api.agent.factory.capability; +import cn.hutool.core.util.ClassUtil; import org.reflections.Reflections; import work.slhaf.partner.api.agent.factory.AgentBaseFactory; import work.slhaf.partner.api.agent.factory.capability.annotation.*; -import work.slhaf.partner.api.agent.factory.capability.exception.DuplicateCapabilityException; -import work.slhaf.partner.api.agent.factory.capability.exception.UnMatchedCapabilityException; -import work.slhaf.partner.api.agent.factory.capability.exception.UnMatchedCapabilityMethodException; -import work.slhaf.partner.api.agent.factory.capability.exception.UnMatchedCoordinatedMethodException; +import work.slhaf.partner.api.agent.factory.capability.exception.*; import work.slhaf.partner.api.agent.factory.context.AgentRegisterContext; import work.slhaf.partner.api.agent.factory.context.CapabilityFactoryContext; import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule; @@ -67,14 +65,29 @@ public class CapabilityCheckFactory extends AgentBaseFactory { @Override protected void run() { - //TODO 对于CoordinateManager的所注类进行唯一性检验以及检测是否留有公开的无参构造方法 loadCoresAndCapabilities(); checkCountAndCapabilities(); checkCapabilityMethods(); checkCoordinatedMethods(); + checkCoordinatedManager(); checkInjectCapability(); } + private void checkCoordinatedManager() { + reflections.getTypesAnnotatedWith(CoordinateManager.class) + .stream() + .filter(ClassUtil::isNormalClass) + .forEach(managerClass -> { + try { + if (!managerClass.getDeclaredConstructor().canAccess(null)) { + throw new CapabilityCheckFailedException("CoordinateManager 所注类的无参构造方法未公开!"); + } + } catch (NoSuchMethodException e) { + throw new CapabilityCheckFailedException("CoordinateManager 所注类缺少无参构造方法!"); + } + }); + } + private void loadCoresAndCapabilities() { cores.addAll(reflections.getTypesAnnotatedWith(CapabilityCore.class)); capabilities.addAll(reflections.getTypesAnnotatedWith(Capability.class)); @@ -86,8 +99,8 @@ public class CapabilityCheckFactory extends AgentBaseFactory { private void checkInjectCapability() { reflections.getFieldsAnnotatedWith(InjectCapability.class).forEach(field -> { Class declaringClass = field.getDeclaringClass(); - if (!isAssignableFromAnnotation(declaringClass, CapabilityHolder.class)){ - throw new UnMatchedCapabilityException("InjectCapability 注解只能用于 CapabilityHolder 注解所在类,检查该类是否使用了@CapabilityHolder注解或者受其标注的注解或父类: "+declaringClass); + if (!isAssignableFromAnnotation(declaringClass, CapabilityHolder.class)) { + throw new UnMatchedCapabilityException("InjectCapability 注解只能用于 CapabilityHolder 注解所在类,检查该类是否使用了@CapabilityHolder注解或者受其标注的注解或父类: " + declaringClass); } }); } diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/capability/CapabilityRegisterFactory.java b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/capability/CapabilityRegisterFactory.java index 7edb1148..75e28ecf 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/capability/CapabilityRegisterFactory.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/capability/CapabilityRegisterFactory.java @@ -1,5 +1,6 @@ package work.slhaf.partner.api.agent.factory.capability; +import cn.hutool.core.util.ClassUtil; import org.reflections.Reflections; import work.slhaf.partner.api.agent.factory.AgentBaseFactory; import work.slhaf.partner.api.agent.factory.capability.annotation.*; @@ -18,6 +19,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Set; import java.util.function.Function; +import java.util.stream.Collectors; import static work.slhaf.partner.api.agent.util.AgentUtil.methodSignature; @@ -79,10 +81,30 @@ public class CapabilityRegisterFactory extends AgentBaseFactory { @Override protected void run() { + setCapabilityHolderInstances(); setCoreInstances(); generateRouterTable(); } + private void setCapabilityHolderInstances() { + Set> collect = reflections.getTypesAnnotatedWith(CapabilityHolder.class).stream() + .filter(ClassUtil::isNormalClass) + .filter(clazz -> !capabilityHolderInstances.containsKey(clazz)) + .collect(Collectors.toSet()); + for (Class clazz : collect) { + try { + Constructor constructor = clazz.getDeclaredConstructor(); + if (constructor.canAccess(null)) { + throw new CapabilityFactoryExecuteFailedException("缺少无参构造方法的类: " + clazz); + } + Object o = constructor.newInstance(); + capabilityHolderInstances.put(clazz, o); + }catch (Exception e){ + throw new CapabilityFactoryExecuteFailedException("创建代理对象失败: " + clazz, e); + } + } + } + /** * 生成函数路由表 */ diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/config/ConfigLoaderFactory.java b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/config/ConfigLoaderFactory.java index 3922e197..16d56984 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/config/ConfigLoaderFactory.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/config/ConfigLoaderFactory.java @@ -57,7 +57,7 @@ public class ConfigLoaderFactory extends AgentBaseFactory { * 对模型Config与Prompt分别进行检验,除了都必须包含default外,还需要确保数量、key一致,毕竟是模型配置与提示词 */ private void check() { - log.info("[ConfigLoaderFactory]: 执行config与prompt检测..."); + log.info("执行config与prompt检测..."); if (!modelConfigMap.containsKey("default")) { throw new ConfigNotExistException("缺少默认配置! 需确保存在一个模型配置的key为`default`"); } @@ -72,7 +72,6 @@ public class ConfigLoaderFactory extends AgentBaseFactory { log.warn("存在未被提示词包含的模型配置,该配置将无法生效!"); } //检查提示词数量与`ActivateModel`的实现数量是否一致 - - log.info("[ConfigLoaderFactory]: 检测完毕."); + log.info("检测完毕."); } } diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/module/ModuleCheckFactory.java b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/module/ModuleCheckFactory.java index ef3e0564..f43613b9 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/module/ModuleCheckFactory.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/module/ModuleCheckFactory.java @@ -67,6 +67,8 @@ public class ModuleCheckFactory extends AgentBaseFactory { moduleConstructorsCheck(annotatedModules.subModuleTypes()); //检查实现了ActivateModel的模块数量、名称与prompt是否一致 activateModelImplCheck(); + //检查hook注解所在位置是否正确 + hookLocationCheck(); } private ExtendedModules getExtendedModules() { @@ -128,17 +130,6 @@ public class ModuleCheckFactory extends AgentBaseFactory { preHookLocationCheck(); //检查@Init注解 initHookLocationCheck(); - //检查@AgentModule注解是否只位于普通类上 - agentModuleLocationCheck(); - } - - private void agentModuleLocationCheck() { - Set> types = reflections.getTypesAnnotatedWith(AgentModule.class); - for (Class type : types) { - if (!ClassUtil.isNormalClass(type)) { - throw new ModuleCheckException("AgentModule 注解仅能位于普通类上! 异常类信息: " + type.getSimpleName()); - } - } } private void initHookLocationCheck() { diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/module/ModuleInitHookExecuteFactory.java b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/module/ModuleInitHookExecuteFactory.java index 55e569fb..5d2a585e 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/module/ModuleInitHookExecuteFactory.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/module/ModuleInitHookExecuteFactory.java @@ -11,6 +11,8 @@ import work.slhaf.partner.api.agent.factory.module.pojo.MetaMethod; import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule; import work.slhaf.partner.api.agent.factory.module.pojo.MetaSubModule; import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule; +import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningSubModule; +import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.Module; import work.slhaf.partner.api.agent.util.AgentUtil; import java.lang.reflect.InvocationTargetException; @@ -30,7 +32,7 @@ import static work.slhaf.partner.api.agent.util.AgentUtil.methodSignature; * *
    *
  1. - *

    {@link ModuleInitHookExecuteFactory#collectInitHookMethods(Class)}

    + *

    {@link ModuleInitHookExecuteFactory#collectInitHookMethods(Class, Class)}

    * 分别遍历前置模块拿到的模块列表({@link ModuleInitHookExecuteFactory#moduleList}, {@link ModuleInitHookExecuteFactory#subModuleList}),通过 {@link AgentUtil#collectExtendedClasses(Class, Class)} 收集到当前模块类的继承链上的所有类后,收集其所有带有 {@link Init} 注解的方法 *
  2. *
  3. @@ -57,12 +59,12 @@ public class ModuleInitHookExecuteFactory extends AgentBaseFactory { protected void run() { //遍历模块列表,并向上查找@Init注解 for (MetaSubModule metaSubModule : subModuleList) { - List initHookMethods = collectInitHookMethods(metaSubModule.getClazz()); + List initHookMethods = collectInitHookMethods(metaSubModule.getClazz(),AgentRunningModule.class); proceedInitMethods(metaSubModule, initHookMethods); } for (MetaModule metaModule : moduleList) { - List initHookMethods = collectInitHookMethods(metaModule.getClazz()); + List initHookMethods = collectInitHookMethods(metaModule.getClazz(), AgentRunningSubModule.class); proceedInitMethods(metaModule, initHookMethods); } } @@ -77,8 +79,8 @@ public class ModuleInitHookExecuteFactory extends AgentBaseFactory { } } - private List collectInitHookMethods(Class clazz) { - Set> classes = collectExtendedClasses(clazz, AgentRunningModule.class); + private List collectInitHookMethods(Class clazz, Class target) { + Set> classes = collectExtendedClasses(clazz, target); return classes.stream() .map(Class::getDeclaredMethods) .flatMap(Arrays::stream) diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/module/ModuleProxyFactory.java b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/module/ModuleProxyFactory.java index 65e5b19d..77b0c6e6 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/module/ModuleProxyFactory.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/module/ModuleProxyFactory.java @@ -1,5 +1,6 @@ package work.slhaf.partner.api.agent.factory.module; +import lombok.Getter; import net.bytebuddy.ByteBuddy; import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.implementation.bind.annotation.*; @@ -14,11 +15,13 @@ import work.slhaf.partner.api.agent.factory.module.annotation.BeforeExecute; import work.slhaf.partner.api.agent.factory.module.annotation.InjectModule; import work.slhaf.partner.api.agent.factory.module.exception.ModuleInstanceGenerateFailedException; import work.slhaf.partner.api.agent.factory.module.exception.ModuleProxyGenerateFailedException; +import work.slhaf.partner.api.agent.factory.module.exception.ProxiedModuleRunningException; import work.slhaf.partner.api.agent.factory.module.pojo.BaseMetaModule; import work.slhaf.partner.api.agent.factory.module.pojo.MetaMethod; import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule; import work.slhaf.partner.api.agent.factory.module.pojo.MetaSubModule; import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule; +import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningSubModule; import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.Module; import java.lang.reflect.Method; @@ -74,7 +77,8 @@ public class ModuleProxyFactory extends AgentBaseFactory { private void injectSubModule() { for (MetaModule module : moduleList) { - Arrays.stream(module.getClazz().getFields()) + //因为实际上ByteBuddy生成的是module.getClazz()的子类,所以应当使用getDeclaredFields()获取字段 + Arrays.stream(module.getClazz().getDeclaredFields()) .filter(field -> field.isAnnotationPresent(InjectModule.class)) .forEach(field -> { try { @@ -92,15 +96,14 @@ public class ModuleProxyFactory extends AgentBaseFactory { } private void createProxiedInstances() { - generateModuleProxy(moduleList); - generateModuleProxy(subModuleList); + generateModuleProxy(moduleList, AgentRunningModule.class); + generateModuleProxy(subModuleList, AgentRunningSubModule.class); updateInstanceMap(moduleInstances, moduleList); updateInstanceMap(subModuleInstances, subModuleList); updateCapabilityHolderInstances(); } private void updateCapabilityHolderInstances() { - //TODO 扫描并添加所有与@CapabilityHolder相关的实例 capabilityHolderInstances.putAll(moduleInstances); capabilityHolderInstances.putAll(subModuleInstances); } @@ -112,29 +115,38 @@ public class ModuleProxyFactory extends AgentBaseFactory { } - private void generateModuleProxy(List list) { + private void generateModuleProxy(List list, Class overrideSource) { for (BaseMetaModule module : list) { Class clazz = module.getClazz(); try { MethodsListRecord record = collectHookMethods(clazz); //生成实例 - generateProxiedInstances(record, module); + generateProxiedInstances(record, module, overrideSource); } catch (Exception e) { throw new ModuleProxyGenerateFailedException("创建代理对象失败: " + clazz.getSimpleName(), e); } } } - private void generateProxiedInstances(MethodsListRecord record, BaseMetaModule module) { + private void generateProxiedInstances(MethodsListRecord record, BaseMetaModule module, Class overrideSource) { try { Class clazz = module.getClazz(); Class proxyClass = new ByteBuddy() .subclass(clazz) - .method(ElementMatchers.isOverriddenFrom(AgentRunningModule.class)) + .method(ElementMatchers.isOverriddenFrom(overrideSource)) .intercept(MethodDelegation.to(new ModuleProxyInterceptor(record.post, record.pre))) .make() .load(ModuleProxyFactory.class.getClassLoader()) .getLoaded(); + +// new ByteBuddy() +// .subclass(clazz) +// .method(ElementMatchers.isOverriddenFrom(overrideSource)) +// .intercept(MethodDelegation.to(new ModuleProxyInterceptor(record.post, record.pre))) +// +// .make() +// .saveIn(new File("./generated-classes")); + module.setInstance(proxyClass.getConstructor().newInstance()); } catch (Exception e) { throw new ModuleProxyGenerateFailedException("模块Hook代理生成失败! 代理失败的模块名: " + module.getClazz().getSimpleName(), e); @@ -188,7 +200,7 @@ public class ModuleProxyFactory extends AgentBaseFactory { private void collectHookMethods(List post, List pre, Class clazz) { - Method[] methods = clazz.getMethods(); + Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { if (method.isAnnotationPresent(BeforeExecute.class)) { MetaMethod metaMethod = new MetaMethod(); @@ -204,18 +216,38 @@ public class ModuleProxyFactory extends AgentBaseFactory { } } - public record ModuleProxyInterceptor(List postHookMethods, List preHookMethods) { + @Getter + @SuppressWarnings("ClassCanBeRecord") + public static class ModuleProxyInterceptor { + + private final List postHookMethods; + private final List preHookMethods; + + public ModuleProxyInterceptor(List postHookMethods, List preHookMethods) { + this.postHookMethods = postHookMethods; + this.preHookMethods = preHookMethods; + } + @RuntimeType public Object intercept(@Origin Method method, @AllArguments Object[] allArguments, @SuperCall Callable zuper, @This Object proxy) throws Exception { - for (MetaMethod metaMethod : preHookMethods) { - metaMethod.getMethod().invoke(proxy); - } + executeHookMethods(preHookMethods, proxy); Object res = zuper.call(); - for (MetaMethod metaMethod : postHookMethods) { - metaMethod.getMethod().invoke(proxy); - } + executeHookMethods(postHookMethods, proxy); return res; } + + private void executeHookMethods(List hookMethods, Object proxy) { + for (MetaMethod metaMethod : hookMethods) { + Method m = metaMethod.getMethod(); + try { + m.setAccessible(true); + m.invoke(proxy); + } catch (Exception e) { + throw new ProxiedModuleRunningException("hook方法执行异常: " + m.getDeclaringClass() + "#" + m.getName(), e); + } + } + } + } record MethodsListRecord(List post, List pre) { diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/module/annotation/AgentModule.java b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/module/annotation/AgentModule.java index d60a0a37..a0ae8b59 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/module/annotation/AgentModule.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/module/annotation/AgentModule.java @@ -3,10 +3,7 @@ package work.slhaf.partner.api.agent.factory.module.annotation; import work.slhaf.partner.api.agent.factory.capability.annotation.CapabilityHolder; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +import java.lang.annotation.*; /** * 用于注解执行模块 @@ -14,6 +11,7 @@ import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @CapabilityHolder +@Inherited public @interface AgentModule { /** diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/module/exception/ProxiedModuleRunningException.java b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/module/exception/ProxiedModuleRunningException.java new file mode 100644 index 00000000..612dc432 --- /dev/null +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/factory/module/exception/ProxiedModuleRunningException.java @@ -0,0 +1,13 @@ +package work.slhaf.partner.api.agent.factory.module.exception; + +import work.slhaf.partner.api.agent.runtime.exception.AgentRuntimeException; + +public class ProxiedModuleRunningException extends AgentRuntimeException { + public ProxiedModuleRunningException(String message) { + super(message); + } + + public ProxiedModuleRunningException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/config/AgentConfigManager.java b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/config/AgentConfigManager.java index dc531d15..291936dc 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/config/AgentConfigManager.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/config/AgentConfigManager.java @@ -3,7 +3,6 @@ package work.slhaf.partner.api.agent.runtime.config; import lombok.Data; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import work.slhaf.partner.api.agent.factory.config.exception.ConfigNotExistException; import work.slhaf.partner.api.agent.factory.config.exception.ConfigUpdateFailedException; import work.slhaf.partner.api.agent.factory.config.exception.PromptNotExistException; import work.slhaf.partner.api.agent.factory.config.pojo.ModelConfig; @@ -11,9 +10,7 @@ import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule; import work.slhaf.partner.api.chat.pojo.Message; import java.util.HashMap; -import java.util.HashSet; import java.util.List; -import java.util.Set; @Slf4j @Data diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/config/FileAgentConfigManager.java b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/config/FileAgentConfigManager.java index e11dc602..011ac781 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/config/FileAgentConfigManager.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/config/FileAgentConfigManager.java @@ -77,7 +77,7 @@ public class FileAgentConfigManager extends AgentConfigManager { protected HashMap loadModuleEnabledStatusMap() { File file = new File(MODULE_ENABLED_STATUS_CONFIG_FILE); try { - HashMap moduleEnabledStatus = new HashMap<>(); + moduleEnabledStatus = new HashMap<>(); if (!file.exists()) { file.createNewFile(); for (MetaModule module : moduleList) { diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/exception/GlobalExceptionHandler.java b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/exception/GlobalExceptionHandler.java index b5fb92d7..ce373d28 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/exception/GlobalExceptionHandler.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/exception/GlobalExceptionHandler.java @@ -1,5 +1,8 @@ package work.slhaf.partner.api.agent.runtime.exception; +import lombok.extern.slf4j.Slf4j; + +@Slf4j public class GlobalExceptionHandler { public static GlobalExceptionHandler INSTANCE = new GlobalExceptionHandler(); @@ -16,7 +19,7 @@ public class GlobalExceptionHandler { exceptionCallback.onFailedException((AgentLaunchFailedException) e); break; default: - throw new RuntimeException("未经处理的异常!", e); + log.error("未知异常: ", e); } } diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/interaction/flow/abstracts/ActivateModel.java b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/interaction/flow/abstracts/ActivateModel.java index f02348eb..1c61d561 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/interaction/flow/abstracts/ActivateModel.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/interaction/flow/abstracts/ActivateModel.java @@ -2,7 +2,6 @@ package work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts; import cn.hutool.core.bean.BeanUtil; import work.slhaf.partner.api.agent.factory.config.pojo.ModelConfig; -import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule; import work.slhaf.partner.api.agent.factory.module.annotation.Init; import work.slhaf.partner.api.agent.runtime.config.AgentConfigManager; import work.slhaf.partner.api.agent.runtime.interaction.flow.entity.Model; diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/interaction/flow/abstracts/AgentRunningModule.java b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/interaction/flow/abstracts/AgentRunningModule.java index 134ccae4..9d43095c 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/interaction/flow/abstracts/AgentRunningModule.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/interaction/flow/abstracts/AgentRunningModule.java @@ -1,5 +1,10 @@ package work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts; +import lombok.extern.slf4j.Slf4j; +import work.slhaf.partner.api.agent.factory.module.annotation.AfterExecute; +import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule; +import work.slhaf.partner.api.agent.factory.module.annotation.BeforeExecute; +import work.slhaf.partner.api.agent.factory.module.annotation.CoreModule; import work.slhaf.partner.api.agent.runtime.interaction.flow.entity.RunningFlowContext; import java.io.IOException; @@ -7,6 +12,27 @@ import java.io.IOException; /** * 流程执行模块基类 */ +@Slf4j public abstract class AgentRunningModule extends Module { public abstract void execute(C context) throws IOException, ClassNotFoundException; + + @BeforeExecute + private void beforeLog() { + log.debug("[{}] 模块执行开始...", getModuleName()); + } + + @AfterExecute + private void afterLog() { + log.debug("[{}] 模块执行结束...", getModuleName()); + } + + private String getModuleName(){ + if (this.getClass().isAnnotationPresent(AgentModule.class)) { + return this.getClass().getAnnotation(AgentModule.class).name(); + } else if (this.getClass().isAnnotationPresent(CoreModule.class)) { + return CoreModule.class.getAnnotation(AgentModule.class).name(); + }else { + return "Unknown Module"; + } + } } diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/interaction/flow/abstracts/AgentRunningSubModule.java b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/interaction/flow/abstracts/AgentRunningSubModule.java index 037c604a..7b0ab156 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/interaction/flow/abstracts/AgentRunningSubModule.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/runtime/interaction/flow/abstracts/AgentRunningSubModule.java @@ -1,8 +1,35 @@ package work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts; +import lombok.extern.slf4j.Slf4j; +import work.slhaf.partner.api.agent.factory.module.annotation.AfterExecute; +import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule; +import work.slhaf.partner.api.agent.factory.module.annotation.BeforeExecute; +import work.slhaf.partner.api.agent.factory.module.annotation.CoreModule; + +@Slf4j public abstract class AgentRunningSubModule extends Module { public abstract O execute(I data); + + @BeforeExecute + private void beforeLog() { + log.debug("[{}] 模块执行开始...", getModuleName()); + } + + @AfterExecute + private void afterLog() { + log.debug("[{}] 模块执行结束...", getModuleName()); + } + + private String getModuleName(){ + if (this.getClass().isAnnotationPresent(AgentModule.class)) { + return this.getClass().getAnnotation(AgentModule.class).name(); + } else if (this.getClass().isAnnotationPresent(CoreModule.class)) { + return CoreModule.class.getAnnotation(AgentModule.class).name(); + }else { + return "Unknown Module"; + } + } } diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/util/AgentUtil.java b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/util/AgentUtil.java index 03edaa8e..f72d3808 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/agent/util/AgentUtil.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/agent/util/AgentUtil.java @@ -49,6 +49,7 @@ public final class AgentUtil { public static Set> collectExtendedClasses(Class clazz, Class targetClass) { Set> classes = new HashSet<>(); collectExtendedClasses(classes, clazz, targetClass); + classes.add(clazz); return classes; } diff --git a/Partner-Main/src/main/java/work/slhaf/partner/core/cognation/CognationCore.java b/Partner-Main/src/main/java/work/slhaf/partner/core/cognation/CognationCore.java index 1555b535..3e416460 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/core/cognation/CognationCore.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/core/cognation/CognationCore.java @@ -56,6 +56,7 @@ public class CognationCore extends PersistableObject { } else { FileUtils.createParentDirectories(filePath.toFile().getParentFile()); connectCores(this); + this.activeData = new ActiveData(); this.serialize(); } setupHook(this); diff --git a/Partner-Main/src/main/java/work/slhaf/partner/core/cognation/pojo/ActiveData.java b/Partner-Main/src/main/java/work/slhaf/partner/core/cognation/pojo/ActiveData.java index 429eecc1..a6826748 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/core/cognation/pojo/ActiveData.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/core/cognation/pojo/ActiveData.java @@ -1,14 +1,21 @@ package work.slhaf.partner.core.cognation.pojo; import lombok.Data; +import lombok.EqualsAndHashCode; +import work.slhaf.partner.api.common.entity.PersistableObject; import work.slhaf.partner.core.submodule.memory.pojo.EvaluatedSlice; +import java.io.Serial; import java.util.HashMap; import java.util.List; +@EqualsAndHashCode(callSuper = true) @Data -public class ActiveData { - private HashMap> activatedSlices; +public class ActiveData extends PersistableObject { + private HashMap> activatedSlices = new HashMap<>(); + + @Serial + private static final long serialVersionUID = 1L; public void updateActivatedSlices(String userId, List memorySlices) { activatedSlices.put(userId, memorySlices); diff --git a/Partner-Main/src/main/java/work/slhaf/partner/module/common/module/CoreRunningModule.java b/Partner-Main/src/main/java/work/slhaf/partner/module/common/module/CoreRunningModule.java deleted file mode 100644 index 39489981..00000000 --- a/Partner-Main/src/main/java/work/slhaf/partner/module/common/module/CoreRunningModule.java +++ /dev/null @@ -1,7 +0,0 @@ -package work.slhaf.partner.module.common.module; - -import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule; -import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowContext; - -public abstract class CoreRunningModule extends AgentRunningModule { -} diff --git a/Partner-Main/src/main/java/work/slhaf/partner/module/common/module/PostRunningModule.java b/Partner-Main/src/main/java/work/slhaf/partner/module/common/module/PostRunningModule.java index 3104f630..4b05fdb0 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/module/common/module/PostRunningModule.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/module/common/module/PostRunningModule.java @@ -3,5 +3,19 @@ package work.slhaf.partner.module.common.module; import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule; import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowContext; +import java.io.IOException; + public abstract class PostRunningModule extends AgentRunningModule { + + @Override + public final void execute(PartnerRunningFlowContext context) throws IOException, ClassNotFoundException { + boolean trigger = context.getModuleContext().getExtraContext().getBoolean("post_process_trigger"); + if (!trigger){ + return; + } + doExecute(context); + } + + protected void doExecute(PartnerRunningFlowContext context){} + } diff --git a/Partner-Main/src/main/java/work/slhaf/partner/module/common/module/PreRunningModule.java b/Partner-Main/src/main/java/work/slhaf/partner/module/common/module/PreRunningModule.java index 024f2b65..1f08555a 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/module/common/module/PreRunningModule.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/module/common/module/PreRunningModule.java @@ -1,7 +1,6 @@ package work.slhaf.partner.module.common.module; import lombok.extern.slf4j.Slf4j; -import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule; import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule; import work.slhaf.partner.module.common.entity.AppendPromptData; import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowContext; @@ -32,11 +31,9 @@ public abstract class PreRunningModule extends AgentRunningModule implements ActivateModel { @InjectCapability private CognationCapability cognationCapability; diff --git a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/memory/selector/MemorySelector.java b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/memory/selector/MemorySelector.java index d87fb69b..127647f9 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/memory/selector/MemorySelector.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/memory/selector/MemorySelector.java @@ -5,7 +5,6 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability; -import work.slhaf.partner.api.agent.factory.module.annotation.AfterExecute; import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule; import work.slhaf.partner.api.agent.factory.module.annotation.InjectModule; import work.slhaf.partner.core.cognation.CognationCapability; @@ -59,6 +58,7 @@ public class MemorySelector extends PreRunningModule { List evaluatedSlices = selectAndEvaluateMemory(runningFlowContext, extractorResult); cognationCapability.updateActivatedSlices(userId, evaluatedSlices); } + setModuleContextRecall(runningFlowContext); } private List selectAndEvaluateMemory(PartnerRunningFlowContext runningFlowContext, ExtractorResult extractorResult) throws IOException, ClassNotFoundException { @@ -79,7 +79,6 @@ public class MemorySelector extends PreRunningModule { return memorySlices; } - @AfterExecute(order = 1) private void setModuleContextRecall(PartnerRunningFlowContext runningFlowContext) { String userId = runningFlowContext.getUserId(); boolean recall = cognationCapability.hasActivatedSlices(userId); diff --git a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/memory/selector/extractor/MemorySelectExtractor.java b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/memory/selector/extractor/MemorySelectExtractor.java index ff116f9d..f4350063 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/memory/selector/extractor/MemorySelectExtractor.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/memory/selector/extractor/MemorySelectExtractor.java @@ -94,6 +94,9 @@ public class MemorySelectExtractor extends AgentRunningSubModule m.getText().split("->")[0].isEmpty()); return extractorResult; } diff --git a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/memory/updater/MemoryUpdater.java b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/memory/updater/MemoryUpdater.java index 418740eb..cfec4d20 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/memory/updater/MemoryUpdater.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/memory/updater/MemoryUpdater.java @@ -96,7 +96,7 @@ public class MemoryUpdater extends PostRunningModule { } @Override - public void execute(PartnerRunningFlowContext context) { + public void doExecute(PartnerRunningFlowContext context) { if (context.isFinished()) { log.warn("[MemoryUpdater] 流程强制结束, 不触发记忆被动更新机制"); return; diff --git a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/perceive/updater/PerceiveUpdater.java b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/perceive/updater/PerceiveUpdater.java index 7e32bf45..3dfc4bf3 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/perceive/updater/PerceiveUpdater.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/perceive/updater/PerceiveUpdater.java @@ -7,17 +7,16 @@ import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapabili import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule; import work.slhaf.partner.api.agent.factory.module.annotation.Init; import work.slhaf.partner.api.agent.factory.module.annotation.InjectModule; -import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule; import work.slhaf.partner.common.thread.InteractionThreadPoolExecutor; import work.slhaf.partner.core.cognation.CognationCapability; import work.slhaf.partner.core.submodule.perceive.PerceiveCapability; import work.slhaf.partner.core.submodule.perceive.pojo.User; +import work.slhaf.partner.module.common.module.PostRunningModule; import work.slhaf.partner.module.modules.perceive.updater.relation_extractor.RelationExtractor; import work.slhaf.partner.module.modules.perceive.updater.relation_extractor.pojo.RelationExtractResult; import work.slhaf.partner.module.modules.perceive.updater.static_extractor.StaticMemoryExtractor; import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowContext; -import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -31,7 +30,7 @@ import java.util.concurrent.locks.ReentrantLock; @Slf4j @Data @AgentModule(name = "perceive_updater", order = 8) -public class PerceiveUpdater extends AgentRunningModule { +public class PerceiveUpdater extends PostRunningModule { private static volatile PerceiveUpdater perceiveUpdater; @@ -53,12 +52,9 @@ public class PerceiveUpdater extends AgentRunningModule { - boolean trigger = context.getModuleContext().getExtraContext().getBoolean("perceive_updater"); - if (!trigger){ - return; - } ReentrantLock userLock = new ReentrantLock(); User user = new User(); user.setUuid(context.getUserId()); diff --git a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/process/PostprocessExecutor.java b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/process/PostprocessExecutor.java index f482d1cb..8148abd3 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/process/PostprocessExecutor.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/process/PostprocessExecutor.java @@ -5,8 +5,8 @@ import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability; import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule; +import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule; import work.slhaf.partner.core.cognation.CognationCapability; -import work.slhaf.partner.module.common.module.PostRunningModule; import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowContext; import java.io.IOException; @@ -15,7 +15,7 @@ import java.io.IOException; @Slf4j @Data @AgentModule(name = "postprocess_executor", order = 6) -public class PostprocessExecutor extends PostRunningModule { +public class PostprocessExecutor extends AgentRunningModule { private static final int POST_PROCESS_TRIGGER_ROLL_LIMIT = 36; diff --git a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/process/PreprocessExecutor.java b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/process/PreprocessExecutor.java index 5f2bb368..e90a5b05 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/process/PreprocessExecutor.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/process/PreprocessExecutor.java @@ -1,9 +1,10 @@ package work.slhaf.partner.module.modules.process; import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; -import work.slhaf.partner.api.agent.factory.capability.annotation.CapabilityHolder; import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability; +import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule; import work.slhaf.partner.api.agent.factory.module.annotation.Init; import work.slhaf.partner.core.cognation.CognationCapability; import work.slhaf.partner.core.submodule.perceive.PerceiveCapability; @@ -17,9 +18,10 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.HashMap; +@EqualsAndHashCode(callSuper = true) @Data @Slf4j -@CapabilityHolder +@AgentModule(name = "preprocess_executor", order = 1) public class PreprocessExecutor extends PreRunningModule { private static volatile PreprocessExecutor preprocessExecutor; diff --git a/Partner-Main/src/main/java/work/slhaf/partner/runtime/interaction/WebSocketGateway.java b/Partner-Main/src/main/java/work/slhaf/partner/runtime/interaction/WebSocketGateway.java index 19981a67..b4b14a77 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/runtime/interaction/WebSocketGateway.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/runtime/interaction/WebSocketGateway.java @@ -38,6 +38,7 @@ public class WebSocketGateway extends WebSocketServer implements AgentGateway { - try { - //关闭WebSocketServer - this.stop(); - log.info("WebSocketServer 已关闭"); - } catch (Exception e) { - log.error("WebSocketServer关闭失败: ", e); - } - })); + try { + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + try { + // 先断开所有客户端连接 + for (WebSocket webSocket : getConnections()) { + try { + webSocket.close(1001, "Server shutting down"); + } catch (Exception e) { + log.warn("关闭客户端连接时出错: ", e); + } + } + //关闭WebSocketServer,给10秒超时时间确保连接正确关闭 + this.stop(10000); + log.info("WebSocketServer 已关闭"); + } catch (IllegalStateException e) { + log.warn("无法添加关闭钩子,JVM可能已在关闭过程中: ", e); + } catch (Exception e) { + log.error("WebSocketServer关闭失败: ", e); + } + })); + } catch (IllegalStateException e) { + log.warn("无法添加关闭钩子,JVM可能已在关闭过程中: ", e); + } } @Override diff --git a/README.md b/README.md index 12e415d8..d15c4440 100644 --- a/README.md +++ b/README.md @@ -47,35 +47,35 @@ Partner 的目标不是复现某种单一能力,而是尝试在结构中形成 ## 模块(已实现/正在实现) - 预处理模块: `PreprocessExecutor` - 后处理模块: `PostprocessExecutor` +- 主对话模块: `CoreModel` - 记忆模块 - 记忆选择模块: `MemorySelector` - 主题提取模块: `MemorySelectExtractor` - 切片评估模块: `SliceSelectEvaluator` - 记忆更新模块: `MemoryUpdater` - - 记忆总结模块: `MemorySummarizer` - - 静态记忆提取模块: `StaticMemoryExtractor` + - 记忆总结模块[多聊天对象]: `MultiSummarizer` + - 记忆总结模块[单聊天对象]: `SingleSummarizer` + - 记忆总结模块[汇总]:`TotalSummarizer` - 感知模块 - 感知选择模块: `PerceiveSelector` - 感知更新模块: `PerceiveUpdater` - 关系提取模块: `RelationExtractor` - - 静态记忆提取模块: `StaticExtractor` -- 任务调度模块 + - 静态记忆提取模块: `StaticMemoryExtractor` +- 任务调度模块(待实现) - 任务评估模块: `TaskEvaluator` - 任务执行模块: `TaskExecutor` - 任务规划模块: `TaskScheduler` -- 主对话模块: `CoreModel` ## 当前问题 - 系统的正常运作效果取决于各模块中大模型对于`prompt`的遵循能力,目前来看`qwen3`的遵循效果明显较好,但在轮次较多时,也容易出现不遵循的情况。 ## 规划 -- [ ] 完成框架与本体的适配工作 - [ ] 实现任务与主动调度模块,目前打算用 `时间轮算法` 实现定时操作 - [ ] 完善具备‘记忆切片、实体图谱、向量召回’的三维记忆融合架构,包含 Episodic + Semantic + Fuzzy 三类记忆 - [ ] 服务端与客户端的通信加上消息队列,防止消息因连接断开而丢失。 - [ ] 实现流式输出,同时在各模块执行时可向客户端返回回调信息,优化使用体验。(现在用的是`websocket`与客户端通信, 应该实现这点会简单些) - [ ] 踩坑。 -- [ ] 实现角色演进机制 +- [ ] 实现演进机制 ## License This project is not licensed for public use. All rights reserved.