OpenClaw记忆管理教程:打造个性化AI对话

欢迎来到OpenClaw 7天学习教程的第六天!在前五天的学习中,我们已经完成了基础安装、个性定制、飞书集成和技能扩展。今天,我们将深入探讨OpenClaw的记忆管理与个性化对话能力,让你的AI助手能够更好地记住与你的交流内容,形成更连贯、个性化的对话体验。

🧠 理解AI助手的记忆系统

OpenClaw能够变成你的助手,而不是问一句答一句的AI非常重要的一点是它的记忆功能。合理配置记忆功能,可以让AI更了解你、了解你们的工作进度并提供支持,但是太长的记忆会让每次对话都有超长的上下文,token燃烧飞快,所以合理配置OpenClaw的记忆系统格外重要。本章内容比较进阶,可以根据需求,选择性学习,不一定需要完全按照教程设置。

根据OpenClaw的设计,AI助手的记忆系统主要基于文件存储,分为以下几个部分:

记忆类型

  1. 短期记忆:当前对话会话中的内容,会随会话结束而消失
  2. 日常记录:每日记录 memory/YYYY-MM-DD.md,记录每天对话的重要
  3. 长期记忆MEMORY.md 文件,存储经过整理的重要信息和上下文

记忆管理原则

  1. 只在主会话加载:长期记忆只在与用户的直接对话中加载,不在共享上下文中加载
  2. 写下来才能记住:重要信息必须写入文件,而不是"心理记录"
  3. 安全第一:不在群聊或共享场景下暴露个人信息
  4. 定期整理:从日常记录中提炼重要信息到长期记忆

📝 创建基础记忆文件结构

让我们建立一个有效的记忆文件结构(可能初始化时已经创建好了,如果没有按照以下命令创建):

  1. 首先,创建必要的目录和文件:
Code
# 创建记忆目录
mkdir -p ~/.openclaw/memory

# 创建长期记忆文件
touch ~/.openclaw/MEMORY.md

# 创建今天的日常记录文件(格式为YYYY-MM-DD.md)
touch ~/.openclaw/memory/$(date +%Y-%m-%d).md
  1. 初始化长期记忆文件 (MEMORY.md) 结构:
Code
cat > ~/.openclaw/MEMORY.md << 'EOF'
# 长期记忆索引

这是OpenClaw助手的长期记忆文件,存储所有重要信息的索引和关键内容。

## 用户偏好

*记录用户的重要偏好和习惯。*

- **通信偏好**: [尚未记录]
- **工作习惯**: [尚未记录]
- **兴趣爱好**: [尚未记录]

## 进行中的项目

*当前正在进行的项目及其状态。*

-

## 知识库索引

*重要知识的索引,按类别组织。*

- **技术笔记**: `knowledge/tech/`
- **工作流程**: `knowledge/workflows/`
- **常用命令**: `knowledge/commands.md`

## 重要决策记录

*记录重要决策及其背景原因。*

- 尚未有记录

## 定期回顾

*定期回顾和反思的记录。*

- 尚未有记录

EOF

📔 MEMORY.md 的结构与管理

长期记忆文件(MEMORY.md)是AI助手记忆系统的核心。它应该是一个精心组织的索引,而不是所有记忆的堆砌。以下是一些最佳实践:

  1. 结构化索引:使用清晰的章节来组织不同类型的信息
  2. 引用而非复制:引用具体文件而不是将所有内容复制到一处
  3. 定期更新:从日常记忆文件中提炼重要信息,更新长期记忆
  1. 创建项目进度追踪文件:
Code
# 创建项目目录
mkdir -p ~/.openclaw/projects/openclaw_learning

# 创建项目进度文件
cat > ~/.openclaw/projects/openclaw_learning/progress.md << 'EOF'
# OpenClaw学习进度

## 最新状态

- **当前进度**: 学习Day 6 - 记忆管理与个性化对话
- **完成日期**: [尚未完成]
- **下一步**: 完成Day 7 - 多模态与高级应用

## 进度详情

### Day 1: 基础安装与配置
- ✅ 完成安装
- ✅ 完成基础配置
- ✅ 测试基本功能

### Day 2: 个性化定制
- ✅ 完成个性设置
- ✅ 配置提示词模板
- ✅ 测试个性化回复

### Day 3: 飞书集成
- ✅ 完成飞书机器人创建
- ✅ 建立OpenClaw与飞书的连接
- ✅ 测试消息收发功能

### Day 4: 工具使用与插件
- ✅ 配置基础工具
- ✅ 添加自定义插件
- ✅ 测试工具功能

### Day 5: 技能扩展
- ✅ 学习技能概念
- ✅ 添加自定义技能
- ✅ 测试技能功能

### Day 6: 记忆管理与个性化对话
- 🔄 设置记忆文件结构
- 🔄 创建记忆管理流程
- 🔄 测试记忆功能

### Day 7: 多模态与高级应用
- ⏳ 未开始

## 学习笔记

- OpenClaw是一个功能强大的AI助手框架,可以通过多种方式进行定制
- 个性化设置可以让助手更符合特定场景的需求
- 工具和技能扩展极大增强了助手的能力范围

EOF

🔖 创建记忆管理脚本

为了更方便地管理记忆,我们可以创建一些辅助脚本:

  1. 创建每日记忆文件生成脚本:
Code
cat > ~/.openclaw/scripts/create_daily_memory.sh << 'EOF'
#!/bin/bash

# 设置记忆目录
MEMORY_DIR=~/.openclaw/memory

# 确保目录存在
mkdir -p $MEMORY_DIR

# 获取今天的日期
TODAY=$(date +%Y-%m-%d)
MEMORY_FILE="$MEMORY_DIR/$TODAY.md"

# 如果文件不存在,则创建
if [ ! -f "$MEMORY_FILE" ]; then
    echo "# 记忆记录: $TODAY" > "$MEMORY_FILE"
    echo "" >> "$MEMORY_FILE"
    echo "## 对话摘要" >> "$MEMORY_FILE"
    echo "" >> "$MEMORY_FILE"
    echo "## 重要信息" >> "$MEMORY_FILE"
    echo "" >> "$MEMORY_FILE"
    echo "## 行动项" >> "$MEMORY_FILE"
    echo "" >> "$MEMORY_FILE"
    echo "创建了今天的记忆文件: $MEMORY_FILE"
else
    echo "今天的记忆文件已存在: $MEMORY_FILE"
fi
EOF

chmod +x ~/.openclaw/scripts/create_daily_memory.sh
  1. 创建记忆搜索脚本:
Code
cat > ~/.openclaw/scripts/search_memory.sh << 'EOF'
#!/bin/bash

# 设置搜索目录
MEMORY_DIR=~/.openclaw/memory
LONG_TERM_MEMORY=~/.openclaw/MEMORY.md
PROJECTS_DIR=~/.openclaw/projects

