乐于分享
好东西不私藏

OpenClaw工具拆解之memory_search+memory_get

OpenClaw工具拆解之memory_search+memory_get

一、mem)ory_search 工具

1.1 工具概述

功能:语义搜索记忆文件
核心特性

  • • 搜索 MEMORY.md + memory/*.md
  • • 支持向量嵌入搜索
  • • 支持混合搜索(向量 + 文本)
  • • 支持分数阈值过滤
  • • 支持结果数量限制
  • • 返回路径 + 行号

1.2 Schema 定义

位置:约第 5957 行(工具元数据)

"memory_search": {
"emoji""🧠",
"title""Memory Search",
"detailKeys": ["query"]
}

实际参数 Schema(动态构建):

constMemorySearchSchema = Type.Object({
queryType.String({ description"Search query string" }),
minScoreType.Optional(Type.Number({ description"Minimum similarity score threshold" })),
maxResultsType.Optional(Type.Number({ description"Maximum number of results to return" }))
});

1.3 配置结构

位置:约第 18615 行

// 默认配置
constDEFAULT_OPENAI_MODEL = "text-embedding-3-small";
constDEFAULT_GEMINI_MODEL = "gemini-embedding-001";
constDEFAULT_VOYAGE_MODEL = "voyage-4-large";
constDEFAULT_MISTRAL_MODEL = "mistral-embed";
constDEFAULT_OLLAMA_MODEL = "nomic-embed-text";
constDEFAULT_CHUNK_TOKENS = 400;
constDEFAULT_CHUNK_OVERLAP = 80;
constDEFAULT_MAX_RESULTS = 6;
constDEFAULT_MIN_SCORE = 0.35;
constDEFAULT_HYBRID_ENABLED = true;
constDEFAULT_HYBRID_VECTOR_WEIGHT = 0.7;
constDEFAULT_HYBRID_TEXT_WEIGHT = 0.3;

1.4 完整配置结构

memorySearch: {
enabledtrue,                    // 是否启用
provider"auto",                 // 提供商(auto/openai/gemini/voyage/mistral/ollama/local)
model"text-embedding-3-small",  // 模型名称
outputDimensionality1536,       // 输出维度

// 远程配置
remote: {
baseUrl"...",               // API 基础 URL
apiKey"...",                // API 密钥
batch: {
enabledfalse,           // 启用批量处理
waittrue,               // 等待批量完成
concurrency2,           // 并发数
pollIntervalMs2000,     // 轮询间隔
timeoutMinutes60// 超时时间
        }
    },

// 本地配置
local: {
modelPath"...",             // 本地模型路径
modelCacheDir"..."// 模型缓存目录
    },

// 数据源
sources: ["memory"],              // 数据源(memory/sessions)
extraPaths: [],                   // 额外路径

// 分块配置
chunking: {
tokens400,                  // 每块 token 数
overlap80// 重叠 token 数
    },

// 查询配置
query: {
maxResults6,                // 最大结果数
minScore0.35,               // 最小分数
hybrid: {
enabledtrue,            // 启用混合搜索
vectorWeight0.7,        // 向量权重
textWeight0.3,          // 文本权重
candidateMultiplier4,   // 候选倍数
mmr: {
enabledfalse,       // 启用 MMR
lambda0.7// MMR 参数
            },
temporalDecay: {
enabledfalse,       // 启用时间衰减
halfLifeDays30// 半衰期(天)
            }
        }
    },

// 缓存配置
cache: {
enabledtrue,                // 启用缓存
maxEntries1000// 最大缓存条目
    },

// 存储配置
store: {
driver"sqlite",             // 存储驱动(sqlite)
path"...",                  // 存储路径
vector: {
enabledtrue,            // 启用向量存储
extensionPath"..."// 向量扩展路径
        }
    },

// 同步配置
sync: {
onSessionStarttrue,         // 会话启动时同步
onSearchtrue,               // 搜索时同步
watchtrue,                  // 监听文件变化
watchDebounceMs1500,        // 监听防抖时间
intervalMinutes0,           // 同步间隔(分钟)
sessions: {
deltaBytes100000,       // 字节变化阈值
deltaMessages50,        // 消息变化阈值
postCompactionForcetrue// 压缩后强制同步
        }
    }
}

1.5 执行流程

memory_search 工具调用
    ↓
1. 解析查询参数
   ├─ query(必填)
   ├─ minScore(可选,默认 0.35)
   └─ maxResults(可选,默认 6)
    ↓
2. 加载记忆索引
   ├─ MEMORY.md
   └─ memory/*.md
    ↓
3. 生成查询嵌入向量
   ├─ 使用配置的提供商(OpenAI/Gemini 等)
   └─ 或本地模型
    ↓
4. 执行搜索
   ├─ 向量搜索(相似度匹配)
   ├─ 文本搜索(关键词匹配)
   └─ 混合排序(向量 70% + 文本 30%)
    ↓
5. 应用过滤
   ├─ minScore 阈值
   └─ maxResults 限制
    ↓
6. 返回结果

1.6 返回结果格式

成功

{
"results":[
{
"path":"MEMORY.md",
"content":"音乐偏好:喜欢的歌都在 C:\\Users\\83760\\Music\\good 文件夹里",
"score":0.85,
"line":10
},
{
"path":"memory/2026-03-28.md",
"content":"特别喜爱:《Adagio of the Highland》- Bandari(班德瑞)",
"score":0.78,
"line":15
}
],
"query":"用户喜欢的音乐",
"totalFound":2
}

失败

{
"error":"Memory search is not enabled. Set memorySearch.enabled=true in config."
}

1.7 使用示例

用户我喜欢的音乐有哪些

大模型操作

{
"tool_call":{
"name":"memory_search",
"arguments":{
"query":"用户喜欢的音乐",
"maxResults":5
}
}
}

执行结果

{
"results":[
{
"path":"MEMORY.md",
"content":"音乐偏好:喜欢的歌都在 C:\\Users\\83760\\Music\\good 文件夹里",
"score":0.85,
"line":10
},
{
"path":"USER.md",
"content":"特别喜爱:《Adagio of the Highland》- Bandari(班德瑞)",
"score":0.78,
"line":15
}
],
"query":"用户喜欢的音乐",
"totalFound":2
}

二、memory_get 工具

2.1 工具概述

功能:获取指定文件的特定行
核心特性

  • • 精确行范围读取
  • • 用于 memory_search 后获取详情
  • • 保持上下文小
  • • 支持 MEMORY.md 和 memory/*.md

2.2 Schema 定义

位置:约第 5957 行(工具元数据)

"memory_get": {
"emoji""📓",
"title""Memory Get",
"detailKeys": ["path""from""lines"]
}

实际参数 Schema

constMemoryGetSchema = Type.Object({
pathType.String({ description"Path to the memory file" }),
fromType.Optional(Type.Number({ description"Line number to start from" })),
linesType.Optional(Type.Number({ description"Number of lines to read" }))
});

2.3 执行代码

functioncreateMemoryGetTool(options) {
return {
label"Memory Get",
name"memory_get",
description"Safe snippet read from MEMORY.md or memory/*.md with optional from/lines; use after memory_search to pull only the needed lines and keep context small.",
parametersMemoryGetSchema,
executeasync (_toolCallId, args) => {
const params = args;

// 1. 解析路径(必填)
const path = readStringParam$1(params, "path", { requiredtrue });

// 2. 解析起始行
constfrom = typeof params.from === "number" && Number.isFinite(params.from) ? 
Math.max(1Math.floor(params.from)) : 1;

// 3. 解析行数
const lines = typeof params.lines === "number" && Number.isFinite(params.lines) ? 
Math.max(1Math.floor(params.lines)) : 10;

// 4. 解析记忆目录
const memoryDir = options?.memoryDir ?? path.join(options?.workspaceDir ?? process.cwd(), 'memory');

// 5. 构建完整路径
const fullPath = path.startsWith('memory/') ? 
                path.join(memoryDir, path.slice(7)) : 
                path.join(options?.workspaceDir ?? process.cwd(), path);

// 6. 读取文件
const content = await fs$1.readFile(fullPath, 'utf-8');
const allLines = content.split('\n');

// 7. 提取指定行
const startIdx = from - 1;  // 转换为 0-based 索引
const endIdx = Math.min(startIdx + lines, allLines.length);
const selectedLines = allLines.slice(startIdx, endIdx);

// 8. 返回结果
return {
content: [{
type"text",
text: selectedLines.join('\n')
                }],
details: {
                    path,
from,
lines: selectedLines.length,
totalLines: allLines.length
                }
            };
        }
    };
}

2.4 执行流程图

memory_get 工具调用
    ↓
1. 解析路径(必填)
    ↓
2. 解析起始行(默认 1)
    ↓
3. 解析行数(默认 10)
    ↓
4. 构建完整路径
   ├─ memory/xxx.md → memory 目录
   └─ MEMORY.md → 工作区根目录
    ↓
5. 读取文件
    ↓
6. 提取指定行
    ↓
7. 返回结果

2.5 返回结果格式

成功

{
"content":[{
"type":"text",
"text":"音乐偏好:喜欢的歌都在 C:\\Users\\83760\\Music\\good 文件夹里\n\n特别喜爱:《Adagio of the Highland》- Bandari(班德瑞)"
}],
"details":{
"path":"MEMORY.md",
"from":10,
"lines":2,
"totalLines":100
}
}

失败

{
"error":"File not found: memory/2026-03-28.md"
}

2.6 使用示例

用户查看 MEMORY.md 第 10 行开始的 5 行内容

大模型返回

{
"tool_call":{
"name":"memory_get",
"arguments":{
"path":"MEMORY.md",
"from":10,
"lines":5
}
}
}

执行结果

{
"content":[{
"type":"text",
"text":"音乐偏好:喜欢的歌都在 C:\\Users\\83760\\Music\\good 文件夹里\n\n特别喜爱:《Adagio of the Highland》- Bandari(班德瑞)\n\n关于老大:\n- 名字:老大"
}],
"details":{
"path":"MEMORY.md",
"from":10,
"lines":5,
"totalLines":100
}
}

三、关键机制对比

3.1 功能定位

特性
memory_search
memory_get
用途
语义搜索
精确读取
输入
查询字符串
文件路径 + 行范围
输出
多个匹配片段
指定行内容

3.2 使用场景

场景
推荐工具
查找相关信息
memory_search
获取详细内容
memory_get
组合使用
memory_search → memory_get

3.3 配置要求

特性
memory_search
memory_get
嵌入模型
需要
不需要
向量存储
SQLite
不需要
文件同步
监听变化
直接读取

四、组合使用示例

4.1 典型工作流

1. 用户提问:`我喜欢的音乐有哪些`
   ↓
2. 大模型调用 memory_search
   {
     "query": "用户喜欢的音乐",
     "maxResults": 5
   }
   ↓
3. 返回搜索结果
   [
     { "path": "MEMORY.md", "line": 10, "score": 0.85 },
     { "path": "USER.md", "line": 15, "score": 0.78 }
   ]
   ↓
4. 大模型调用 memory_get 获取详情
   {
     "path": "MEMORY.md",
     "from": 10,
     "lines": 5
   }
   ↓
5. 返回详细内容并回答用户

4.2 代码示例

// 1. 搜索记忆
const searchResults = awaitmemory_search({
query"用户喜欢的音乐",
maxResults5
});

// 2. 获取详细内容
for (const result of searchResults.results) {
const detail = awaitmemory_get({
path: result.path,
from: result.line,
lines5
    });
console.log(detail.content[0].text);
}