From 987768d8352b6446a371d277c80b416b09f2cb34 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 9 Apr 2026 08:44:44 +0800 Subject: [PATCH] refactor: rename to Graph Memory Demo, remove OpenClaw branding --- README.md | 225 ++++++------------ docker/README.md | 8 +- docker/docker-compose.yml | 25 +- docker/start.sh | 8 +- ...claw_neo4j_demo.py => graph_memory_demo.py | 13 +- scripts/start_neo4j_docker.sh | 12 +- 6 files changed, 109 insertions(+), 182 deletions(-) rename openclaw_neo4j_demo.py => graph_memory_demo.py (98%) diff --git a/README.md b/README.md index e94a2e9..a91cef9 100644 --- a/README.md +++ b/README.md @@ -1,173 +1,92 @@ - OpenClaw: 零上下文图原生自主记忆系统 - 1. 核心范式 - 状态完全外部化:LLM实例不保留任何对话历史、不维护内部记忆、不依赖上下文窗口。每轮推理仅依赖: - - 当前用户输入 - - 图数据库实时查询返回的子图 - - 系统提供的元认知指令 - 模型即控制器:与传统"工具调用"不同,模型不是被动响应预设触发器,而是主动评估信息需求、自主决策记忆操作(查询/写入/删除/修正)。 - 图即唯一真相源:所有会话状态、实体关系、推理轨迹以节点-边形式持久化于Neo4j,模型通过显式工具调用与状态交互。 +# Graph Memory Demo - --- +纯图数据库记忆存储 Demo - 验证无上下文对话系统 - 2. 架构组件 - 2.1 工具层(Skill System) - { - "tools": [ - { - "name": "memory_recall", - "description": "当你对当前输入中的实体、指代、或关系不确定时,调用此工具检索相关记忆。输入为自然语言查询意图,系统将返回相关子图。", - "parameters": { - "query_intent": "string", // 模型用自然语言描述想查什么 - "seed_entities": ["string"], // 可选:已识别的实体ID - "depth": "number" // 期望的遍历深度,由模型根据复杂度决定 - } - }, - { - "name": "memory_commit", - "description": "当你认为当前对话包含对未来轮次有价值的信息时,将抽取的三元组写入图库。仅在信息具有跨轮次引用潜力时调用。", - "parameters": { - "triplets": [ - {"subject": "string", "relation": "string", "object": "string", "confidence": "float"} - ], - "entity_types": ["string"], // 模型动态提议类型 - "temporal_tag": "string" // 可选:时间标记(如'2026-04-08') - } - }, - { - "name": "memory_purge", - "description": "当你发现记忆中的信息与当前认知矛盾,或用户明确要求更正时,删除指定关系。优先于memory_commit执行以维护一致性。", - "parameters": { - "criteria": { - "subject_contains": "string", - "relation_type": "string", - "time_before": "string" - } - } - }, - { - "name": "memory_introspect", - "description": "检索当前对话会话的元数据:已讨论的实体、关系密度、记忆热点。用于自我监控信息缺口。", - "parameters": {} - } - ] - } +## 概述 - 2.2 控制流(每轮交互) - 用户输入 - ↓ - [LLM首次推理] → 评估:我是否理解所有实体和指代? - ↓ 是/否 - ├─→ 调用memory_recall(自主决定查询深度和范围) - │ └─→ 返回子图(JSON格式) - ├─→ 调用memory_introspect(可选:检查会话状态) - ↓ - [LLM二次推理] → 基于检索结果生成回复草稿 - ↓ - [LLM三次推理] → 评估:本次对话产生的新信息价值? - ↓ 高/低 - ├─→ 调用memory_commit(动态类型,可变粒度) - └─→ 跳过写入 - ↓ - 返回给用户 +本 Demo 验证使用 Neo4j 图数据库替代传统上下文窗口的可行性。每轮对话通过 DeepSeek API Tool Calls 实现自主记忆存取。 - 关键:每轮可能包含多次工具调用序列,模型自主编排调用顺序(如先purge后commit,或多次recall逐步探索)。 - 2.3 数据模型(动态Schema) - 节点: - (:Entity { - id: "模型生成或系统分配", - canonical_name: "标准命名", - aliases: ["别名列表"], - type: "模型动态提议", // 无封闭列表,系统仅做相似性归一化 - first_seen: timestamp, - last_accessed: timestamp, - access_count: int, - embedding: vector // 用于语义相似度去重 - }) +## 核心工具 - 关系: - (:Entity)-[:RELATION { - type: "模型定义的关系语义", - timestamp: timestamp, - session_id: "对话线程ID", - confidence: float, - valid_until: timestamp // 支持临时性知识 - }]->(:Entity) +| 工具 | 功能 | +|------|------| +| memory_recall | 检索历史记忆 | +| memory_commit | 写入记忆(三元组) | +| memory_purge | 修正/删除记忆 | +| memory_introspect | 查看会话状态 | +| memory_archive | 归档旧关系 | +| memory_cleanup | 物理清理 | - 会话锚点: - (:Session {id: "uuid", created: timestamp})-[:CONTAINS]->(:Entity) +## 快速开始 +### 1. 安装 Neo4j - --- +```bash +# Ubuntu/Debian +bash scripts/install_neo4j_ubuntu.sh - 3. 自治决策机制 - 3.1 元认知Prompt(系统指令) - 你是OpenClaw的自主记忆控制器。你的上下文窗口为空,你是无状态的。 +# CentOS/RHEL +bash scripts/install_neo4j_centos.sh - 可用记忆操作: - 1. recall: 当你遇到指代("那个"、"它"、"之前说的")、未知实体、或需要验证的事实时调用 - 2. commit: 仅当信息满足以下条件时写入: - - 用户明确偏好/属性("我喜欢Python") - - 跨轮次可引用的事实("项目X的截止日期是...") - - 推理链的关键中间结论 - 不要写入:临时例子、闲聊寒暄、已存储的冗余信息 - 3. purge: 检测到用户更正("不对,我是说...")或逻辑矛盾时立即执行 +# openEuler +bash scripts/install_neo4j_openeuler.sh - 决策原则: - - 不确定性驱动查询:只要存在歧义,优先recall而非猜测 - - 写入抑制:宁可少写,不要写噪(图库污染代价高) - - 类型复用:优先使用已存在的entity_types,新类型仅在语义无法归约时创建 +# Docker +bash scripts/start_neo4j_docker.sh +``` - 3.2 并发与一致性 - 竞态处理: - - 每轮工具调用携带session_id和turn_id - - Neo4j使用MERGE确保实体幂等性(基于embedding相似度阈值去重) - - 关系写入使用CREATE(允许重复关系带不同timestamp,形成时序链) - 长事务支持: - 若单轮需要多次recall(如探索性查询),模型在单次API调用中使用parallel_tool_calls并行发起,减少RTT。 +### 2. 配置环境变量 - --- +```bash +export DEEPSEEK_API_KEY="your-api-key" +export NEO4J_PASSWORD="neo4j" +``` - 4. 与常规架构的本质差异 - 维度 传统RAG MemGPT OpenClaw - 记忆位置 向量库+上下文窗口 分层虚拟内存 图数据库(唯一) - 检索触发 固定策略(如top-k) OS式页面置换 模型自主决策 - 写入控制 自动分块存储 自动换页 模型价值判断 - 结构化 平面向量 线性序列 拓扑图结构 - 一致性 最终一致 虚拟内存一致 显式事务(purge+commit) +### 3. 运行 Demo - --- +```bash +python graph_memory_demo.py +``` - 5. 工程实现要点 - 5.1 性能优化(针对你的系统背景) - 连接池管理: - - Neo4j驱动配置max_connection_pool_size: 20(匹配龙虾工作线程数) - - 工具调用使用session.run的短事务,避免长连接占用 - 查询优化: - - recall工具内部实现:先向量相似度检索(快速定位),再图遍历(关系展开) - - 对高频查询路径(如"用户偏好")建立索引:CREATE INDEX entity_type_idx FOR (e:Entity) ON (e.type) - 批处理: - - memory_commit支持单轮批量写入(UNWIND $triplets),减少IO次数 - 5.2 故障与降级 - 图库离线: - - 工具返回特定错误码(GRAPH_UNAVAILABLE) - - 模型进入"无记忆模式":明确告知用户"我暂时无法访问历史记录",而非静默幻觉 - 写入失败: - - 本地jsonl日志作为WAL(Write-Ahead Log),后台进程重放 - - 模型接收commit_partial_success反馈,知道哪些信息已丢失 - 5.3 监控指标 - - 记忆命中率:recall返回非空结果的比例(衡量查询有效性) - - 写入信噪比:commit频率 vs 后续recall实际引用的比例 - - 类型熵:动态创建的entity_types数量及分布(防止过度碎片化) +### 4. Docker 一键部署 - --- +```bash +cd docker +./start.sh +``` - 6. 实验验证路径 - 1. 基线对比:相同长对话任务(50+轮),对比本架构与32k上下文窗口的事实一致性准确率 - 2. 消融实验:固定recall策略(强制每轮查询)vs 自主决策,测量查询次数-准确率曲线 - 3. 压力测试:模拟100并发会话,监测Neo4j连接池争用及延迟P99 - 4. 故障注入:随机丢弃commit操作,验证模型能否通过后续recall发现不一致并修正 +## 架构说明 - --- +- **无上下文**: 每次请求仅带当前输入,不含历史消息 +- **图数据库**: 所有记忆存储在 Neo4j 图中 +- **自主决策**: 模型自主判断何时查询/写入记忆 - 这套架构的终极验证是:当上下文窗口物理上设为1(仅保留当前输入)时,系统能否维持连贯、准确、有记忆的多轮对话。如果成功,则证明图外部化完全替代了参数化记忆。 - \ No newline at end of file +## 文件结构 + +``` +. +├── graph_memory_demo.py # 主程序 +├── scripts/ # 各发行版安装脚本 +│ ├── install_neo4j_ubuntu.sh +│ ├── install_neo4j_centos.sh +│ ├── install_neo4j_openeuler.sh +│ └── start_neo4j_docker.sh +├── docker/ # Docker 部署 +│ ├── docker-compose.yml +│ ├── start.sh +│ └── .env.example +└── README.md +``` + +## Neo4j 配置 + +- HTTP: http://localhost:7474 +- Bolt: bolt://localhost:7687 +- 用户: neo4j / (设置密码) + +## 测试验证 + +```bash +# 测试 Neo4j 连接 +cypher-shell -u neo4j -p your_password "MATCH (n) RETURN count(n)" +``` diff --git a/docker/README.md b/docker/README.md index 06c2e25..d861837 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,6 +1,6 @@ -# OpenClaw Docker 部署 +# Graph Memory Demo Docker 部署 -一键启动 OpenClaw 纯图数据库对话 Demo。 +一键启动纯图数据库记忆存储 Demo。 ## 快速开始 @@ -21,7 +21,7 @@ docker compose up -d ## 启动后 - Neo4j Browser: http://localhost:7474 -- 登录用户: neo4j / openclaw123 +- 登录用户: neo4j / graph123 - 应用运行在终端交互模式 ## 停止 @@ -46,4 +46,4 @@ docker/ ├── start.sh # 一键启动脚本 ├── .env.example # 环境变量模板 └── README.md # 本文件 -``` \ No newline at end of file +``` diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 2ff3461..928db2e 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -3,12 +3,12 @@ version: '3.8' services: neo4j: image: neo4j:5 - container_name: openclaw-neo4j + container_name: graph-memory-neo4j ports: - "7474:7474" - "7687:7687" environment: - - NEO4J_AUTH=neo4j/openclaw123 + - NEO4J_AUTH=neo4j/graph123 - NEO4J_PLUGINS=["apoc"] - NEO4J_server_memory_heap_initial__size=256m - NEO4J_server_memory_heap_max__size=512m @@ -17,34 +17,41 @@ services: - neo4j_logs:/logs restart: unless-stopped healthcheck: - test: ["CMD-SHELL", "return cypher-shell -u neo4j -p openclaw123 'RETURN 1' 2>/dev/null || exit 1"] + test: ["CMD-SHELL", "return cypher-shell -u neo4j -p graph123 'RETURN 1' 2>/dev/null || exit 1"] interval: 30s timeout: 10s retries: 5 + networks: + - graph-memory-net - openclaw: + demo: image: python:3.11-slim - container_name: openclaw-app + container_name: graph-memory-app ports: - "8000:8000" environment: - NEO4J_URI=bolt://neo4j:7687 - NEO4J_USER=neo4j - - NEO4J_PASSWORD=openclaw123 + - NEO4J_PASSWORD=graph123 - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY:-your-api-key-here} volumes: - ..:/app - - ../openclaw_neo4j_demo.py:/app/openclaw_neo4j_demo.py working_dir: /app command: > - sh -c "pip install --quiet neo4j openai && python openclaw_neo4j_demo.py" + sh -c "pip install --quiet neo4j openai && python graph_memory_demo.py" stdin_open: true tty: true depends_on: neo4j: condition: service_healthy restart: unless-stopped + networks: + - graph-memory-net volumes: neo4j_data: - neo4j_logs: \ No newline at end of file + neo4j_logs: + +networks: + graph-memory-net: + driver: bridge \ No newline at end of file diff --git a/docker/start.sh b/docker/start.sh index 55ead46..bbefc86 100644 --- a/docker/start.sh +++ b/docker/start.sh @@ -1,10 +1,10 @@ #!/bin/bash -# OpenClaw Docker 一键启动脚本 +# Graph Memory Demo Docker 一键启动脚本 set -e echo "========================================" -echo "OpenClaw Docker 一键启动" +echo "Graph Memory Demo Docker 一键启动" echo "========================================" # 检查 Docker 和 Docker Compose @@ -42,7 +42,7 @@ fi # 启动服务 echo "" -echo "启动 Neo4j 和 OpenClaw 应用..." +echo "启动 Neo4j 和 Graph Memory Demo 应用..." $DOCKER_COMPOSE up -d # 等待 Neo4j 就绪 @@ -60,7 +60,7 @@ $DOCKER_COMPOSE ps echo "" echo "访问地址:" echo " Neo4j Browser: http://localhost:7474" -echo " Neo4j 用户: neo4j / openclaw123" +echo " Neo4j 用户: neo4j / graph123" echo "" echo "停止服务: docker compose down" echo "查看日志: docker compose logs -f" \ No newline at end of file diff --git a/openclaw_neo4j_demo.py b/graph_memory_demo.py similarity index 98% rename from openclaw_neo4j_demo.py rename to graph_memory_demo.py index 6c03e4c..3fcac91 100644 --- a/openclaw_neo4j_demo.py +++ b/graph_memory_demo.py @@ -1,7 +1,8 @@ #!/usr/bin/env python3 """ -OpenClaw 纯图数据库调用 Demo - Neo4j 真实数据库版本 +Graph Memory Demo - 纯图数据库调用 Demo 基于 DeepSeek API Tool Calls 实现摒弃传统上下文的自主记忆多轮对话 +验证目的:无上下文纯图数据库记忆存储 """ import json @@ -507,7 +508,7 @@ def format_recall_result(result: dict) -> str: return "\n".join(lines) -class OpenClawClient: +class GraphMemoryClient: def __init__(self, api_key: str, base_url: str, graph: Neo4jGraph): from openai import OpenAI self.client = OpenAI(api_key=api_key, base_url=base_url) @@ -516,7 +517,7 @@ class OpenClawClient: self.system_prompt = self._build_system_prompt() def _build_system_prompt(self) -> str: - return """你是 OpenClaw 的自主记忆助手。 + return """你是图数据库记忆助手。 ## 核心职责 你是用户的长期记忆助手。每次对话后,你**必须**主动决定是否需要将关键信息写入记忆图库。 @@ -597,7 +598,7 @@ query_intent 应该是**逗号分隔的多个关键词**,并包含**同义词/ global CURRENT_TURN print("\n" + "=" * 60) - print("OpenClaw 纯图数据库对话 Demo (Neo4j)") + print("Graph Memory Demo - 纯图数据库对话 (Neo4j)") print("=" * 60) print(f"会话ID: {CURRENT_SESSION_ID}") print(f"Neo4j: {NEO4J_URI}") @@ -681,7 +682,7 @@ query_intent 应该是**逗号分隔的多个关键词**,并包含**同义词/ def main(): - print("OpenClaw Demo - Neo4j 纯图数据库调用的多轮对话") + print("Graph Memory Demo - 纯图数据库调用的多轮对话") print("-" * 40) if not DEEPSEEK_API_KEY: @@ -704,7 +705,7 @@ def main(): print("请确保 Neo4j 已启动,或运行 scripts/ 下的安装脚本") return - client = OpenClawClient(DEEPSEEK_API_KEY, DEEPSEEK_BASE_URL, graph) + client = GraphMemoryClient(DEEPSEEK_API_KEY, DEEPSEEK_BASE_URL, graph) client.chat_loop() graph.close() diff --git a/scripts/start_neo4j_docker.sh b/scripts/start_neo4j_docker.sh index 6c6ee99..c5c13e8 100644 --- a/scripts/start_neo4j_docker.sh +++ b/scripts/start_neo4j_docker.sh @@ -14,16 +14,16 @@ if ! command -v docker &> /dev/null; then fi # 检查并停止现有容器 -if docker ps -a | grep -q openclaw-neo4j; then +if docker ps -a | grep -q graph-memory-neo4j; then echo "[Info] 停止现有容器..." - docker stop openclaw-neo4j 2>/dev/null || true - docker rm openclaw-neo4j 2>/dev/null || true + docker stop graph-memory-neo4j 2>/dev/null || true + docker rm graph-memory-neo4j 2>/dev/null || true fi # 启动 Neo4j echo "[Info] 启动 Neo4j 容器..." docker run -d \ - --name openclaw-neo4j \ + --name graph-memory-neo4j \ -p 7474:7474 \ -p 7687:7687 \ -e NEO4J_AUTH=neo4j/neo4j \ @@ -78,8 +78,8 @@ echo "" echo "远程 Neo4j 配置示例:" echo " NEO4J_URI=bolt://192.168.1.100:7687 \\" echo " NEO4J_PASSWORD=your_password \\" -echo " python /home/program/graph_enable_ability/openclaw_neo4j_demo.py" +echo " python /home/program/graph_enable_ability/graph_memory_demo.py" echo "" echo "启动对话:" echo " cd $PROJECT_DIR && source venv/bin/activate" -echo " python /home/program/graph_enable_ability/openclaw_neo4j_demo.py" \ No newline at end of file +echo " python /home/program/graph_enable_ability/graph_memory_demo.py" \ No newline at end of file