dsh-agent-loop-experiment:給官方 agent loop 加一層收斂策略

前言

DSH 的 @deepseek-ai/dsh-agent-loop 負責「調模型、跑工具、重複」這條主循環。它的行爲是通用的:沒有步驟預算概念,模型在長任務裏反覆重讀、重新生成整份文件、用 shell 參數塞大段腳本,循環會一直配合下去。

dsh-agent-loop-experiment 就是針對這一現象的隔離實驗。它保持官方循環實現字節級不變,只在公開提示詞與 agent 鉤子之上添加收斂策略,並作爲 bundle 補丁替換官方循環條目。項目由 Jaylor-Wang 維護,MIT 許可,固定支持 DSH 0.2.2-rc.1。

下面介紹它的能力、安裝方式、配置與驗證流程。

這是什麼

一層收斂策略實驗包,同時是一個可直接替換官方循環的 bundle。

它對應官方循環的四件事:

  • 運行時策略(runtime fingerprinting):觀察操作指紋,攔截連續無進展的重複調用與過大的 shell 參數。
  • 有限恢復(finite recovery):爲本輪原生 write 的大段寫入失敗提供一次短引用恢復,只移除無效的 justification 參數。
  • 文件改動防護(file mutation guards):識別整文件重寫與大文件重寫風險,按 observe / enforce 分級。
  • 軟工具要求(soft tool requirements):提醒模型使用預期工具,攔截繞路副作用。

官方循環實現本身不被修改,src/index.js 掛載一個官方循環、在相同作用域掛載策略;替換功能由 dsh.bundle.patch 與 src/replacement.js 提供,替換類繼承官方循環。

版本與包結構

包名爲 dsh-agent-loop-experiment,版本 0.2.2-rc.1,標記 private,license 爲 MIT。engines.dsh 精確約束 0.2.2-rc.1,engines.node 要求 >=24.0.0。peerDependencies 裏的 @deepseek-ai/dsh-* 系列均對齊 0.2.2-rc.1。

入口通過 exports 暴露四段:

入口 用途
. 掛載官方循環 + 策略的包入口
./baseline 未修改的官方基線
./policy 只加載收斂策略
./replacement 使用官方平鋪配置的單一服務替換入口

這是編譯產物包,實驗層使用原生 ES module,無需編譯。README 上標有 63 個測試通過。

收斂策略配置

策略配置集中在 src/convergence.js。獨立入口默認關閉策略,作爲 bundle 安裝時由 bundle 配置明確開啓。

配置 默認值 含義
enabled false 顯式開啓收斂策略
softStepBudget 8 完成這麼多模型步驟後,在下一次已需要的請求中提醒一次
recoverFailedWrites true 大段寫入參數錯誤的短引用恢復,可獨立關閉
runtimePolicy.mode enforce off / observe / enforce,enforce 下攔截無進展與大 Shell Payload
runtimePolicy.noProgressLimit 2 相同命令指紋連續重複的容忍閾值
runtimePolicy.recoveryAttemptLimit 1 恢復引用可嘗試次數上限
runtimePolicy.minLargeWriteBytes 8192 大寫入字節閾值
runtimePolicy.maxShellCommandBytes 4096 Shell 命令行字節上限(防 spawn ENAMETOOLONG)
runtimePolicy.maxInlineScriptBytes 512 單次內聯腳本字節上限(python -c / node -e)
fileMutationPolicy.mode observe off / observe / enforce
fileMutationPolicy.minLargeWriteBytes 8192 大文件重寫閾值(字節)
fileMutationPolicy.reminderLimit 1 重寫風險提示次數上限
softToolRequirement.enabled true 軟工具要求管理器開關
softToolRequirement.reminderLimit 1 每項軟要求提醒次數上限
softToolRequirement.maxViolations 2 違反後容忍並阻斷繞路的最大次數

軟工具要求需要宿主通過 SoftToolRequirementManager.addRequirement(session, options) 按任務顯式激活,要求狀態只保留到當前 turn 結束。拒絕結果爲帶 code、nextAction 與 retryable 的 JSON。當前沒有自動強制 tool choice,真實模型誤拒絕率也尚未驗證,enforce 使用前需完成 A/B。

安裝與啓用

下面是 EXPERIMENT.md 給出的官方插件管理命令。它使用 link: 前綴指向本機已存在的 DSH 安裝目錄,路徑按你自己的機器替換,不要照搬示例裏的盤符。

dsh plugin --profile web add "link:E:/Github/dsh-agent-loop"

前置步驟:在本包目錄下執行

npm run setup:local
npm test
npm run inspect:profile

setup:local 從本機 DSH 安裝複用同版本依賴,缺失的依賴創建本地目錄鏈接,不訪問註冊表、不寫宿主安裝。已有依賴版本不符時會拒絕,不會自動覆蓋。運行時可以再執行 npm run inspect:profile。它只在內存中合成替換後的配置,不啓動服務、不讀憑據、不改 profile。檢查通過時可看到原循環被禁用、新循環啓用、原配置保留、0 警告。

inspect:profile 不通過就不要切換。DSH 的 config 是整體替換,所以覆蓋片段必須一併保留 agents 和 maxParallelToolCalls:

- id: dsh-agent-loop-experiment:loop
  name: dsh-agent-loop-experiment/replacement
  config:
    agents: []
    maxParallelToolCalls: 10
    convergence:
      enabled: true
      softStepBudget: 8

確認後啓動:

dsh web

這是服務端循環替換,不需要重建 Web 前端,也不能只靠刷新頁面生效。需要停止 dsh web、安裝鏈接、再重啓進程並新建會話。安裝後在包目錄再跑一次 npm run inspect:profile,確認 bundleAlreadySelected 爲 true、activeLoopCount 爲 1,再啓動。

