用 dsh-tool-regex 給 DeepSeek Harness 裝上確定性正則工具

前言

智能體處理日誌、校驗用戶給的 pattern、從一段文本里抽出字段,正則幾乎是默認手段。問題是:模型「心算」正則的錯誤率很高,也沒法把中間結果交給人覈對。常見替代是讓模型現寫一段 node -e 或 Python,再通過 bash 跑——多一次進程開銷,也多一層現寫腳本的正確性風險。

DeepSeek Harness(dsh)內置的 grep 只能做文件域搜索,不能對任意字符串做測試、提取、替換,更不能解釋一段 pattern 到底在匹配什麼。社區插件 dsh-tool-regex 就是爲這件事準備的:給當前 dsh 進程註冊一個 regex 工具,用確定性的純函數結果代替心算。

本文按插件目錄頁、GitHub 倉庫 README 與源碼交叉覈對後整理:它是什麼、四個 action 怎麼用、怎麼安裝,以及 ReDoS 相關的邊界。

這是什麼

dsh-tool-regex 是一款面向 DeepSeek Harness 的工具與能力插件,由 GitHub 組織 omdsh-dev 維護,倉庫地址是 omdsh-dev/dsh-tool-regex。目錄頁收錄日期爲 2026-08-14,許可證 MIT,主要語言 TypeScript。截至本文查閱時,倉庫星標爲 3。

它解決的是這一類任務:

  • 判斷一段文本是否匹配給定 pattern
  • 從日誌或任意字符串中提取編號捕獲組、命名捕獲組
  • 做帶 $1 / $2 / $$ 語義的安全替換
  • 不執行匹配的前提下,把 pattern 拆成人能讀的解釋節點

插件以 Profile Bundle 形式接入。package.json 裏包名聲明爲 @deepseek-ai/dsh-tool-regex,安裝後會在 profile 的 layer stack 插入 row id tool-regex。這是社區開源插件,不是 DeepSeek / 幻方的官方應用;DeepSeek Harness 本身的設計原則是「一切皆插件」,社區目錄 deepseek-harness-plugin.com 是獨立站點,與官方倉庫無從屬關係。

運行時沒有第三方依賴:package.json 沒有 dependencies 字段,peer 依賴由 profile 提供(@deepseek-ai/cordis@deepseek-ai/dsh-tools@deepseek-ai/dsh-invariants)。引擎側是純函數;test / find / replace 會再進 worker 線程執行。

核心功能

插件只註冊一個工具:regex。調用時用 action 區分四類操作,統一返回 JSON 文本字符串。

四個 action

action 做什麼 輸出形態
test 判斷是否匹配 {"matched":true}{"matched":false}
find 收集全部匹配:下標、完整匹配、編號組 captures、命名組 groups 數組;零匹配返回 []
replace 全局安全替換,返回結果文本和替換次數 {"result":"...","replaced":1}
explain 靜態解析 pattern,輸出人讀節點序列 節點數組,例如 {"kind":"escape","text":"\\d","meaning":"A digit [0-9]"}

幾點行爲需要單獨記住:

  1. test 不會自動加首尾錨點。整串匹配要由模型自己寫成 ^...$
  2. findreplace 在沒有 g 時會自動補 g,否則只能拿到第一處匹配。
  3. explain 是差異化能力:只做線性 tokenizer,不構造 RegExp 實例、不執行匹配,因此天然免疫 ReDoS。節點上限 4,096,超限返回 regex: explain: pattern too complex

README 裏的三個可復現例子如下。

提取捕獲組:

regex { action: "find", pattern: "(\\w+)@(\\w+)", input: "a@b x c@d" }

返回兩處匹配,第一處大致是 {"index":0,"match":"a@b","captures":["a","b"],"groups":null},第二處從下標 6 開始,對應 c@d

交換兩個單詞:

regex { action: "replace", pattern: "(\\w+) (\\w+)", input: "hello world", replacement: "$2 $1" }

得到 {"result":"world hello","replaced":1}

解釋一段日期片段:

