feat: A_Memorix:加强严格模式、错误与删除语义
在 A_Memorix 中强制更严格的检索语义,并改进错误传播与删除结果报告。 强制/校验受支持的搜索模式(search/time/hybrid/episode/aggregate);移除 semantic 模式,并对不支持的模式返回明确错误。将 kernel 和 plugin 构造函数中的默认值从 hybrid 改为 search。(plugins/A_memorix/core/runtime/sdk_memory_kernel.py, plugins/A_memorix/plugin.py) 对 time/hybrid 模式要求必须提供 time_start/time_end,并在文档、快速开始和 README 中体现该语义。(plugins/A_memorix/QUICK_START.md, plugins/A_memorix/README.md) 改进删除预览/执行语义:跟踪“请求的来源”与“匹配的来源”,基于匹配/删除项计算成功状态,并返回详细计数(requested_source_count、matched_source_count、deleted_paragraph_count、error)。修复来源删除逻辑,使其基于匹配到的来源执行删除。(plugins/A_memorix/core/runtime/sdk_memory_kernel.py) 在搜索执行中移除遗留的 semantic 映射,并规范化 query_type 处理。(plugins/A_memorix/core/utils/search_execution_service.py) 向调用方传播后端搜索错误:为 MemorySearchResult 增加 success/error 字段,兼容多种运行时响应封装,并在异常时返回失败结果。更新调用方以处理并报告搜索失败。(src/services/memory_service.py, src/plugin_runtime/capabilities/data.py, src/chat/brain_chat/PFC/pfc_KnowledgeFetcher.py, src/memory_system/retrieval_tools/query_long_term_memory.py)
This commit is contained in:
@@ -41,6 +41,8 @@ class MemorySearchResult:
|
||||
summary: str = ""
|
||||
hits: List[MemoryHit] = field(default_factory=list)
|
||||
filtered: bool = False
|
||||
success: bool = True
|
||||
error: str = ""
|
||||
|
||||
def to_text(self, limit: int = 5) -> str:
|
||||
if not self.hits:
|
||||
@@ -55,6 +57,8 @@ class MemorySearchResult:
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
return {
|
||||
"success": self.success,
|
||||
"error": self.error,
|
||||
"summary": self.summary,
|
||||
"hits": [item.to_dict() for item in self.hits],
|
||||
"filtered": self.filtered,
|
||||
@@ -92,13 +96,33 @@ class MemoryService:
|
||||
runtime = get_plugin_runtime_manager()
|
||||
if not runtime.is_running:
|
||||
raise RuntimeError("plugin_runtime 未启动")
|
||||
return await runtime.invoke_plugin(
|
||||
response = await runtime.invoke_plugin(
|
||||
method="plugin.invoke_tool",
|
||||
plugin_id=PLUGIN_ID,
|
||||
component_name=component_name,
|
||||
args=args or {},
|
||||
timeout_ms=max(1000, int(timeout_ms or 30000)),
|
||||
)
|
||||
# 兼容新旧运行时返回:
|
||||
# - 旧版: 直接返回工具结果(dict)
|
||||
# - 新版: 返回 Envelope,工具结果在 payload.result 中
|
||||
if isinstance(response, dict):
|
||||
return response
|
||||
payload = getattr(response, "payload", None)
|
||||
if isinstance(payload, dict):
|
||||
if isinstance(payload.get("result"), dict):
|
||||
return payload["result"]
|
||||
return payload
|
||||
model_dump = getattr(response, "model_dump", None)
|
||||
if callable(model_dump):
|
||||
dumped = model_dump()
|
||||
if isinstance(dumped, dict):
|
||||
inner_payload = dumped.get("payload")
|
||||
if isinstance(inner_payload, dict):
|
||||
if isinstance(inner_payload.get("result"), dict):
|
||||
return inner_payload["result"]
|
||||
return inner_payload
|
||||
return response
|
||||
|
||||
async def _invoke_admin(
|
||||
self,
|
||||
@@ -134,7 +158,7 @@ class MemoryService:
|
||||
@staticmethod
|
||||
def _coerce_search_result(payload: Any) -> MemorySearchResult:
|
||||
if not isinstance(payload, dict):
|
||||
return MemorySearchResult()
|
||||
return MemorySearchResult(success=False, error="invalid_payload")
|
||||
hits: List[MemoryHit] = []
|
||||
for item in payload.get("hits", []) or []:
|
||||
if not isinstance(item, dict):
|
||||
@@ -158,10 +182,15 @@ class MemoryService:
|
||||
title=str(item.get("title", "") or ""),
|
||||
)
|
||||
)
|
||||
success_raw = payload.get("success")
|
||||
error = str(payload.get("error", "") or "")
|
||||
success = (not bool(error)) if success_raw is None else bool(success_raw)
|
||||
return MemorySearchResult(
|
||||
summary=str(payload.get("summary", "") or ""),
|
||||
hits=hits,
|
||||
filtered=bool(payload.get("filtered", False)),
|
||||
success=success,
|
||||
error=error,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -179,7 +208,7 @@ class MemoryService:
|
||||
query: str,
|
||||
*,
|
||||
limit: int = 5,
|
||||
mode: str = "hybrid",
|
||||
mode: str = "search",
|
||||
chat_id: str = "",
|
||||
person_id: str = "",
|
||||
time_start: str | float | None = None,
|
||||
@@ -212,7 +241,7 @@ class MemoryService:
|
||||
return self._coerce_search_result(payload)
|
||||
except Exception as exc:
|
||||
logger.warning("长期记忆搜索失败: %s", exc)
|
||||
return MemorySearchResult()
|
||||
return MemorySearchResult(success=False, error=str(exc))
|
||||
|
||||
async def ingest_summary(
|
||||
self,
|
||||
|
||||
Reference in New Issue
Block a user