dsh-session-index:讓 agent 能檢索歷史會話的 DSH 全文索引插件

前言

用 DSH 開發智能體,很快會碰到一個具體問題:會話之間是互相隔開的。新開一輪對話,agent 查不到上一次說過什麼、調用過哪些工具。想自己寫插件訂閱 session/event 攢一份記錄也不夠——session/event 是”提交後追加”的事件流,恢復(resume)的會話不會重放 seed 歷史事件,舊會話的內容拿不到。

dsh-session-index 補的就是這個缺口:把所有會話內容建成一份跨會話的全文索引,並暴露成模型可以直接調用的工具。下面介紹它的定位、工作方式和安裝步驟。

這是什麼

dsh-session-index 是 DeepSeek Harness 的會話全文索引插件,以組合包(dsh.bundle)形式分發,作者是 longyu065,當前版本 0.1.0,MIT 許可。

它監聽 session/event 事件流,把會話內容抽取成可檢索文檔,構建跨會話倒排索引,再通過 session_search / session_index_stats 兩個工具暴露給模型,讓 agent 能檢索之前任何一次對話裏說過什麼、做過什麼。

索引的內容包括:user/messageassistant/message 的 text(reasoning 可選)、tool/call(工具名 + 參數)、tool/resultsession/title

核心功能

即時索引與歷史回填

每個 session/event 追加立即入索引,按 sessionId#seq 冪等去重,回填與即時事件重疊時不會重複計數。

針對恢復會話不重放歷史事件的缺口,插件啓動時做兩步回填:

  1. 先用 ctx.sessions.list() 索引內存中的活動會話;
  2. 再用 ctx.sessionPersistence.list() 配合 readFrom(id, watermark+1),按水位線增量補全落盤的舊會話。

水位線同時存在內存和持久化索引文件裏,重啓後只補增量。

混合檢索

preferFts 開啓(默認)時,FTS5 與內存索引並跑、按會話去重合並:

  • 框架的 ctx.sessionQuery(SQLite FTS5)負責英文/詞級召回;
  • 內置的二元組索引補足中文召回。FTS5 的 unicode61 分詞器不做中文切詞,整串 CJK 是單個 token,”可以跨會話搜索歷史了”匹配不到”跨會話搜索”,二元組召回正好互補。

engine 字段報告實際使用的檢索引擎:memory / fts5 / hybrid

富卡片

檢索結果會投影成 Web UI 的 card:'search' 卡片:presentCall / presentResult 配合 output.presentationMeta,把命中按會話分組渲染成可展開列表,組頭是會話 id 和標題,組內是命中片段。卡片數據隨 tool/result 事件持久化,可回放。

持久化與清理

索引文檔按 JSONL 追加到 $DSH_HOME/session-index/<sessionId>.jsonl,重啓只補增量。會話銷燬時(session/disposed),同步移除該會話的全部文檔與索引文件。

隱私開關

兩個配置項控制索引範圍:

  • indexReasoning:默認關,不索引 CoT 思考文本;
  • indexToolResults:默認開,控制是否索引工具返回結果。

安裝與啓用

源碼在 GitHub 倉庫(鏈接見文末),本地拿到倉庫後分三步安裝:

# ① 打包(在倉庫根目錄)
pnpm pack          # 產出 dsh-session-index-0.1.0.tgz
# ② 裝進 profile(web = 桌面端用的 profile)
dsh plugin --profile web add ./dsh-session-index-0.1.0.tgz
# ③ 重啓桌面應用 / dsh web

爲什麼用 tarball 而不是 add ./目錄:pnpm 對 link: 協議的本地目錄包不會安裝它的 dependencies(實測);pnpm pack 出的 tarball 是普通包,依賴會正常裝進 profile 的 .pnpm 子樹,bundle 內的 @deepseek-ai/* 導入才能解析。

組合包自帶一份 cordis.patch.yml,做兩件事:掛載插件本身;把框架自帶的 FTS5(session-query-sqlite)從默認的 openAt: never 改成 openAt: first-search,持久化路徑設爲 $DSH_HOME/session-query.sqlite。這樣 session_search 會自動進入混合檢索。不想用這層覆蓋,就在自己 profile 的 cordis.patch.yml 裏再覆蓋該行——patch 按層後寫覆蓋前寫。

配置項

默認值 說明
dataDir ''(自動 = $DSH_HOME/session-index 索引落盤目錄,填自定義路徑可改位置
maxResults 20 session_search 默認最大命中數
maxSnippetChars 240 摘要片段最大字符數(Unicode 碼點)
maxDocChars 4000 單條文檔索引的最大字符數,截斷防工具結果膨脹
indexReasoning false 是否索引 assistant 的 reasoning 思考文本
indexToolResults true 是否索引工具返回結果
preferFts true 是否優先用框架 FTS5 做混合檢索,false 則純內存索引

開發與測試

插件源碼是單文件可擦除 TS(src/session-index.ts),Node 22.18+ 原生類型剝離即可加載。運行依賴 @deepseek-ai/cordis ^4.0.1@deepseek-ai/dsh-tools ^0.1.0-rc.6@deepseek-ai/schemastery ^3.18.1,隨 tarball 正常裝進 profile。

本地開發時,@deepseek-ai/* 依賴需要先做個符號鏈接:

mkdir -p node_modules && ln -sfn <dsh安裝目錄>/node_modules/@deepseek-ai node_modules/@deepseek-ai

<dsh安裝目錄> 通常是 ~/.npm/_npx/<hash>/,桌面端與 dsh web 共用同一份。tsc 類型檢查還需要 @types/node

測試和構建:

node test-index.mjs    # 引擎獨立測試,不啓動 dsh,65 項斷言
pnpm run build         # tsc 編譯 src → dist/ → index.js

適用場景與注意

適合的場景:希望 agent 能”回憶”之前任何一次對話內容的 DSH 用戶——查上次的結論、翻之前的工具調用記錄、跨會話延續上下文,都靠這份索引。

使用前注意幾點已知限制:

  • 索引目錄應由單個 dsh 進程獨佔,多進程共享同一 dataDir 未做併發保護;
  • 中文按二元組召回,單字查詢(如”插”)只能命中孤立單字文檔,建議至少輸入兩字;
  • 框架 FTS5 不索引 session/titlekind='title' 過濾走內存索引;
  • 卡片內暫無”跳轉原會話”交互(框架 wire format 無 link/action 塊),卡片攜帶會話 id 和標題,配合側邊欄定位;
  • session/disposed 只清理插件自己的內存與 JSONL 文件,不影響原始會話日誌。

另外,插件以當前 dsh 進程的權限運行。它的源碼是單文件,安裝前把 src/session-index.ts 過一遍、確認 MIT 許可符合預期,成本不高。

結尾

dsh-session-index 做的事不復雜:把所有會話內容建成一份可檢索的索引,暴露成兩個工具,agent 因此能查到之前任何一次對話裏說過什麼、做過什麼。索引、回填、混合檢索、卡片展示都在包內完成,MIT 許可,源碼單文件可審。

  • GitHub:https://github.com/longyu065/dsh-session-index
  • 社區目錄頁:https://www.skillhub.cn/plugins/longyu065/dsh-session-index

社區目錄是獨立站點,與 DeepSeek / 幻方無官方從屬關係,僅作插件索引使用。

羽毛球分组比赛记分
小程序二维码

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

小夜