测试代码
python
"""
MemU 框架完整 CRUD 操作示例
这个脚本演示了如何使用 MemU 框架进行:
- Create(创建):创建新的记忆项
- Read(读取):读取和查询记忆项
- Update(更新):更新现有记忆项
- Delete(删除):删除记忆项
- Retrieve(检索):使用自然语言检索记忆
使用方法:
python test.py
"""
import asyncio
import os
from typing import Dict, List, Any
from memu.app import MemoryService
class MemUCRUDDemo:
"""MemU CRUD 操作演示类"""
def __init__(self, api_key: str):
"""初始化 MemoryService"""
self.service = MemoryService(
# LLM 配置
llm_profiles={
"default": {
"base_url": "https://api.siliconflow.cn/v1",
"api_key": api_key,
"chat_model": "Qwen/Qwen2.5-Coder-32B-Instruct",
"client_backend": "sdk"
},
"embedding": {
"base_url": "https://api.siliconflow.cn/v1",
"api_key": api_key,
"embed_model": "BAAI/bge-large-zh-v1.5"
}
},
# PostgreSQL 数据库配置(Docker 容器,端口 5433)
database_config={
"metadata_store": {
"provider": "postgres",
"dsn": "postgresql://root:123456@localhost:5433/root"
}
},
# 记忆类别配置
memorize_config={
"memory_categories": [
{"name": "personal_info", "description": "个人信息和基本资料"},
{"name": "skills", "description": "技能和专业能力"},
{"name": "preferences", "description": "偏好和习惯"},
{"name": "work_experience", "description": "工作经验和项目经历"},
]
},
)
self.created_items = [] # 存储创建的记忆项 ID
async def demo_create(self) -> List[str]:
"""演示创建(Create)操作"""
print("\n" + "="*60)
print("1. CREATE(创建)操作演示")
print("="*60)
# 创建多个不同类型的记忆项
memories_to_create = [
{
"memory_type": "profile",
"memory_content": "用户名叫张三,是一位30岁的软件工程师,居住在北京",
"memory_categories": ["personal_info"],
},
{
"memory_type": "skill",
"memory_content": "精通 Python、JavaScript 和 Go 语言,有5年全栈开发经验",
"memory_categories": ["skills"],
},
{
"memory_type": "behavior",
"memory_content": "喜欢早上编码,习惯使用 VS Code 编辑器,偏好敏捷开发方法",
"memory_categories": ["preferences"],
},
{
"memory_type": "event",
"memory_content": "2023年主导开发了一个微服务架构的电商平台,服务百万用户",
"memory_categories": ["work_experience"],
},
]
created_ids = []
for idx, memory_data in enumerate(memories_to_create, 1):
try:
result = await self.service.create_memory_item(**memory_data)
item_id = result.get("memory_item", {}).get("id")
created_ids.append(item_id)
print(f"\n[OK] 记忆项 {idx} 创建成功:")
print(f" - ID: {item_id}")
print(f" - 类型: {memory_data['memory_type']}")
print(f" - 内容: {memory_data['memory_content'][:50]}...")
print(f" - 分类: {', '.join(memory_data['memory_categories'])}")
except Exception as e:
print(f"\n[FAIL] 记忆项 {idx} 创建失败: {e}")
self.created_items = created_ids
print(f"\n总计创建了 {len(created_ids)} 个记忆项")
return created_ids
async def demo_read(self, item_ids: List[str]):
"""演示读取(Read)操作"""
print("\n" + "="*60)
print("2. READ(读取)操作演示")
print("="*60)
if not item_ids:
print("\n没有可读取的记忆项")
return
# 读取单个记忆项(通过 list 方法)
print("\n--- 读取单个记忆项 ---")
try:
first_item_id = item_ids[0]
# MemU 没有 get_memory_item 方法,使用 list_memory_items 获取所有项
all_items_result = await self.service.list_memory_items()
all_items = all_items_result.get('items', [])
# 在结果中查找指定 ID 的项
item = next((i for i in all_items if i.get('id') == first_item_id), None)
if item:
print(f"\n[OK] 成功读取记忆项:")
print(f" - ID: {item.get('id')}")
print(f" - 类型: {item.get('memory_type')}")
print(f" - 摘要: {item.get('summary')}")
print(f" - 创建时间: {item.get('created_at')}")
else:
print(f"\n[FAIL] 未找到 ID 为 {first_item_id} 的记忆项")
except Exception as e:
print(f"\n[FAIL] 读取失败: {e}")
# 列出所有记忆项
print("\n--- 列出所有记忆项 ---")
try:
result = await self.service.list_memory_items()
items = result.get('items', [])
print(f"\n[OK] 找到 {len(items)} 个记忆项:")
for idx, item in enumerate(items, 1):
print(f"\n {idx}. ID: {item.get('id')}")
print(f" 类型: {item.get('memory_type')}")
print(f" 摘要: {item.get('summary', '')[:60]}...")
except Exception as e:
print(f"\n[FAIL] 列出记忆项失败: {e}")
# 列出所有类别
print("\n--- 列出所有记忆类别 ---")
try:
result = await self.service.list_memory_categories()
categories = result.get('categories', [])
print(f"\n[OK] 找到 {len(categories)} 个类别:")
for idx, category in enumerate(categories, 1):
print(f"\n {idx}. 名称: {category.get('name')}")
print(f" 描述: {category.get('description', 'N/A')}")
summary = category.get('summary', '')
if summary:
print(f" 摘要: {summary[:80]}...")
except Exception as e:
print(f"\n[FAIL] 列出类别失败: {e}")
async def demo_update(self, item_ids: List[str]):
"""演示更新(Update)操作"""
print("\n" + "="*60)
print("3. UPDATE(更新)操作演示")
print("="*60)
if not item_ids:
print("\n没有可更新的记忆项")
return
# 更新第一个记忆项
try:
item_id = item_ids[0]
# 先读取原始内容
all_items_result = await self.service.list_memory_items()
all_items = all_items_result.get('items', [])
original = next((i for i in all_items if i.get('id') == item_id), None)
if original:
print(f"\n原始内容:")
print(f" - 摘要: {original.get('summary')}")
# 更新内容(参数名是 memory_id,不是 item_id)
updated_content = "用户名叫张三,是一位30岁的高级软件工程师,居住在北京,拥有计算机硕士学位"
result = await self.service.update_memory_item(
memory_id=item_id, # 注意:参数名是 memory_id
memory_content=updated_content,
)
print(f"\n[OK] 记忆项更新成功:")
print(f" - ID: {item_id}")
print(f" - 新内容: {updated_content}")
# 再次读取验证更新
await asyncio.sleep(1) # 等待更新完成
all_items_result = await self.service.list_memory_items()
all_items = all_items_result.get('items', [])
updated = next((i for i in all_items if i.get('id') == item_id), None)
if updated:
print(f"\n更新后的摘要:")
print(f" - {updated.get('summary')}")
else:
print(f"\n[FAIL] 未找到 ID 为 {item_id} 的记忆项")
except Exception as e:
print(f"\n[FAIL] 更新失败: {e}")
async def demo_retrieve(self):
"""演示检索(Retrieve)操作"""
print("\n" + "="*60)
print("4. RETRIEVE(检索)操作演示")
print("="*60)
# 定义多个查询
queries = [
"用户的基本信息是什么?",
"用户会哪些编程语言?",
"用户的工作习惯和偏好",
"用户有什么项目经验?",
]
for idx, query_text in enumerate(queries, 1):
print(f"\n--- 查询 {idx}: {query_text} ---")
try:
# 使用 RAG 方法检索(方法在初始化时配置)
result = await self.service.retrieve(
queries=[{"role": "user", "content": {"text": query_text}}]
)
# 显示检索结果
items = result.get("items", [])
categories = result.get("categories", [])
print(f"\n[OK] 找到 {len(items)} 个相关记忆项:")
for item_idx, item in enumerate(items[:3], 1): # 只显示前3个
print(f"\n {item_idx}. 类型: {item.get('memory_type')}")
print(f" 摘要: {item.get('summary', '')[:80]}...")
if 'score' in item:
print(f" 相似度: {item.get('score', 0):.4f}")
if categories:
print(f"\n 相关类别: {', '.join([c.get('name', '') for c in categories[:3]])}")
except Exception as e:
print(f"\n[FAIL] 检索失败: {e}")
async def demo_delete(self, item_ids: List[str]):
"""演示删除(Delete)操作"""
print("\n" + "="*60)
print("5. DELETE(删除)操作演示")
print("="*60)
if not item_ids:
print("\n没有可删除的记忆项")
return
# 删除最后一个记忆项
if len(item_ids) > 0:
item_id = item_ids[-1]
try:
# 先读取要删除的项
all_items_result = await self.service.list_memory_items()
all_items = all_items_result.get('items', [])
item = next((i for i in all_items if i.get('id') == item_id), None)
if item:
print(f"\n准备删除记忆项:")
print(f" - ID: {item_id}")
print(f" - 类型: {item.get('memory_type')}")
print(f" - 摘要: {item.get('summary', '')[:60]}...")
# 执行删除(参数名是 memory_id,不是 item_id)
await self.service.delete_memory_item(memory_id=item_id)
print(f"\n[OK] 记忆项删除成功")
# 验证删除
await asyncio.sleep(1) # 等待删除完成
all_items_result = await self.service.list_memory_items()
all_items = all_items_result.get('items', [])
deleted_item = next((i for i in all_items if i.get('id') == item_id), None)
if deleted_item:
print(f"\n[FAIL] 警告: 记忆项仍然存在")
else:
print(f"[OK] 验证: 记忆项已被删除")
else:
print(f"\n[FAIL] 未找到 ID 为 {item_id} 的记忆项")
except Exception as e:
print(f"\n[FAIL] 删除失败: {e}")
async def demo_memorize(self):
"""演示 memorize() 方法 - 从文件提取记忆"""
print("\n" + "="*60)
print("6. MEMORIZE(记忆化)操作演示")
print("="*60)
# 创建一个临时对话文件
import json
import tempfile
conversation = {
"messages": [
{"role": "user", "content": "我最近在学习 Rust 语言"},
{"role": "assistant", "content": "很好!Rust 是一门很棒的系统编程语言"},
{"role": "user", "content": "是的,我特别喜欢它的内存安全特性"},
{"role": "assistant", "content": "Rust 的所有权系统确实很独特"},
]
}
# 创建临时文件
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False, encoding='utf-8') as f:
json.dump(conversation, f, ensure_ascii=False)
temp_file = f.name
try:
print(f"\n从对话文件提取记忆...")
print(f"文件: {temp_file}")
result = await self.service.memorize(
resource_url=temp_file,
modality="conversation"
)
items = result.get("items", [])
categories = result.get("categories", [])
print(f"\n[OK] 记忆化成功:")
print(f" - 提取了 {len(items)} 个记忆项")
print(f" - 更新了 {len(categories)} 个类别")
if items:
print(f"\n 提取的记忆项:")
for idx, item in enumerate(items, 1):
print(f"\n {idx}. 类型: {item.get('memory_type')}")
print(f" 摘要: {item.get('summary', '')[:60]}...")
except Exception as e:
print(f"\n[FAIL] 记忆化失败: {e}")
finally:
# 清理临时文件
try:
os.unlink(temp_file)
except:
pass
async def main():
"""主函数 - 运行所有 CRUD 演示"""
print("\n" + "="*60)
print("MemU 框架 CRUD 操作完整演示")
print("="*60)
# 创建演示实例
api_key = "硅基流动秘钥!"
demo = MemUCRUDDemo(api_key)
try:
# 1. 创建记忆项
created_ids = await demo.demo_create()
print(created_ids)
# 等待一下,确保数据已保存
await asyncio.sleep(1)
# 2. 读取记忆项
await demo.demo_read(created_ids)
# 3. 更新记忆项
await demo.demo_update(created_ids)
# 4. 检索记忆
await demo.demo_retrieve()
# 5. 记忆化操作
await demo.demo_memorize()
# 6. 删除记忆项
await demo.demo_delete(created_ids)
except Exception as e:
print(f"\n发生错误: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
asyncio.run(main())
前置条件
✅ Docker Desktop 已安装并运行
✅ 端口 5433 未被占用
步骤 1:拉取并启动 PostgreSQL 容器
打开命令行,执行:
bash
docker run -d \
--name memu-postgres \
-e POSTGRES_USER=root \
-e POSTGRES_PASSWORD=123456 \
-e POSTGRES_DB=root \
-p 5433:5432 \
pgvector/pgvector:pg16
参数说明:
- -d: 后台运行
- --name memu-postgres: 容器名称
- -e POSTGRES_USER=root: 数据库用户名
- -e POSTGRES_PASSWORD=123456: 数据库密码
- -e POSTGRES_DB=root: 默认数据库名
- -p 5433:5432: 端口映射(宿主机5433 → 容器5432)
- pgvector/pgvector:pg16: 使用带 pgvector 的 PostgreSQL 16 镜像
步骤 2:验证容器运行状态
bash
docker ps | findstr memu-postgres
预期输出:
f045f26e59ce pgvector/pgvector:pg16 ... Up X minutes 0.0.0.0:5433->5432/tcp memu-postgres
步骤 3:验证 pgvector 扩展
bash
docker exec memu-postgres psql -U root -d root -c "CREATE EXTENSION IF NOT EXISTS vector;"
预期输出:
CREATE EXTENSION
步骤 4:安装 Python 依赖
bash
pip install psycopg2-binary asyncpg pgvector
预期输出:
Successfully installed asyncpg-0.31.0 psycopg2-binary-2.9.11 pgvector-0.4.2
步骤 5:配置 MemU 框架
编辑 test.py 文件,在 MemoryService 初始化中添加:
bash
self.service = MemoryService(
llm_profiles={
"default": {
"base_url": "https://api.siliconflow.cn/v1",
"api_key": api_key,
"chat_model": "Qwen/Qwen2.5-Coder-32B-Instruct",
"client_backend": "sdk"
},
"embedding": {
"base_url": "https://api.siliconflow.cn/v1",
"api_key": api_key,
"embed_model": "BAAI/bge-large-zh-v1.5"
}
},
# PostgreSQL 数据库配置
database_config={
"metadata_store": {
"provider": "postgres",
"dsn": "postgresql://root:123456@localhost:5433/root"
}
},
memorize_config={
"memory_categories": [
{"name": "personal_info", "description": "个人信息和基本资料"},
{"name": "skills", "description": "技能和专业能力"},
{"name": "preferences", "description": "偏好和习惯"},
{"name": "work_experience", "description": "工作经验和项目经历"},
]
},
)
步骤 6:测试连接
运行测试脚本:
bash
python test.py
预期输出:
bash
============================================================
MemU 框架 CRUD 操作完整演示
============================================================
============================================================
1. CREATE(创建)操作演示
============================================================
[OK] 记忆项 1 创建成功:
- ID: b0e80599-1910-46a5-a7cf-bea4f4a35fbc
...
---
步骤 7:验证数据持久化
查看数据库表:
bash
docker exec memu-postgres psql -U root -d root -c "\dt"
预期输出:
bash
Schema | Name | Type | Owner
--------+-------------------+-------+-------
public | alembic_version | table | root
public | category_items | table | root
public | memory_categories | table | root
public | memory_items | table | root
public | resources | table | root
查看记忆项数量:
bash
docker exec memu-postgres psql -U root -d root -c "SELECT COUNT(*) FROM memory_items;"
步骤 8:Navicat 连接配置
bash
在 Navicat 中创建新的 PostgreSQL 连接:
连接名: MemU-PostgreSQL
主机: localhost
端口: 5433
初始数据库: root
用户名: root
密码: 123456
点击"测试连接" → "连接成功" → "确定"
常用容器管理命令
查看容器状态
bash
docker ps | findstr memu-postgres
停止容器
bash
docker stop memu-postgres
启动容器
bash
docker start memu-postgres
重启容器
bash
docker restart memu-postgres
查看容器日志
bash
docker logs memu-postgres
删除容器(会丢失数据)
bash
docker rm -f memu-postgres
数据库操作
进入 PostgreSQL 命令行
bash
docker exec -it memu-postgres psql -U root -d root
查看所有表
bash
docker exec memu-postgres psql -U root -d root -c "\dt"
查看记忆项
bash
docker exec memu-postgres psql -U root -d root -c "SELECT * FROM memory_items;"
查看记忆类别
bash
docker exec memu-postgres psql -U root -d root -c "SELECT * FROM memory_categories;"
清空所有数据(慎用)
bash
docker exec memu-postgres psql -U root -d root -c "TRUNCATE memory_items, category_items, memory_categories, resources CASCADE;"
数据备份与恢复
备份数据库
bash
docker exec memu-postgres pg_dump -U root root > memu_backup.sql
恢复数据库
bash
docker exec -i memu-postgres psql -U root -d root < memu_backup.sql
优势总结
✅ 一键安装:一条命令完成 PostgreSQL + pgvector 安装
✅ 环境隔离:不影响现有的 PostgreSQL(端口 5432)
✅ 数据持久化:数据存储在 Docker volume 中,容器重启不丢失
✅ 易于管理:使用 Docker 命令轻松管理
✅ 跨平台:Windows/Linux/Mac 都可以使用相同的命令
故障排查
问题 1:端口被占用
检查端口占用
bash
netstat -ano | findstr :5433
使用其他端口(如 5434)
bash
docker run -d --name memu-postgres ... -p 5434:5432 ...
记得修改 test.py 中的端口号
问题 2:容器无法启动
查看错误日志
bash
docker logs memu-postgres
删除旧容器重新创建
bash
docker rm -f memu-postgres
然后重新执行步骤 1
问题 3:连接被拒绝
确认容器正在运行
bash
docker ps | findstr memu-postgres
确认端口映射正确
bash
docker port memu-postgres
这就是完整的安装和配置流程!你现在已经有一个功能完整的 PostgreSQL + pgvector 数据库用于 MemU 框架了。🎉