refactor: rename to Graph Memory Demo, remove OpenClaw branding
This commit is contained in:
225
README.md
225
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(仅保留当前输入)时,系统能否维持连贯、准确、有记忆的多轮对话。如果成功,则证明图外部化完全替代了参数化记忆。
|
||||
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
.
|
||||
├── 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)"
|
||||
```
|
||||
|
||||
@ -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 # 本文件
|
||||
```
|
||||
```
|
||||
|
||||
@ -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:
|
||||
neo4j_logs:
|
||||
|
||||
networks:
|
||||
graph-memory-net:
|
||||
driver: bridge
|
||||
@ -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"
|
||||
@ -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()
|
||||
|
||||
@ -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"
|
||||
echo " python /home/program/graph_enable_ability/graph_memory_demo.py"
|
||||
Reference in New Issue
Block a user