Files
my-project/doc/青龙记忆系统/MEMO配置指南.md
T

13 KiB

青龙记忆系统配置文档

创建时间: 2026-02-09 状态: ✅ 已验证有效 适用: 青龙 (192.168.0.31)


1. 系统架构

┌─────────────────────────────────────────────────────────────────┐
│                        青龙 (192.168.0.31)                       │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────┐     ┌─────────────────┐     ┌────────────────┐  │
│  │   Qdrant    │────▶│  simple_memory  │────▶│  OpenClaw      │  │
│  │  (向量库)   │     │    (记忆工具)   │     │   Gateway      │  │
│  │ localhost   │     │  /opt/mem0/     │     │  :18789        │  │
│  │   :6333    │     └─────────────────┘     └────────────────┘  │
│  └─────────────┘                                               │
│        ▲                                                       │
│        │                                                       │
│  ┌─────┴─────┐                                                 │
│  │  Ollama   │                                                 │
│  │ localhost │                                                 │
│  │  :11434   │                                                 │
│  └───────────┘                                                 │
│        ▲                                                       │
│        │ nomic-embed-text:latest (本地嵌入)                      │
└─────────────────────────────────────────────────────────────────┘
        │
        │ REST API
        ▼
┌─────────────────────────────────────────────────────────────────┐
│                   192.168.0.66 (代理服务器)                      │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────┐                                               │
│  │   Ollama    │                                               │
│  │  :11434     │                                               │
│  │             │                                               │
│  │ qwen3:4b    │  ← LLM (语言模型)                            │
│  │ (2381MB)    │                                               │
│  └─────────────┘                                               │
└─────────────────────────────────────────────────────────────────┘

2. 组件配置

2.1 Qdrant 向量数据库

部署方式: Docker Compose

# docker-compose.yml (位于 /opt/memos/)
services:
  qdrant:
    image: qdrant/qdrant:v1.7.0
    ports:
      - "6333:6333"
      - "6334:6334"
    volumes:
      - qdrant_data:/qdrant/storage

volumes:
  qdrant_data:

启动命令:

cd /opt/memos
docker compose up -d

集合配置:

参数 值
集合名称 mem0_memories
向量维度 768
距离度量 Cosine (余弦相似度)
状态 green (健康)

验证命令:

# 检查服务状态
curl http://localhost:6333/collections

# 查看集合详情
curl http://localhost:6333/collections/mem0_memories

# 查看所有记忆
curl http://localhost:6333/collections/mem0_memories/points/scroll \
  -H "Content-Type: application/json" \
  -d '{"limit":10,"with_payload":true}'

2.2 本地 Ollama 嵌入模型

安装模型:

# 安装 nomic-embed-text (用于向量化)
ollama pull nomic-embed-text:latest

# 查看已安装模型
ollama list

模型信息:

模型 大小 用途 维度
nomic-embed-text:latest 261MB 文本向量化 768
mxbai-embed-large:latest 638MB 备用嵌入 1024

验证命令:

# 测试嵌入功能
curl http://localhost:11434/v1/embeddings \
  -H "Content-Type: application/json" \
  -d '{"model":"nomic-embed-text:latest","input":"测试文本"}'

预期输出:

{
  "data": [{
    "embedding": [0.123, 0.456, ...],  // 768 维向量
    "index": 0,
    "object": "embedding"
  }],
  "model": "nomic-embed-text:latest",
  "object": "list",
  "usage": {"prompt_tokens": 10, "total_tokens": 10}
}

2.3 远程 LLM (192.168.0.66)

部署服务器: 192.168.0.66

安装模型:

# 安装 qwen3:4b
ollama pull qwen3:4b

模型信息:

模型 大小 用途
qwen3:4b 2381MB 语言模型推理

验证命令:

# 测试 LLM
curl http://192.168.0.66:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3:4b",
    "messages": [{"role": "user", "content": "你好"}],
    "stream": false
  }'