regex { action: "explain", pattern: "\\d{4}-\\d{2}" }

會拆成轉義 \d、量詞 {4}、字面量 - 等節點,並帶上英文 meaning 字段。

工具參數

參數 必填 說明
action test / find / replace / explain
pattern JavaScript 正則語法,不要帶外圍 /;上限 16KB
input test/find/replace 必需 待匹配文本;上限 64,000 字節(UTF-8)
flags "gi";允許 g i m s u y d v,必須唯一且合法
replacement replace 時需要 替換文本,走 JS 原生字符串替換路徑;上限 16KB
limit find 最多報告多少處匹配,默認 50,鉗制到 1,000

flags 是逐字符校驗的:非法字符報 regex: invalid flag "q",重複報 regex: duplicate flag "g"。無效 pattern 捕獲 SyntaxError,錯誤信息裏通常帶位置,格式爲 regex: invalid pattern: ...,不會把宿主打崩。

replace 明確走 String.prototype.replace字符串替換路徑,沒有 new Function,也沒有 eval$1 / $2 是編號組,$$ 是字面量 $,命名組走 JS 原生 $<name> 語義;未知引用按 V8 規則字面保留(例如 $0)。

ReDoS 多層防線

JS 正則的災難性回溯是真實威脅,典型例子是 (a+)+$ 配超長輸入。倉庫 README 和工具描述都寫了同一套防線,源碼 src/index.tssrc/engine.ts 與之對應:

  1. worker 硬超時test / find / replace 在可終止的 worker 線程裏同步執行,預算 1,000ms,到期調用 worker.terminate(),返回 regex: execution timed out (1000ms)。工具管道自己的 timeoutMs 對同步阻塞體只是協作式的,單靠它不夠,所以才單獨開 worker。
  2. 入口拒絕,不截斷:輸入超過 64KB、pattern 超過 16KB、replacement 超過 16KB,直接報錯,不進入回溯。
  3. 輸出與匹配數上限:輸出超過 1MB(例如 $`` /$’造成的替換放大)拒絕而非截斷;findlimit` 默認 50、上限 1,000。
  4. explain 零執行:只做靜態掃描,任何 pattern 都即時返回。

工具描述和 README 都警告模型:不要對不可信的大輸入使用無錨點的嵌套量詞,例如 (a+)+(.*)*。超時能擋住宿主被掛死,但不能把病理 pattern 變成「安全可用」。

安裝與啓用

目錄頁給出的安裝命令是(以頁面原文爲準):

dsh plugin add github:omdsh-dev/dsh-tool-regex

需要可復現安裝時,固定 commit 哈希:

dsh plugin add github:omdsh-dev/dsh-tool-regex#commit

#commit 換成實際哈希。倉庫 main 在 2026-08-14 的最新提交是 457c84fed7849003dd006145fe7838519c8fc132。固定哈希之後,上游再推送不會悄悄改變你機器上跑的代碼。

README 推薦按 profile 安裝。web(交互式網頁)和 headless(dsh run 默認)是兩套不同的 profile,裝到一邊不會自動覆蓋另一邊:

# 交互式(web)profile
dsh plugin --profile web add github:omdsh-dev/dsh-tool-regex

# 一次性任務(headless)profile
dsh plugin --profile headless add github:omdsh-dev/dsh-tool-regex

也可以先在倉庫裏 npm pack,再用生成的 tarball 安裝:

npm pack
dsh plugin --profile web add ./dsh-tool-regex-<version>.tgz

包內 cordis.patch.yml 會在安裝後把插件插入 layer stack,row id 爲 tool-regex。缺失的 peer 依賴由 profile 的 profiles/node_modules 回退安裝提供。Windows 路徑請用正斜槓,例如 C:/...

package.json 聲明的 Node 引擎是 ^22.19.0 || >=24.0.0。README 寫明本插件已按 @deepseek-ai/dsh@0.1.0-rc.6(npm 私有包)做過隔離消費驗證,啓動方式示例爲 npx -p @deepseek-ai/dsh@0.1.0-rc.6 dsh web,並明確不要 install -g 全局安裝。這是倉庫自述的兼容線,不是對所有 dsh 快照的保證。

驗證是否裝上:

dsh --profile web --dump-config | grep tool-regex

跑一次真實調用:

dsh run "使用 regex 工具測試 d+ 是否匹配 abc123"

典型用法

下面按 README 的契約,把四個 action 對應到常見任務。pattern 一律按 JavaScript 語法寫,不要加 /.../ 外圍斜槓。

1. 先解釋,再執行。 用戶丟過來一段看不懂的正則時,先 explain。它不跑匹配,只返回節點序列,適合把「這段 pattern 在幹什麼」展示給人看。未閉合的 [ / ( 會帶位置報錯,例如 regex: explain: unmatched "[" at position N

2. 從日誌裏抽字段。find,需要命名組時寫成 (?<name>...),結果裏的 groups 會帶上名字;只要編號組時看 captureslimit 默認 50,日誌很長時顯式設一個更小的值,避免輸出膨脹。

3. 做可覈對的替換。replace,依賴 $1 這類引用,而不是讓模型手寫拼接。零匹配時返回原文且 replaced 爲 0,便於判斷「到底有沒有改到」。

4. 只問是否命中。test。若要「整串等於」而不是「中間出現」,pattern 自己加 ^$test 不會自動補 g,避免 lastIndex 把後續判斷帶偏。

空 pattern 是合法的(匹配空串)。帶 u / v 時,空匹配按 code point 推進,避免 UTF-16 代理對被命中兩次。這些邊界在 src/engine.ts 裏按 ECMAScript AdvanceStringIndex 實現,測試文件 engine.spec.ts 覆蓋了 flags、64KB 上限和病理 pattern 的 worker 取消。

適用場景與注意事項

適合這些情況:

  • 智能體要驗證用戶提供的正則,並給出可展示的解釋,而不是口頭保證「這段能用」
  • 從一段內存中的文本(日誌片段、表單值、模型剛生成的字符串)提取字段,而不是搜工作區文件——搜文件仍應走內置 grep
  • 需要帶捕獲組的替換,且不希望模型去拼 node -e 腳本
  • 擔心病理正則把宿主卡死,需要硬超時和輸入上限

不適合、或需要額外小心的情況:

  • 把不可信的超長輸入配上無錨點嵌套量詞。超時能終止 worker,但這次調用仍然失敗。
  • explain 當成完整的正則語義引擎。它是 tokenizer:能識別錨點、字符類、分組、量詞、轉義、交替,解釋文本是英文 meaning;複雜到超過 4,096 個節點會直接拒絕。
  • 只裝了 web profile、卻用 dsh run 做一次性任務。dsh run 默認走 headless,兩邊要分別安裝。
  • 把目錄頁或 scoped 包名理解成官方出品。維護者是 omdsh-dev,許可證文件版權人爲 2026 whiteicey,包名帶 @deepseek-ai/ 前綴是 DSH 插件常見寫法,不代表由 DeepSeek 官方發佈。

目錄頁的安全提示需要照做:插件以當前 dsh 進程的權限運行,安裝時可能執行代碼。 安裝前檢查源代碼倉庫和許可證;需要可復現安裝時固定 commit 哈希。這不是走個過場——GitHub 源安裝拿到的是源碼而不是預構建產物,信任邊界就是你本機上的 dsh 進程。

小結

dsh-tool-regex 把「對任意文本做正則」收成一個確定性工具:test 判斷、find 提取、replace 安全替換、explain 靜態解釋。和讓模型現寫腳本再丟給 bash 相比,它少一層正確性風險;和內置 grep 相比,它不依賴文件。真正要看的是邊界:worker 1 秒硬超時、輸入 / pattern / 輸出上限,以及 explain 不執行代碼。

目錄頁:https://deepseek-harness-plugin.com/zh-CN/plugins/dsh-tool-regex/

GitHub:https://github.com/omdsh-dev/dsh-tool-regex

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

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

小夜