摘要

本文深入探讨 OpenClaw 框架中的 memory_search 语义搜索功能。从向量搜索原理、工具参数详解、搜索策略优化到实战应用场景,全面解析如何高效检索记忆内容。通过实际案例演示用户偏好查询、历史决策追溯、问题解决方案检索等典型场景,帮助开发者构建具有智能记忆检索能力的 AI 应用,实现"过目不忘"的效果。🔍


1. 引言 - 为什么需要语义搜索?

1.1 传统搜索的局限

问题 说明 示例
关键词匹配 只能匹配精确词 搜"偏好"找不到"喜好"
无语义理解 不理解查询意图 搜"怎么解决"找不到"解决方案"
结果排序差 无法按相关性排序 最相关的结果排在后面
上下文缺失 无法关联相关内容 找不到上下文相关的信息

1.2 语义搜索的优势

传统搜索

查询

关键词匹配

返回结果

查询

向量化

相似度计算

排序

返回结果

1.3 memory_search 核心能力

能力 说明 效果
语义理解 理解查询的真实意图 搜"不喜欢"能找到"偏好"
模糊匹配 容忍拼写和表达差异 搜"飞书"能找到"Feishu"
相关性排序 按相似度排序结果 最相关的排在最前
多源检索 同时搜索多个记忆文件 一次查询所有日志

2. memory_search 工具详解

2.1 工具签名

memory_search(
    query: str,           # 搜索查询文本
    maxResults: int = 5,  # 最大返回结果数
    minScore: float = 0.5 # 最小相关性分数阈值
)

2.2 参数详解

参数 类型 默认值 说明
query string 必填 搜索查询文本
maxResults int 5 返回的最大结果数量
minScore float 0.5 最小相关性分数(0-1)

2.3 返回格式

{
  "results": [
    {
      "path": "MEMORY.md",
      "lines": "10-15",
      "content": "用户偏好:简洁表达风格",
      "score": 0.95
    },
    {
      "path": "memory/2026-04-10.md",
      "lines": "20-25",
      "content": "用户要求文章不要太长",
      "score": 0.82
    }
  ],
  "provider": "none",
  "citations": "auto",
  "mode": "fts-only"
}

2.4 相关性分数解读

分数范围 含义 建议
0.9-1.0 高度相关 直接使用
0.7-0.9 相关 可参考使用
0.5-0.7 弱相关 需要进一步判断
< 0.5 不相关 通常不返回

3. 搜索策略优化

3.1 查询优化技巧

技巧 说明 示例
使用关键词 提取核心关键词 “用户偏好” 而非 “用户有什么偏好”
组合查询 组合多个关键词 “文章 结构 决策”
使用同义词 尝试不同表达 “偏好” 或 “喜好” 或 “倾向”
添加上下文 提供更多上下文 “Gateway 启动失败 解决方案”

3.2 参数调优策略

太少

太多

合适

开始搜索

结果数量

降低 minScore

提高 minScore

完成

相关性如何

优化查询词

是否遗漏

增加 maxResults

3.3 搜索场景与参数建议

场景 maxResults minScore 说明
精确查找 3 0.7 只需要最相关的结果
广泛搜索 10 0.4 需要尽可能多的结果
决策追溯 5 0.6 查找历史决策
问题检索 5 0.5 查找类似问题

4. 实战应用场景

4.1 场景一:用户偏好查询

用户问题

我之前说过喜欢什么样的文章风格?

AI 内部调用

memory_search(
    query="用户 文章 风格 偏好",
    maxResults=5,
    minScore=0.5
)

返回结果

{
  "results": [
    {
      "path": "MEMORY.md",
      "lines": "15-18",
      "content": "## 沟通偏好\n- 表达风格:简洁直接,不喜欢啰嗦\n- 文章格式:表格 + 代码块 + 图表",
      "score": 0.92
    },
    {
      "path": "memory/2026-04-10.md",
      "lines": "5-8",
      "content": "用户反馈:文章太长了,希望更简洁",
      "score": 0.78
    }
  ]
}

AI 回复

根据记忆,你喜欢简洁直接的文章风格,不喜欢啰嗦。文章格式方面,你偏好表格 + 代码块 + 图表的组合形式。之前你也提过文章不要太长。

4.2 场景二:历史决策追溯

用户问题

我们为什么选择 5 阶段的文章结构?

AI 内部调用

memory_search(
    query="文章结构 阶段 决策 原因",
    maxResults=3,
    minScore=0.6
)

返回结果

{
  "results": [
    {
      "path": "memory/2026-03-14.md",
      "lines": "20-30",
      "content": "## 重要决策\n### 决策:文章采用 5 阶段结构\n- 选择:方案 B\n- 原因:\n  1. 由浅入深更符合学习曲线\n  2. 读者可以按阶段学习\n  3. 便于后续扩展",
      "score": 0.89
    }
  ]
}

AI 回复

根据 2026-03-14 的决策记录,选择 5 阶段结构的原因是:

  1. 由浅入深更符合学习曲线 - 读者可以循序渐进
  2. 读者可以按阶段学习 - 不同水平的读者找到适合自己的阶段
  3. 便于后续扩展 - 可以方便地增加新阶段