3. 记忆系统工具

3.1 工具位置

/opt/mem0/
├── simple_memory.py      # 主工具 (推荐使用)
├── qinglong_memory.py    # 备用工具
├── config.yaml           # mem0ai 配置 (暂未使用)
└── test_*.py             # 测试脚本

3.2 simple_memory.py 功能

添加记忆:

python3 /opt/mem0/simple_memory.py add "这是青龙的测试记忆"

搜索记忆:

python3 /opt/mem0/simple_memory.py search "青龙"

基于记忆对话:

python3 /opt/mem0/simple_memory.py chat "青龙会做什么?"

3.3 完整源代码

#!/usr/bin/env python3
"""
青龙记忆系统 - 稳定版
- Embedder: 本地 nomic-embed-text:latest
- LLM: 192.168.0.66 qwen3:4b
- 向量库: Qdrant localhost:6333
"""

import sys
import json
import requests
import hashlib
import numpy as np

OLLAMA_LOCAL = 'http://localhost:11434'
OLLAMA_66 = 'http://192.168.0.66:11434'
QDRANT = 'http://localhost:6333'
COLLECTION = 'mem0_memories'

def get_embedding(text):
    """获取向量 (本地 nomic)"""
    resp = requests.post(
        f'{OLLAMA_LOCAL}/v1/embeddings',
        json={'model': 'nomic-embed-text:latest', 'input': text}
    )
    return resp.json()['data'][0]['embedding']

def cosine_sim(a, b):
    """计算余弦相似度"""
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

def add_memory(content, user_id='qinglong'):
    """添加记忆"""
    vector = get_embedding(content)
    point_id = int(hashlib.md5(content.encode()).hexdigest()[:8], 16)
    
    requests.put(
        f'{QDRANT}/collections/{COLLECTION}/points',
        json={
            'points': [{
                'id': point_id,
                'vector': vector,
                'payload': {'content': content, 'user_id': user_id}
            }]
        }
    )
    print(f'ADDED: {point_id}')

def search_memory(query, limit=5):
    """搜索记忆"""
    query_vec = get_embedding(query)
    
    resp = requests.post(
        f'{QDRANT}/collections/{COLLECTION}/points/scroll',
        json={'limit': 100, 'with_vector': True}
    )
    
    results = []
    for p in resp.json()['result']['points']:
        if p.get('vector') and p.get('payload'):
            score = cosine_sim(query_vec, p['vector'])
            results.append((p['payload']['content'], score))
    
    results.sort(key=lambda x: x[1], reverse=True)
    
    for content, score in results[:limit]:
        print(f'- {content} (score: {score:.3f})')

def chat_with_memory(prompt):
    """基于记忆的对话"""
    query_vec = get_embedding(prompt)
    
    resp = requests.post(
        f'{QDRANT}/collections/{COLLECTION}/points/scroll',
        json={'limit': 100, 'with_vector': True}
    )
    
    memories = []
    for p in resp.json()['result']['points']:
        if p.get('vector') and p.get('payload'):
            score = cosine_sim(query_vec, p['vector'])
            if score > 0.7:
                memories.append((p['payload']['content'], score))
    
    memories.sort(key=lambda x: x[1], reverse=True)
    context = '\n'.join([m[0] for m in memories[:3]])
    
    # 调用 qwen3:4b
    resp = requests.post(
        f'{OLLAMA_66}/v1/chat/completions',
        json={
            'model': 'qwen3:4b',
            'messages': [{'role': 'user', 'content': f'相关记忆:\n{context}\n\n用户: {prompt}'}],
            'stream': False
        }
    )
    return resp.json()['choices'][0]['message']['content']

