memoryweave/scripts/migrate_hermes.py

107 lines
3.3 KiB
Python
Raw Permalink 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.

"""Hermes LanceDB → 织忆 MemoryWeave 迁移脚本 (v2)
用单条 commit走服务端 BGE 编码,确保向量对齐。
"""
import json, time, requests
from concurrent.futures import ThreadPoolExecutor, as_completed
import lancedb
import pyarrow as pa
HERMES_DB = "/home/muc/.hermes/memory_db/lancedb"
ZHIYI_URL = "http://localhost:7821"
ZHIYI_KEY = "zhiyi-dev-key-2026"
WORKERS = 4
def log(msg):
print(f"[migrate] {msg}", flush=True)
def arrow_to_dicts(table: pa.Table) -> list[dict]:
rows = []
cols = table.column_names
for i in range(table.num_rows):
row = {}
for c in cols:
row[c] = table.column(c)[i].as_py()
rows.append(row)
return rows
def commit_one(r: dict) -> bool:
"""提交单条记忆到织忆"""
content = str(r.get("content", r.get("text", "")))
if not content.strip():
return False
try:
resp = requests.post(
f"{ZHIYI_URL}/api/v1/commit",
headers={"X-API-Key": ZHIYI_KEY, "Content-Type": "application/json"},
json={
"content": content,
"category": str(r.get("category", "general")),
"namespace": "hermes-main",
"agent_id": "hermes-a06",
},
timeout=30,
)
return resp.status_code in (200, 201)
except:
return False
def main():
log(f"打开 Hermes LanceDB: {HERMES_DB}")
db = lancedb.connect(HERMES_DB)
tables = db.table_names()
log(f"发现 {len(tables)} 个表: {tables}")
all_records = []
for tbl_name in tables:
tbl = db.open_table(tbl_name)
rows = arrow_to_dicts(tbl.to_arrow())
log(f" {tbl_name}: {len(rows)}")
all_records.extend(rows)
total = len(all_records)
log(f"总计 {total}准备迁移到织忆namespace=hermes-main")
if total == 0:
log("无可迁移数据,退出")
return
# 并发迁移
migrated = 0
failed = 0
start = time.time()
with ThreadPoolExecutor(max_workers=WORKERS) as pool:
futures = {pool.submit(commit_one, r): i for i, r in enumerate(all_records)}
for f in as_completed(futures):
idx = futures[f]
try:
if f.result():
migrated += 1
else:
failed += 1
except:
failed += 1
if (migrated + failed) % 50 == 0:
elapsed = time.time() - start
rate = (migrated + failed) / elapsed
log(f" [{migrated+failed}/{total}] ✅{migrated}{failed} ({rate:.1f}/s)")
# 验证
log(f"\n迁移完成: ✅{migrated}{failed} / {total} ({time.time()-start:.0f}s)")
resp = requests.get(f"{ZHIYI_URL}/api/v1/stats", headers={"X-API-Key": ZHIYI_KEY})
stats = resp.json()
log(f"织忆当前: {stats['total_memories']} 条记忆")
# 召回验证
test = requests.post(
f"{ZHIYI_URL}/api/v1/recall",
headers={"X-API-Key": ZHIYI_KEY, "Content-Type": "application/json"},
json={"query": "牧尘用什么系统", "limit": 3},
).json()
log(f"召回测试: {test['count']} 条, top={test['results'][0]['content'][:60] if test['results'] else 'N/A'}")
log("✅ 迁移完成")
if __name__ == "__main__":
main()