Files

142 lines
5.4 KiB
Python
Raw Permalink Normal View History

from collections import defaultdict
from collections.abc import Callable
from typing import Any, cast
from zhenxun.services.ai.context.rag.backends import StorageBackend
from zhenxun.services.ai.utils.logger import log_memory as logger
from zhenxun.services.ai.utils.scope import BaseScopeBuilder
from zhenxun.utils.utils import infer_plugin_namespace
from .models import MemoryConfig
from .storage.backends import (
InMemoryChatContext,
)
from .storage.interfaces import (
BaseChatContext,
IClearableBackend,
)
class MemoryCleaner(BaseScopeBuilder["MemoryCleaner"]):
"""
声明式记忆清理构建器 (Query Builder)。
为第三方开发者提供极端友好的链式 API,彻底屏蔽底层前缀逻辑。
"""
def __init__(self, manager: "GlobalMemoryManager"):
super().__init__()
self.manager = manager
self._config: Any = None
def config(self, cfg: Any):
"""指定私有记忆配置(自动识别未全局注册 of 第三方私有数据库实例)"""
self._config = cfg.build() if hasattr(cfg, "build") else cfg
return self
async def clear_target(self, target_name: str):
"""底层派发器:定向清理指定注册名称的泛型扩展后端数据"""
ns_dict = self.manager._backends.get(target_name, {})
for backend in ns_dict.values():
if isinstance(backend, IClearableBackend):
await backend.clear_by_query(self._selector)
else:
logger.warning(
f"后端 {backend.__class__.__name__}"
"未实现 IClearableBackend 协议,已跳过清理。"
)
async def clear_short_term(self):
"""一键清理目标范围下的短期对话历史记忆"""
if isinstance(self._config, MemoryConfig) and isinstance(
self._config.short_term.backend, IClearableBackend
):
await self._config.short_term.backend.clear_by_query(self._selector)
else:
await self.clear_target("chat")
async def clear_slots(self):
"""一键清理目标范围下的记忆槽数据"""
await self.clear_target("slots")
async def clear_long_term(self):
"""一键清理目标范围下的长期向量记忆 (RAG Vector Database)"""
for factory in self.manager._storage_factories.values():
storage = factory()
if isinstance(storage, IClearableBackend):
await storage.clear_by_query(self._selector)
async def clear_all(self):
"""一键清理指定范围下的所有生命周期记忆(对话、记忆槽、RAG、及其他泛型扩展后端)"""
if isinstance(self._config, MemoryConfig) and isinstance(
self._config.short_term.backend, IClearableBackend
):
await self._config.short_term.backend.clear_by_query(self._selector)
for target_name in self.manager._backends:
await self.clear_target(target_name)
await self.clear_long_term()
logger.info(
f"🧹 成功清理作用域 '{self._selector.scope_prefix}'下的所有记忆痕迹!"
)
class GlobalMemoryManager:
"""
全局记忆大管家 (IoC 容器)。
使用现代化依赖注入机制管理短/长期记忆引擎的默认实例。
"""
def __init__(self):
self._backends: dict[str, dict[str, Any]] = defaultdict(dict)
self.register_backend("chat", InMemoryChatContext(), "global")
from zhenxun.services.ai.context.rag.backends import DictStorageBackend
self._storage_factories: dict[str, Callable[[], StorageBackend]] = {
"global": lambda: DictStorageBackend()
}
def register_backend(
self, backend_type: str, backend: Any, scope: str | None = None
) -> None:
"""泛型注册:注册任意类型的存储后端"""
ns = scope if scope is not None else infer_plugin_namespace()
self._backends[backend_type][ns] = backend
def get_backend(self, backend_type: str, namespace: str = "global") -> Any | None:
"""泛型获取:获取任意类型的存储后端"""
backends = self._backends.get(backend_type, {})
return backends.get(namespace) or backends.get("global")
def register_chat_backend(
self, backend: BaseChatContext, scope: str | None = None
) -> None:
"""注册特定命名空间的短期记忆存储后端。"""
self.register_backend("chat", backend, scope)
def register_storage_factory(
self, factory: Callable[[], StorageBackend], scope: str | None = None
) -> None:
"""注册特定命名空间的长期记忆向量存储工厂。"""
ns = scope if scope is not None else infer_plugin_namespace()
self._storage_factories[ns] = factory
def cleaner(self) -> MemoryCleaner:
"""获取声明式记忆清理构建器,供第三方开发者极速清理指定记忆"""
return MemoryCleaner(self)
def get_chat_context(
self, config: MemoryConfig | None, namespace: str = "global"
) -> BaseChatContext | None:
"""根据配置分配对应的短期对话历史实例"""
if not config or not config.short_term.enable:
return None
backend_cfg = config.short_term.backend
if backend_cfg is not None:
return cast(BaseChatContext, backend_cfg)
return self.get_backend("chat", namespace)
memory_manager = GlobalMemoryManager()