if __name__ == '__main__':
    cmd = sys.argv[1] if len(sys.argv) > 1 else 'search'
    
    if cmd == 'add':
        content = sys.argv[2] if len(sys.argv) > 2 else ''
        if content:
            add_memory(content)
        else:
            print('Usage: python3 simple_memory.py add "内容"')
    
    elif cmd == 'search':
        query = sys.argv[2] if len(sys.argv) > 2 else ''
        if query:
            search_memory(query)
        else:
            print('Usage: python3 simple_memory.py search "关键词"')
    
    elif cmd == 'chat':
        prompt = ' '.join(sys.argv[2:]) if len(sys.argv) > 2 else ''
        if prompt:
            print(chat_with_memory(prompt))
        else:
            print('Usage: python3 simple_memory.py chat "用户问题"')

4. OpenClaw 集成

4.1 配置文件位置

/root/.openclaw/openclaw.json

4.2 关键配置

{
  "models": {
    "providers": {
      "minimax": { ... },
      "deepseek": { ... },
      "ollama": {
        "baseUrl": "http://localhost:11434/v1",
        "apiKey": "ollama-local",
        "models": [
          {
            "id": "nomic-embed-text:latest",
            "name": "Nomic Embed"
          }
        ]
      }
    }
  },
  "agents": {
    "defaults": {
      "model": {
        "primary": "minimax/minimax-m2.1"
      },
      "memorySearch": {
        "provider": "openai",
        "remote": {
          "baseUrl": "http://localhost:11434/v1",
          "apiKey": "sk-local-ollama-fake-key"
        },
        "model": "nomic-embed-text:latest"
      }
    }
  }
}

4.3 工具集成 (可选)

将 simple_memory.py 添加为 OpenClaw 工具:

{
  "tools": {
    "custom": {
      "memory_add": {
        "command": "python3 /opt/mem0/simple_memory.py add",
        "args": ["content"]
      },
      "memory_search": {
        "command": "python3 /opt/mem0/simple_memory.py search", 
        "args": ["query"]
      }
    }
  }
}

5. 问题排查

5.1 常见问题

问题 原因 解决方案
向量维度不匹配 集合创建时维度错误 删除集合,重新创建 768 维
搜索无结果 没有设置 with_vector 添加 with_vector: true
Qdrant 无法连接 Docker 容器未运行 docker ps 检查,docker start
Ollama 连接超时 服务未启动 ollama serve 启动服务
payload 为空 存储时未包含 payload 确认 upsert 请求包含 payload

5.2 调试命令

# 1. 检查 Qdrant 服务
curl http://localhost:6333/health

# 2. 检查集合
curl http://localhost:6333/collections/mem0_memories

# 3. 查看所有记忆 (带向量)
curl http://localhost:6333/collections/mem0_memories/points/scroll \
  -H "Content-Type: application/json" \
  -d '{"limit":10,"with_vector":true}'

# 4. 测试嵌入
curl http://localhost:11434/v1/embeddings \
  -H "Content-Type: application/json" \
  -d '{"model":"nomic-embed-text:latest","input":"测试"}'

# 5. 检查 Docker 状态
docker ps | grep qdrant

5.3 重置集合

# 删除旧集合
curl -X DELETE http://localhost:6333/collections/mem0_memories

# 重建集合 (768维)
curl -X PUT http://localhost:6333/collections/mem0_memories \
  -H "Content-Type: application/json" \
  -d '{"vectors":{"size":768,"distance":"Cosine"}}'

6. 性能指标

6.1 当前状态

指标 值
记忆数量 3 条
向量维度 768
搜索相似度 0.6 - 0.9+
Qdrant 状态 green

6.2 资源占用

组件 内存 CPU
Qdrant ~100MB 低
Ollama (嵌入) ~300MB 低
192.168.0.66 qwen3:4b ~2.4GB 中

7. 未来优化

  • 将 simple_memory.py 集成到 OpenClaw 工具
  • 添加记忆自动过期机制
  • 实现多用户记忆隔离
  • 优化搜索算法 (使用 HNSW 索引)
  • 添加记忆可视化界面

8. 参考资料


文档版本: v1.0 (2026-02-09) 作者: 2号机 (守护者)