前言¶
在 DSH 裏編排智能體時,經常需要“先確認條件再動手”:上一輪是否報錯、用戶是否確認了某個方案、測試是否通過。把判斷寫進提示詞,判斷過程會佔用主上下文;判斷服從規則、命令參數等還可能改寫後續請求的緩存前綴。dsh-if 把這件事收成一條自定義 /if 命令:判斷交給一個繼承當前會話上下文的 fork 子代理,條件成立時才把 /if 下方的指令作爲一條普通用戶消息發給主 agent,不成立則什麼都不做。
下面介紹它的能力、安裝、用法與需要注意的約束。
這是什麼¶
- 插件名:
dsh-if,倉庫tlewa/dsh-if,npm 包名dsh-if。 - 維護者:TLEWA,許可證 MIT。
- 分類:工作流;社區目錄頁登記爲 GitHub 1 stars。
- 定位:給 DeepSeek Harness 加一條
/if斜槓命令,用 LLM 判斷一個條件,成立時才發送指令。
判斷器是一個 fork 子代理,繼承當前會話的工具、system prompt 與消息歷史,只在末尾追加一條判斷指令。判斷請求與主會話下一次請求共享逐字節一致的 tools → system → messages 前綴,因此可以複用 provider 的 prompt cache / KV cache。
涉及英文原文的表述摘自該插件的 GitHub README;目錄頁與維護者信息來自其社區目錄條目。
核心功能¶
下面按 README「功能」一節逐條列出,均爲已覈實能力。
- 上下文條件判斷。判斷器繼承當前會話的工具、system prompt 與歷史消息,按條件回答
YES或NO。 - 複用 KV 緩存。fork 子代理只追加一條尾部 user 消息,前綴與主會話一致,可命中 provider 前綴緩存。
- 只讀判斷。工具目錄保持不變,執行期 guard 只放行
read/glob/grep/web_search/web_fetch/skill等只讀工具,寫入、修改、執行命令、子代理一律拒絕。 - 與普通消息同隊列。
/if作爲一條普通消息進入輸入框上方的隊列面板,可編輯、刪除、↑ 插話;回合開始時才判斷,成立就把這條消息原地換成指令。 - 兩種排隊模式。默認
message,即與普通消息同隊列;background保留 0.2.x 行爲,命令立即返回,判斷在後臺跑。 - 條件成立才發送。只有
YES才把指令作爲用戶消息發給主 agent;NO完全不觸發主 agent。 - 判斷不進上下文。判斷在獨立子會話完成,不寫主會話事件,不調用
agent.inject。 - 命令不泄露參數。
recordInput: false,log-only 的command/run也不記錄條件或指令。 - 多行條件。第一行是條件,其餘行是指令;條件有多行時用單獨一行
---分隔。 - 自動回退。host 沒有可繼承上下文的 fork provider 時,回退到一次性
ctx.llm.stream+ 約 24k 字符純文本記錄。 - 防止誤發。條件爲空、指令爲空、判斷輸出不是
YES/NO、或判斷超時,都返回錯誤且不發送。
安裝與啓用¶
環境要求:
- DSH
0.2.1-rc.5或更新版本。 - Node.js
20.3或更新版本(使用AbortSignal.any/AbortSignal.timeout)。
從 npm 安裝(推薦)¶
- 打開側邊欄「插件」頁 →「安裝插件」。
- 輸入包名並確認:
dsh-if
- 安裝完成後重啓 DSH(host 插件在 profile 啓動時加載)。
固定版本:
dsh-if@0.3.4
命令行等價寫法:
dsh plugin --profile desktop add dsh-if@0.3.4
從 GitHub 安裝¶
lib/ 是可直接運行的源碼,不需要本地構建:
https://github.com/TLEWA/dsh-if
固定到標籤或 Release 附件:
dsh plugin --profile desktop add github:TLEWA/dsh-if#v0.3.4
https://github.com/TLEWA/dsh-if/releases/download/v0.3.4/dsh-if-0.3.4.tgz
從源碼安裝¶
git clone https://github.com/TLEWA/dsh-if.git
cd dsh-if
npm test
dsh plugin --profile desktop add .
重啓 DSH 後,在輸入框輸入 /if,斜槓面板會出現該命令。
典型用法¶
基本形式:第一行是條件,其餘行是指令。
/if 1+1=2
請只回復 OK
條件本身有多行時,用單獨一行 --- 分隔:
/if 用戶已經確認方案 A
並且測試已經通過
---
請開始執行方案 A
也可以只寫一行條件和一個單行指令,/if 後面的第一個換行就是分隔點。
分隔符優先:只要出現過單獨一行的 ---,它右邊的部分一定全是指令。所以指令正文裏不要單獨成行寫 ---(Markdown 水平線),否則它前面的內容會被當成條件的一部分。
判斷語義¶
- 判斷由當前會話配置的模型完成,不是 JavaScript 或數學求值器。
1+1=2只是最小示例,條件可以是“用戶是否已經確認方案”“上一條回覆是否包含錯誤”等。 - 判斷器只被要求輸出
YES或NO;輸出裏沒有可識別結果時按判斷失敗處理,不發送指令。 - 判斷器可以只讀地查看文件、檢索代碼來確認事實,但不能做任何修改。
- 條件需要的信息在當前上下文裏找不到、或條件含糊無法確定時,判爲不成立:寧可不動,也不誤發指令。
- UI 只顯示通用結果,不回顯條件、指令或判斷原文。
工作方式¶
README 把實現拆成九步,摘要如下。
- 通過
ctx.effect(() => ctx.commands.register(...))註冊/if,並設置recordInput: false;註冊掛在插件 fiber 上,停用時一併註銷。 - 入隊。
message模式把原文/if <條件>\n<指令>作爲普通 user 消息agent.followup()到會話隊列,進的是宿主 durable inbox,客戶端排隊面板照常顯示、可編輯、可刪除、可插話。 - 輪次邊界攔截。回合開始時宿主按
agent/pre-stepwaterfall 領取這批消息,插件把以/if開頭的條目挑出來先在原地判斷:成立就把 content 換成指令,不成立就從批次刪除。判斷失敗時該條同樣刪除,並在會話裏記一張「【/if 未執行】」錯誤命令卡片,可用卡片右側「取回 /if」一鍵放回。 - 首選 fork 子代理判斷。用
ctx.subagents.getProvider('fork')取 provider(要求inheritsParentContext === true),再以startActivation({ provider: 'fork', childId, request: { parent, agentOptions, prompt }, delivery: 'caller' })啓動判斷子會話。 - 丟掉繼承來的待辦。fork 的種子會帶回父會話入隊的 next-turn 消息和未領走的 next-step 插話,插件在拿到子 agent 時把這兩條隊列中除自己判斷 prompt 以外的待辦全部
remove,父會話隊列不受影響。 - 執行期只讀限制。
ctx.tools.guard僅對判斷子會話生效,只讀工具放行,寫入、命令、子代理被拒;工具目錄不裁剪,緩存前綴不變。 - 判斷超時 60 秒;只有
YES時把指令作爲帶id和role: 'user'的已識別消息交給主 agent。 - 回退路徑。宿主沒有可繼承上下文的 fork provider 時,
historyTranscript()讀取agent.session.deriveMessages(),只保留 user / assistant / tool 消息,生成最多約 24k 字符純文本記錄(每條最多 3k 字符,保留頭尾),再用ctx.llm.stream()發起一次性判斷請求;該請求不帶主會話sessionId,命中不了主緩存。 background模式跳過上面的入隊與輪次攔截兩步,命令立即返回“已排隊”,判斷由後臺任務完成;多個/if按發送順序串行判斷。
配置¶
配置寫在 profile 的 cordis.patch.yml:
# profile 的 cordis.patch.yml
- id: if-command
name: 'dsh-if'
config:
mode: message # 默認。background = 0.2.x 的老行爲
mode: message(默認):/if先作爲普通用戶消息排隊,輪次開始時再判斷。條目內容是/if <條件>+ 指令原文,出現在隊列面板裏,編輯它即等同於改條件與指令。mode: background:0.2.x 行爲。命令立即返回“已排隊”,判斷交給後臺任務,不佔隊列位置。判斷失敗時會在會話裏記一張if命令卡片說明原因。
也可以不改文件:插件 → dsh-if → 配置 裏有「判斷方式」下拉框,切換即時生效(mode 聲明爲 volatile 字段,設置頁直接改寫運行中的配置)。插件用 Config(@deepseek-ai/schemastery)描述該字段,mode 缺省即爲 message,未知字段被忽略。
KV 緩存與上下文隔離¶
這部分是刻意的設計約束,不是可選項。
/if命令、條件、指令、判斷 prompt、判斷結果都不寫入主會話;command/run和command/done都是 log-only 事件。- 判斷在 fork 子代理裏完成,tools、system prompt、歷史消息全部繼承,只在末尾追加一條 user 消息,因此前綴與主會話下一步逐字節一致,provider 的 prefix cache / KV cache 可以直接複用。
- 判斷子會話是獨立會話,不追加主會話的 session 事件,只讀歷史;工具目錄不裁剪,裁剪反而會改變前綴、破壞緩存。
- 代價是透明的:每次判斷都會把整段上下文重發一次,token 計數按全量算,命中緩存的部分按 provider 的緩存價計費;會話越長,單次判斷的絕對 token 數越大。
- 條件不成立時主會話沒有任何變化;條件成立時唯一改動是在歷史末尾追加一條普通用戶消息,已有前綴不變,不會調用
agent.inject,也不會編輯、替換或刪除已有 session 事件。
適用場景與注意¶
適合需要在主流程裏插入條件門控的場景:方案確認後執行、測試通過後再繼續、上一輪有錯時再補一條指令。判斷會消耗一次上下文重發,長會話下絕對 token 數不小,適合低頻、條件明確的門控,不適合把每個判斷都鋪到高頻路徑。
注意兩點:
- 插件以當前 dsh 進程的權限運行,相關判斷邏輯在
lib/中是可直接運行的源碼,安裝前建議檢查源碼與許可證;該插件爲 MIT 許可。 - 判斷依賴宿主提供的 fork provider 與
ctx.tools.guard,缺失時自動回退到 transcript 判斷,該退路命中不了主緩存。其他 host 能力邊界請對照 README 的「兼容性」一節。
結尾¶
dsh-if 的價值在於把“判斷條件”和“執行指令”分開:判斷髮生在獨立子會話,不污染主上下文,成立時只追加一條普通消息,從而保住主請求的可複用前綴。它定位明確、約束寫在明面上,適合需要條件門控的 DSH 工作流。
- 目錄頁:https://www.skillhub.cn/plugins/TLEWA/dsh-if
- GitHub:https://github.com/TLEWA/dsh-if
社區目錄是獨立站點,與 DeepSeek、幻方無官方從屬關係。