初始化提交
This commit is contained in:
commit
887c1f449e
963 files changed
+166869
No files matched your search
Whitespace-only changes.
@@ -0,0 +1,91 @@
|
||||
"""记忆上下文组装与检索结果数据结构(纯领域,无 IO)。
|
||||
|
||||
``MemoryRetrievalResult`` 持有已加载的 Memory ORM 实例(由 services/memory 检索后传入),
|
||||
``build_memory_context`` 把它组装成注入上下文的文本。本模块只接收已加载数据、输出结构化对象。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
|
||||
from app.core.time import utc_now
|
||||
from app.models.memory import Memory
|
||||
|
||||
|
||||
class MemoryRetrievalResult(BaseModel):
|
||||
"""记忆检索结果(持有已加载的 Memory ORM 实例列表)。"""
|
||||
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
|
||||
memories: list[Memory]
|
||||
|
||||
|
||||
def _to_aware(dt: datetime | None) -> datetime | None:
|
||||
"""确保 datetime 有时区信息,naive 视为 UTC。"""
|
||||
if dt is None:
|
||||
return None
|
||||
if dt.tzinfo is None:
|
||||
return dt.replace(tzinfo=UTC)
|
||||
return dt
|
||||
|
||||
|
||||
def build_memory_context(result: MemoryRetrievalResult, *, max_length: int = 3000) -> str | None:
|
||||
"""把检索到的记忆组装成注入上下文的文本;无记忆时返回 None。
|
||||
|
||||
按**重要性降序**排列,每条附带重要性标签和相对时间。
|
||||
超过 ``max_length`` 字符时截断,避免上下文窗口膨胀。
|
||||
"""
|
||||
if not result.memories:
|
||||
return None
|
||||
|
||||
now = utc_now()
|
||||
|
||||
def _mem_sort_key(m: Memory) -> float:
|
||||
"""排序键:重要性(越高越优先),同时辅助时间衰减。"""
|
||||
ca = _to_aware(m.created_at)
|
||||
hours_ago = (now - ca).total_seconds() / 3600 if ca else 0
|
||||
decay = max(0.5, 1.0 - hours_ago / 720) # 30 天内缓慢衰减
|
||||
return (m.importance or 0.5) * decay
|
||||
|
||||
sorted_mems = sorted(result.memories, key=_mem_sort_key, reverse=True)
|
||||
|
||||
lines: list[str] = []
|
||||
total_chars = 0
|
||||
for idx, item in enumerate(sorted_mems):
|
||||
importance_label = _importance_label(item.importance)
|
||||
ca = _to_aware(item.created_at)
|
||||
hours_ago = (now - ca).total_seconds() / 3600 if ca else 0
|
||||
time_label = _time_ago_str(hours_ago)
|
||||
line = f"- 「{item.title}」{time_label} [{importance_label}]\n {item.content}"
|
||||
line_len = len(line) + 1 # +1 for newline
|
||||
if total_chars + line_len > max_length:
|
||||
remaining = len(sorted_mems) - idx
|
||||
if remaining > 0:
|
||||
lines.append(f"…以及 {remaining} 条其他记忆(已截断)")
|
||||
break
|
||||
lines.append(line)
|
||||
total_chars += line_len
|
||||
|
||||
return "相关记忆:\n" + "\n".join(lines)
|
||||
|
||||
|
||||
def _importance_label(importance: float) -> str:
|
||||
if importance >= 0.8:
|
||||
return "★重要"
|
||||
if importance >= 0.5:
|
||||
return "●一般"
|
||||
return "○参考"
|
||||
|
||||
|
||||
def _time_ago_str(hours_ago: float) -> str:
|
||||
if hours_ago < 1:
|
||||
return "刚刚"
|
||||
if hours_ago < 24:
|
||||
return f"{int(hours_ago)}小时前"
|
||||
days = int(hours_ago / 24)
|
||||
if days < 30:
|
||||
return f"{days}天前"
|
||||
months = int(days / 30)
|
||||
return f"{months}个月前"
|
||||
Reference in new issue
Block a user