# 检查参数
if [ $# -eq 0 ]; then
    echo "用法: $0 <搜索关键词>"
    exit 1
fi

# 获取搜索词
SEARCH_TERM="$*"
echo "搜索: '$SEARCH_TERM'"
echo "========================================"

# 搜索长期记忆
echo "## 在长期记忆中搜索"
if [ -f "$LONG_TERM_MEMORY" ]; then
    grep -i --color=always "$SEARCH_TERM" "$LONG_TERM_MEMORY" | head -n 10
    RESULTS=$(grep -i -c "$SEARCH_TERM" "$LONG_TERM_MEMORY")
    echo "找到 $RESULTS 处匹配"
else
    echo "长期记忆文件不存在"
fi

echo "========================================"

# 搜索日常记忆
echo "## 在日常记忆中搜索"
if [ -d "$MEMORY_DIR" ]; then
    grep -i --color=always -r "$SEARCH_TERM" "$MEMORY_DIR" | head -n 10
    RESULTS=$(grep -i -r -c "$SEARCH_TERM" "$MEMORY_DIR" | wc -l)
    echo "找到 $RESULTS 处匹配"
else
    echo "记忆目录不存在"
fi

echo "========================================"

# 搜索项目文件
echo "## 在项目文件中搜索"
if [ -d "$PROJECTS_DIR" ]; then
    grep -i --color=always -r "$SEARCH_TERM" "$PROJECTS_DIR" | head -n 10
    RESULTS=$(grep -i -r -c "$SEARCH_TERM" "$PROJECTS_DIR" | wc -l)
    echo "找到 $RESULTS 处匹配"
else
    echo "项目目录不存在"
fi
EOF

chmod +x ~/.openclaw/scripts/search_memory.sh
  1. 创建记忆摘要生成脚本:
Code
cat > ~/.openclaw/scripts/summarize_daily_memory.sh << 'EOF'
#!/bin/bash

# 设置记忆目录
MEMORY_DIR=~/.openclaw/memory
LONG_TERM_MEMORY=~/.openclaw/MEMORY.md

# 获取昨天的日期
YESTERDAY=$(date -d "yesterday" +%Y-%m-%d)
MEMORY_FILE="$MEMORY_DIR/$YESTERDAY.md"

# 检查昨天的记忆文件是否存在
if [ ! -f "$MEMORY_FILE" ]; then
    echo "昨天的记忆文件不存在: $MEMORY_FILE"
    exit 1
fi

echo "正在处理昨天的记忆文件: $MEMORY_FILE"

# 使用OpenClaw生成摘要
# 这里假设OpenClaw有一个命令行接口
# 实际上你可能需要通过API或其他方式与OpenClaw交互
echo "请求OpenClaw生成摘要..."

# 生成摘要的提示词
PROMPT="请为以下日常记忆内容生成一个简洁的摘要,提取出所有重要信息、决策和行动项。这些信息将被添加到长期记忆中。只返回摘要内容,不需要其他解释。记忆内容如下:\n\n$(cat $MEMORY_FILE)"

# 这里你需要根据OpenClaw的实际接口来调用它
# 例如,可能是通过API调用
# 以下仅为示例,需要根据实际情况修改
# openclaw generate "$PROMPT" > summary.txt

echo "摘要已生成,请检查并手动添加到长期记忆文件: $LONG_TERM_MEMORY"
EOF

chmod +x ~/.openclaw/scripts/summarize_daily_memory.sh
  1. 添加这些脚本到启动流程中:
Code
cat >> ~/.openclaw/startup.sh << 'EOF'

# 创建今天的记忆文件
~/.openclaw/scripts/create_daily_memory.sh

# 输出记忆系统已准备好的消息
echo "记忆系统已准备就绪!"
EOF

👤 创建用户偏好记录文件

为了更好地跟踪用户偏好,我们可以创建专门的偏好文件:

Code
mkdir -p ~/.openclaw/knowledge

cat > ~/.openclaw/knowledge/user_preferences.md << 'EOF'
# 用户偏好记录

本文件记录用户的各种偏好和习惯,以便提供更加个性化的服务。

## 通信偏好

- **沟通风格**: [尚未记录]
- **回复长度**: [尚未记录]
- **回复格式**: [尚未记录]
- **反馈方式**: [尚未记录]

## 工作习惯

- **工作时间**: [尚未记录]
- **专注时段**: [尚未记录]
- **休息模式**: [尚未记录]
- **提醒设置**: [尚未记录]

## 内容偏好

- **信息详细度**: [尚未记录]
- **技术复杂度**: [尚未记录]
- **示例偏好**: [尚未记录]
- **视觉元素**: [尚未记录]

## 个人兴趣

- **专业领域**: [尚未记录]
- **学习主题**: [尚未记录]
- **娱乐偏好**: [尚未记录]
- **其他兴趣**: [尚未记录]

## 更新记录

- **初始创建**: [日期]
- **最近更新**: [日期]
EOF

# 更新MEMORY.md中的索引
sed -i 's|**兴趣爱好**: \[尚未记录\]|**兴趣爱好**: 参见 `knowledge/user_preferences.md`|' ~/.openclaw/MEMORY.md

🗂️ 创建项目模板

为了更好地管理项目相关的记忆,我们可以创建一个项目模板:

Code
mkdir -p ~/.openclaw/templates

cat > ~/.openclaw/templates/project_template.md << 'EOF'
# [项目名称]

## 项目概览

- **开始日期**: [YYYY-MM-DD]
- **预计完成**: [YYYY-MM-DD]
- **项目类型**: [类型]
- **优先级**: [高/中/低]

## 最新状态

- **当前阶段**: [阶段描述]
- **完成度**: [进度百分比]
- **最近更新**: [YYYY-MM-DD]

## 目标与范围

[描述项目的主要目标和范围]

## 任务清单

- [ ] 任务1
  - [ ] 子任务1.1
  - [ ] 子任务1.2
- [ ] 任务2
- [ ] 任务3

## 参考资料

- [参考资料1]
- [参考资料2]

## 笔记与思考

[项目相关的笔记和思考]

## 决策记录

| 日期 | 决策 | 原因 | 替代方案 | 影响 |
|------|------|------|----------|------|
| [日期] | [决策] | [原因] | [替代方案] | [影响] |

## 进展日志

### [YYYY-MM-DD]
- [进展内容]

EOF

# 创建一个项目创建脚本
cat > ~/.openclaw/scripts/create_project.sh << 'EOF'
#!/bin/bash

# 检查参数
if [ $# -eq 0 ]; then
    echo "用法: $0 <项目名称>"
    exit 1
fi

# 获取项目名称并规范化
PROJECT_NAME="$*"
DIR_NAME=$(echo "$PROJECT_NAME" | tr ' ' '_' | tr '[:upper:]' '[:lower:]')

# 设置项目目录
PROJECTS_DIR=~/.openclaw/projects
PROJECT_DIR="$PROJECTS_DIR/$DIR_NAME"

# 确保目录存在
mkdir -p "$PROJECT_DIR"

# 拷贝模板
TEMPLATE=~/.openclaw/templates/project_template.md
cp "$TEMPLATE" "$PROJECT_DIR/progress.md"

# 替换项目名称
sed -i "s/\[项目名称\]/$PROJECT_NAME/" "$PROJECT_DIR/progress.md"
sed -i "s/\[YYYY-MM-DD\]/$(date +%Y-%m-%d)/" "$PROJECT_DIR/progress.md"

# 更新长期记忆索引
MEMORY_FILE=~/.openclaw/MEMORY.md
if grep -q "## 进行中的项目" "$MEMORY_FILE"; then
    # 添加到现有项目列表
    sed -i "/## 进行中的项目/a - **$PROJECT_NAME**: 参见 \`projects/$DIR_NAME/progress.md\`" "$MEMORY_FILE"
else
    # 如果没有项目部分,添加它
    echo "## 进行中的项目" >> "$MEMORY_FILE"
    echo "" >> "$MEMORY_FILE"
    echo "- **$PROJECT_NAME**: 参见 \`projects/$DIR_NAME/progress.md\`" >> "$MEMORY_FILE"
fi

echo "项目 '$PROJECT_NAME' 已创建: $PROJECT_DIR/progress.md"
echo "长期记忆文件已更新"
EOF

chmod +x ~/.openclaw/scripts/create_project.sh

📊 创建记忆提取与整理工作流

以下是一个简单的工作流,用于从对话中提取重要信息并整理到记忆文件中:

  1. 创建记忆管理工作流文件:
Code
mkdir -p ~/.openclaw/workflows

cat > ~/.openclaw/workflows/memory_workflow.py << 'EOF'
import os
import re
import json
from datetime import datetime
from openclaw.agents import Agent
from openclaw.utils.logger import logger

class MemoryManager:
    def __init__(self):
        # 设置记忆文件路径
        self.memory_dir = os.path.expanduser("~/.openclaw/memory")
        self.long_term_memory = os.path.expanduser("~/.openclaw/MEMORY.md")
        
        # 确保记忆目录存在
        os.makedirs(self.memory_dir, exist_ok=True)
        
        # 获取今天的日期
        self.today = datetime.now().strftime("%Y-%m-%d")
        self.daily_memory_file = os.path.join(self.memory_dir, f"{self.today}.md")
        
        # 确保今天的记忆文件存在
        self._ensure_daily_file()
    
    def _ensure_daily_file(self):
        """确保今天的记忆文件存在"""
        if not os.path.exists(self.daily_memory_file):
            with open(self.daily_memory_file, 'w', encoding='utf-8') as f:
                f.write(f"# 记忆记录: {self.today}\n\n")
                f.write("## 对话摘要\n\n")
                f.write("## 重要信息\n\n")
                f.write("## 行动项\n\n")
    
    def append_to_daily_memory(self, section, content):
        """添加内容到今天的记忆文件"""
        self._ensure_daily_file()
        
        with open(self.daily_memory_file, 'r', encoding='utf-8') as f:
            lines = f.readlines()
        
        # 找到指定部分
        section_pattern = f"## {section}"
        section_index = -1
        next_section_index = len(lines)
        
        for i, line in enumerate(lines):
            if line.strip() == section_pattern:
                section_index = i
            elif section_index >= 0 and line.startswith("## "):
                next_section_index = i
                break
        
        if section_index >= 0:
            # 在部分末尾添加内容
            timestamp = datetime.now().strftime("%H:%M")
            content_with_timestamp = f"- [{timestamp}] {content}\n"
            lines.insert(next_section_index, content_with_timestamp)
            
            with open(self.daily_memory_file, 'w', encoding='utf-8') as f:
                f.writelines(lines)
            
            return True
        
        return False
    
    def extract_important_info(self, text, agent):
        """从文本中提取重要信息"""
        if not agent:
            return None
            
        extract_prompt = f"""
        请分析以下文本,提取出以下三类信息:
        1. 重要信息:任何值得记住的事实、偏好或关键点
        2. 决策:任何做出的决定或承诺
        3. 行动项:需要跟进的任何任务或提醒
        
        对于每一类,如果有相关内容,请以简洁的方式列出;如果没有,返回"无"。
        只返回提取的信息,格式如下:
        
        重要信息:
        - [提取的信息1]
        - [提取的信息2]
        
        决策:
        - [提取的决策1]
        - [提取的决策2]
        
        行动项:
        - [提取的行动项1]
        - [提取的行动项2]
        
        文本:
        {text}
        """
        
        response = agent.generate(extract_prompt)
        return response
    
    def process_conversation(self, messages, agent):
        """处理对话并提取重要信息"""
        # 合并对话内容
        conversation = "\n".join([
            f"{m.get('role', 'unknown')}: {m.get('content', '')}" 
            for m in messages[-10:]  # 只处理最近的10条消息
        ])
        
        # 提取重要信息
        extracted = self.extract_important_info(conversation, agent)
        
        if extracted:
            # 处理提取的信息
            info_match = re.search(r'重要信息:\n(.*?)\n\n', extracted, re.DOTALL)
            decisions_match = re.search(r'决策:\n(.*?)\n\n', extracted, re.DOTALL)
            actions_match = re.search(r'行动项:\n(.*?)$', extracted, re.DOTALL)
            
            if info_match and info_match.group(1).strip() != "无":
                for line in info_match.group(1).strip().split('\n'):
                    if line.strip() and not line.strip() == "- 无":
                        self.append_to_daily_memory("重要信息", line.strip().lstrip('- '))
            
            if decisions_match and decisions_match.group(1).strip() != "无":
                for line in decisions_match.group(1).strip().split('\n'):
                    if line.strip() and not line.strip() == "- 无":
                        self.append_to_daily_memory("重要决策", line.strip().lstrip('- '))
            
            if actions_match and actions_match.group(1).strip() != "无":
                for line in actions_match.group(1).strip().split('\n'):
                    if line.strip() and not line.strip() == "- 无":
                        self.append_to_daily_memory("行动项", line.strip().lstrip('- '))

# 创建记忆管理器实例
memory_manager = MemoryManager()

def register_callbacks(agent):
    @agent.on_conversation_end
    def process_ended_conversation(messages, **kwargs):
        """在对话结束时处理记忆"""
        if len(messages) > 3:  # 只处理足够长的对话
            memory_manager.process_conversation(messages, agent)
    
    @agent.after_user_message
    def detect_memory_commands(message, **kwargs):
        """检测与记忆相关的命令"""
        # 检测记忆相关命令
        if re.search(r'^(记住|请记住|记录|请记录).*', message, re.IGNORECASE):
            # 提取要记住的内容
            content = re.sub(r'^(记住|请记住|记录|请记录)\s*', '', message)
            
            # 添加到今天的记忆
            memory_manager.append_to_daily_memory("重要信息", content)
            
            return "我已经记住了这条信息,并将其添加到今天的记忆文件中。"
        
        return None  # 继续正常处理消息
EOF

# 在OpenClaw启动时注册记忆工作流
echo 'openclaw workflow register memory_workflow' >> ~/.openclaw/startup.sh

🔍 用户偏好提取工作流

让我们创建一个用户偏好提取工作流:

Code
cat > ~/.openclaw/workflows/preference_workflow.py << 'EOF'
import os
import re
import json
from datetime import datetime
from openclaw.agents import Agent
from openclaw.utils.logger import logger

class PreferenceManager:
    def __init__(self):
        self.preferences_file = os.path.expanduser("~/.openclaw/knowledge/user_preferences.md")
        
        # 确保目录存在
        os.makedirs(os.path.dirname(self.preferences_file), exist_ok=True)
        
        # 确保偏好文件存在
        if not os.path.exists(self.preferences_file):
            self._create_default_preferences()
    
    def _create_default_preferences(self):
        """创建默认的偏好文件"""
        with open(self.preferences_file, 'w', encoding='utf-8') as f:
            f.write("# 用户偏好记录\n\n")
            f.write("本文件记录用户的各种偏好和习惯,以便提供更加个性化的服务。\n\n")
            f.write("## 通信偏好\n\n")
            f.write("- **沟通风格**: [尚未记录]\n")
            f.write("- **回复长度**: [尚未记录]\n")
            f.write("- **回复格式**: [尚未记录]\n\n")
            f.write("## 工作习惯\n\n")
            f.write("- **工作时间**: [尚未记录]\n")
            f.write("- **专注时段**: [尚未记录]\n\n")
            f.write("## 内容偏好\n\n")
            f.write("- **信息详细度**: [尚未记录]\n")
            f.write("- **技术复杂度**: [尚未记录]\n\n")
            f.write("## 个人兴趣\n\n")
            f.write("- **专业领域**: [尚未记录]\n")
            f.write("- **学习主题**: [尚未记录]\n\n")
            f.write("## 更新记录\n\n")
            f.write(f"- **初始创建**: {datetime.now().strftime('%Y-%m-%d')}\n")
            f.write(f"- **最近更新**: {datetime.now().strftime('%Y-%m-%d')}\n")
    
    def update_preference(self, category, key, value):
        """更新用户偏好"""
        if not os.path.exists(self.preferences_file):
            self._create_default_preferences()
        
        with open(self.preferences_file, 'r', encoding='utf-8') as f:
            lines = f.readlines()
        
        # 查找分类
        category_pattern = f"## {category}"
        category_index = -1
        next_category_index = len(lines)
        
        for i, line in enumerate(lines):
            if line.strip() == category_pattern:
                category_index = i
            elif category_index >= 0 and line.startswith("## "):
                next_category_index = i
                break
        
        # 如果找不到分类,添加一个
        if category_index == -1:
            category_index = next_category_index - 1
            lines.insert(category_index + 1, f"## {category}\n\n")
            next_category_index += 2
        
        # 查找键
        key_pattern = f"- **{key}**:"
        key_found = False
        
        for i in range(category_index + 1, next_category_index):
            if key_pattern in lines[i]:
                lines[i] = f"- **{key}**: {value}\n"
                key_found = True
                break
        
        # 如果找不到键,添加一个
        if not key_found:
            lines.insert(next_category_index, f"- **{key}**: {value}\n")
        
        # 更新最近更新时间
        update_time = f"- **最近更新**: {datetime.now().strftime('%Y-%m-%d')}\n"
        update_found = False
        
        for i, line in enumerate(lines):
            if "- **最近更新**:" in line:
                lines[i] = update_time
                update_found = True
                break
        
        if not update_found:
            lines.append("\n## 更新记录\n\n")
            lines.append(update_time)
        
        with open(self.preferences_file, 'w', encoding='utf-8') as f:
            f.writelines(lines)
        
        return True
    
    def extract_preferences(self, text, agent):
        """从文本中提取用户偏好"""
        if not agent:
            return None
            
        extract_prompt = f"""
        请从以下文本中提取用户明确表达的偏好,并按以下格式返回:
        
        偏好:
        - 分类: [分类], 键: [键], 值: [值]
        - 分类: [分类], 键: [键], 值: [值]
        
        分类可以是:通信偏好、工作习惯、内容偏好、个人兴趣或其他合适的类别。
        键应该是具体的偏好类型,如沟通风格、回复长度等。
        只提取明确表达的偏好,不要猜测。如果没有明确的偏好,返回"未发现明确的偏好表达"。
        
        文本:
        {text}
        """
        
        response = agent.generate(extract_prompt)
        
        # 解析响应
        if "未发现明确的偏好表达" in response:
            return None
            
        preferences = []
        pref_lines = re.findall(r'- 分类: (.*?), 键: (.*?), 值: (.*?)$', response, re.MULTILINE)
        
        for category, key, value in pref_lines:
            preferences.append({
                "category": category.strip(),
                "key": key.strip(),
                "value": value.strip()
            })
            
        return preferences

# 创建偏好管理器实例
preference_manager = PreferenceManager()

def register_callbacks(agent):
    @agent.after_user_message
    def extract_preferences(message, **kwargs):
        """从用户消息中提取偏好"""
        # 尝试提取偏好
        preferences = preference_manager.extract_preferences(message, agent)
        
        if preferences:
            for pref in preferences:
                preference_manager.update_preference(
                    pref["category"], 
                    pref["key"], 
                    pref["value"]
                )
            
            logger.info(f"已提取并更新 {len(preferences)} 个用户偏好")
        
        # 检测显式的偏好设置命令
        if re.search(r'^设置偏好\s+.*', message, re.IGNORECASE):
            match = re.match(r'^设置偏好\s+([^:]+):\s*(.+)$', message)
            if match:
                key, value = match.groups()
                # 简单确定分类
                if key.lower() in ['沟通风格', '回复长度', '回复格式']:
                    category = "通信偏好"
                elif key.lower() in ['工作时间', '专注时段', '休息模式']:
                    category = "工作习惯"
                elif key.lower() in ['信息详细度', '技术复杂度', '示例偏好']:
                    category = "内容偏好"
                else:
                    category = "个人兴趣"
                
                preference_manager.update_preference(category, key, value)
                return f"已设置偏好: {key} = {value}"
        
        return None  # 继续正常处理
EOF

# 在OpenClaw启动时注册偏好工作流
echo 'openclaw workflow register preference_workflow' >> ~/.openclaw/startup.sh

📔 MEMORY.md 的结构与管理

长期记忆文件(MEMORY.md)是AI助手记忆系统的核心。它应该是一个精心组织的索引,而不是所有记忆的堆砌。以下是一些最佳实践:

  1. 结构化索引:使用清晰的章节来组织不同类型的信息
  2. 引用而非复制:引用具体文件而不是将所有内容复制到一处
  3. 定期更新:从日常记忆文件中提炼重要信息,更新长期记忆
  4. 安全考虑:仅在与用户的直接对话中加载,不在共享上下文中暴露

让我们更新MEMORY.md的结构,增加一些实用的索引:

Code
cat > ~/.openclaw/MEMORY.md << 'EOF'
# 长期记忆索引

这是OpenClaw助手的长期记忆文件,存储所有重要信息的索引和关键内容。它只在主会话中加载,不在共享上下文中加载。

## 用户基本信息

*关于用户的基本信息,帮助提供个性化服务。*

- **通信偏好**: 参见 `knowledge/user_preferences.md` - 通信偏好部分
- **工作习惯**: 参见 `knowledge/user_preferences.md` - 工作习惯部分
- **个人兴趣**: 参见 `knowledge/user_preferences.md` - 个人兴趣部分

## 进行中的项目

*当前正在进行的项目及其状态。*

- **OpenClaw学习**: 参见 `projects/openclaw_learning/progress.md`

## 知识库索引

*重要知识的索引,按类别组织。*

- **技术笔记**: `knowledge/tech/`
- **工作流程**: `knowledge/workflows/`
- **常用命令**: `knowledge/commands.md`

## 重要决策记录

*记录重要决策及其背景原因。*

- 参见每个项目目录下的 `decisions.md` 文件

## 最近记忆

*最近的重要记忆,按时间倒序排列。*

- **2023-06-01**: 用户开始学习OpenClaw,对AI助手的个性化定制特别感兴趣
- **2023-06-02**: 完成了OpenClaw的基础设置和个性化定制
- **2023-06-03**: 设置了飞书集成功能,增强了与团队的协作能力
- **2023-06-04**: 学习并配置了多种工具和插件,扩展了功能范围
- **2023-06-05**: 掌握了技能扩展的方法,增强了专业能力

## 记忆系统使用指南

*如何有效使用记忆系统的说明。*

### 记忆命令

- **记住 [内容]**: 将重要信息添加到当天的记忆文件
- **设置偏好 [键]: [值]**: 设置用户偏好
- **创建项目 [项目名称]**: 创建新项目并建立相关记忆文件

### 文件结构

- **MEMORY.md**: 长期记忆索引文件
- **memory/YYYY-MM-DD.md**: 每日记忆文件
- **projects/**: 项目相关记忆
- **knowledge/**: 知识库和用户偏好

### 最佳实践

- 使用"记住"命令保存重要信息
- 定期整理每日记忆,提炼到长期记忆
- 项目信息保存在专门的项目文件中
- 在MEMORY.md中保持清晰的索引结构
EOF

🔮 高级记忆实践:上下文检索

让我们创建一个上下文检索系统,帮助AI在对话中智能地检索相关记忆:

Code
cat > ~/.openclaw/workflows/context_retrieval_workflow.py << 'EOF'
import os
import re
from datetime import datetime, timedelta
from openclaw.agents import Agent
from openclaw.utils.logger import logger

class ContextRetriever:
    def __init__(self):
        self.memory_dir = os.path.expanduser("~/.openclaw/memory")
        self.long_term_memory = os.path.expanduser("~/.openclaw/MEMORY.md")
        self.projects_dir = os.path.expanduser("~/.openclaw/projects")
        self.knowledge_dir = os.path.expanduser("~/.openclaw/knowledge")
    
    def simple_keyword_search(self, query, file_content):
        """简单的关键词搜索"""
        # 将查询分解为关键词
        keywords = query.lower().split()
        content = file_content.lower()
        
        # 计算匹配度
        matches = sum(1 for keyword in keywords if keyword in content)
        return matches / len(keywords) if keywords else 0
    
    def retrieve_from_file(self, query, filepath, max_chars=1000):
        """从文件中检索相关内容"""
        if not os.path.exists(filepath):
            return None
            
        try:
            with open(filepath, 'r', encoding='utf-8') as f:
                content = f.read()
                
            # 简单的相关性检查
            relevance = self.simple_keyword_search(query, content)
            
            if relevance > 0.3:  # 只返回足够相关的内容
                # 找到最相关的部分
                best_section = content
                
                # 如果内容太长,尝试找到最相关的部分
                if len(content) > max_chars:
                    sections = re.split(r'\n#+\s+', content)
                    best_relevance = 0
                    
                    for section in sections:
                        section_relevance = self.simple_keyword_search(query, section)
                        if section_relevance > best_relevance:
                            best_relevance = section_relevance
                            best_section = section
                    
                    # 如果还是太长,截断它
                    if len(best_section) > max_chars:
                        best_section = best_section[:max_chars] + "..."
                
                return {
                    "content": best_section,
                    "source": os.path.basename(filepath),
                    "relevance": relevance
                }
        except Exception as e:
            logger.error(f"读取文件 {filepath} 时出错: {e}")
            
        return None
    
    def search_recent_memories(self, query, days=7):
        """搜索最近的记忆文件"""
        results = []
        
        # 获取最近几天的日期
        dates = []
        for i in range(days):
            date = (datetime.now() - timedelta(days=i)).strftime("%Y-%m-%d")
            dates.append(date)
        
        # 搜索每天的记忆文件
        for date in dates:
            memory_file = os.path.join(self.memory_dir, f"{date}.md")
            result = self.retrieve_from_file(query, memory_file)
            if result:
                results.append(result)
        
        return results
    
    def search_long_term_memory(self, query):
        """搜索长期记忆"""
        return self.retrieve_from_file(query, self.long_term_memory)
    
    def search_projects(self, query):
        """搜索项目文件"""
        results = []
        
        if os.path.exists(self.projects_dir):
            for project in os.listdir(self.projects_dir):
                project_dir = os.path.join(self.projects_dir, project)
                if os.path.isdir(project_dir):
                    progress_file = os.path.join(project_dir, "progress.md")
                    result = self.retrieve_from_file(query, progress_file)
                    if result:
                        results.append(result)
        
        return results
    
    def search_knowledge(self, query):
        """搜索知识库"""
        results = []
        
        if os.path.exists(self.knowledge_dir):
            for file in os.listdir(self.knowledge_dir):
                if file.endswith(".md"):
                    knowledge_file = os.path.join(self.knowledge_dir, file)
                    result = self.retrieve_from_file(query, knowledge_file)
                    if result:
                        results.append(result)
        
        return results
    
    def retrieve_context(self, query):
        """检索与查询相关的上下文"""
        all_results = []
        
        # 搜索长期记忆
        ltm_result = self.search_long_term_memory(query)
        if ltm_result:
            all_results.append(ltm_result)
        
        # 搜索最近记忆
        recent_results = self.search_recent_memories(query)
        all_results.extend(recent_results)
        
        # 搜索项目
        project_results = self.search_projects(query)
        all_results.extend(project_results)
        
        # 搜索知识库
        knowledge_results = self.search_knowledge(query)
        all_results.extend(knowledge_results)
        
        # 按相关性排序
        sorted_results = sorted(all_results, key=lambda x: x["relevance"], reverse=True)
        
        # 只返回最相关的几个结果
        top_results = sorted_results[:3]
        
        if not top_results:
            return None
            
        # 格式化上下文
        context = "以下是与当前查询相关的记忆内容:\n\n"
        for result in top_results:
            context += f"--- 来自 {result['source']} ---\n{result['content']}\n\n"
            
        return context

# 创建上下文检索器实例
context_retriever = ContextRetriever()

def register_callbacks(agent):
    @agent.before_generate
    def inject_relevant_context(prompt, **kwargs):
        """在生成回复前注入相关上下文"""
        # 检索相关上下文
        context = context_retriever.retrieve_context(prompt)
        
        if context:
            # 在提示前添加上下文
            augmented_prompt = f"{context}\n\n当前查询: {prompt}"
            return augmented_prompt
        
        return prompt
EOF

# 在OpenClaw启动时注册上下文检索工作流
echo 'openclaw workflow register context_retrieval_workflow' >> ~/.openclaw/startup.sh

📝 创建记忆维护命令

为了简化记忆的维护,我们创建一个简单的命令行工具:

Code
cat > ~/.openclaw/scripts/memory-cli.sh << 'EOF'
#!/bin/bash

# 设置基础目录
BASE_DIR=~/.openclaw
MEMORY_DIR=$BASE_DIR/memory
PROJECTS_DIR=$BASE_DIR/projects
KNOWLEDGE_DIR=$BASE_DIR/knowledge

# 帮助信息
show_help() {
    echo "OpenClaw记忆管理工具"
    echo ""
    echo "用法: memory-cli [命令] [参数]"
    echo ""
    echo "可用命令:"
    echo "  today             创建或打开今天的记忆文件"
    echo "  add [内容]        添加内容到今天的记忆"
    echo "  list [天数]       列出最近的记忆文件 (默认: 7天)"
    echo "  search [关键词]   搜索记忆"
    echo "  project new [名称] 创建新项目"
    echo "  project list      列出所有项目"
    echo "  summary [日期]    生成指定日期的记忆摘要 (默认: 昨天)"
    echo "  help              显示此帮助信息"
    echo ""
}

# 创建今天的记忆文件
create_today_memory() {
    TODAY=$(date +%Y-%m-%d)
    TODAY_FILE="$MEMORY_DIR/$TODAY.md"
    
    mkdir -p "$MEMORY_DIR"
    
    if [ ! -f "$TODAY_FILE" ]; then
        echo "# 记忆记录: $TODAY" > "$TODAY_FILE"
        echo "" >> "$TODAY_FILE"
        echo "## 对话摘要" >> "$TODAY_FILE"
        echo "" >> "$TODAY_FILE"
        echo "## 重要信息" >> "$TODAY_FILE"
        echo "" >> "$TODAY_FILE"
        echo "## 行动项" >> "$TODAY_FILE"
        echo "" >> "$TODAY_FILE"
        echo "创建了今天的记忆文件: $TODAY_FILE"
    else
        echo "今天的记忆文件已存在: $TODAY_FILE"
    fi
    
    # 如果EDITOR环境变量已设置,则打开文件
    if [ ! -z "$EDITOR" ]; then
        $EDITOR "$TODAY_FILE"
    else
        # 尝试几个常见的编辑器
        if command -v nano > /dev/null; then
            nano "$TODAY_FILE"
        elif command -v vim > /dev/null; then
            vim "$TODAY_FILE"
        else
            echo "提示: 设置EDITOR环境变量以自动打开文件"
        fi
    fi
}

# 添加内容到今天的记忆
add_to_today() {
    if [ $# -eq 0 ]; then
        echo "错误: 请提供要添加的内容"
        return 1
    fi
    
    TODAY=$(date +%Y-%m-%d)
    TODAY_FILE="$MEMORY_DIR/$TODAY.md"
    
    mkdir -p "$MEMORY_DIR"
    
    if [ ! -f "$TODAY_FILE" ]; then
        create_today_memory
    fi
    
    # 添加到重要信息部分
    TIMESTAMP=$(date +%H:%M)
    echo "- [$TIMESTAMP] $*" >> "$TODAY_FILE"
    
    echo "已添加到今天的记忆文件"
}

# 列出最近的记忆文件
list_memories() {
    DAYS=${1:-7}
    
    echo "最近 $DAYS 天的记忆文件:"
    echo "------------------------"
    
    for i in $(seq 0 $(($DAYS - 1))); do
        DATE=$(date -d "$i days ago" +%Y-%m-%d)
        FILE="$MEMORY_DIR/$DATE.md"
        
        if [ -f "$FILE" ]; then
            # 计算文件行数作为内容指示
            LINES=$(wc -l < "$FILE")
            
            # 提取第一个标题作为摘要
            SUMMARY=$(grep -m 1 "^# " "$FILE" | sed 's/^# //')
            
            echo "$DATE ($LINES 行) - $SUMMARY"
        fi
    done
}

# 搜索记忆
search_memories() {
    if [ $# -eq 0 ]; then
        echo "错误: 请提供搜索关键词"
        return 1
    fi
    
    SEARCH_TERM="$*"
    
    echo "搜索: '$SEARCH_TERM'"
    echo "------------------------"
    
    # 搜索记忆目录
    if [ -d "$MEMORY_DIR" ]; then
        echo "在记忆文件中:"
        grep -l -i "$SEARCH_TERM" "$MEMORY_DIR"/*.md 2>/dev/null | while read FILE; do
            FILENAME=$(basename "$FILE")
            echo "- $FILENAME:"
            grep -i --color=always -A 1 -B 1 "$SEARCH_TERM" "$FILE" | head -n 5
            echo "  ..."
            echo ""
        done
    fi
    
    # 搜索项目目录
    if [ -d "$PROJECTS_DIR" ]; then
        echo "在项目文件中:"
        find "$PROJECTS_DIR" -name "*.md" -exec grep -l -i "$SEARCH_TERM" {} \; | while read FILE; do
            REL_PATH=${FILE#$BASE_DIR/}
            echo "- $REL_PATH:"
            grep -i --color=always -A 1 -B 1 "$SEARCH_TERM" "$FILE" | head -n 5
            echo "  ..."
            echo ""
        done
    fi
    
    # 搜索知识库
    if [ -d "$KNOWLEDGE_DIR" ]; then
        echo "在知识库中:"
        find "$KNOWLEDGE_DIR" -name "*.md" -exec grep -l -i "$SEARCH_TERM" {} \; | while read FILE; do
            REL_PATH=${FILE#$BASE_DIR/}
            echo "- $REL_PATH:"
            grep -i --color=always -A 1 -B 1 "$SEARCH_TERM" "$FILE" | head -n 5
            echo "  ..."
            echo ""
        done
    fi
    
    # 搜索长期记忆
    LONG_TERM="$BASE_DIR/MEMORY.md"
    if [ -f "$LONG_TERM" ] && grep -q -i "$SEARCH_TERM" "$LONG_TERM"; then
        echo "在长期记忆中:"
        grep -i --color=always -A 1 -B 1 "$SEARCH_TERM" "$LONG_TERM" | head -n 5
        echo "  ..."
        echo ""
    fi
}

# 创建新项目
create_project() {
    if [ $# -eq 0 ]; then
        echo "错误: 请提供项目名称"
        return 1
    fi
    
    PROJECT_NAME="$*"
    DIR_NAME=$(echo "$PROJECT_NAME" | tr ' ' '_' | tr '[:upper:]' '[:lower:]')
    PROJECT_DIR="$PROJECTS_DIR/$DIR_NAME"
    
    mkdir -p "$PROJECT_DIR"
    
    # 创建项目文件
    PROGRESS_FILE="$PROJECT_DIR/progress.md"
    TODAY=$(date +%Y-%m-%d)
    
    cat > "$PROGRESS_FILE" << END
# $PROJECT_NAME

## 项目概览

- **开始日期**: $TODAY
- **预计完成**: [待定]
- **项目类型**: [待定]
- **优先级**: [待定]

## 最新状态

- **当前阶段**: 初始化
- **完成度**: 0%
- **最近更新**: $TODAY

## 目标与范围

[项目目标和范围描述]

## 任务清单

- [ ] 初始化项目
- [ ] 定义具体目标
- [ ] 规划实施步骤

## 参考资料

- [待添加]

## 笔记与思考

[项目相关的笔记和思考]

## 决策记录

| 日期 | 决策 | 原因 | 替代方案 | 影响 |
|------|------|------|----------|------|
| $TODAY | 创建项目 | 需要组织相关信息 | 无结构化记录 | 更好地跟踪进度 |

## 进展日志

### $TODAY
- 创建了项目框架
END
    
    echo "已创建项目: $PROJECT_NAME"
    echo "项目文件: $PROGRESS_FILE"
    
    # 更新长期记忆
    MEMORY_FILE="$BASE_DIR/MEMORY.md"
    if grep -q "## 进行中的项目" "$MEMORY_FILE"; then
        sed -i "/## 进行中的项目/a - **$PROJECT_NAME**: 参见 \`projects/$DIR_NAME/progress.md\`" "$MEMORY_FILE"
    fi
}

# 列出所有项目
list_projects() {
    echo "项目列表:"
    echo "------------------------"
    
    if [ -d "$PROJECTS_DIR" ]; then
        for PROJECT in $(ls -1 "$PROJECTS_DIR"); do
            if [ -d "$PROJECTS_DIR/$PROJECT" ]; then
                # 尝试提取项目名称和状态
                PROGRESS_FILE="$PROJECTS_DIR/$PROJECT/progress.md"
                
                if [ -f "$PROGRESS_FILE" ]; then
                    # 提取项目名称
                    NAME=$(grep -m 1 "^# " "$PROGRESS_FILE" | sed 's/^# //')
                    # 提取当前阶段
                    STAGE=$(grep -A 1 "**当前阶段**:" "$PROGRESS_FILE" | tail -n 1 | sed 's/- //g')
                    # 提取完成度
                    PROGRESS=$(grep -A 1 "**完成度**:" "$PROGRESS_FILE" | tail -n 1 | sed 's/- //g')
                    # 提取最后更新时间
                    UPDATE=$(grep -A 1 "**最近更新**:" "$PROGRESS_FILE" | tail -n 1 | sed 's/- //g')
                    
                    echo "$NAME [$STAGE, $PROGRESS, 更新: $UPDATE]"
                else
                    echo "$PROJECT [无进度文件]"
                fi
            fi
        done
    else
        echo "项目目录不存在"
    fi
}

# 生成记忆摘要
generate_summary() {
    DATE=${1:-$(date -d "yesterday" +%Y-%m-%d)}
    MEMORY_FILE="$MEMORY_DIR/$DATE.md"
    
    if [ ! -f "$MEMORY_FILE" ]; then
        echo "错误: 无法找到 $DATE 的记忆文件"
        return 1
    fi
    
    echo "生成 $DATE 的记忆摘要..."
    
    # 这里我们只做简单的提取,实际上可能需要更复杂的摘要生成逻辑
    echo "摘要 ($DATE):"
    echo "------------------------"
    
    # 提取重要信息
    echo "重要信息:"
    grep -A 100 "^## 重要信息" "$MEMORY_FILE" | grep -m 100 -B 100 "^##" | grep -v "^## " | grep "^\- "
    
    # 提取行动项
    echo ""
    echo "行动项:"
    grep -A 100 "^## 行动项" "$MEMORY_FILE" | grep -m 100 -B 100 "^##" | grep -v "^## " | grep "^\- "
    
    # 提示手动添加到长期记忆
    echo ""
    echo "请考虑将这些重要信息添加到长期记忆文件 (MEMORY.md) 中"
}

# 主函数
main() {
    case "$1" in
        today)
            create_today_memory
            ;;
        add)
            shift
            add_to_today "$@"
            ;;
        list)
            list_memories "$2"
            ;;
        search)
            shift
            search_memories "$@"
            ;;
        project)
            case "$2" in
                new)
                    shift 2
                    create_project "$@"
                    ;;
                list)
                    list_projects
                    ;;
                *)
                    echo "未知的项目命令: $2"
                    show_help
                    ;;
            esac
            ;;
        summary)
            generate_summary "$2"
            ;;
        help|--help|-h)
            show_help
            ;;
        *)
            echo "未知命令: $1"
            show_help
            ;;
    esac
}

# 如果没有参数,显示帮助
if [ $# -eq 0 ]; then
    show_help
    exit 1
fi

main "$@"
EOF

chmod +x ~/.openclaw/scripts/memory-cli.sh

# 创建符号链接到用户的bin目录
mkdir -p ~/bin
ln -sf ~/.openclaw/scripts/memory-cli.sh ~/bin/memory-cli

# 添加到PATH(如果还没有的话)
if ! grep -q "PATH=\$PATH:~/bin" ~/.bashrc; then
    echo 'export PATH=$PATH:~/bin' >> ~/.bashrc
    echo '记忆管理CLI工具已安装,请重新加载终端或运行 "source ~/.bashrc" 使其生效'
fi

🧩 创建记忆小部件

最后,让我们添加一个交互式记忆小部件,方便用户查看和管理记忆:

Code
mkdir -p ~/.openclaw/widgets

cat > ~/.openclaw/widgets/memory_widget.html << 'EOF'
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>OpenClaw记忆管理</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            line-height: 1.6;
            margin: 0;
            padding: 20px;
            color: #333;
            background-color: #f9f9f9;
        }
        h1, h2, h3 {
            color: #2c3e50;
        }
        .container {
            max-width: 800px;
            margin: 0 auto;
            background-color: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
        }
        .tabs {
            display: flex;
            margin-bottom: 20px;
            border-bottom: 1px solid #ddd;
        }
        .tab {
            padding: 10px 20px;
            cursor: pointer;
            margin-right: 5px;
            border-radius: 5px 5px 0 0;
            background-color: #f1f1f1;
        }
        .tab.active {
            background-color: #3498db;
            color: white;
        }
        .tab-content {
            display: none;
        }
        .tab-content.active {
            display: block;
        }
        input, textarea, button, select {
            padding: 8px;
            margin-bottom: 10px;
            border-radius: 4px;
            border: 1px solid #ddd;
            width: 100%;
        }
        button {
            background-color: #3498db;
            color: white;
            border: none;
            cursor: pointer;
            width: auto;
        }
        button:hover {
            background-color: #2980b9;
        }
        .card {
            border: 1px solid #ddd;
            border-radius: 4px;
            padding: 10px;
            margin-bottom: 10px;
            background-color: white;
        }
        .search-result {
            margin-top: 20px;
            border-top: 1px solid #ddd;
            padding-top: 10px;
        }
        .memory-item {
            border-bottom: 1px solid #eee;
            padding: 5px 0;
        }
        .highlight {
            background-color: #ffffcc;
            padding: 2px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>OpenClaw记忆管理</h1>
        
        <div class="tabs">
            <div class="tab active" data-tab="search">搜索记忆</div>
            <div class="tab" data-tab="add">添加记忆</div>
            <div class="tab" data-tab="projects">项目管理</div>
            <div class="tab" data-tab="preferences">用户偏好</div>
        </div>
        
        <div class="tab-content active" id="search">
            <h2>搜索记忆</h2>
            <input type="text" id="search-input" placeholder="输入关键词搜索...">
            <button id="search-btn">搜索</button>
            
            <div class="search-options">
                <label>
                    <input type="checkbox" id="search-memory" checked>
                    日常记忆
                </label>
                <label>
                    <input type="checkbox" id="search-long-term" checked>
                    长期记忆
                </label>
                <label>
                    <input type="checkbox" id="search-projects" checked>
                    项目文件
                </label>
            </div>
            
            <div id="search-results" class="search-result"></div>
        </div>
        
        <div class="tab-content" id="add">
            <h2>添加记忆</h2>
            <select id="memory-type">
                <option value="info">重要信息</option>
                <option value="action">行动项</option>
                <option value="decision">决策</option>
            </select>
            <textarea id="memory-content" rows="4" placeholder="输入要记住的内容..."></textarea>
            <button id="add-memory-btn">添加到今天的记忆</button>
            <div id="add-result"></div>
        </div>
        
        <div class="tab-content" id="projects">
            <h2>项目管理</h2>
            <div id="projects-list">
                <h3>当前项目</h3>
                <div id="current-projects">
                    加载中...
                </div>
                
                <h3>创建新项目</h3>
                <input type="text" id="project-name" placeholder="项目名称">
                <button id="create-project-btn">创建项目</button>
                <div id="project-result"></div>
            </div>
        </div>
        
        <div class="tab-content" id="preferences">
            <h2>用户偏好</h2>
            <div id="preferences-section">
                <h3>添加新偏好</h3>
                <select id="preference-category">
                    <option value="通信偏好">通信偏好</option>
                    <option value="工作习惯">工作习惯</option>
                    <option value="内容偏好">内容偏好</option>
                    <option value="个人兴趣">个人兴趣</option>
                </select>
                <input type="text" id="preference-key" placeholder="偏好名称 (如: 回复长度)">
                <input type="text" id="preference-value" placeholder="偏好值 (如: 简洁)">
                <button id="add-preference-btn">添加偏好</button>
                
                <h3>当前偏好</h3>
                <div id="current-preferences">
                    加载中...
                </div>
                <div id="preference-result"></div>
            </div>
        </div>
    </div>

    <script>
        // 切换标签
        document.querySelectorAll('.tab').forEach(tab => {
            tab.addEventListener('click', () => {
                // 移除所有活动标签
                document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
                document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
                
                // 激活当前标签
                tab.classList.add('active');
                const tabId = tab.getAttribute('data-tab');
                document.getElementById(tabId).classList.add('active');
            });
        });
        
        // 模拟数据 (在实际实现中,这些数据应该从OpenClaw记忆文件中读取)
        const mockData = {
            memories: [
                { date: '2023-06-05', type: 'info', content: '用户喜欢简洁的回复风格' },
                { date: '2023-06-04', type: 'action', content: '提醒用户下周参加项目会议' },
                { date: '2023-06-03', type: 'info', content: '用户对AI助手的定制功能特别感兴趣' }
            ],
            projects: [
                { name: 'OpenClaw学习', progress: '75%', stage: '记忆管理' },
                { name: '网站开发', progress: '30%', stage: '设计阶段' }
            ],
            preferences: {
                '通信偏好': [
                    { key: '回复风格', value: '简洁' },
                    { key: '回复格式', value: '结构化' }
                ],
                '工作习惯': [
                    { key: '工作时间', value: '上午9点至下午6点' }
                ]
            }
        };
        
        // 搜索功能
        document.getElementById('search-btn').addEventListener('click', () => {
            const query = document.getElementById('search-input').value.trim();
            if (query === '') return;
            
            const resultsDiv = document.getElementById('search-results');
            resultsDiv.innerHTML = '<h3>搜索结果</h3>';
            
            // 模拟搜索结果
            const results = mockData.memories.filter(m => 
                m.content.toLowerCase().includes(query.toLowerCase())
            );
            
            if (results.length === 0) {
                resultsDiv.innerHTML += '<p>没有找到匹配的结果</p>';
                return;
            }
            
            results.forEach(result => {
                const highlighted = result.content.replace(
                    new RegExp(query, 'gi'),
                    match => `<span class="highlight">${match}</span>`
                );
                
                const card = document.createElement('div');
                card.className = 'card';
                card.innerHTML = `
                    <p><strong>${result.date}</strong> (${result.type})</p>
                    <p>${highlighted}</p>
                `;
                resultsDiv.appendChild(card);
            });
        });
        
        // 添加记忆
        document.getElementById('add-memory-btn').addEventListener('click', () => {
            const type = document.getElementById('memory-type').value;
            const content = document.getElementById('memory-content').value.trim();
            
            if (content === '') {
                document.getElementById('add-result').innerHTML = '<p style="color:red;">请输入内容</p>';
                return;
            }
            
            // 模拟添加记忆
            const today = new Date().toISOString().split('T')[0];
            mockData.memories.unshift({
                date: today,
                type: type,
                content: content
            });
            
            document.getElementById('memory-content').value = '';
            document.getElementById('add-result').innerHTML = '<p style="color:green;">记忆已添加!</p>';
            
            // 3秒后清除结果消息
            setTimeout(() => {
                document.getElementById('add-result').innerHTML = '';
            }, 3000);
        });
        
        // 加载项目列表
        function loadProjects() {
            const projectsDiv = document.getElementById('current-projects');
            projectsDiv.innerHTML = '';
            
            mockData.projects.forEach(project => {
                const card = document.createElement('div');
                card.className = 'card';
                card.innerHTML = `
                    <h4>${project.name}</h4>
                    <p>进度: ${project.progress}</p>
                    <p>当前阶段: ${project.stage}</p>
                    <button class="view-project-btn" data-project="${project.name}">查看详情</button>
                `;
                projectsDiv.appendChild(card);
            });
            
            // 添加查看详情事件
            document.querySelectorAll('.view-project-btn').forEach(btn => {
                btn.addEventListener('click', () => {
                    const projectName = btn.getAttribute('data-project');
                    alert(`显示项目 ${projectName} 的详细信息`);
                });
            });
        }
        
        // 创建项目
        document.getElementById('create-project-btn').addEventListener('click', () => {
            const projectName = document.getElementById('project-name').value.trim();
            
            if (projectName === '') {
                document.getElementById('project-result').innerHTML = '<p style="color:red;">请输入项目名称</p>';
                return;
            }
            
            // 模拟创建项目
            mockData.projects.push({
                name: projectName,
                progress: '0%',
                stage: '初始化'
            });
            
            document.getElementById('project-name').value = '';
            document.getElementById('project-result').innerHTML = '<p style="color:green;">项目已创建!</p>';
            
            // 更新项目列表
            loadProjects();
            
            // 3秒后清除结果消息
            setTimeout(() => {
                document.getElementById('project-result').innerHTML = '';
            }, 3000);
        });
        
        // 加载偏好
        function loadPreferences() {
            const preferencesDiv = document.getElementById('current-preferences');
            preferencesDiv.innerHTML = '';
            
            Object.entries(mockData.preferences).forEach(([category, prefs]) => {
                const categoryDiv = document.createElement('div');
                categoryDiv.className = 'preference-category';
                categoryDiv.innerHTML = `<h4>${category}</h4>`;
                
                prefs.forEach(pref => {
                    const prefDiv = document.createElement('div');
                    prefDiv.className = 'memory-item';
                    prefDiv.innerHTML = `<strong>${pref.key}:</strong> ${pref.value}`;
                    categoryDiv.appendChild(prefDiv);
                });
                
                preferencesDiv.appendChild(categoryDiv);
            });
        }
        
        // 添加偏好
        document.getElementById('add-preference-btn').addEventListener('click', () => {
            const category = document.getElementById('preference-category').value;
            const key = document.getElementById('preference-key').value.trim();
            const value = document.getElementById('preference-value').value.trim();
            
            if (key === '' || value === '') {
                document.getElementById('preference-result').innerHTML = '<p style="color:red;">请输入偏好名称和值</p>';
                return;
            }
            
            // 模拟添加偏好
            if (!mockData.preferences[category]) {
                mockData.preferences[category] = [];
            }
            
            // 检查是否已存在
            const existingIndex = mockData.preferences[category].findIndex(p => p.key === key);
            if (existingIndex >= 0) {
                mockData.preferences[category][existingIndex].value = value;
            } else {
                mockData.preferences[category].push({ key, value });
            }
            
            document.getElementById('preference-key').value = '';
            document.getElementById('preference-value').value = '';
            document.getElementById('preference-result').innerHTML = '<p style="color:green;">偏好已添加!</p>';
            
            // 更新偏好列表
            loadPreferences();
            
            // 3秒后清除结果消息
            setTimeout(() => {
                document.getElementById('preference-result').innerHTML = '';
            }, 3000);
        });
        
        // 初始加载
        loadProjects();
        loadPreferences();
    </script>
</body>
</html>
EOF

🎯 今日小结

在Day 6中,我们深入探讨了OpenClaw基于文件的记忆管理系统,包括:

  1. 记忆文件结构:建立了清晰的记忆文件组织方式
    • 长期记忆索引 (MEMORY.md)
    • 日常记忆记录 (memory/YYYY-MM-DD.md)
    • 项目记忆管理 (projects/)
    • 知识库索引 (knowledge/)
  2. 记忆管理工具:创建了一系列便于记忆管理的工具和脚本
    • 日常记忆创建和管理
    • 记忆搜索功能
    • 项目创建和管理
    • 记忆摘要生成
  3. 工作流实现:开发了记忆管理相关的工作流
    • 从对话中提取重要信息
    • 用户偏好的识别和存储
    • 上下文相关记忆检索
    • 记忆命令处理
  4. 记忆最佳实践:学习了有效管理AI记忆的最佳方法
    • 使用索引而不是堆积所有内容
    • 定期整理和提炼记忆
    • 分离临时记忆和长期记忆
    • 保护隐私和敏感信息

通过这些功能,你的AI助手现在能够:

  • 记住重要的对话内容和用户偏好
  • 在对话中智能地引用相关的历史记忆
  • 有效地管理项目信息和进度
  • 维护持续的上下文理解,提供更个性化的服务

与复杂的向量数据库不同,我们采用了基于文件的记忆系统,使其更易于理解、使用和维护,同时保留了强大的记忆能力。

🔮 明日预告

明天,我们将迎来OpenClaw 7天学习教程的最后一天:Day 7: 多模态与高级应用

我们将探讨如何:

  • 实现图像识别和处理能力
  • 添加语音交互功能
  • 创建多模态工作流
  • 构建复杂的应用场景
  • 学习高级部署和优化技巧

准备好让你的AI助手进入多模态时代,处理图像、语音等更丰富的内容形式了吗?明天见!🚀


同专题推荐