dsh-rag-memory:QQ 機器人的本地 RAG 長期記憶

前言

給 QQ 機器人接大模型時,上下文窗口只能帶最近幾輪對話,羣裏的約定、用戶說過的事實、前幾天的討論很難穩定進 prompt。常見做法是手寫 Redis 或全文搜索,中文分詞和語義召回往往要各搞一套,還要和 DSH 進程裏的插件生命週期對齊。

下面介紹維護者 Yslehui 在 DSH 插件生態裏發佈的 dsh-rag-memory:把羣聊/私聊消息、事實與摘要存進本地 SQLite,用中文友好的 BM25 與 Embedding 混合檢索,可選 Rerank 精排,再通過獨立 HTTP 接口供機器人調用。數據不上傳,未配置向量或 Rerank 時會自動降級爲純 BM25,插件仍可用。

這是什麼

dsh-rag-memory 是 DSH 分類「記憶」下的插件(npm 包名 dsh-rag-memory,當前版本 0.1.1,MIT 許可證)。定位是:面向 DeepSeek Harness(DSH)QQ 機器人的本地 RAG 長期記憶——存儲與檢索都在本機完成,經本地 HTTP 暴露 API,不經過 DSH Web 的登錄認證。

實現上依賴 Node 內置 node:sqlite,無原生編譯步驟,README 說明可在桌面與 Android(Node 環境)上使用。引擎要求:Node >=22.5.0,DSH >=0.2.1-rc.1。

核心功能

  1. 持久化:消息、事實、畫像、筆記等寫入 SQLite(默認 WAL),默認路徑爲 $DSH_HOME/dsh-rag-memory/memory.db。
  2. 按 scope 隔離:建議 group:<羣號>、private:<QQ號>,檢索與寫入均帶 scope。
  3. 混合檢索:中文分詞 BM25 + Embedding 向量召回;開啓 rerank 時可再精排。返回結果中 sources 標明命中通道(bm25 / vector / rerank),degraded 列出降級原因。
  4. 直接產出注入文本:/context 接口返回已格式化的記憶塊,可拼進 system prompt。
  5. 可選鑑權:配置非空 token 時,請求需帶 x-memory-token 頭。

Embedding 與 Rerank 兼容 OpenAI 風格的 /v1/embeddings 與 /v1/rerank(文檔舉例硅基流動、Jina、Cohere 等)。API Key 寫在 cordis.patch.yml 中,勿提交到公開倉庫。

安裝與啓用

從 npm 安裝(README 給出的命令):

dsh plugin --profile web add dsh-rag-memory

本地目錄開發安裝:

dsh plugin --profile web add ./dsh-rag-memory

裝完後服務前綴爲 http://127.0.0.1:39001/rag-memory(獨立端口;被佔用時自動遞增到 39020)。README 寫明裝上即生效,無需重啓引擎。

在 cordis.patch.yml 的 config 中可調整數據庫路徑、默認檢索條數、Embedding 與 Rerank 開關及模型端點,例如:

config:
  dbPath: ''            # 空 = $DSH_HOME/dsh-rag-memory/memory.db
  token: ''             # 非空時,請求需帶 x-memory-token 頭
  defaultK: 8
  embedding:
    enabled: true
    baseURL: 'https://api.siliconflow.cn/v1'
    apiKey: 'sk-...'
    model: 'BAAI/bge-m3'
  rerank:
    enabled: true
    baseURL: 'https://api.siliconflow.cn/v1'
    apiKey: 'sk-...'
    model: 'BAAI/bge-reranker-v2-m3'

HTTP 接口概覽

方法 路徑 作用
GET /health 健康檢查與能力狀態
GET /stats 各 scope 條數、向量條數
POST /ingest 批量寫入消息
POST /search 混合檢索
POST /context 檢索並拼好可注入的文本塊
POST /save 直接存一條事實/畫像/筆記
GET /profile?scope= 列出事實類記憶
POST /delete 按 id 刪除
POST /clear 按 scope 清空(需 confirm: true)

典型用法

寫入與檢索

收到消息後異步入庫,避免阻塞回復;調模型前按用戶輸入取相關記憶。

寫入示例(POST /ingest):

{
  "scope": "group:123456",
  "items": [
    { "text": "小明說他下週三去杭州出差", "speaker": "小明", "ts": 1700000000000 },
    { "text": "羣裏在討論週末去爬山", "kind": "message" }
  ]
}

kind 可爲 message(默認)、fact、profile、note、event。

檢索示例(POST /search):

{ "scope": "group:123456", "query": "小明什麼時候去杭州", "k": 8 }

需要可直接注入 prompt 的文本時,調用 POST /context:

{ "scope": "group:123456", "query": "小明出差", "k": 6, "maxChars": 2000 }

返回的 context 形如帶序號與時間的發言摘要,README 建議拼在機器人當輪的 system 段末尾。

Node 接入片段

README 中的最小接入方式如下(不配 token 時無需額外頭):

const MEMORY = 'http://127.0.0.1:39001/rag-memory'
const scope = `group:${groupId}`

// 收到消息:先入庫(不阻塞回復)
fetch(`${MEMORY}/ingest`, {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ scope, items: [{ text, speaker: nickname, ts: Date.now() }] }),
}).catch(() => {})

// 調模型前:取相關記憶
const res = await fetch(`${MEMORY}/context`, {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ scope, query: userText, k: 8 }),
})
const { context } = await res.json()
const system = context ? `${basePrompt}\n\n${context}` : basePrompt

適用場景與注意

適合:需要在 QQ 羣/私聊場景做長期記憶、又希望數據和索引留在本機的 DSH 機器人作者;願意按需配置 Embedding/Rerank 以提升中文問句召回,或接受純 BM25 降級。

注意:

  • 插件以當前 DSH 進程權限運行,安裝前請閱讀 GitHub 源碼 與 MIT 許可證,自行評估安全與合規。
  • 默認 HTTP 監聽本機;若暴露到公網需自行加固網絡與 token。
  • 備份可複製 $DSH_HOME/dsh-rag-memory 目錄,或使用 SQLite 的 VACUUM INTO;按 scope 清空前建議先 GET /stats 確認條數。

DSH 社區插件目錄(如 SkillHub 條目)爲獨立索引站點,與 DeepSeek / 幻方無官方從屬關係;發現插件通常通過 DSH「插件 → 發現」添加市場索引源,而非官方應用商店。

結尾

經過上面的步驟,你可以把 dsh-rag-memory 當作機器人側的本地記憶層:入庫走 /ingest,進模型前走 /context,檢索鏈路在資料中已寫清降級行爲。進一步細節以倉庫 README 爲準。

  • 目錄頁:https://www.skillhub.cn/plugins/Yslehui/dsh-rag-memory
  • GitHub:https://github.com/Yslehui/dsh-rag-memory
羽毛球分组比赛记分
小程序二维码

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

小夜