前言¶
用 DSH 給編程題做助教時,常見的兩個失敗不是模型不夠聰明,而是流程上沒有約束:一是憑印象下結論,比如「你這裏下標寫錯了」,其實沒跑過學生代碼;二是忍不住給答案,學生說一句「就給我看一眼完整代碼」,模型就把正解貼出來了。這兩件事靠自覺擋不住,靠一條系統提示也擋不住。
buguoshixc/dsh-doctor 的思路是把回答鏈路拆成工具:歸因必須來自一次真實執行的裁決結果,面向學生的回覆發出前必須先過一道門控,門控判定「能跑出結果」或「與正解高度相似」就攔下來。它不是又一個提示詞模板,而是插進 DSH 工作流裏的插件。
這是什麼¶
插件維護者是 buguoshixc,分類爲工作流,採用 MIT 許可證(package.json 裏聲明 "license": "MIT")。一句話定位:給 DSH 桌面端加一個「診斷模式」agent 預設,外加一個零第三方依賴的 Python 判定核,讓模型在回答之前先跑代碼拿證據,用蘇格拉底式提問帶學生自己修。
作者給出的自我界定很明確,是這幾樣;不是另外幾樣:
| 是 | 不是 |
|---|---|
| DSH 插件(bundle 加 agent preset) | LLM 應用;不調用任何模型 API |
| 離線判定核(Python 3.11+ 標準庫,零第三方依賴) | 判題雲服務;不接 judge0、不聯網 |
| 兩個原生工具加一份教學技能加一個預設 | Web 平臺;沒有前端、沒有數據庫、沒有 HTTP 服務 |
| 一個答案門控 | 安全沙箱;本地執行只有超時、內存上限、盡力禁網 |
架構叫「架構 C」:會話裏的模型負責出用例和正解,工具只負責裁決。判定核不生成任何東西,也不需要 API key,只做三件確定性的事——跑代碼、比輸出、擋答案。
安裝與啓用¶
官方安裝命令來自 README 和 docs/INSTALL.md,裝到桌面 profile:
dsh plugin --profile desktop add github:buguoshixc/dsh-doctor
裝完必須重啓 DSH,然後在新建會話的預設選擇器裏選「診斷模式」。有兩種等價做法:把 docs/INSTALL-PROMPT.md 裏的 prompt 粘給 agent,讓它自己體檢加安裝加驗收;dsh plugin 會把參數轉發給 profile 目錄裏的 pnpm,GitHub 短名解析、緩存、鎖文件都是 pnpm 的行爲。
前置條件按 docs/INSTALL.md 的檢查項:
| 依賴 | 要求 | 檢查命令 |
|---|---|---|
| DSH | 桌面版 0.2.1-rc.3 及以上(0.3.0 以下) |
dsh --version |
| Python | 3.11+,且能被 python 或 python3 找到 |
python --version |
| Git | 從 GitHub 安裝時需要 | git --version |
package.json 裏寫明的版本約束是:
"engines": { "node": ">=22.0.0", "dsh": ">=0.2.1-rc.3 <0.3.0" }
本包沒有構建步驟,純 ESM 加純 Python,不需要 prepare 腳本。Python 找不到時典型報錯是 E_NO_PYTHON,README 給的做法是用 DSH_DOCTOR_PYTHON 寫死解釋器絕對路徑,或確認它裝在 PATH 裏,Windows 下 py -3 是最後一個候選。
兩個工具¶
插件註冊兩個原生工具,JSON Schema 與執行體在 lib/tools.mjs。
doctor_judge:唯一裁決器¶
只要學生給了代碼加題目,就先調它。不跑就下結論等於編造證據。
參數(來自 README):
problem 題面全文(Markdown,含示例)
code 學生代碼全文
cases 用例集 JSON,形如 {"func_name":"…","cases":[{"case_id","input","expected","kind"}]}
refs 1~4 份正解代碼,會交叉校驗
func_name / timeout_ms / memory_mb 可選
它先跑正解做自校驗:任何一份正解與 expected 不符,立刻返回 verdict=REF_REJECTED,不執行學生代碼、不進入歸因。這樣「模型自己寫錯正解」不會變成「學生被冤枉」。
成功路徑返回 verdict、compile、ref_status、failure_distribution、counterexample、category / category_label、confidence 和 reason。README 給了一個 lc-053-maximum-subarray 邊界錯誤樣本的節選:
{
"verdict": "WA",
"phenotype": "WA",
"compile": { "passed": true, "errors": "" },
"ref_status": "trusted",
"failure_distribution": { "total": 5, "failed": 1, "pattern": "boundary_only" },
"counterexample": {
"case_id": "b1",
"input": [[-3, -2, -5]],
"expected": -2,
"actual": 0,
"kind": "boundary"
},
"category": 3,
"category_label": "邊界處理錯",
"confidence": "high",
"reason": "1/5 條用例失敗,失敗模式 boundary_only,歸類爲第 3 類(邊界處理錯)"
}
counterexample 裏寫死的 case_id、input、expected、actual,是模型唯一可以寫進回覆的事實。字段全表見 docs/SCHEMA.md。
doctor_gate:回答門控¶
任何面向學生的回覆,發出之前必須調它。三層判定:
1、layer1 能跑即攔:抽出回覆裏的代碼片段真的執行,能跑出結果就判 block。只看語法不夠——while 左指針 < 右指針: 語法合法,但它跑不起來,是合格僞代碼。
2、layer2 相似度防漏:與正解做 AST 結構相似度(0.55 權重)加 token Jaccard(0.45 權重)加權;>=0.75 判 downgrade-to-level2,>=0.60 打 suspect=true 放行但標記。
3、fail-closed:內容像代碼卻分析不了,一律攔或降級,絕不當成「安全」。
返回裏的 action 只有 pass 和 block,downgrade-to-level2 落在 recommended_level 和 reasons 裏。README 給的樣本:
{
"action": "block",
"reason": "layer1 判定爲可運行代碼(定義了 twoSum)",
"layer1": { "runnable": true, "detail": "定義了 twoSum" },
"layer2": { "similarity": 1.0, "ast_sim": 1.0, "token_sim": 1.0, "suspect": true },
"leaked_fragments": ["def twoSum(nums, target):\n # 正解 B:哈希表一次遍歷,O(n)\n …"],
"recommended_level": 1,
"reasons": ["extract:found_fragment", "layer1:runnable"]
}
「診斷模式」預設與技能手冊¶
預設 id 是 diagnose,名稱是「診斷模式」。README 給了它的聲明方式與組合說明,另附一份舊格式的等價描述(presets/diagnose/,說明裏寫 DSH 0.2.1 起不讀該目錄,留作對照):
| 項 | 內容 |
|---|---|
| persona | 中文助教人格;鐵律:過 gate、不給完整代碼、只用工具證據、REF_REJECTED 時先修不歸因 |
| 聲明的工具面 | bash(POSIX)/ pwsh(Windows)、read/write/edit、glob/grep、skill |
| 插件自帶工具 | doctor_judge、doctor_gate |
| 技能 | doctor,只在預設裏可見:includeDefaultRoots: false 加隨包目錄 |
| 繼承的 host 工具 | present、ask_user_question 等,由 profile 決定 |
真正的「度」在 presets/skills/doctor/SKILL.md 這份教學手冊裏。技能不是裝飾,它是提示工程的一部分,作用是讓模型每次會話都讀到「先跑代碼、再組織回覆、再過門控」這個順序。另外預設不到 {{cwd}} 這類提示變量——DSH 0.2.1 起在 preset persona 裏會整輪失敗,只用 {{model}}。
怎麼驗證裝對了¶
docs/INSTALL.md 給的驗收流程很具體:新建一個「診斷模式」會話,貼一段有明顯錯誤的代碼,例如:
def maxSubArray(nums):
best = 0
for x in nums:
best = max(best, best + x)
return best
期望的模型行爲按順序是:先寫一份自己的用例集和正解,調用 doctor_judge;回覆裏引用具體的反例,case_id、輸入、期望值、實際值都要有;組織回覆後調用 doctor_gate,action 不是 pass 就改寫重試;最終回覆裏沒有完整可運行代碼,而是一到兩個引導性問題。
只要「工具調用」面板裏出現了 doctor_judge 和 doctor_gate,說明插件裝對了。如果模型壓根沒調工具,說明技能沒被加載或它沒讀技能。
想覈對包本身的質量,README 給的命令是:
bash scripts/verify.sh
它跑環境自檢、零第三方依賴掃描、Python 單元測試(README 寫的是 93 個)、Node 單元測試(README 寫的是 22 個,含用本機真實 @deepseek-ai/dsh-tools 校驗 schema 的契約測試)、三題 fixture 演示(AC/WA/CE/TLE/REF_REJECTED 加門控三種動作)、包元數據契約、stdout 純淨性,全綠退出碼 0。
包的暴露面和依賴關係也值得看一眼。files 白名單包含 lib/、doctor_core/、presets/、locale/、icon.svg、cordis.patch.yml、scripts/verify.sh 和部分 docs/;三個 peer dependency 都標了 optional: true:
"peerDependencies": {
"@deepseek-ai/dsh-tools": ">=0.2.1-rc.3 <0.3.0",
"@deepseek-ai/dsh-agent-preset": ">=0.2.1-rc.3 <0.3.0",
"@deepseek-ai/cordis": ">=4.0.0 <5.0.0"
}
誠實的邊界¶
README 自己寫了幾條不保證,這些不是免責聲明式的套話,而是設計上的固有代價。
正解由模型生成,這是架構 C 的固有代價。 只能做到「正解與題面示例不符就終止」,做不到「保證正解正確」。所以 doctor_gate 是最後一道防線,不是唯一一道。
本地執行不是安全沙箱。 只有 5 秒牆鍾超時、256MB RLIMIT_AS,以及盡力而爲的網絡屏蔽(替換 socket.socket)。Windows 上 resource 模塊不存在,內存上限不生效,會帶 memory_limit_not_enforced 標記。真正的隔離要靠 OS 級沙箱。
只支持 Python。 C++ 與 Java 的 wrapper、原平臺的 tree-sitter 相似度都沒搬過來。
「必須先過 gate」是提示工程,不是機制。 工具能攔住被送進來的回覆,攔不住模型乾脆不調用它。降低風險的辦法是技能裏寫死步驟,加上 persona 裏的第一條鐵律。
適用場景與注意¶
適合的情況寫清楚:
- 編程題助教、在線判題輔導,需要「先跑再答」的流程約束;
- 想用確定性執行證據替代憑印象下的歸因;
- DSH 桌面版版本在
0.2.1-rc.3到0.3.0之間,且本機有 Python 3.11+。
限於當前的資料,下面這些需要讀者在裝之前自行確認,資料裏沒有給出結論:
- 多用戶併發場景下的行爲,資料沒有提;
- 非 Python 語言、以及需要更嚴格隔離的執行環境,README 明確說不支持;
- 正解正確性對應的模型能力上限,插件本身只能做到
REF_REJECTED終止,不能保證; - 這個插件以當前 DSH 進程的權限運行,判定核會真的執行回覆裏抽出來的代碼。安裝前應打開 GitHub 倉庫和
docs/SCHEMA.md、docs/PLUGIN_API.md、docs/EXTRACTION.md覈對一遍源碼與許可證。社區目錄頁是獨立站點,與 DeepSeek / 幻方無官方從屬關係。
結尾¶
dsh-doctor 的價值不在多一個工具,而在把「先跑代碼再回答」「答案由門控擋不由自律擋」寫進了插件。對做編程題助教的人來說,它比單純寫一條系統提示更硬的地方是:歸因必須帶 case_id 和實際輸出,完整可運行的代碼一定被 doctor_gate 攔下。代價是正解仍由模型給出,本地執行也不是安全邊界。
目錄頁:https://www.skillhub.cn/plugins/buguoshixc/dsh-doctor
GitHub:https://github.com/buguoshixc/dsh-doctor