4.3 场景三:问题解决方案检索

用户问题

之前 Gateway 启动失败是怎么解决的?

AI 内部调用

memory_search(
    query="Gateway 启动失败 解决",
    maxResults=5,
    minScore=0.5
)

返回结果

{
  "results": [
    {
      "path": "memory/2026-04-05.md",
      "lines": "10-20",
      "content": "## 遇到的问题\n### 问题:Gateway 启动失败\n- 原因:端口 18800 被占用\n- 解决:kill -9 <PID> 后重启",
      "score": 0.91
    },
    {
      "path": "memory/2026-03-20.md",
      "lines": "15-18",
      "content": "Gateway 启动报错:检查配置文件路径",
      "score": 0.65
    }
  ]
}

AI 回复

根据历史记录,Gateway 启动失败有两种情况:

情况一(最相关)

  • 原因:端口 18800 被占用
  • 解决方案
    1. 检查端口占用:lsof -i :18800
    2. 终止占用进程:kill -9 <PID>
    3. 重新启动:openclaw gateway start

情况二

  • 原因:配置文件路径错误
  • 解决方案:检查 openclaw.yaml 路径是否正确

4.4 场景四:任务进度查询

用户问题

我们的文章项目进度怎么样了?

AI 内部调用

memory_search(
    query="文章 项目 进度 完成",
    maxResults=3,
    minScore=0.5
)

返回结果

{
  "results": [
    {
      "path": "MEMORY.md",
      "lines": "10-12",
      "content": "## 项目上下文\n- 目标:完成100篇技术文章\n- 已完成:42篇\n- 完成率:42%",
      "score": 0.88
    },
    {
      "path": "memory/2026-04-13.md",
      "lines": "5-10",
      "content": "## 项目进度\n- 总目标:100篇文章\n- 已完成:42篇\n- 今日完成:第41、42篇",
      "score": 0.82
    }
  ]
}

AI 回复

根据最新记录,文章项目进度如下:

项目 数值
总目标 100 篇文章
已完成 42 篇
完成率 42%
今日完成 第41、42篇

5. 高级搜索技巧

5.1 组合查询

# 搜索用户关于文章的所有反馈
memory_search(
    query="用户 文章 反馈 意见 建议",
    maxResults=10,
    minScore=0.4
)

5.2 时间范围限定

# 先确定日期范围,再搜索
# 搜索最近7天的记录
for i in range(7):
    date = today - timedelta(days=i)
    # 可以先读取文件再进行本地搜索
    content = read(f"memory/{date}.md")
    # 或使用 memory_search 自动覆盖所有文件

5.3 多轮搜索

第一轮搜索

结果满意?

返回结果

优化查询

第二轮搜索

结果满意?

扩大范围

第三轮搜索

5.4 搜索结果后处理

def process_search_results(results):
    """对搜索结果进行后处理"""
    processed = []
    for result in results:
        # 提取关键信息
        item = {
            "source": result["path"],
            "content": result["content"],
            "relevance": result["score"],
            "date": extract_date(result["path"])
        }
        processed.append(item)
    
    # 按相关性排序
    processed.sort(key=lambda x: x["relevance"], reverse=True)
    return processed

6. 搜索性能优化

6.1 索引优化

优化项 说明 效果
定期重建索引 更新向量索引 提高搜索准确性
分块存储 大文件分块索引 减少搜索范围
缓存热点 缓存常用查询 加快响应速度

6.2 查询优化

优化项 说明 效果
精简查询 使用关键词而非长句 提高匹配精度
避免重复 缓存查询结果 减少重复计算
批量查询 合并多个查询 减少API调用

6.3 结果优化

优化项 说明 效果
结果去重 合并重复内容 减少冗余
智能摘要 提取关键信息 提高可读性
上下文补充 补充前后文 提高理解度

7. 常见问题与解决

Q1:搜索结果不准确怎么办?

解决方案

  1. 优化查询关键词
  2. 调整 minScore 阈值
  3. 尝试不同的表达方式
  4. 使用更具体的查询

Q2:搜索结果太多怎么办?

解决方案

  1. 提高 minScore 阈值
  2. 减少 maxResults
  3. 使用更精确的查询
  4. 添加更多关键词

Q3:搜索结果太少怎么办?

解决方案

  1. 降低 minScore 阈值
  2. 增加 maxResults
  3. 使用更宽泛的查询
  4. 尝试同义词

Q4:搜索速度慢怎么办?

解决方案

  1. 减少搜索范围
  2. 使用缓存
  3. 优化查询复杂度
  4. 定期清理旧日志

8. 最佳实践总结

8.1 搜索策略清单

  • 使用关键词而非长句
  • 根据场景调整参数
  • 多轮搜索逐步优化
  • 对结果进行后处理
  • 缓存常用查询结果

8.2 参数配置建议

场景 maxResults minScore 查询策略
精确查找 3 0.7 关键词组合
广泛搜索 10 0.4 单个关键词
决策追溯 5 0.6 决策相关词
问题检索 5 0.5 问题+解决

8.3 下一步

  • 第44篇:OpenClaw 记忆维护:自动整理与归档
  • 第45篇:OpenClaw 上下文管理:Token 优化策略

参考资料

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