内存

OpenClaw 内存?代理工作区中的纯 Markdown*。文件是真相来源;模型只”记住”写入磁盘的内容?

内存搜索工具由活动的内存插件提供(默认:memory-core)。使?plugins.slots.memory = "none" 禁用内存插件?

内存文件(Markdown?

默认工作区布局使用两层内存?

  • memory/YYYY-MM-DD.md
    • 每日日志(仅追加)?
    • 会话开始时读取今天和昨天?
  • MEMORY.md(可选)
    • 精选的长期内存?
    • 仅在主、私人会话中加载(绝不在群组上下文中)?

这些文件位于工作区下(agents.defaults.workspace,默?~/.openclaw/workspace)。完整布局见代理工作区?

内存工具

OpenClaw 为这?Markdown 文件暴露两个面向代理的工具:

  • memory_search ?对索引片段的语义召回?
  • memory_get ?读取特定 Markdown 文件/行范围的定向读取?

memory_get 现在**在文件不存在时优雅降?*(例如,今天的每日日志在首次写入之前)。内置管理器?QMD 后端都返?{ text: "", path } 而不是抛?ENOENT,因此代理可以处?尚无记录”并继续其工作流,而无需将工具调用包装在 try/catch 逻辑中?

何时写入内存

  • 决策、偏好和持久事实写入 MEMORY.md?
  • 日常笔记和运行上下文写入 memory/YYYY-MM-DD.md?
  • 如果有人?记住这个”,写下来(不要保存在 RAM 中)?
  • 这个领域仍在演变。提醒模型存储记忆会有帮助;它会知道怎么做?
  • 如果你想让某些东西记住,**让机器人?*到内存中?

自动内存刷新(压缩前 ping?

当会?接近自动压缩**时,OpenClaw 触发一?静默的、代理驱动的轮次,提醒模型在上下文被压缩之前写入持久内存。默认提示明确说模型可以回复,但通常 NO_REPLY 是正确的响应,这样用户永远不会看到这个轮次?

这由 agents.defaults.compaction.memoryFlush 控制?

{
  agents: {
    defaults: {
      compaction: {
        reserveTokensFloor: 20000,
        memoryFlush: {
          enabled: true,
          softThresholdTokens: 4000,
          systemPrompt: "Session nearing compaction. Store durable memories now.",
          prompt: "Write any lasting notes to memory/YYYY-MM-DD.md; reply with NO_REPLY if nothing to store.",
        },
      },
    },
  },
}

详情?

  • **软阈?*:当会话 token 估计超过 contextWindow - reserveTokensFloor - softThresholdTokens 时触发刷新?
  • 默认静默:提示包?NO_REPLY 以便不交付任何内容?
  • 两个提示:用户提示加上系统提示附加提醒?
  • **每次压缩周期一次刷?*(在 sessions.json 中跟踪)?
  • **工作区必须可?*:如果会话在沙箱中运行且 workspaceAccess: "ro" ?"none",则跳过刷新?

有关完整压缩生命周期,参见会话管理 + 压缩?

向量内存搜索

OpenClaw 可以?MEMORY.md ?memory/*.md 上构建一个小向量索引,以便语义查询可以找到相关笔记,即使措辞不同?

默认值:

  • 默认启用?
  • 监视内存文件更改(防抖)?
  • ?agents.defaults.memorySearch 下配置内存搜索(不是顶级 memorySearch)?
  • 默认使用远程嵌入。如果未设置 memorySearch.provider,OpenClaw 自动选择?
    1. local 如果配置?memorySearch.local.modelPath 且文件存在?
    2. openai 如果可以解析 OpenAI 密钥?
    3. gemini 如果可以解析 Gemini 密钥?
    4. voyage 如果可以解析 Voyage 密钥?
    5. mistral 如果可以解析 Mistral 密钥?
    6. 否则内存搜索保持禁用直到配置?
  • 本地模式使用 node-llama-cpp,可能需?pnpm approve-builds?
  • 使用 sqlite-vec(如果有)加?SQLite 内的向量搜索?

远程嵌入**需?*嵌入 provider ?API 密钥。OpenClaw 从认证配置文件、models.providers.*.apiKey 或环境变量解析密钥。Codex OAuth 仅涵盖聊?completions?*不满?*内存搜索的嵌入。对?Gemini,使?GEMINI_API_KEY ?models.providers.google.apiKey。对?Voyage,使?VOYAGE_API_KEY ?models.providers.voyage.apiKey。对?Mistral,使?MISTRAL_API_KEY ?models.providers.mistral.apiKey。使用自定义 OpenAI 兼容端点时,设置 memorySearch.remote.apiKey(和可选的 memorySearch.remote.headers)?

QMD 后端(实验性)

设置 memory.backend = "qmd" 将内?SQLite 索引器替换为 QMD:一个本地优先的搜索辅助工具,结?BM25 + 向量 + 重新排序。Markdown 保持为真相来源;OpenClaw 调用 QMD 进行检索。关键点?

前置条件

  • 默认禁用。按配置选择加入(memory.backend = "qmd")?
  • 单独安装 QMD CLI(bun install -g https://github.com/tobi/qmd 或获取发布版)并确保 qmd 二进制文件在 gateway ?PATH 上?
  • QMD 需要允许扩展的 SQLite 构建(macOS ?brew install sqlite)?
  • QMD 通过 Bun + node-llama-cpp 完全本地运行,并在首次使用时?HuggingFace 自动下载 GGUF 模型(不需要单独的 Ollama 守护进程)?
  • gateway 通过设置 XDG_CONFIG_HOME ?XDG_CACHE_HOME 在自包含?XDG 主目录下运行 QMD,位?~/.openclaw/agents/<agentId>/qmd/?
  • OS 支持:一旦安?Bun + SQLite,macOS ?Linux 开箱即用。Windows 最好通过 WSL2 支持?

辅助工具如何运行

  • gateway ?~/.openclaw/agents/<agentId>/qmd/(配?+ 缓存 + sqlite DB)下编写自包含的 QMD 主目录?
  • 集合通过 qmd collection add ?memory.qmd.paths(加上默认工作区内存文件)创建,然后 qmd update + qmd embed 在启动时和可配置间隔(memory.qmd.update.interval,默?5 分钟)运行?
  • gateway 现在在启动时初始?QMD 管理器,因此定期更新计时器甚至在第一?memory_search 调用之前就已启动?
  • 启动刷新默认在后台运行,因此聊天启动不会被阻塞;设置 memory.qmd.update.waitForBootSync = true 保持之前的阻塞行为?
  • 搜索通过 memory.qmd.searchMode 运行(默?qmd search --json;也支持 vsearch ?query)。如果所选模式在你的 QMD 构建上拒绝标志,OpenClaw 使用 qmd query 重试。如?QMD 失败或二进制文件丢失,OpenClaw 自动回退到内?SQLite 管理器,因此内存工具保持工作?
  • OpenClaw 今天不公开 QMD 嵌入批量大小调优;批量行为由 QMD 自己控制?
  • 首次搜索可能很慢:QMD 可能在第一?qmd query 运行时下载本?GGUF 模型(重新排序器/查询扩展)?
    • OpenClaw 在运?QMD 时自动设?XDG_CONFIG_HOME/XDG_CACHE_HOME?

    • 如果你想手动预下载模型(并预?OpenClaw 使用的相同索引),使用代理的 XDG 目录运行一次性查询?

      OpenClaw ?QMD 状态位于你?状态目?(默?~/.openclaw)。你可以通过导出?OpenClaw 使用的相?XDG 变量来指?qmd 相同的索引:

      # 选择?OpenClaw 使用的相同状态目?
      STATE_DIR="${OPENCLAW_STATE_DIR:-$HOME/.openclaw}"
      
      export XDG_CONFIG_HOME="$STATE_DIR/agents/main/qmd/xdg-config"
      export XDG_CACHE_HOME="$STATE_DIR/agents/main/qmd/xdg-cache"
      
      # (可选)强制索引刷新 + 嵌入
      qmd update
      qmd embed
      
      # 预热 / 触发首次模型下载
      qmd query "test" -c memory-root --json >/dev/null 2>&1

*配置表面(memory.qmd.*?

  • command(默?qmd):覆盖可执行文件路径?
  • searchMode(默?search):选择哪个 QMD 命令支持 memory_searchsearchvsearchquery)?
  • includeDefaultMemory(默?true):自动索引 MEMORY.md + memory/**/*.md?
  • paths[]:添加额外目?文件(path、可?pattern、可选稳?name)?
  • sessions:选择加入会话 JSONL 索引(enabledretentionDaysexportDir)?
  • update:控制刷新节奏和维护执行(intervaldebounceMsonBootwaitForBootSyncembedIntervalcommandTimeoutMsupdateTimeoutMsembedTimeoutMs)?
  • limits:限制召回负载(maxResultsmaxSnippetCharsmaxInjectedCharstimeoutMs)?
  • scope:与 session.sendPolicy 相同的模式。默认仅 DM(deny 所有,直接聊天 allow);放宽它以在群?频道中显?QMD 命中?
    • match.keyPrefix 匹配**规范?*的会话键(小写,剥离任何前导 agent:<id>:)。例如:discord:channel:?
    • match.rawKeyPrefix 匹配原始会话键(小写),包括 agent:<id>:。例如:agent:main:discord:?
    • 遗留:match.keyPrefix: "agent:..." 仍然被视为原始键前缀,但为清晰起见首?rawKeyPrefix?
  • ?scope 拒绝搜索时,OpenClaw 记录带有派生 channel/chatType 的警告,以便更容易调试空结果?
  • 来自工作区外的片段在 memory_search 结果中显示为 qmd/<collection>/<relative-path>memory_get 理解该前缀并从配置?QMD 集合根读取?
  • ?memory.qmd.sessions.enabled = true 时,OpenClaw 导出清理过的会话记录(用?助手轮次)到 ~/.openclaw/agents/<id>/qmd/sessions/ 下的专用 QMD 集合,以?memory_search 可以召回最近的对话而不触及内置 SQLite 索引?
  • ?memory.citations ?auto/on 时,memory_search 片段现在包含 Source: <path#line> 页脚;设?memory.citations = "off" 保持路径元数据内部(代理仍然收到 memory_get 的路径,但片段文本省略页脚,系统提示警告代理不要引用它)?

示例

memory: {
  backend: "qmd",
  citations: "auto",
  qmd: {
    includeDefaultMemory: true,
    update: { interval: "5m", debounceMs: 15000 },
    limits: { maxResults: 6, timeoutMs: 4000 },
    scope: {
      default: "deny",
      rules: [
        { action: "allow", match: { chatType: "direct" } },
        // Normalized session-key prefix (strips `agent:<id>:`).
        { action: "deny", match: { keyPrefix: "discord:channel:" } },
        // Raw session-key prefix (includes `agent:<id>:`).
        { action: "deny", match: { rawKeyPrefix: "agent:main:discord:" } },
      ]
    },
    paths: [
      { name: "docs", path: "~/notes", pattern: "**/*.md" }
    ]
  }
}

引用和回退

  • memory.citations 无论后端如何都适用(auto/on/off)?
  • ?QMD 运行时,我们标记 status().backend = "qmd",以便诊断显示哪个引擎服务了结果。如?QMD 子进程退出或无法解析 JSON 输出,搜索管理器记录警告并返回内?provider(现?Markdown 嵌入)直?QMD 恢复?

额外内存路径

如果你想索引默认工作区布局之外?Markdown 文件,添加显式路径:

agents: {
  defaults: {
    memorySearch: {
      extraPaths: ["../team-docs", "/srv/shared-notes/overview.md"]
    }
  }
}

注意?

  • 路径可以是绝对路径或相对于工作区?
  • 目录递归扫描 .md 文件?
  • 仅索?Markdown 文件?
  • 符号链接被忽略(文件或目录)?

Gemini 嵌入(原生)

设置 provider ?gemini 以直接使?Gemini 嵌入 API?

agents: {
  defaults: {
    memorySearch: {
      provider: "gemini",
      model: "gemini-embedding-001",
      remote: {
        apiKey: "YOUR_GEMINI_API_KEY"
      }
    }
  }
}

注意?

  • remote.baseUrl 是可选的(默认为 Gemini API 基础 URL)?
  • remote.headers 让你在需要时添加额外头?
  • 默认模型:gemini-embedding-001?

如果你想使用自定?OpenAI 兼容端点(OpenRouter、vLLM 或代理),你可以?remote 配置?OpenAI provider 一起使用:

agents: {
  defaults: {
    memorySearch: {
      provider: "openai",
      model: "text-embedding-3-small",
      remote: {
        baseUrl: "https://api.example.com/v1/",
        apiKey: "YOUR_OPENAI_COMPAT_API_KEY",
        headers: { "X-Custom-Header": "value" }
      }
    }
  }
}

如果你不想设?API 密钥,使?memorySearch.provider = "local" 或设?memorySearch.fallback = "none"?

回退?

  • memorySearch.fallback 可以?openaigeminivoyagemistrallocal ?none?
  • 回退 provider 仅在主嵌?provider 失败时使用?

批量索引(OpenAI + Gemini + Voyage):

  • 默认禁用。为大规模索引设?agents.defaults.memorySearch.remote.batch.enabled = true(OpenAI、Gemini ?Voyage)?
  • 默认行为等待批量完成;如需要可调整 remote.batch.waitremote.batch.pollIntervalMs ?remote.batch.timeoutMinutes?
  • 设置 remote.batch.concurrency 控制我们并行提交多少批量作业(默认:2)?
  • 批量模式适用?memorySearch.provider = "openai" ?"gemini" 并使用相应的 API 密钥?
  • Gemini 批量作业使用异步嵌入批量端点,需?Gemini Batch API 可用?

为什?OpenAI 批量快速且便宜?

配置示例?

agents: {
  defaults: {
    memorySearch: {
      provider: "openai",
      model: "text-embedding-3-small",
      fallback: "openai",
      remote: {
        batch: { enabled: true, concurrency: 2 }
      },
      sync: { watch: true }
    }
  }
}

工具?

  • memory_search ?返回带文件和行范围的片段?
  • memory_get ?按路径读取内存文件内容?

本地模式?

  • 设置 agents.defaults.memorySearch.provider = "local"?
  • 提供 agents.defaults.memorySearch.local.modelPath(GGUF ?hf: URI)?
  • 可选:设置 agents.defaults.memorySearch.fallback = "none" 以避免远程回退?

内存工具如何工作

  • memory_search ?MEMORY.md + memory/**/*.md 中的 Markdown 片段进行语义搜索(~400 token 目标?0 token 重叠)。它返回片段文本(上限约 700 字符)、文件路径、行范围、分数、provider/模型,以及我们是否从本地 ?远程嵌入回退。不返回完整文件负载?
  • memory_get 读取特定内存 Markdown 文件(相对于工作区),可选择从起始行开始并读取 N 行。拒?MEMORY.md / memory/ 之外的路径?
  • 仅当 memorySearch.enabled 对代理解析为 true 时,这两个工具才启用?

什么被索引(以及何时)

  • 文件类型:仅 Markdown(MEMORY.mdmemory/**/*.md)?
  • 索引存储:每个代理的 SQLite,位?~/.openclaw/memory/<agentId>.sqlite(可通过 agents.defaults.memorySearch.store.path 配置,支?{agentId} 令牌)?
  • 新鲜度:MEMORY.md + memory/ 上的监视器将索引标记为脏(防?1.5s)。同步在会话开始、搜索或按间隔安排时调度,并异步运行。会话记录使用增量阈值触发后台同步?
  • 重新索引触发:索引存储嵌?provider/model + 端点指纹 + 分块参数。如果其中任何一项更改,OpenClaw 自动重置并重新索引整个存储?

混合搜索(BM25 + 向量?

启用时,OpenClaw 结合?

  • **向量相似?*(语义匹配,措辞可以不同?
  • **BM25 关键字相关?*(精?token,如 ID、环境变量、代码符号)

如果你的平台不支持全文搜索,OpenClaw 回退到仅向量搜索?

为什么混合?

向量搜索擅长”这意味着相同的事??

  • “Mac Studio gateway host” vs “运行 gateway 的机?
  • “debounce file updates” vs “避免每次写入时索?

但它可能对精确、高信号 token 较弱?

  • ID(a828e60b3b9895a…?
  • 代码符号(memorySearch.query.hybrid?
  • 错误字符串(“sqlite-vec unavailable”?

BM25(全文)相反:强于精?token,弱于释义。混合搜索是务实的中间立场:**使用两种检索信?*,以便你?自然语言”查询?大海捞针”查询都能获得良好结果?

我们如何合并结果(当前设计)

实现草图?

  1. 从两边检索候选池?
  • 向量:按余弦相似度检索前 maxResults * candidateMultiplier?
  • BM25:按 FTS5 BM25 排名检索前 maxResults * candidateMultiplier(越低越好)?
  1. ?BM25 排名转换?0..1 分数?
  • textScore = 1 / (1 + max(0, bm25Rank))
  1. 按块 ID 联合候选并计算加权分数?
  • finalScore = vectorWeight * vectorScore + textWeight * textScore

注意?

  • vectorWeight + textWeight 在配置解析中规范化为 1.0,因此权重行为如百分比?
  • 如果嵌入不可用(?provider 返回零向量),我们仍然运?BM25 并返回关键字匹配?
  • 如果无法创建 FTS5,我们保持仅向量搜索(无硬失败)?

这不?IR 理论完美”,但它简单、快速,并且倾向于改善真实笔记的召回/精确? 如果我们以后想更花哨,常见的下一步是互惠排名融合(RRF)或分数归一化(min/max ?z-score)然后混合?

后处理管?

在合并向量和关键字分数后,两个可选的后处理阶段在结果到达代理之前优化结果列表?

向量 + 关键??加权合并 ?时间衰减 ?排序 ?MMR ?Top-K 结果

两个阶段默认关闭,可以独立启用?

MMR 重新排序(多样性)

当混合搜索返回结果时,多个片段可能包含相似或重叠的内容。例如,搜索”家庭网络设置”可能返回五个几乎相同的片段,来自不同的每日笔记,都提到相同的路由器配置?

MMR(最大边际相关性) 重新排序结果以平衡相关性和多样性,确保顶级结果覆盖查询的不同方面,而不是重复相同信息?

工作原理?

  1. 按原始相关性(向量 + BM25 加权分数)评分结果?
  2. MMR 迭代选择结果,最大化:λ × 相关?- (1-λ) × max_similarity_to_selected?
  3. 结果之间的相似度使用分词内容?Jaccard 文本相似度测量?

lambda 参数控制权衡?

  • lambda = 1.0 ?纯相关性(无多样性惩罚)
  • lambda = 0.0 ?最大多样性(忽略相关性)
  • 默认:0.7(平衡,轻微相关性偏差)

示例 ?查询?home network setup”

给定这些内存文件?

memory/2026-02-10.md  ?"Configured Omada router, set VLAN 10 for IoT devices"
memory/2026-02-08.md  ?"Configured Omada router, moved IoT to VLAN 10"
memory/2026-02-05.md  ?"Set up AdGuard DNS on 192.168.10.2"
memory/network.md     ?"Router: Omeda ER605, AdGuard: 192.168.10.2, VLAN 10: IoT"

没有 MMR ??3 结果?

1. memory/2026-02-10.md  (score: 0.92)  ?router + VLAN
2. memory/2026-02-08.md  (score: 0.89)  ?router + VLAN (near-duplicate!)
3. memory/network.md     (score: 0.85)  ?reference doc

?MMR(?0.7)??3 结果?

1. memory/2026-02-10.md  (score: 0.92)  ?router + VLAN
2. memory/network.md     (score: 0.85)  ?reference doc (diverse!)
3. memory/2026-02-05.md  (score: 0.78)  ?AdGuard DNS (diverse!)

来自 2 ?8 日的近似重复被删除,代理获得三个不同的信息片段?

*何时启用? 如果你注意到 memory_search 返回冗余或近似重复的片段,特别是每日笔记经常在不同日期重复相似信息时?

时间衰减(最近优先)

具有每日笔记的代理随着时间积累数百个带日期的文件。没有衰减,一个措辞良好的六个月前的笔记可能超过昨天关于同一主题的更新?

时间衰减 根据每个结果的年龄对分数应用指数乘数,因此最近的记忆自然排名更高,而旧的逐渐消失?

decayedScore = score × e^(-λ × ageInDays)

其中 λ = ln(2) / halfLifeDays?

默认半衰?30 天:

  • 今天的笔记:100% 原始分数
  • 7 天前?*~84%**
  • 30 天前?50%*
  • 90 天前?12.5%*
  • 180 天前?*~1.6%**

*永久文件永不衰减?

  • MEMORY.md(根内存文件?
  • memory/ 中未带日期的文件(例?memory/projects.mdmemory/network.md?
  • 这些包含应始终正常排名的持久参考信息?

带日期的每日文件memory/YYYY-MM-DD.md)使用从文件名提取的日期。其他来源(例如会话记录)回退到文件修改时间(mtime)?

示例 ?查询?Rod 的工作时间表是什么?”

给定这些内存文件(今天是 2 ?10 日)?

memory/2025-09-15.md  ?"Rod works Mon-Fri, standup at 10am, pairing at 2pm"  (148 天前)
memory/2026-02-10.md  ?"Rod has standup at 14:15, 1:1 with Zeb at 14:45"    (今天)
memory/2026-02-03.md  ?"Rod started new team, standup moved to 14:15"        (7 天前)

没有衰减?

1. memory/2025-09-15.md  (score: 0.91)  ?最佳语义匹配,但过时了?
2. memory/2026-02-10.md  (score: 0.82)
3. memory/2026-02-03.md  (score: 0.80)

有衰减(halfLife=30):

1. memory/2026-02-10.md  (score: 0.82 × 1.00 = 0.82)  ?今天,无衰减
2. memory/2026-02-03.md  (score: 0.80 × 0.85 = 0.68)  ?7 天,轻微衰减
3. memory/2025-09-15.md  (score: 0.91 × 0.03 = 0.03)  ?148 天,几乎消失

过时?9 月笔记尽管具有最佳原始语义匹配,但仍降至底部?

*何时启用? 如果你的代理有多个月的每日笔记且发现旧、过时的信息排名超过最近的上下文?0 天的半衰期对每日笔记密集的工作流程效果良好;如果你经常参考旧笔记,增加它(例?90 天)?

配置

两个功能都在 memorySearch.query.hybrid 下配置:

agents: {
  defaults: {
    memorySearch: {
      query: {
        hybrid: {
          enabled: true,
          vectorWeight: 0.7,
          textWeight: 0.3,
          candidateMultiplier: 4,
          // 多样性:减少冗余结果
          mmr: {
            enabled: true,    // default: false
            lambda: 0.7       // 0 = 最大多样性,1 = 最大相关?
          },
          // 最近:提升较新记忆
          temporalDecay: {
            enabled: true,    // default: false
            halfLifeDays: 30  // 分数?30 天减?
          }
        }
      }
    }
  }
}

你可以独立启用任一功能?

  • ?MMR ?当你有许多相似笔记但年龄不重要时有用?
  • *仅时间衰? ?当最近重要但你的结果已经多样化时有用?
  • *两? ?推荐用于具有大量、长期运行每日笔记历史的代理?

嵌入缓存

OpenClaw 可以?*块嵌?*缓存?SQLite 中,这样重新索引和频繁更新(尤其是会话记录)不会重新嵌入未更改的文本?

配置?

agents: {
  defaults: {
    memorySearch: {
      cache: {
        enabled: true,
        maxEntries: 50000
      }
    }
  }
}

会话内存搜索(实验性)

你可以选择索引会话记录并通过 memory_search 将其显示。这由实验性标志控制?

agents: {
  defaults: {
    memorySearch: {
      experimental: { sessionMemory: true },
      sources: ["memory", "sessions"]
    }
  }
}

注意?

  • 会话索引?选择加入*(默认关闭)?
  • 会话更新被防抖并异步索引,一旦它们超?delta 阈值(尽力而为)?
  • memory_search 永远不阻塞索引;结果在后台同步完成前可能略微陈旧?
  • 结果仍然仅包括片段;memory_get 仍然限于内存文件?
  • 会话索引按代理隔离(仅该代理的会话日志被索引)?
  • 会话日志位于磁盘上(~/.openclaw/agents/<agentId>/sessions/*.jsonl)。任何具有文件系统访问权限的进程/用户都可以读取它们,因此将磁盘访问视为信任边界。对于更严格的隔离,请在单独 OS 用户或主机下运行代理?

Delta 阈值(显示默认值)?

agents: {
  defaults: {
    memorySearch: {
      sync: {
        sessions: {
          deltaBytes: 100000,   // ~100 KB
          deltaMessages: 50     // JSONL ?
        }
      }
    }
  }
}

SQLite 向量加速(sqlite-vec?

?sqlite-vec 扩展可用时,OpenClaw 将嵌入存储在 SQLite 虚拟表(vec0)中,并在数据库中执行向量距离查询。这保持搜索快速,无需将每个嵌入加载到 JS 中?

配置(可选)?

agents: {
  defaults: {
    memorySearch: {
      store: {
        vector: {
          enabled: true,
          extensionPath: "/path/to/sqlite-vec"
        }
      }
    }
  }
}

注意?

  • enabled 默认?true;禁用时,搜索回退到进程中存储嵌入的余弦相似度?
  • 如果 sqlite-vec 扩展丢失或加载失败,OpenClaw 记录错误并继?JS 回退(无向量表)?
  • extensionPath 覆盖捆绑?sqlite-vec 路径(对自定义构建或非标准安装位置有用)?

本地嵌入自动下载

  • 默认本地嵌入模型:hf:ggml-org/embeddinggemma-300m-qat-q8_0-GGUF/embeddinggemma-300m-qat-Q8_0.gguf(约 0.6 GB)?
  • ?memorySearch.provider = "local" 时,node-llama-cpp 解析 modelPath;如?GGUF 缺失,它自动下载到缓存(?local.modelCachePath 如果设置),然后加载它。下载在重试时恢复?
  • 本地构建要求:运?pnpm approve-builds,选择 node-llama-cpp,然?pnpm rebuild node-llama-cpp?
  • 回退:如果本地设置失败且 memorySearch.fallback = "openai",我们自动切换到远程嵌入(openai/text-embedding-3-small 除非覆盖)并记录原因?

自定?OpenAI 兼容端点示例

agents: {
  defaults: {
    memorySearch: {
      provider: "openai",
      model: "text-embedding-3-small",
      remote: {
        baseUrl: "https://api.example.com/v1/",
        apiKey: "YOUR_REMOTE_API_KEY",
        headers: {
          "X-Organization": "org-id",
          "X-Project": "project-id"
        }
      }
    }
  }
}

注意?

  • remote.* 优先?models.providers.openai.*?
  • remote.headers ?OpenAI 头合并;远程在密钥冲突时获胜。省?remote.headers 以使?OpenAI 默认值?