回退方式:先停止 dsh web,移除手動添加的覆蓋片段,然後

dsh plugin --profile web remove dsh-agent-loop-experiment
dsh web

bundle 移除後禁用官方循環的補丁也會消失,原 agent-loop 條目自動恢復。如果 profile 裏另外寫了 id: agent-loop / disabled: true 的個人覆蓋,也要移除或改爲 false,避免個人層繼續禁用官方循環。

典型用法

接入獨立宿主(不使用 bundle):

import experiment from 'dsh-agent-loop-experiment';

await ctx.plugin(experiment, {
  loop: { maxParallelToolCalls: 10, agents: [] },
  convergence: { enabled: true, softStepBudget: 8 }
});

獨立宿主須提供官方 agents、sessions、llm、tools、systemPrompt 和 sessionProjections 服務,並配置工具執行器與模型適配器。不要在已有官方循環上再掛載包入口。

已經存在官方循環的獨立宿主,可以只加載策略,在 agent setup 的作用域掛載即可隻影響該 agent:

import convergence from 'dsh-agent-loop-experiment/policy';

驗證線上真實行爲之前,先用固定響應跑離線對照:

npm run experiment

它使用固定模型響應腳本,預期兩組都是 4 次請求、4 次工具調用,區別是收斂組追加一次提醒。這驗證策略接線、正常完成與前綴保留,不能證明真實模型會少走步驟。

真實對照需要複製 experiments/live.example.json 爲 experiments/live.local.json,填寫自己的模型、協議和 endpoint,兩組配置保持一致。憑據只通過 apiKeyEnv 指定的環境變量傳入,不寫入配置。默認僅驗證初始化,不發模型請求:

npm run experiment:live -- --config experiments/live.local.json --variant baseline
npm run experiment:live -- --config experiments/live.local.json --variant convergence

準備好發送模型請求後再加 --run。每條命令啓動新的獨立進程與內存會話,不改動 GUI,也不恢復當前會話。

策略的實際行爲與邊界

開啓後,從第一步開始向提示詞加入固定指導,固定指導不隨步驟變化。內容主要包括:輸出大段內容前先決定落盤路徑;新文件用原生 write,計算優先複用已有工具或寫入可複用腳本再按路徑執行;完整文件和大腳本不放進 node -e、python -c、pwsh -Command 等 shell 參數;獨立讀取、搜索和檢查可在同一響應內批量調用,並保留依賴順序與獨佔屏障;局部修改優先複用已有文件內容,只用 edit 和唯一匹配修改,不重新輸出整份文件;資源使用後清理、保留順序。

達到軟預算時,每輪至多向歷史尾部追加一次提醒,提醒由官方循環提交。預算按本輪已接納的 step/start 計數,重試不重複計步,不跨整個會話累計。短任務不出現提醒是預期。

這些指導適用於代碼修改、數據處理、文檔與內容生成等任務,沒有針對特定任務名、文件類型、計算輪數或輸出大小的啓發式攔截。只讀問答與審查不會因此獲得寫入授權。

明確不做的部分:不限制總步驟數、不自動宣佈完成、不修改 provider/model/reasoningEffort、不合具有依賴的調用、不改寫已有工具結果。自然結束、max-tokens、concludeTurn 與拒絕都保持官方行爲。裁剪仍由 dsh-tool-result-trimmer 負責。

大段寫入恢復的觸發條件很窄:只接受本輪原生根 write、8 KiB 至 1 MiB 的完整內容,且錯誤精確爲 invalid escalation: justification is only valid together with sandbox_permissions;原調用必須沒有 sandbox_permissions,只允許 file_path / content / justification 三個參數。插件不解析 shell,也不自動重試。符合條件時追加一次 source.kind 爲 loop-write-recovery 的通知,模型可調用 retry_failed_write({"call_id":"原調用 ID"}) 複用原路徑與逐字相同的內容。可以在 convergence 下用 recoverFailedWrites: false 關閉這個入口。

如果宿主使用 complete 系統提示,普通提示詞 section 會按官方規則被覆蓋,收斂指導可能不進入系統提示。運行中開啓或關閉會改變當時的提示詞,對照實驗應從全新會話開始;本實驗未承諾熱切換時緩存前綴不變。

適用場景與注意

適合:已經在 DSH Web profile 或獨立宿主上跑長任務、想對照實驗收斂策略對提示詞與步驟數的實際影響的人;以及想保留官方循環、只疊加一層可選策略的維護者。

注意:

  • 插件以當前 DSH 進程的權限運行,可以讀寫該進程工作目錄與憑據環境。安裝前先讀 src/convergence.js、src/replacement.js、src/failure-recovery.js 與 cordis.patch.yml,確認補丁範圍。許可證是 MIT。
  • 安裝命令裏 link: 前綴指向本地目錄,私有包可本地安裝、不需要發佈到 npm。不要在包內另跑 npm install 或 pnpm install,也不要僅爲消除 peer 警告補裝宿主已有的 Cordis、React。
  • 固定支持 0.2.2-rc.1,宿主升級後需重新執行 setup:local、相關驗證與 inspect:profile,版本不符先處理兼容性。當前結果不構成對未來版本的兼容保證。
  • 需要確保 profile 裏只有一個循環服務啓用。同時存在 agent-loop 與實驗條目會導致衝突。
  • 把 enabled 改爲 false 可保留替換循環、只關閉收斂策略,適合做同進程對照;更乾淨的對照是回退到官方循環後再開。

目錄頁與倉庫:

  • https://www.skillhub.cn/plugins/Jaylor-Wang/dsh-agent-loop-experiment
  • https://github.com/Jaylor-Wang/dsh-agent-loop-experiment
羽毛球分组比赛记分
小程序二维码

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

小夜