尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Agent持久化记忆与Redis+MySQL混合存储架构实践

Agent持久化记忆与Redis+MySQL混合存储架构实践 1. 项目概述在Agent开发领域持久化记忆和会话连续性一直是提升用户体验的关键技术痛点。想象一下当你与智能助手对话时如果每次重启应用都需要重新介绍自己、重复之前的对话内容这种体验有多糟糕。这正是我们需要为Agent构建海马体的原因——通过持久化记忆实现断点续聊功能。这个项目的核心目标是为Agent系统赋予长期记忆能力使其能够跨会话保存用户交互历史记住用户偏好和个性化设置在服务重启后恢复之前的对话上下文实现多设备间的状态同步2. 技术选型与架构设计2.1 存储方案对比我们主要评估了两种主流存储方案特性RedisMySQL数据类型键值、哈希、列表、集合等关系型表格读写性能极高(10万/秒)中等(数千/秒)持久化机制RDB快照/AOF日志ACID事务保障适用场景高频读写/临时数据结构化数据/复杂查询内存占用全内存操作磁盘缓冲池2.2 混合存储架构基于性能与可靠性的平衡我们采用RedisMySQL的混合架构[Agent服务] ├── [Redis] # 处理实时会话数据 │ ├── 会话状态缓存 │ ├── 短期记忆存储 │ └── 高频访问数据 └── [MySQL] # 持久化核心数据 ├── 用户档案 ├── 长期对话历史 └── 知识图谱Redis作为前端高速缓存处理实时性要求高的操作MySQL作为后端持久化存储确保数据可靠性。两者通过定时同步机制保持数据一致性。3. 核心实现细节3.1 记忆数据结构设计会话记忆模型class ConversationMemory: def __init__(self): self.session_id uuid.uuid4().hex # 唯一会话标识 self.user_profile {} # 用户特征 self.dialog_stack [] # 对话上下文栈 self.preferences { # 用户偏好 language: zh-CN, timezone: Asia/Shanghai } self.knowledge_graph {} # 个性化知识图谱Redis存储方案使用Hash存储用户档案使用List存储对话历史使用Sorted Set实现时间线索引设置合理的TTL实现自动过期3.2 断点续聊实现流程会话初始化def init_session(user_id): # 检查Redis中是否有未完成会话 session_data redis.hgetall(fsession:{user_id}) if session_data: # 恢复已有会话 memory deserialize(session_data) else: # 从MySQL加载基础档案 profile mysql.query(SELECT * FROM user_profiles WHERE id%s, user_id) # 创建新会话 memory ConversationMemory() memory.user_profile profile return memory对话状态保存def save_context(memory): # 实时保存到Redis redis.hmset(fsession:{memory.session_id}, serialize(memory)) # 异步写入MySQL queue.enqueue(background_save, memory) def background_save(memory): with mysql.transaction(): # 保存对话历史 mysql.execute( INSERT INTO conversation_history VALUES (%s, %s, %s), (memory.session_id, memory.user_profile[id], json.dumps(memory.dialog_stack)) ) # 更新用户偏好 mysql.execute( UPDATE user_profiles SET preferences%s WHERE id%s, (json.dumps(memory.preferences), memory.user_profile[id]) )3.3 记忆压缩与检索优化长期运行的Agent会积累大量记忆数据需要特殊处理记忆分级策略短期记忆保留最近7天完整对话Redis存储中期记忆保留30天内摘要信息MySQL存储长期记忆提取关键特征存入知识图谱记忆检索优化def retrieve_memory(user_id, query): # 先从Redis查询近期记忆 recent redis.lrange(frecent_mem:{user_id}, 0, -1) matches fuzzy_search(recent, query) if not matches: # 查询中期记忆 mids mysql.query( SELECT summary FROM midterm_memory WHERE user_id%s AND created_at%s, (user_id, datetime.now()-timedelta(days30)) ) matches fuzzy_search(mids, query) if not matches: # 查询知识图谱 matches knowledge_graph.search(user_id, query) return matches[:5] # 返回最相关的5条记忆4. 性能优化实践4.1 Redis调优技巧管道化操作pipe redis.pipeline() pipe.hset(fuser:{user_id}, last_active, now()) pipe.expire(fsession:{session_id}, 3600) pipe.execute()内存优化配置# redis.conf关键参数 maxmemory 2gb maxmemory-policy allkeys-lru hash-max-ziplist-entries 512 hash-max-ziplist-value 64连接池管理redis_pool ConnectionPool( hostlocalhost, port6379, max_connections50, socket_timeout5 )4.2 MySQL优化策略索引设计CREATE INDEX idx_user_sessions ON conversation_history (user_id, created_at DESC);分表策略def get_history_table(user_id): # 按用户ID哈希分表 table_num hash(user_id) % 16 return fconversation_history_{table_num}批量插入优化# 使用executemany批量插入 data [(s.id, s.user_id, s.data) for s in sessions] mysql.executemany( INSERT INTO conversation_history VALUES (%s,%s,%s), data )5. 常见问题与解决方案5.1 数据一致性问题场景Redis缓存与MySQL数据库不一致解决方案双写策略所有更新同时写入Redis和MySQL异步校验定时任务检查数据差异故障恢复通过MySQL日志重建Redis缓存def consistent_update(memory): # 开启事务 with mysql.transaction(): # 先更新MySQL update_mysql(memory) # 再更新Redis update_redis(memory) # 设置Redis过期时间 redis.expire(fsession:{memory.session_id}, 3600)5.2 内存溢出问题场景长期运行后Redis内存占用过高解决方案实施记忆分级策略设置合理的TTL使用SCAN代替KEYS遍历监控内存使用情况def clean_old_memories(): cursor 0 while cursor ! 0: cursor, keys redis.scan( cursorcursor, matchsession:*, count100 ) for key in keys: last_active redis.hget(key, last_active) if last_active (now() - 86400): redis.delete(key)5.3 会话恢复失败场景服务重启后无法恢复完整会话状态解决方案实现会话快照机制定期持久化关键状态增加校验和恢复流程def restore_session(session_id): # 尝试从Redis恢复 data redis.hgetall(fsession:{session_id}) if data: return deserialize(data) # 从MySQL恢复 data mysql.query( SELECT data FROM session_backups WHERE session_id%s, session_id ) if data: # 重建Redis缓存 redis.hmset(fsession:{session_id}, data) return deserialize(data) raise SessionNotFoundError6. 扩展与进阶6.1 多设备同步方案实现跨设备状态同步需要考虑冲突解决策略最后写入优先/人工确认增量同步机制状态压缩算法def sync_devices(user_id, new_state): # 获取当前所有设备状态 devices redis.smembers(fuser_devices:{user_id}) # 比较版本号 for device in devices: device_state redis.get(fdevice_state:{device}) if device_state[version] new_state[version]: # 推送状态更新 push_notification(device, new_state) # 更新主状态 redis.set(fuser_state:{user_id}, new_state)6.2 记忆个性化处理高级记忆处理技术包括基于重要性的记忆衰减算法情感标记的记忆强化上下文相关的记忆激活def update_memory_weights(memory): for event in memory.events: # 基于时间衰减 time_decay 0.9 ** ((now() - event.time).days) # 基于情感强化 emotion_boost 1 0.5 * event.emotion_score # 基于频率调整 freq_factor math.log(1 event.access_count) # 综合权重 event.weight time_decay * emotion_boost * freq_factor # 标准化权重 total sum(e.weight for e in memory.events) for event in memory.events: event.weight / total6.3 性能监控指标关键监控指标及采集方法指标名称采集方式告警阈值会话恢复成功率日志分析/探针检测99.9%记忆检索延迟Redis/Mysql慢查询日志200ms内存使用率Redis INFO命令80%数据同步延迟时间戳比对5秒请求吞吐量应用层埋点低于基线30%实施示例def monitor_performance(): metrics { redis_mem: redis.info()[used_memory], qps: get_qps_counter(), sync_lag: get_sync_lag() } if metrics[redis_mem] config.MAX_REDIS_MEM: alert(Redis内存过高) if metrics[sync_lag] 5000: # 5秒 alert(数据同步延迟过高)在实际部署中我们发现当用户对话历史超过10万条时直接使用LIKE查询会导致性能急剧下降。通过引入Elasticsearch作为二级索引将检索耗时从1200ms降低到了80ms左右。具体实现是为每条记忆生成关键词索引使用ES的倒排索引加速查找同时保持主数据仍在Redis/MySQL中。
返回列表