feat:用户画像功能

This commit is contained in:
2026-09-14 00:19:31 +08:00
parent cf8fcf63c9
commit a7f9e182a4
17 changed files with 971 additions and 37 deletions
+39
View File
@@ -9,9 +9,11 @@ from config.database.mysql import get_session_factory
from tool.confidence_rank import FinalConfidenceRankTool
from .archive import ConversationArchiver
from .composed_profile import ComposedProfileService
from .customer_relation import CustomerRelationMemory
from .customer_product import CustomerProductMemory
from .context_builder import build_customer_memory_context
from .holdings import CustomerHoldingsMemory
from .long_term import LongTermMemoryService
from .interest_topic import InterestTopicTracker
from .profile import CustomerProfileMemory
@@ -32,6 +34,8 @@ class MemoryService:
work_orders: WorkOrderMemory | None = None,
relations: CustomerRelationMemory | None = None,
products: CustomerProductMemory | None = None,
holdings: CustomerHoldingsMemory | None = None,
composed: ComposedProfileService | None = None,
long_term: LongTermMemoryService | None = None,
archiver: ConversationArchiver | None = None,
rank_tool: FinalConfidenceRankTool | None = None,
@@ -43,6 +47,13 @@ class MemoryService:
self.work_orders = work_orders or WorkOrderMemory()
self.relations = relations or CustomerRelationMemory()
self.products = products or CustomerProductMemory()
self.holdings = holdings or CustomerHoldingsMemory()
self.composed = composed or ComposedProfileService(
profile=self.profile,
long_term=self.long_term,
holdings=self.holdings,
redis=self.short_term.redis,
)
self.long_term = long_term or LongTermMemoryService()
self.archiver = archiver or ConversationArchiver(short_term=self.short_term)
self.rank_tool = rank_tool or FinalConfidenceRankTool()
@@ -109,11 +120,35 @@ class MemoryService:
top_k=limit,
)
ranked_memories = [MemoryUnitDTO.model_validate(item) for item in ranked]
holdings_summary = None
try:
holdings_summary, holdings_warnings = await self.holdings.summary(
db, customer_id
)
warnings.extend(holdings_warnings)
except Exception as exc:
warnings.append(f"holdings_recall_failed:{type(exc).__name__}")
composed_payload: dict[str, Any] | None = None
try:
composed_payload, composed_warnings = await self.composed.compose(
db,
customer_id=customer_id,
query=query,
profile=profile,
memories=ranked,
holdings_summary=holdings_summary,
)
warnings.extend(composed_warnings)
except Exception as exc:
warnings.append(f"composed_profile_failed:{type(exc).__name__}")
return build_customer_memory_context(
customer_id=customer_id,
session_id=session_id,
short_term_messages=short_term_messages,
customer_profile=profile,
composed_profile=composed_payload,
work_orders=work_orders,
customer_relations=customer_relations,
customer_products=customer_products,
@@ -155,6 +190,10 @@ class MemoryService:
"""记录一次重复兴趣主题信号,达到阈值后允许写入长期记忆。"""
return await self.interest_tracker.record(customer_id, tag)
async def invalidate_composed(self, customer_id: int) -> list[str]:
"""失效最终画像缓存,供画像回写/持仓变更后调用。"""
return await self.composed.invalidate(customer_id)
async def close_session(
self,
*,