fix:记忆架构优化

This commit is contained in:
2026-09-13 21:22:54 +08:00
parent dd281b3361
commit 41284f0bb1
8 changed files with 354 additions and 11 deletions
+65 -4
View File
@@ -2,6 +2,7 @@
from __future__ import annotations
import asyncio
import contextvars
import logging
import uuid
@@ -72,13 +73,20 @@ class MemoryConversationContext:
class MemoryAwareClientAgent:
"""在现有客服 Agent 外包裹记忆召回、候选保存和降级处理。"""
"""在现有客服 Agent 外包裹记忆召回、候选保存和降级处理。
def __init__(self, *, agent, memory_service, context, extractor=None):
候选记忆保存默认放入后台任务执行(background_saves=True),不阻塞
客服响应;测试或需要确定性顺序的场景可设为 False 改回同步执行。
"""
def __init__(self, *, agent, memory_service, context, extractor=None,
background_saves: bool = True):
self.agent = agent
self.memory_service = memory_service
self.context = context
self.extractor = extractor
self.background_saves = background_saves
self._pending_saves: set[asyncio.Task] = set()
async def handle(self, session_id: str, query: str, *, trace_id: str, customer_id: int) -> dict:
"""执行记忆召回、客服回答、消息写入和候选记忆保存。"""
@@ -107,7 +115,7 @@ class MemoryAwareClientAgent:
result = await self.agent.handle(
session_id, query, trace_id=trace_id, customer_id=customer_id
)
if self.extractor is not None:
if self.extractor is not None and not self.background_saves:
await self._save_candidates(
customer_id,
session_id,
@@ -117,6 +125,15 @@ class MemoryAwareClientAgent:
trace_id=trace_id,
)
result["memory_warnings"] = list(warnings)
if self.extractor is not None and self.background_saves:
self._spawn_save(
customer_id,
session_id,
query,
memory_context,
warnings,
trace_id=trace_id,
)
return result
finally:
_active_customer.reset(message_token)
@@ -124,6 +141,35 @@ class MemoryAwareClientAgent:
_active_warnings.reset(warnings_token)
_active_memory_context.reset(context_token)
def _spawn_save(
self,
customer_id,
session_id,
query,
context,
warnings,
*,
trace_id: str | None = None,
) -> None:
"""把候选记忆保存放入后台任务;任务异常已自捕获,不击穿响应。"""
task = asyncio.create_task(
self._save_candidates(
customer_id,
session_id,
query,
context,
warnings,
trace_id=trace_id,
)
)
self._pending_saves.add(task)
task.add_done_callback(self._pending_saves.discard)
async def wait_for_pending_saves(self) -> None:
"""等待全部后台保存完成,供测试与优雅退出使用。"""
if self._pending_saves:
await asyncio.gather(*list(self._pending_saves), return_exceptions=True)
async def _save_candidates(
self,
customer_id,
@@ -157,9 +203,24 @@ class MemoryAwareClientAgent:
try:
evidence_count = 1
if candidate.get("signal_type") == "interest_query":
# 兴趣主题首次出现即保存为候选,后续由长期记忆按精确内容合并证据。
# 兴趣主题先计数:达到阈值才固化为长期记忆,避免单次关注污染画像。
candidate["memory_type"] = "CUSTOMER_PREFERENCE"
candidate["source"] = "dialogue_inferred"
try:
_, reached = await self.memory_service.record_interest_signal(
customer_id=customer_id, tag=candidate["tag"]
)
except Exception as exc:
logger.exception(
"client interest signal failed: trace_id=%s customer_id=%s tag=%s",
trace_id,
customer_id,
candidate.get("tag"),
)
warnings.append(f"interest_signal_failed:{type(exc).__name__}")
continue
if not reached:
continue
memory = MemoryUnitDTO(
customer_id=customer_id,
session_id=session_id,