fix:收敛A_Memorix最小回归修复
最小修复聊天摘要写回游标恢复、摘要元数据透传、webui反馈参数解析、embedding批次缓存索引、图存储清理与配置默认值回归,并补齐针对性回归测试,确保问题解决且不影响现有逻辑。
This commit is contained in:
@@ -385,19 +385,19 @@ class EmbeddingAPIAdapter:
|
||||
|
||||
semaphore = asyncio.Semaphore(self.max_concurrent)
|
||||
|
||||
async def encode_with_semaphore(text: str, index: int):
|
||||
async def encode_with_semaphore(text: str, batch_index: int, absolute_index: int):
|
||||
async with semaphore:
|
||||
embedding = await self._get_embedding_direct(text, dimensions=dimensions)
|
||||
if embedding is None:
|
||||
raise RuntimeError(f"文本 {index} 编码失败:embedding 返回为空")
|
||||
raise RuntimeError(f"文本 {absolute_index} 编码失败:embedding 返回为空")
|
||||
vector = self._validate_embedding_vector(
|
||||
embedding,
|
||||
source=f"文本 {index}",
|
||||
source=f"文本 {absolute_index}",
|
||||
)
|
||||
return index, vector
|
||||
return batch_index, vector
|
||||
|
||||
tasks = [
|
||||
encode_with_semaphore(text, offset + index)
|
||||
encode_with_semaphore(text, index, offset + index)
|
||||
for index, text in uncached_items
|
||||
]
|
||||
results = await asyncio.gather(*tasks)
|
||||
|
||||
@@ -803,6 +803,7 @@ class SDKMemoryKernel:
|
||||
context_length: Optional[int] = None,
|
||||
include_personality: Optional[bool] = None,
|
||||
time_end: Optional[float] = None,
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
) -> Dict[str, Any]:
|
||||
await self.initialize()
|
||||
assert self.summary_importer
|
||||
@@ -811,6 +812,7 @@ class SDKMemoryKernel:
|
||||
context_length=context_length,
|
||||
include_personality=include_personality,
|
||||
time_end=time_end,
|
||||
metadata=metadata,
|
||||
)
|
||||
if success:
|
||||
await self.rebuild_episodes_for_sources([self._build_source("chat_summary", chat_id, [])])
|
||||
@@ -854,6 +856,12 @@ class SDKMemoryKernel:
|
||||
context_length=self._optional_int(summary_meta.get("context_length")),
|
||||
include_personality=summary_meta.get("include_personality"),
|
||||
time_end=time_end,
|
||||
metadata={
|
||||
**summary_meta,
|
||||
"external_id": external_token,
|
||||
"chat_id": str(chat_id or "").strip(),
|
||||
"source_type": "chat_summary",
|
||||
},
|
||||
)
|
||||
result.setdefault("external_id", external_id)
|
||||
result.setdefault("chat_id", chat_id)
|
||||
|
||||
@@ -1294,6 +1294,7 @@ class GraphStore:
|
||||
if current_n == 0:
|
||||
logger.warning("检测到空图元数据但邻接矩阵仍然存在,已重置为空图。")
|
||||
self._adjacency = None
|
||||
self._edge_hash_map = defaultdict(set)
|
||||
elif current_n > adj_n:
|
||||
logger.warning(f"检测到图存储维度不匹配: 节点数={current_n}, 矩阵大小={adj_n}. 正在自动修复...")
|
||||
self._expand_adjacency_matrix(current_n - adj_n)
|
||||
@@ -1305,6 +1306,14 @@ class GraphStore:
|
||||
self._adjacency = csc_matrix((current_n, current_n), dtype=np.float32)
|
||||
else:
|
||||
self._adjacency = csr_matrix((current_n, current_n), dtype=np.float32)
|
||||
self._edge_hash_map = defaultdict(
|
||||
set,
|
||||
{
|
||||
(src_idx, dst_idx): set(hashes)
|
||||
for (src_idx, dst_idx), hashes in self._edge_hash_map.items()
|
||||
if src_idx < current_n and dst_idx < current_n
|
||||
},
|
||||
)
|
||||
|
||||
self._adjacency_dirty = True
|
||||
logger.info(
|
||||
|
||||
@@ -178,6 +178,27 @@ class MetadataStore:
|
||||
int(knowledge_type_result.get("normalized", 0) or 0),
|
||||
)
|
||||
|
||||
def _ensure_memory_feedback_task_columns(self, cursor: sqlite3.Cursor) -> None:
|
||||
"""补齐 memory_feedback_tasks 历史库缺失的 rollback_* 列。"""
|
||||
cursor.execute("PRAGMA table_info(memory_feedback_tasks)")
|
||||
feedback_task_columns = {row[1] for row in cursor.fetchall()}
|
||||
feedback_task_migrations = {
|
||||
"rollback_status": "ALTER TABLE memory_feedback_tasks ADD COLUMN rollback_status TEXT DEFAULT 'none'",
|
||||
"rollback_plan_json": "ALTER TABLE memory_feedback_tasks ADD COLUMN rollback_plan_json TEXT",
|
||||
"rollback_result_json": "ALTER TABLE memory_feedback_tasks ADD COLUMN rollback_result_json TEXT",
|
||||
"rollback_error": "ALTER TABLE memory_feedback_tasks ADD COLUMN rollback_error TEXT",
|
||||
"rollback_requested_by": "ALTER TABLE memory_feedback_tasks ADD COLUMN rollback_requested_by TEXT",
|
||||
"rollback_reason": "ALTER TABLE memory_feedback_tasks ADD COLUMN rollback_reason TEXT",
|
||||
"rollback_requested_at": "ALTER TABLE memory_feedback_tasks ADD COLUMN rollback_requested_at REAL",
|
||||
"rolled_back_at": "ALTER TABLE memory_feedback_tasks ADD COLUMN rolled_back_at REAL",
|
||||
}
|
||||
for col, sql in feedback_task_migrations.items():
|
||||
if col not in feedback_task_columns:
|
||||
try:
|
||||
cursor.execute(sql)
|
||||
except sqlite3.OperationalError as e:
|
||||
logger.warning(f"Schema迁移失败 (memory_feedback_tasks.{col}): {e}")
|
||||
|
||||
def close(self) -> None:
|
||||
"""关闭数据库连接"""
|
||||
if self._conn:
|
||||
@@ -641,24 +662,7 @@ class MetadataStore:
|
||||
CREATE INDEX IF NOT EXISTS idx_person_profile_refresh_queue_requested
|
||||
ON person_profile_refresh_queue(requested_at DESC)
|
||||
""")
|
||||
cursor.execute("PRAGMA table_info(memory_feedback_tasks)")
|
||||
feedback_task_columns = {row[1] for row in cursor.fetchall()}
|
||||
feedback_task_migrations = {
|
||||
"rollback_status": "ALTER TABLE memory_feedback_tasks ADD COLUMN rollback_status TEXT DEFAULT 'none'",
|
||||
"rollback_plan_json": "ALTER TABLE memory_feedback_tasks ADD COLUMN rollback_plan_json TEXT",
|
||||
"rollback_result_json": "ALTER TABLE memory_feedback_tasks ADD COLUMN rollback_result_json TEXT",
|
||||
"rollback_error": "ALTER TABLE memory_feedback_tasks ADD COLUMN rollback_error TEXT",
|
||||
"rollback_requested_by": "ALTER TABLE memory_feedback_tasks ADD COLUMN rollback_requested_by TEXT",
|
||||
"rollback_reason": "ALTER TABLE memory_feedback_tasks ADD COLUMN rollback_reason TEXT",
|
||||
"rollback_requested_at": "ALTER TABLE memory_feedback_tasks ADD COLUMN rollback_requested_at REAL",
|
||||
"rolled_back_at": "ALTER TABLE memory_feedback_tasks ADD COLUMN rolled_back_at REAL",
|
||||
}
|
||||
for col, sql in feedback_task_migrations.items():
|
||||
if col not in feedback_task_columns:
|
||||
try:
|
||||
cursor.execute(sql)
|
||||
except sqlite3.OperationalError as e:
|
||||
logger.warning(f"Schema迁移失败 (memory_feedback_tasks.{col}): {e}")
|
||||
self._ensure_memory_feedback_task_columns(cursor)
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS external_memory_refs (
|
||||
external_id TEXT PRIMARY KEY,
|
||||
@@ -953,6 +957,7 @@ class MetadataStore:
|
||||
CREATE INDEX IF NOT EXISTS idx_person_profile_refresh_queue_requested
|
||||
ON person_profile_refresh_queue(requested_at DESC)
|
||||
""")
|
||||
self._ensure_memory_feedback_task_columns(cursor)
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS external_memory_refs (
|
||||
external_id TEXT PRIMARY KEY,
|
||||
@@ -3945,6 +3950,8 @@ class MetadataStore:
|
||||
"episodes", "episode_paragraphs",
|
||||
"episode_rebuild_sources", "episode_pending_paragraphs",
|
||||
"paragraph_vector_backfill",
|
||||
"memory_feedback_tasks", "memory_feedback_action_logs",
|
||||
"paragraph_stale_relation_marks", "person_profile_refresh_queue",
|
||||
]
|
||||
for table in tables:
|
||||
cursor.execute(f"DELETE FROM {table}")
|
||||
|
||||
@@ -225,6 +225,7 @@ class SummaryImporter:
|
||||
context_length: Optional[int] = None,
|
||||
include_personality: Optional[bool] = None,
|
||||
time_end: Optional[float] = None,
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
) -> Tuple[bool, str]:
|
||||
"""
|
||||
从指定的聊天流中提取记录并执行总结导入
|
||||
@@ -327,7 +328,14 @@ class SummaryImporter:
|
||||
}
|
||||
|
||||
# 6. 执行导入
|
||||
await self._execute_import(summary_text, entities, relations, stream_id, time_meta=time_meta)
|
||||
await self._execute_import(
|
||||
summary_text,
|
||||
entities,
|
||||
relations,
|
||||
stream_id,
|
||||
time_meta=time_meta,
|
||||
metadata=metadata,
|
||||
)
|
||||
|
||||
# 7. 持久化
|
||||
self.vector_store.save()
|
||||
@@ -393,6 +401,7 @@ class SummaryImporter:
|
||||
relations: List[Dict[str, str]],
|
||||
stream_id: str,
|
||||
time_meta: Optional[Dict[str, Any]] = None,
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
"""将数据写入存储"""
|
||||
# 获取默认知识类型
|
||||
@@ -407,6 +416,7 @@ class SummaryImporter:
|
||||
hash_value = self.metadata_store.add_paragraph(
|
||||
content=summary,
|
||||
source=f"chat_summary:{stream_id}",
|
||||
metadata=metadata,
|
||||
knowledge_type=knowledge_type.value,
|
||||
time_meta=time_meta,
|
||||
)
|
||||
|
||||
@@ -375,30 +375,6 @@ def _preflight_impl(config_path: Path, data_dir: Path) -> Dict[str, Any]:
|
||||
"memory_feedback_tasks rollback columns missing under current schema version",
|
||||
)
|
||||
)
|
||||
elif not has_stale_marks:
|
||||
checks.append(
|
||||
CheckItem(
|
||||
"CP-15",
|
||||
"error",
|
||||
"paragraph_stale_relation_marks table missing under current schema version",
|
||||
)
|
||||
)
|
||||
elif not has_profile_refresh_queue:
|
||||
checks.append(
|
||||
CheckItem(
|
||||
"CP-16",
|
||||
"error",
|
||||
"person_profile_refresh_queue table missing under current schema version",
|
||||
)
|
||||
)
|
||||
elif not has_feedback_rollback_status or not has_feedback_rollback_plan:
|
||||
checks.append(
|
||||
CheckItem(
|
||||
"CP-17",
|
||||
"error",
|
||||
"memory_feedback_tasks rollback columns missing under current schema version",
|
||||
)
|
||||
)
|
||||
|
||||
if _sqlite_table_exists(conn, "relations"):
|
||||
row = conn.execute("SELECT COUNT(*) FROM relations").fetchone()
|
||||
|
||||
Reference in New Issue
Block a user