dsh-memory-search:Markdown 笔记的本地记忆检索插件

前言

DeepSeek Harness (DSH) 采用插件化架构,生态中已有多个记忆插件。dsh-memory-search 是由 JackZo400 开发的一个长期记忆检索插件。它不依赖云端 API,通过本地 embedding 和 SQLite FTS5 实现混合召回,解决了 Agent 随时间推移遗忘上下文的问题。

核心功能

该插件专注于将本地 Markdown 笔记转化为 Agent 可检索的记忆。

  1. 混合召回:结合本地 embedding 向量检索与 SQLite FTS5 关键词检索。
  2. RRF 融合:使用 Reciprocal Rank Fusion 算法融合两路召回结果,兼顾语义与关键词。
  3. 零 API 花费:向量模型跑在本地,无需调用外部服务。
  4. 降级能力:不安装模型也能使用(仅跑关键词),适合轻量级场景。
  5. 双出口:支持 Agent 主动调用 memory_search 工具,也支持每轮对话自动召回相关记忆注入上下文。
  6. 密级过滤:支持根据文件名或会话映射过滤记忆可见性(如公开、个人、私密)。
  7. 增量索引:支持按文件修改时间(mtime)和大小增量重建索引。

安装与配置

安装

安装命令如下:

dsh plugin --profile web add github:JackZo400/dsh-memory-search

环境要求

  • Node.js 版本需 ≥ 22.5(使用内置 node:sqlite)。
  • 若需开启向量检索,需安装 node-llama-cpp 及对应的 GGUF 嵌入模型(该依赖列在 optionalDependencies 中,不影响关键词检索)。

配置示例

安装后,需在对应 profile 的 patch 中插入配置。以下是一个基础配置示例:

- insert:
    - id: memory-search
      name: dsh-memory-search
      config:
        dbPath: .dsh-memory/index.db    # 索引库路径,相对路径基于 dsh 工作目录
        roots:                          # 语料根目录,递归收集 .md 文件
          - ./memory
        modelPath: ''                   # 嵌入模型路径;留空则只跑关键词
        recall:
          enabled: true                 # 开启每轮自动召回
          limit: 4                      # 每轮最多召回条数
          budgetChars: 1600             # 注入上下文的字符预算
          order: 130                    # 在系统提示中的排序位置
        embedding:
          enabled: true
          threads: 6                    # CPU 线程数
          contextSize: 1024             # 上下文窗口
          batchSize: 256
          queryInstruction: ''          # 可选:嵌入指令前缀
        search:
          candidatePool: 40             # 每路召回的候选数量
          rrfK: 10                      # RRF 平滑常数
        exclude: ['**/.index/**', '**/node_modules/**']
        syncIntervalMs: 300000          # 扫描语料变更的时间间隔(毫秒)
        acceptSpecChange: false         # 换切块规则时需设为 true

配置要点

  • 语料根目录 (roots):不配置即为空索引。建议将 Markdown 笔记放在该目录下。
  • 模型路径 (modelPath):留空时插件仅建立关键词索引。若开启 embedding.enabled 但未填模型路径,语义检索将不可用。
  • 切块规则 (acceptSpecChange):插件采用启发式切块(基于空行、列表、标题)。若需修改切块逻辑并重新计算向量,必须将 acceptSpecChange 设为 true。
  • 密级过滤:不配置 sessionMap 时,所有会话视为 owner,不做过滤。

工作原理与语料准备

工作流程

  1. 扫描与切块:插件按 roots 扫描 .md 文件,根据空行、列表项、标题等启发式规则进行切块。
  2. 索引建立:
    • 向量索引:将切块内容转为向量存入 SQLite BLOB。
    • 关键词索引:使用中文 bigram 分词建立 FTS5 索引。
  3. 查询召回:
    • 用户查询分别进入向量检索和关键词检索。
    • 两路结果按名次进行 RRF 融合。
    • 根据密级配置和来源权重进行过滤。
    • 返回 Top-K 结果。

语料准备建议

  • 切块规范:建议一条一事,段落间空行,避免将两件相关的事塞入同一块,影响检索精度。
  • 密级文件:可利用文件名区分密级,例如 public.md、personal.md、secret.md。

测试

项目提供了测试脚本,用于验证切块、分词、索引及检索功能。

node test/selftest.mjs         # 自检切块、分词、索引与检索
node test/plugin-selftest.mjs  # 插件契约测试(工具注册、提示注入等)
node test/spec-guard.mjs       # 切块规范闸测试
npm test                       # 执行上述所有测试

若需评估召回质量,可运行评测脚本(需根据自身语料修改题目):

node test/recall-eval.mjs --db .dsh-memory/index.db --corpus ./memory

已知局限

  1. 切块规则:依赖启发式规则(空行/列表/标题),对长段落笔记的处理不如专门的分词模型精准。
  2. 中文分词:仅支持 bigram 分词,缺乏词表,语法理解能力有限。
  3. 模型兼容性:仅在 Qwen3-Embedding-0.6B 上验证,更换模型需注意维度及 queryInstruction 配置。
  4. 性能:向量检索采用全量扫描,语料量过大(上万块)时性能可能下降。
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