fischer-agentkit/src/agentkit/memory/working.py

98 lines
3.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Working Memory - 基于 Redis 的短期任务记忆"""
import json
import logging
from datetime import datetime, timezone
from typing import Any
import redis.asyncio as aioredis
from agentkit.memory.base import Memory, MemoryItem
logger = logging.getLogger(__name__)
class WorkingMemory(Memory):
"""Working Memory - 当前任务的上下文和中间状态
基于 Redis 实现支持自动过期TTL
生命周期:单次任务。
"""
def __init__(
self,
redis: aioredis.Redis,
key_prefix: str = "agentkit:working",
default_ttl: int = 3600,
):
self._redis = redis
self._key_prefix = key_prefix
self._default_ttl = default_ttl
def _make_key(self, key: str) -> str:
return f"{self._key_prefix}:{key}"
async def store(self, key: str, value: Any, metadata: dict[str, Any] | None = None) -> None:
redis_key = self._make_key(key)
item = MemoryItem(
key=key,
value=value,
metadata=metadata or {},
created_at=datetime.now(timezone.utc),
)
await self._redis.setex(
redis_key,
self._default_ttl,
json.dumps(item.to_dict(), default=str),
)
async def retrieve(self, key: str) -> MemoryItem | None:
redis_key = self._make_key(key)
data = await self._redis.get(redis_key)
if data is None:
return None
item_dict = json.loads(data)
return MemoryItem(
key=item_dict["key"],
value=item_dict["value"],
metadata=item_dict.get("metadata", {}),
score=item_dict.get("score", 1.0),
created_at=datetime.fromisoformat(item_dict["created_at"]) if item_dict.get("created_at") else datetime.now(timezone.utc),
)
async def search(self, query: str, top_k: int = 5, filters: dict[str, Any] | None = None) -> list[MemoryItem]:
"""Working Memory 不支持语义检索,按 key 前缀匹配"""
pattern = self._make_key(f"{query}*")
keys = []
async for key in self._redis.scan_iter(match=pattern, count=top_k):
keys.append(key)
if len(keys) >= top_k:
break
items = []
for key in keys:
data = await self._redis.get(key)
if data:
item_dict = json.loads(data)
items.append(MemoryItem(
key=item_dict["key"],
value=item_dict["value"],
metadata=item_dict.get("metadata", {}),
score=1.0,
created_at=datetime.now(timezone.utc),
))
return items
async def delete(self, key: str) -> bool:
redis_key = self._make_key(key)
return bool(await self._redis.delete(redis_key))
async def clear(self, prefix: str = "") -> int:
"""清除指定前缀的所有 Working Memory"""
pattern = self._make_key(f"{prefix}*")
count = 0
async for key in self._redis.scan_iter(match=pattern):
await self._redis.delete(key)
count += 1
return count